Skip to content

Locate the bounce event by chunked integration with the DVODE root convention - #164

Draft
krystophny wants to merge 7 commits into
mainfrom
ode-verify-events
Draft

Locate the bounce event by chunked integration with the DVODE root convention#164
krystophny wants to merge 7 commits into
mainfrom
ode-verify-events

Conversation

@krystophny

Copy link
Copy Markdown
Member

This draft PR publishes the existing committed state of ode-verify-events so the local branch/worktree can be retired after review.

Checks were not run in this cleanup operation; the branch-specific CI should provide validation.

Wire the fortnum numerical-core library via CMake FetchContent
(git@github.com:lazy-fortran/fortnum.git, pinned to a7faa3c) guarded by
if(NOT TARGET fortnum) so a parent build that already provides the target
is reused. Link the static library into neo_rt; its module directory is
exported PUBLIC, so neo_rt and the diagnostics library that links neo_rt
both see the fortnum modules.

This commit adds the dependency without changing any solver call site; the
existing DVODE path is untouched and still in use. Subsequent commits move
the orbit integrations onto the fortnum ODE solver and then drop DVODE.
Replace the DVODE calls in the two fixed-interval, no-event integrations
with the fortnum DOP853 solver:

- orbit.f90 bounce_fast: ode_solve_dop from 0 to taub, take the final
  recorded state. The fortnum status maps onto the legacy istate the
  transport caller branches on (2 success, -1 step budget exhausted, 0
  other), so dvode_error_context still fires on the exhausted-budget case
  and the public bounce_fast signature is unchanged.
- diag/diag_bounce_debug.f90 probe_bounce: ode_integrate_dop, then read
  solution%nsteps, solution%nrejected and the last solution%h into the
  diagnostic columns the scan previously filled from get_stats.
- freq.f90: drop the vode_thread_init shim. The fortnum integrator keeps
  no module-level state, so freq_thread_init has nothing VODE-specific to
  initialise.

The event-based bounce_integral and the vode dependency itself stay until
the next commit so this change is reviewable on its own.
Two defects surfaced once bounce_fast ran on fortnum DOP853 instead of
DVODE, both caught only by the CI Debug build (gfortran 13,
-ffpe-trap=zero,overflow,invalid,underflow):

- timestep_transport left ydot(7), the unused abs(B) slot, uninitialised.
  DVODE ignored the stray derivative, but DOP853 carries every component
  through its stage combinations, so the leftover denormal tripped the
  underflow trap inside dop853_step. Zero the trailing integrands the
  routine does not compute, matching what timestep already does.

- The bounceavg(3:4) perturbed-Hamiltonian integrands oscillate at the
  resonant harmonic but are driven, not fed back into the orbit, so the
  rtol error estimate barely constrains them. The unconstrained adaptive
  step grew too coarse and the oscillatory integral came out wrong (D11
  off by an order of magnitude). Drive bounce_fast through
  ode_integrate_dop with hmax = taub/200 to keep the step fine enough;
  this recovers the DVODE result to four significant figures.
bounce_integral switches from the chunked DVODE root search to the
fortnum dop853 integrator plus a post-integration event scan.

ode_problem_t carries the bounce event: event => bounce_event,
event_direction set per branch (passing crosses a full 2*pi turn in the
sign_vpar_htheta direction -> RISING for sign_vpar_htheta>0, FALLING
otherwise; trapped returns to th0 rising from below -> RISING, matching
the old (yold(1)-th0)<0 accept filter), terminal_event=.true. After
ode_integrate_dop, ode_event_scan locates the crossing and yields
t_event/y_event; the no-event branch keeps the existing diagnostic dump.

The event functions reproduce the original bounceroots zero locations:
passing g = (theta-th0) - sign*2*pi, trapped g = theta-th0.

CMakeLists drops find_or_fetch(vode) and the vode include/link/dependency.
neo_rt no longer pulls the external DVODE solver; fortnum is the sole ODE
backend. .gitignore ignores .sloptools/artifacts/.
…nvention

The fortnum migration integrated a single fixed [0, n_turns*dt] span and
scanned the recorded trace once. Two defects made 9/14 ripple golden cases
abort with no bounce event for near-separatrix passing orbits:

- The passing event was g = (theta-th0) - sign_vpar_htheta*2*pi, which roots
  at theta-th0 = sign_vpar_htheta*2*pi. When sign_vpar_htheta < 0 the orbit
  still advances theta by +2*pi, so g never crossed zero and the scan found
  nothing. Restore the old bounceroots form sign_vpar_htheta*(2*pi-(theta-th0))
  (root always at +2*pi advance) and the matching trapped form, and select the
  crossing direction from the sign of theta motion through each root.

- ode_integrate_dop has no terminal-event support, so a single fixed span both
  failed to bracket late events and integrated ~200 turns of a near-separatrix
  orbit, exhausting max_steps. Integrate in dt-sized chunks and scan after each,
  re-seeding from the chunk endpoint until the crossing is bracketed, mirroring
  the old DVODE until-event loop.

Bump fortnum to 4c560b0.
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.

1 participant