Skip to content

Refactor generic Rosenbrock perform_step! to converge with RosenbrockCache#3100

Closed
ChrisRackauckas-Claude wants to merge 1 commit intoSciML:masterfrom
ChrisRackauckas-Claude:refactor-generic-rosenbrock-converge
Closed

Refactor generic Rosenbrock perform_step! to converge with RosenbrockCache#3100
ChrisRackauckas-Claude wants to merge 1 commit intoSciML:masterfrom
ChrisRackauckas-Claude:refactor-generic-rosenbrock-converge

Conversation

@ChrisRackauckas-Claude
Copy link
Copy Markdown
Contributor

Summary

  • Replace macro-generated perform_step! code (gen_perform_step, gen_constant_perform_step, gen_initialize) with a shared loop function _rosenbrock_stage_loop!() used by both GenericRosenbrockMutableCache and RosenbrockCache
  • Add GenericRosenbrockConstantCache abstract type and _ks() accessors for dispatch on generic caches
  • Store array-based tableaus via _make_rosenbrock_tableau() instead of named-field structs, enabling uniform tab.a[i,j] access across all methods
  • Fix existing bug where generated code never persisted cache.linsolve = linres.cache
  • Net -60 lines: eliminates ~230 lines of code generation while converging two independent implementations into one shared loop

Details

The generic Rosenbrock (W) methods previously used macro-based code generation to produce specialized perform_step! for 21 algorithms across 5 macro families (@ROS2, @ROS23, @ROS34PW, @Rosenbrock4, @RosenbrockW6S4OS). Meanwhile, RosenbrockCache (Rodas4/5/6P) already had a clean loop-based perform_step! with an identical inner loop structure. This PR converges them.

Key design decisions:

  • _rosenbrock_stage_loop! handles stages 2..s, parameterized by tab_a, dtC, dtd, and stage_limiter! to accommodate differences between generic (no stage limiter, locally allocated dtC) and Rodas (stage limiter, pre-allocated dtC)
  • Stage 1 stays in each perform_step! because the first dolinsolve call has different kwargs
  • Accepts one extra f evaluation per step for 6 Rosenbrock4 algorithms (previously the a4j=a3j optimization avoided this), since the linear solve dominates cost
  • Only the inplace (mutable cache) version shares the loop; the non-inplace version remains separate due to fundamentally different APIs (dolinsolve vs W\b)

Test plan

  • All 26 algorithms pass smoke tests (both inplace and out-of-place)
  • Pkg.test("OrdinaryDiffEqRosenbrock") passes — convergence tests for all 21 generic + all Rodas methods

🤖 Generated with Claude Code

methods where a4j=a3j) into a properly-sized, type-converted tableau suitable for the
generic loop-based `perform_step!`.
"""
function _make_rosenbrock_tableau(raw_tab::RosenbrockAdaptiveTableau, ::Type{T}, ::Type{T2}) where {T, T2}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need any of this? Can't we just port these methods to the RosenbrockTableau directly?

@ChrisRackauckas-Claude ChrisRackauckas-Claude force-pushed the refactor-generic-rosenbrock-converge branch from 15201b1 to 51ca208 Compare March 16, 2026 14:26
…Cache

Replace macro-generated code (gen_perform_step, gen_constant_perform_step,
gen_initialize) with a shared loop function used by both
GenericRosenbrockMutableCache and RosenbrockCache.

Key changes:
- Add GenericRosenbrockConstantCache abstract type for dispatch
- Add _ks() accessors to get stage vectors as tuples from generic caches
- Extract _rosenbrock_stage_loop!() shared by generic and Rodas methods
- Add generic initialize!/perform_step! dispatching on abstract cache types
- Refactor RosenbrockCache perform_step to use shared loop
- Store array-based tableaus via _make_rosenbrock_tableau() instead of
  named-field structs, enabling uniform tab.a[i,j] access
- Remove gen_initialize, gen_constant_perform_step, gen_perform_step
- Strip :init and :performstep branches from all 5 macros
- Fix bug: generated code never persisted cache.linsolve = linres.cache

Net: -60 lines, eliminates ~230 lines of code generation while converging
two independent implementations into one shared loop.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas-Claude ChrisRackauckas-Claude force-pushed the refactor-generic-rosenbrock-converge branch from 51ca208 to 335565a Compare March 17, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants