Source code for hiten.algorithms.poincare.synodic.base

"""User-facing interface for synodic Poincare sections.

This module provides the main `SynodicMap` class that serves as the
user-facing interface for synodic Poincare section detection on
precomputed trajectories. It implements a facade pattern that mirrors
the API of other return-map modules while providing specialized
functionality for synodic sections.

The main class :class:`~hiten.algorithms.poincare.synodic.base.SynodicMap` extends the abstract base class
to provide detection capabilities on precomputed trajectory data,
including support for orbits, manifolds, and custom trajectories.

"""

from typing import Generic, Literal, Optional, Sequence, Tuple

from hiten.algorithms.poincare.synodic.backend import _SynodicDetectionBackend
from hiten.algorithms.poincare.synodic.config import _SynodicMapConfig
from hiten.algorithms.poincare.synodic.engine import _SynodicEngine
from hiten.algorithms.poincare.synodic.interfaces import _SynodicInterface
from hiten.algorithms.poincare.synodic.strategies import _NoOpStrategy
from hiten.algorithms.poincare.synodic.types import SynodicMapResults
from hiten.algorithms.types.core import (ConfigT, DomainT, InterfaceT, ResultT,
                                         _HitenBaseFacade)


[docs] class SynodicMapPipeline(_HitenBaseFacade, Generic[DomainT, InterfaceT, ConfigT, ResultT]): """User-facing interface for synodic Poincare section detection. This class provides a facade that mirrors the API of other return-map modules while specializing in synodic Poincare section detection on precomputed trajectories. It does not propagate trajectories; callers supply them explicitly through various input methods. Parameters ---------- map_cfg : :class:`~hiten.algorithms.poincare.synodic.config._SynodicMapConfig`, optional Configuration object containing detection parameters, section geometry, and refinement settings. If None, uses default configuration. Attributes ---------- config : :class:`~hiten.algorithms.poincare.synodic.config._SynodicMapConfig` The map configuration object. _engine : :class:`~hiten.algorithms.poincare.synodic.engine._SynodicEngine` The engine that coordinates detection and refinement. _sections : dict[str, :class:`~hiten.algorithms.poincare.core.base._Section`] Cache of computed sections keyed by section parameters. _section : :class:`~hiten.algorithms.poincare.core.base._Section` or None The most recently computed section. Notes ----- This class implements a facade pattern that provides a consistent interface for synodic Poincare section detection while hiding the complexity of the underlying detection and refinement algorithms. The class supports multiple input methods: - Custom trajectories via :meth:`~hiten.algorithms.poincare.synodic.base.SynodicMap.from_trajectories` - Periodic orbits via :meth:`~hiten.algorithms.poincare.synodic.base.SynodicMap.from_orbit` - Manifold structures via :meth:`~hiten.algorithms.poincare.synodic.base.SynodicMap.from_manifold` All time units are in nondimensional units unless otherwise specified. """ def __init__(self, config: _SynodicMapConfig, engine: _SynodicEngine, interface: _SynodicInterface = None, backend: _SynodicDetectionBackend = None) -> None: super().__init__(config, engine, interface, backend)
[docs] @classmethod def with_default_engine( cls, config: _SynodicMapConfig, interface: Optional[_SynodicInterface] = None, backend: Optional[_SynodicDetectionBackend] = None, ) -> "SynodicMapPipeline": """Construct a map with a default-wired engine injected. This mirrors the DI-friendly facades (e.g., ConnectionPipeline) by creating a default engine using the current configuration and injecting it. The engine is wired for the default section coordinate in the config. Parameters ---------- config : :class:`~hiten.algorithms.poincare.synodic.config._SynodicMapConfig` Configuration object for the synodic map. interface : :class:`~hiten.algorithms.poincare.synodic.interfaces._SynodicInterface`, optional Interface object for the synodic map. If None, uses the default _SynodicInterface. backend : :class:`~hiten.algorithms.poincare.synodic.backend._SynodicDetectionBackend`, optional Backend instance for the synodic map. If None, uses the default _SynodicDetectionBackend. Returns ------- :class:`~hiten.algorithms.poincare.synodic.base.SynodicMapPipeline` A synodic map facade instance with a default engine injected. """ from hiten.algorithms.poincare.synodic.backend import \ _SynodicDetectionBackend from hiten.algorithms.poincare.synodic.engine import _SynodicEngine from hiten.algorithms.poincare.synodic.interfaces import \ _SynodicInterface backend = backend or _SynodicDetectionBackend() map_intf = interface or _SynodicInterface() strategy = _NoOpStrategy(config) engine = _SynodicEngine(backend=backend, seed_strategy=strategy, map_config=config, interface=map_intf) return cls(config, engine, map_intf, backend)
[docs] def generate( self, domain_obj: DomainT, override: bool = False, *, section_axis: str | int | None = None, section_offset: float = None, section_normal: Sequence[float] | None = None, plane_coords: Tuple[str, str] = None, interp_kind: Literal["linear", "cubic"] = None, newton_max_iter: int = 4, dedup_point_tol: float = None, max_hits_per_traj: int | None = None, segment_refine: int = None, tol_on_surface: float = None, dedup_time_tol: float = None, n_workers: int | None = None, direction: Literal[1, -1, None] | None = None, ) -> SynodicMapResults: """Compute the section, supporting runtime overrides without mutating config. If no overrides are provided, this defers to the cached, default setup and persists the result. If any overrides are provided, a temporary engine is assembled for this call and the result is returned without polluting the persistent cache. In all cases, this method returns the 2-D points of the section. """ kwargs = { "section_axis": section_axis, "section_offset": section_offset, "section_normal": section_normal, "plane_coords": plane_coords, "interp_kind": interp_kind, "newton_max_iter": newton_max_iter, "dedup_point_tol": dedup_point_tol, "max_hits_per_traj": max_hits_per_traj, "segment_refine": segment_refine, "tol_on_surface": tol_on_surface, "dedup_time_tol": dedup_time_tol, "n_workers": n_workers, "direction": direction, } problem = self._create_problem(domain_obj=domain_obj, override=override, **kwargs) engine = self._get_engine() self._results = engine.solve(problem) return self._results