pyoculus.solvers.manifold

Functions

eig(jacobian)

Compute stable and unstable eigenvalues/eigenvectors of a fixed point.

pyoculus.solvers.manifold.eig(jacobian)

Compute stable and unstable eigenvalues/eigenvectors of a fixed point.

This function calculates the eigenvalues and eigenvectors of a given Jacobian matrix and separates them into stable and unstable components based on their magnitudes.

Parameters:

jacobian (np.ndarray) – A 2x2 Jacobian matrix at the fixed point.

Returns:

lambda_s (float): The stable eigenvalue (\(\vert\lambda\vert < 1\)) vector_s (np.ndarray): The corresponding stable eigenvector lambda_u (float): The unstable eigenvalue (\(\vert\lambda\vert > 1\)) vector_u (np.ndarray): The corresponding unstable eigenvector

Return type:

tuple

Examples

>>> J = np.array([[1.5, 0.5], [0.5, 2.0]])
>>> lambda_s, v_s, lambda_u, v_u = eig(J)
class pyoculus.solvers.manifold.Clinic(manifold: Manifold, eps_s: float, eps_u: float, n_s: int, n_u: int)

A class representing the trajectory of a homoclinic/heteroclinic point.

This class handles the computation and storage of a heteroclinic/homoclinic trajectory, which represent intersections between stable and unstable manifolds of fixed points.

Parameters:
  • manifold – The Manifold object associated to the fixed points and map analyzed.

  • eps_s (float) – Initial distance in the linear regime along stable manifold direction.

  • eps_u (float) – Initial distance in the linear regime along unstable manifold direction.

  • n_s (int) – Number of iterations to apply to the intersection closest to the stable fixed point.

  • n_u (int) – Number of iterations to apply to the intersection closest to the unstable fixed point.

eps_s

Distance parameter along stable manifold.

Type:

float

eps_u

Distance parameter along unstable manifold.

Type:

float

nint_s

Number of stable iterations.

Type:

int

nint_u

Number of unstable iterations.

Type:

int

_fundamental_segments

Fundamental domain bounds.

Type:

dict

_trajectory

Computed clinic orbit.

Type:

np.ndarray

_path_s

Stable manifold path.

Type:

np.ndarray

_path_u

Unstable manifold path.

Type:

np.ndarray

_xend_s

End point on stable manifold.

Type:

np.ndarray

_xend_u

End point on unstable manifold.

Type:

np.ndarray

classmethod from_guess(manifold: Manifold, eps_s: float, eps_u: float, n_s: int, n_u: int, ERR=0.001, **kwargs)

Search a homo/hetero-clinic point.

This function attempts to find the intersection point of the stable and unstable manifolds by iteratively adjusting the provided epsilon guesses using scipy root-finding algorithm.

Parameters:
  • guess_eps_s (float) – Initial guess for the stable manifold epsilon.

  • guess_eps_u (float) – Initial guess for the unstable manifold epsilon.

  • **kwargs – Additional keyword arguments. - root_args (dict): Arguments to pass to the root-finding function. - ERR (float): Error tolerance for verifying the linear regime (default: 1e-3). - n_s (int): Number of times the map needs to be applied for the stable manifold. - n_u (int): Number of times the map needs to be applied for the unstable manifold.

Returns:

A tuple containing the found epsilon values for the stable and unstable manifolds (eps_s, eps_u).

Return type:

tuple

classmethod with_deflation(manifold: Manifold, eps_s: float, eps_u: float, n_s: int, n_u: int, **kwargs)

find a clinic point using a deflation method and bounds to remove previously found clinic points.

property trajectory

Get the complete trajectory of the clinic point.

Computes the trajectory by integrating along stable and unstable manifolds if not already calculated.

Returns:

Array containing the orbit from unstable to stable fixed point.

Return type:

np.ndarray

property x_end_s

Get the endpoint on the stable manifold.

Returns:

Coordinates of the end point on stable manifold.

Return type:

np.ndarray

property x_end_u

Get the endpoint on the unstable manifold.

Returns:

Coordinates of the end point on unstable manifold.

Return type:

np.ndarray

property fundamental_segments

Get the fundamental domain boundaries.

Returns:

Contains ‘stable’ and ‘unstable’ segment bounds.

Return type:

dict

class pyoculus.solvers.manifold.ClinicSet(manifold: Manifold)

A collection of homoclinics/heteroclinics with unstable (\(>_u\)) ordering.

This class manages multiple Clinic objects, maintaining their ordering and ensuring proper fundamental domain representation. It uses the first clinic added to manage the fundamental domain boundaries.

Parameters:

manifold – The Manifold object associated to the fixed points and the map analyzed.

_clinics_list

List of Clinic objects.

Type:

list

fundamental_segments

Fundamental domain boundaries.

Type:

dict

nint_pair

Default iteration numbers (n_s, n_u).

Type:

tuple

total_number_of_points

Return the total number of points in the fundamental clinic trajectory.

stable_segment

Return the stable segment of the fundamental domain.

unstable_segment

Return the unstable segment of the fundamental domain.

record_clinic()

Add a new clinic point to the collection.

reset()

Clear all stored clinics.

is_empty()

Check if the clinic set is empty.

Examples

>>> a_manifold = Manifold(...)
>>> clinic_set = ClinicSet(a_manifold)
>>> clinic_set.record_clinic(myclinic)
property size: int

Number of clinic points in the set.

property is_empty: bool

Check if the clinic set is empty.

property total_number_of_points

the number of elements in the fundamental clinic trajectory

property stable_segment

the stable segment of the fundamental domain

property unstable_segment

the stable segment of the fundamental domain

property stable_epsilons

return the stable epsilons of the clinics, including the end of the fundamental section

property unstable_epsilons

return the unstable epsilons of the clinics, including the end of the fundamental section

property stable_shifts

return the stable shifts of the clinics

property unstable_shifts

return the unstable shifts of the clinics (excluding the clinic defining the fundamental section)

property first_epsilons

return the stable and unstable epsilons of the first clinic in the set

record_clinic(clinic: Clinic, **kwargs) bool

Record a new clinic point in the fundamental domain.

Creates and stores a new Clinic object after converting the given parameters to their fundamental domain representation.

Parameters:
  • eps_s (float) – Initial distance along stable manifold.

  • eps_u (float) – Initial distance along unstable manifold.

  • n_s (int) – Number of iterations for stable manifold.

  • n_u (int) – Number of iterations for unstable manifold.

  • **kwargs – Additional keyword arguments: tol (float, optional): Tolerance for comparing epsilon values. Defaults to 1e-2.

Returns:

True if the clinic was successfully added, False otherwise.

Return type:

bool

Note

If this is the first clinic point, it establishes the fundamental domain boundaries. Otherwise, parameters are converted to their fundamental domain representation.

order()

Order the homo/hetero-clinic points with the induced linear ordering of the unstable manifold >_u.

reset()

remove all known clinics and start afresh.

class pyoculus.solvers.manifold.Manifold(map: <module 'pyoculus.maps.base_map' from '/home/runner/work/pyoculus/pyoculus/pyoculus/maps/base_map.py'>, fixedpoint_1: ~pyoculus.solvers.fixed_point.FixedPoint, fixedpoint_2: ~pyoculus.solvers.fixed_point.FixedPoint = None, dir1: str | float | ~numpy.ndarray[tuple[~typing.Any, ...], ~numpy.dtype[~numpy._typing._array_like._ScalarT]] = None, dir2: str = None, first_stable: bool = None)

Class for computing and analyzing a tangle composed of one stable and one unstable manifold of fixed points.

This class handles the computation of stable and unstable manifolds for fixed points, including finding homoclinic/heteroclinic intersections and calculating the turnstile flux of the tangle.

We need to resolve some duplicity to determine the direction in which to follow the manifolds of each x-point (M*v=e.v. * v => M*-v = -e.v. * v), this is done with the ‘dir’ keywords.

Parameters:
  • map (maps.base_map) – The map defining the dynamical system.

  • fixedpoint_1 (FixedPoint) – First fixed point to consider.

  • fixedpoint_2 (FixedPoint, optional) – Second fixed point to consider if the manifolds go from one to the other.

  • dir1 (str, optional) – Direction if type == str, can be (‘+’ or ‘-’) to multiply eigenvector of the Jacobian. if type == float, approximate angle (with respect of the x-axis) of the manifold to follow if type == np.ndarray, the (approximate) vector of the manifold to follow

  • dir2 (str, optional) – Direction if type == str, can be (‘+’ or ‘-’) for the second manifold. if type == float, approximate angle (with respect of the x-axis) of the manifold to follow if type == np.ndarray, the (approximate) vector of the manifold to follow

  • first_stable (bool, optional) – Whether to follow the stable or unstable manifold departing from the first fixed point. Defaults to True.

fixedpoint_1

First fixed point.

Type:

FixedPoint

fixedpoint_2

Second fixed point.

Type:

FixedPoint

rfp_s

Stable fixed point coordinates.

Type:

np.ndarray

rfp_u

Unstable fixed point coordinates.

Type:

np.ndarray

vector_s

Stable eigenvector.

Type:

np.ndarray

vector_u

Unstable eigenvector.

Type:

np.ndarray

lambda_s

Stable eigenvalue.

Type:

float

lambda_u

Unstable eigenvalue.

Type:

float

stable

Stable manifold points.

Type:

np.array

unstable

Unstable manifold points.

Type:

np.array

clinics

Set of homoclinic/heteroclinic intersections.

Type:

ClinicSet

turnstile_areas

Turnstile areas of the tangle.

Type:

np.array

choose()

Choose the stable and unstable directions for the manifold.

show_directions()

Plot the fixed points and their stable/unstable directions.

show_current_directions()

Plot the current stable and unstable directions.

error_linear_regime()

Metric to evaluate if a point is in the linear regime of a fixed point.

start_config()

Compute a starting configuration for the manifold drawing.

find_epsilon()

Find the epsilon that lies in the linear regime.

compute_manifold()

Compute the stable or unstable manifold.

compute()

Compute the stable and unstable manifolds.

plot()

Plot the stable and unstable manifolds.

find_N()

Find the number of times the map needs to be applied for the stable and unstable points to cross.

find_clinic_single()

Find a single homoclinic/heteroclinic intersection.

find_clinic()

Find all homoclinic/heteroclinic intersections.

compute_turnstile_areas()

Compute the turnstile areas of the tangle.

Raises:
  • TypeError – If fixed points are not FixedPoint instances.

  • ValueError – If fixed points are not successfully computed.

choose(dir_1: Literal['+', '-'] | float | Iterable, dir_2: Literal['+', '-'] | float | Iterable, first_stable: bool) None

Choose manifold stable and unstable directions to define your Manifold problem.

You must choose directions away from the fixed point in which the manifolds actually intersect. The good orientation is the one for which you could create the manifold by going away from the fixed point. Be carefull to this point, otherwise other manifold computations such as clinic finding will fail.

Hint: Use Manifold.show_directions() to help you choose here. This plot shows the fixed points and the stable eigenvector (and its negative) in green, the unstable eigenvector (and it’s negative) in red.

Parameters:
  • dir_1 (str) – ‘+’ or ‘-’ for the stable direction.

  • dir_2 (str) – ‘+’ or ‘-’ for the unstable direction.

  • first_stable (bool) – Whether to follow the stable or unstable manifold from the first point.

classmethod show_directions(fp_1: FixedPoint, fp_2: FixedPoint, **kwargs) tuple[Figure, Axes]

Plot fixed points and their stable/unstable directions.

Helper function to plot the fixed points and their stable and unstable direction. Usefull to look at which direction need to be considered for the inner and outer manifolds before creating a class and analyzed them.

Parameters:
  • fp_1 (FixedPoint) – First fixed point.

  • fp_2 (FixedPoint) – Second fixed point.

  • **kwargs – Optional visualization parameters: pcolors (list): Colors for fixed points. vcolors (list): Colors for eigenvectors. vscale (int): Scale for eigenvectors. dvtext (float): Text distance as fraction.

Returns:

(figure, axis) matplotlib objects.

Return type:

tuple

show_current_directions(vscale=0.2, vcolors=None, **kwargs)

Plot the current stable and unstable directions.

Parameters:

**kwargs – Optional visualization parameters: vcolors (list): Colors for eigenvectors. vscale (int): Scale for the eigenvectors. dvtext (float): Text distance as fraction.

Returns:

(figure, axis) matplotlib objects.

Return type:

tuple

property first_epsilons

return the stable and unstable epsilons of the first clinic in the set

error_linear_regime(epsilon: float, rfp: ndarray, eigenvector: ndarray, direction: int = 1) float

Calculate error in linear regime approximation.

Metric to estimate if the point rfp + epsilon * eigenvector is in the linear regime of rfp point.

Parameters:
  • epsilon (float) – Distance from fixed point.

  • rfp (np.ndarray) – Fixed point coordinates.

  • eigenvector (np.ndarray) – Eigenvector to check.

  • direction (int, optional) – Integration direction. Defaults to 1.

Returns:

Error metric for linear approximation.

Return type:

float

start_config(epsilon, rfp, eigenvalue, eigenvector, neps, direction=1)

Compute a starting configuration for the manifold drawing. It takes a point in the linear regime and devide the interval from the point to its evolution after one nfp into neps points. The interval is computed geometrically.

Parameters:
  • epsilon (float) – initial epsilon

  • rfp (np.array) – fixed point

  • eigenvalue (float) – eigenvalue of the fixed point

  • eigenvector (np.array) – eigenvector of the fixed point

  • neps (int) – number of points

  • direction (int) – direction of the integration (1 for forward, -1 for backward)

Returns:

array of starting points (shape (neps, 2))

Return type:

np.array

find_epsilon(which: str, eps_guess=0.001)

Find the epsilon that lies in the linear regime.

compute_manifold(which: str, eps=None, **kwargs)

Compute the stable or unstable manifold.

Parameters:
  • eps (float) – epsilon in the stable or unstable direction

  • compute_stable (bool) – whether to compute the stable or unstable manifold

Keyword Arguments:
  • eps_guess (float) – guess for epsilon (if eps is not given)

  • neps (int) – number of points in the starting configuration

  • nint (int) – number of intersections

Returns:

array of points on the manifold

Return type:

np.array

compute(eps_s=None, eps_u=None, **kwargs)

Computation of the stable and unstable manifolds.

Parameters:
  • eps_s (float) – epsilon in the stable direction.

  • eps_u (float) – epsilon in the unstable direction

Keyword Arguments:
  • eps_guess_s (float) – guess for epsilon in the stable direction (if eps_s is not given)

  • eps_guess_u (float) – guess for epsilon in the unstable direction (if eps_u is not given)

  • neps_s (int) – number of points in the starting configuration for the stable part

  • neps_u (int) – number of points in the starting configuration for the unstable part

  • nint_s (int) – number of evolutions of the initial segments for the stable part

  • nint_u (int) – number of evolutions of the initial segments for the unstable part

Returns:

A tuple containing two np.array of points, the first one for the stable manifold and the second one for the unstable manifold.

Return type:

tuple

get_lobe_boundary(lobe_number, neps=40, which_section: int = 1)

Compute the boundary of the lobe with the given number (counted from the unstable manifold).

The Manifold class must have a computed at least one clinic, preferrably all of them. The boundary of the lobe is computed by mapping the part of the fundamental section of the unstable manifold between two clinic trajecories lobe_number times, and mapping the section of the stable manifold between two clinictrajectories in the reverse direction (clinic_points-lobe_number) times.

which_section determines which of the two sections of the fundamental domain to use.

plot_lobe_boundary(lobe_number, neps=40, which_section: int = 1, **kwargs)

Plot the boundary of the lobe with the given number (counted from the unstable manifold).

The Manifold class must have a computed at least one clinic, preferrably all of them. The boundary of the lobe is computed by mapping the part of the fundamental section of the unstable manifold between two clinic trajecories lobe_number times, and mapping the section of the stable manifold between two clinictrajectories in the reverse direction (clinic_points-lobe_number) times.

plot_filled_lobe(lobe_number, neps=40, which_section: int = 1, **kwargs)

Plot the filled lobe with the given number (counted from the unstable manifold).

The Manifold class must have a computed at least one clinic, preferrably all of them. The boundary of the lobe is computed by mapping the part of the fundamental section of the unstable manifold between two clinic trajecories lobe_number times, and mapping the section of the stable manifold between two clinictrajectories in the reverse direction (clinic_points-lobe_number) times.

plot(which='both', stepsize_limit=None, **kwargs)

Plot the stable and/or unstable manifolds.

kwargs: which (str): which manifold to plot. Can be ‘stable’, ‘unstable’ or ‘both’. stepsize_limit =

Other kwargs are givent to the plot.

Specific extra plots: rm_points (int): remove the last rm_points points of the manifold.

plot_manifold_copies(which='both', stepsize_limit=None, **kwargs)

plot the images of the manifolds as they appear arount the other islands of the chain, using the periodicity of the fixed points.

find_N(eps_s: float, eps_u: float)

Find the number of times the map needs to be applied for the stable and unstable points to cross.

This method evolves the initial stable \(x_s = x^\star + \varepsilon_s\textbf{e}_s\) and unstable \(x_u = x^\star + \varepsilon_u\textbf{e}_u\) points until they cross. They are alternatively evolved once and when the initial direction is reversed, the number of iterations is returned.

Parameters:
  • eps_s (float, optional) – Initial \(\varepsilon_s\) along the stable manifold direction. Defaults to 1e-3.

  • eps_u (float, optional) – Initial \(\varepsilon_u\) along the unstable manifold direction. Defaults to 1e-3.

Returns:

A tuple containing two integers:
  • n_s (int): Number of iterations for the stable manifold.

  • n_u (int): Number of iterations for the unstable manifold.

Return type:

tuple

find_clinic_single(guess_eps_s, guess_eps_u, n_s=None, n_u=None, reset_clinics=False, nretry=1, ERR=0.001, **kwargs)

Search a homo/hetero-clinic point.

This function attempts to find the intersection point of the stable and unstable manifolds by iteratively adjusting the provided epsilon guesses using scipy root-finding algorithm.

Parameters:
  • guess_eps_s (float) – Initial guess for the stable manifold epsilon.

  • guess_eps_u (float) – Initial guess for the unstable manifold epsilon.

kwargs: Additional keyword arguments.
  • n_s (int): Number of times the map needs to be applied for the stable manifold.

  • n_u (int): Number of times the map needs to be applied for the unstable manifold.

  • reset_clinics: replace all clinics and make this clinic the fundamental segment.

  • nretry: retry by jittering the epsilon guesses n times

  • ERR (float): Error tolerance for verifying the linear regime (default: 1e-3).

**kwargs
  • root_args (dict): Arguments to pass to the root-finding function.

    suggested: {‘jac’:True/False} integrated jacobian or FD for step {‘options’:{‘factor’:1e-3}} takes smaller steps when jac is ill.

Returns:

A tuple containing the found epsilon values for the stable and unstable manifolds (eps_s, eps_u).

Return type:

tuple

find_other_clinic_test(shift_in_stable: float, shift_in_unstable: float = None, nretry=1, **kwargs)

bla

find_other_clinic(shift_in_stable: float, shift_in_unstable: float = None, nretry=1, **kwargs)

Find another clinic trajectory if the Manifold already has a fundamental segment. Starts the clinic trajectory finding with one less total step by shifting the start points Args: shift_in_stable: point in the stable fundamental segment to start the search from, 0 is from the same point

as the first trajectory, 1 is shifted to the end.

shift_in_unstable (optional): point in the unstable fundamental segment to start the search from, if not given same as shift_in_stable.

find_clinics(first_guess_eps_s, first_guess_eps_u, n_points=None, reset_clinics=True, **kwargs)

Args:

plot_clinics(**kwargs)

Plot the clinic trajectories.

integrate(x_many, nintersect, direction=1)

Integrate a set of points x_many for nintersect times in the direction specified. Robust to integration failures and has fixed return shape.

Returns an array of shape (nintersect, len(x_many), _map.dimension).

save(path)

save the manifold object to a .pkl file

classmethod load(path)

load the manifold object from a .pkl file

save_mf_quasr(path)

save the manifold object for a Stellerator field in a .pkl file

load_mf_quasr(path)

load the payload saved by save_mf_quasr into the current instance.