Manifold analysis
Dynlib currently supports 1D manifold tracing for both discrete maps and ODEs, plus search/trace utilities for heteroclinic and homoclinic orbits of ODE models. Once you extract the manifolds (stable/unstable branches or connecting orbits) you can feed the results directly into dynlib.plot.manifold or the plotting guide in manifold plots.
1D manifold tracing
Two helpers live in dynlib.analysis.manifold:
trace_manifold_1d_map(...)for autonomous maps whose stable or unstable subspace is 1D. Stable branches require the model to expose an analytic inverse map (model.inv_rhs), while unstable branches only need the forward map (model.rhs).trace_manifold_1d_ode(...)for ODE systems; it always uses an internal RK4 integrator (independent of the Sim stepper) and traces forward (unstable) or backward (stable) in time from an equilibrium point.
Map manifolds (trace_manifold_1d_map)
Key arguments and workflow:
sim,fp: supply aSimwhose compiled model is a map plus the equilibrium you want to expand (dict or array is accepted).kind="stable"or"unstable"picks the branch. Stable mode additionally requiresmodel.inv_rhs.paramsoverride extra parameters, andboundsdefines an(n_state, 2)observation box so tracing stops once the branch leaves it.clip_marginadds a fractional buffer when integrating;seed_deltaperturbs the fixed point along the chosen eigenvector.steps,hmax,max_points_per_segment, andmax_segmentscontrol how far the sampler walks and how many segments it stores.eig_rank,strict_1d,eig_unit_tol, andeig_imag_toltune the eigenvalue selection so you can force a particular root or relax the strict-1D assumption.jac="auto" | "fd" | "analytic"picks the Jacobian strategy;fd_epssets the finite-difference step.fp_check_toloptionally verifies thatfpis still a fixed point at the provided parameters.
If Numba/JIT is available and the model was compiled with jit=True, the helper employs fast batch evaluation or preallocated fastpaths; otherwise it falls back to safe Python loops with a warning.
ODE manifolds (trace_manifold_1d_ode)
Key knobs:
sim,fp,params, andboundswork as above. Theboundsbox is respected during integration, and you can setclip_marginto buffer it whilestrict_1densures the selected eigenvector really spans a 1D manifold.dt,max_time, andmax_pointscap the internal RK4 integration.resample_h(if non-None) re-samples each branch to roughly equal arc-length spacing for cleaner plotting.seed_deltaseeds the branch along the normalized eigenvector (both positive and negative directions are traced unless the branch leaves early).- Jacobian handling mirrors the map helper (
jac,fd_eps,eig_real_tol,eig_imag_tol). Useeig_rankwhen multiple stable/unstable eigenvalues exist. fp_check_tollets you refuse to trace iffpis no longer a steady state (e.g., due to parameter overrides).
Like the map helper, the ODE tracer prefers a JIT-compiled model but runs even without Numba (with a warning about fallback).
ManifoldTraceResult
Both tracing utilities return a ManifoldTraceResult with these attributes:
kind:"stable"or"unstable".fixed_point: the equilibrium that seeded the branches.branches: a tuple(positive_side, negative_side)where each side is a list of point sequences (np.ndarrayof shape(n_points, n_state)).branch_pos/branch_neg: convenient views of the tuple above.eigenvalue,eigenvector,eig_index,step_mul: spectral information used during the trace.meta: dictionary recording the configuration that produced the result (bounds, params, dt, clip margins, etc.).
These results are directly consumable by dynlib.plot.manifold and expose branches, so you can overlay them with heteroclinic traces, time series, or other decorations (see the plotting guide).
Concrete examples:
examples/analysis/manifold_henon.pytraces the Henon map stable/unstable manifolds and renders them withplot.manifold.examples/analysis/manifold_ode_saddle.pywalks through an analytic saddle, showing how to seed both sides, check the traced curve against closed-form expressions, and plot the result.
Heteroclinic and homoclinic finder/tracer
For ODE models you can search for or trace connecting orbits without manually tweaking shooting segments. The workflow typically is:
- Call a finder to locate a parameter value (and equilibrium pair) that yields a connection.
- Use a tracer at the confirmed parameter to record the orbit.
- Plot the resulting trace alongside the source/target manifolds using
dynlib.plot.manifold.
Heteroclinic utilities
heteroclinic_finder(...)searches for a parameterparamin[param_min, param_max]whose unstable manifold fromsource_eq_guesslands near the stable manifold oftarget_eq_guess. The simplified API accepts thepreset("fast","default","precise"), awindowto constrain search, and convergence tolerances such asgap_tol(miss distance) andx_tol(parameter refinement). The return value,HeteroclinicFinderResult, contains:success: whether a valid orbit was found.param_found: the parameter value that minimized the miss distance.miss: diagnostic struct (HeteroclinicMissResult2DorHeteroclinicMissResultND) with crossing points, gap metrics, and solver status.info: auxiliary diagnostics (preset name, number of scans, etc.).- After the finder succeeds,
heteroclinic_tracer(...)records the actual connection atparam_value. You must specify both equilibria (source_eq,target_eq) and an unstable direction sign (sign_u). The tracer exposes: HeteroclinicTraceResultwith fieldst,X,meta,branches, and a booleansuccessproperty.hit_radius: controls how close the unstable segment must get to the target before stopping (default1e-2).- The same
preset/window/t_max/r_blowshortcuts plus the fullHeteroclinicBranchConfigif you need finer control.
Configuration dataclasses
The finder/tracer pairs also accept structured dataclasses from dynlib.analysis.manifold when you need deterministic control. heteroclinic_finder can take a cfg (HeteroclinicFinderConfig2D or HeteroclinicFinderConfigND) while heteroclinic_tracer accepts cfg_u, and both can be overridden with the simplified preset, trace_cfg, and keyword arguments described above.
HeteroclinicRK45Configtunes the internal RK45 integrator (dt0,min_step,dt_max,atol,rtol,safety,max_steps), which is stored on each branch config.HeteroclinicBranchConfigbundles the settings for a single manifold trace: equilibrium refinement (eq_tol,eq_max_iter, optionaleq_track_max_dist), the leave radius (eps_mode,eps,eps_min,eps_max,r_leave,t_leave_target), integration caps (t_max,s_max,r_blow), optional sections/windowed exit conditions (window_min,window_max,t_min_event,require_leave_before_event), spectral tolerances (eig_real_tol,eig_imag_tol,strict_1d), Jacobian handling (jac,fd_eps), and therkfield that points to aHeteroclinicRK45Config.HeteroclinicFinderConfig2D/HeteroclinicFinderConfigNDpair two branch configs (trace_u,trace_s) with search behavior (scan_n,max_bisect,x_tol,gap_tol,gap_fac,branch_mode,sign_u,sign_s,r_sec,r_sec_mult,r_sec_min_mult, plustau_minfor ND) and optionallyeq_tol/eq_max_iteroverrides. This full config is passed throughcfgand bypasses the simplified kwargs when present.HeteroclinicPresetpackages a branch config, RK settings, and scan parameters so you can request"fast","default", or"precise"(or create a custom preset by instantiating the dataclass yourself) instead of manually setting every field.
See examples/analysis/heteroclinic_finder_tracer.py for a complete heteroclinic hunt + plotting routine.
Homoclinic utilities
homoclinic_finder(...)searches for a parameter such that the unstable and stable manifolds of the same saddle equilibrium reconnect. It accepts the samepresetnames and simplified overrides (window,scan_n,max_bisect,gap_tol,x_tol,t_max,r_blow,r_sec,t_min_event) or a fullHomoclinicFinderConfig. The returnedHomoclinicFinderResultmirrors the heteroclinic finder (with aHomoclinicMissResultdescribing the closest hit).homoclinic_tracer(...)follows a single sign-defined unstable branch until it lands back on the saddle; it returns aHomoclinicTraceResultwhosebranchesattribute can be sent toplot.manifold. The tracer usesHomoclinicBranchConfig, allowing you to tweak RK45 tolerances, leave/return radii, and event detection guards.
Configuration dataclasses
The finder/tracer pair exposes structured configuration dataclasses for advanced tuning. homoclinic_finder accepts a cfg: HomoclinicFinderConfig while homoclinic_tracer can take cfg_u: HomoclinicBranchConfig; supplying these objects bypasses the simplified preset, trace_cfg, and keyword arguments.
HomoclinicRK45Configowns the RK45 parameters (dt0,min_step,dt_max,atol,rtol,safety,max_steps).HomoclinicBranchConfiglayers equilibrium refinement (eq_tol,eq_max_iter,eq_track_max_dist), leave-event control (eps_mode,eps,eps_min,eps_max,r_leave,t_leave_target,r_sec,t_min_event,require_leave_before_event), integration caps (t_max,s_max,r_blow), optional window constraints, spectral thresholds (eig_real_tol,eig_imag_tol,strict_1d), Jacobian handling (jac,fd_eps), and anrkfield referencing aHomoclinicRK45Config.HomoclinicFinderConfigwraps atracebranch config with search-specific knobs (scan_n,max_bisect,gap_tol,x_tol,branch_mode,sign_u) so you can control both the tracing and parameter bisection behavior.HomoclinicPresetbundles a branch config, RK settings, and scan tolerances so"fast","default", or"precise"can be passed directly as thepresetargument; you can also instantiate your own preset if those defaults are not aggressive enough.
Preset Summary:
| Name | Description |
|---|---|
fast |
Quick scan with looser tolerances for exploration. |
default |
Balance of speed and robustness for standard use cases. |
precise |
Tight tolerances, smaller steps, and longer integrations for demanding orbits. |
Both finders/tracers log diag metadata in their result meta objects so you can inspect ODE step counts, RK adjustments, and event triggers if a run fails or only barely succeeds.
Next steps
- Use
trace_manifold_1d_maportrace_manifold_1d_odeonce you know the target equilibrium and want to visualize its stable/unstable branches. Combine theirManifoldTraceResultwith reference plots in manifold plots. - Run the heteroclinic/homoclinic finder scripts from
examples/analysis/{heteroclinic_,homoclinic_}finder_tracer.pyto hunt for parameter values, then trace the orbit at the discovered parameter to create publication-ready visuals.