pynamicalsys 1.0.1__tar.gz → 1.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. pynamicalsys-1.2.2/CHANGELOG.md +43 -0
  2. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/PKG-INFO +35 -15
  3. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/README.md +32 -13
  4. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/pyproject.toml +2 -2
  5. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/__init__.py +8 -1
  6. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/__version__.py +2 -2
  7. pynamicalsys-1.2.2/src/pynamicalsys/continuous_time/chaotic_indicators.py +347 -0
  8. pynamicalsys-1.2.2/src/pynamicalsys/continuous_time/models.py +240 -0
  9. pynamicalsys-1.2.2/src/pynamicalsys/continuous_time/numerical_integrators.py +337 -0
  10. pynamicalsys-1.2.2/src/pynamicalsys/continuous_time/trajectory_analysis.py +163 -0
  11. pynamicalsys-1.2.2/src/pynamicalsys/continuous_time/validators.py +114 -0
  12. pynamicalsys-1.2.2/src/pynamicalsys/core/continuous_dynamical_systems.py +794 -0
  13. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/core/discrete_dynamical_systems.py +44 -45
  14. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/discrete_time/trajectory_analysis.py +3 -2
  15. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys.egg-info/PKG-INFO +35 -15
  16. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys.egg-info/SOURCES.txt +23 -1
  17. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys.egg-info/requires.txt +1 -0
  18. pynamicalsys-1.2.2/tests/continuous_time/test_SALI_and_LDI.ipynb +237 -0
  19. pynamicalsys-1.2.2/tests/continuous_time/test_lyapunov.ipynb +332 -0
  20. pynamicalsys-1.2.2/tests/continuous_time/test_trajectory.ipynb +443 -0
  21. pynamicalsys-1.2.2/tests/discrete-time/test_FTLE.ipynb +101 -0
  22. pynamicalsys-1.2.2/tests/discrete-time/test_RTE.ipynb +146 -0
  23. pynamicalsys-1.2.2/tests/discrete-time/test_SALI.py +62 -0
  24. pynamicalsys-1.2.2/tests/discrete-time/test_bif_diagram.ipynb +187 -0
  25. pynamicalsys-1.2.2/tests/discrete-time/test_chaotic_saddle.ipynb +369 -0
  26. pynamicalsys-1.2.2/tests/discrete-time/test_dig.ipynb +160 -0
  27. pynamicalsys-1.2.2/tests/discrete-time/test_escape.ipynb +577 -0
  28. pynamicalsys-1.2.2/tests/discrete-time/test_fractal_dimension.ipynb +179 -0
  29. pynamicalsys-1.2.2/tests/discrete-time/test_hurst_exponent.ipynb +132 -0
  30. pynamicalsys-1.2.2/tests/discrete-time/test_lyapunov_exponents.ipynb +473 -0
  31. pynamicalsys-1.2.2/tests/discrete-time/test_manifold.ipynb +266 -0
  32. pynamicalsys-1.2.2/tests/discrete-time/test_manifolds.ipynb +264 -0
  33. pynamicalsys-1.2.2/tests/discrete-time/test_period_counter.ipynb +206 -0
  34. pynamicalsys-1.2.2/tests/discrete-time/test_phase_space.ipynb +108 -0
  35. pynamicalsys-1.0.1/CHANGELOG.md +0 -31
  36. pynamicalsys-1.0.1/src/pynamicalsys/core/continuous_dynamical_systems.py +0 -18
  37. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/.gitignore +0 -0
  38. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/CITATION.cff +0 -0
  39. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/CONTRIBUTING.md +0 -0
  40. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/LICENSE +0 -0
  41. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/MANIFEST.in +0 -0
  42. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/setup.cfg +0 -0
  43. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/common/__init__.py +0 -0
  44. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/common/basin_analysis.py +0 -0
  45. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/common/recurrence_quantification_analysis.py +0 -0
  46. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/common/utils.py +0 -0
  47. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/continuous_time/__init__.py +0 -0
  48. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/core/__init__.py +0 -0
  49. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/core/basin_metrics.py +0 -0
  50. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/core/plot_styler.py +0 -0
  51. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/core/time_series_metrics.py +0 -0
  52. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/discrete_time/__init__.py +0 -0
  53. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/discrete_time/dynamical_indicators.py +0 -0
  54. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/discrete_time/models.py +0 -0
  55. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/discrete_time/transport.py +0 -0
  56. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys/discrete_time/validators.py +0 -0
  57. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys.egg-info/dependency_links.txt +0 -0
  58. {pynamicalsys-1.0.1 → pynamicalsys-1.2.2}/src/pynamicalsys.egg-info/top_level.txt +0 -0
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [v1.2.2] - 2025-06-29
9
+
10
+ ### Added
11
+
12
+ - `ContinuousDynamicalSystem` class for simulating and analyzing continuous nonlinear dynamical systems:
13
+ - Integration using the 4th order Runge-Kutta method with fixed time step.
14
+ - Integration using the adaptive 4th/5th order Runge-Kutta method with adaptive time step.
15
+ - Trajectory computation.
16
+ - Lyapunov exponents calculation.
17
+ - The smallest aligment index (SALI) and linear dependence index (LDI) for chaos detection.
18
+
19
+ ## [v1.0.0] - 2025-06-16
20
+
21
+ ### Added
22
+
23
+ - `DiscreteDynamicalSystems` class for simulating and analyzing discrete nonlinear dynamical systems:
24
+ - Trajectory computation.
25
+ - Chaotic indicators.
26
+ - Fixed points, periodic orbits, and manifolds.
27
+ - Statistical analysis of ensemble of trajetories.
28
+ - Escape basin quantification.
29
+ - Initial release of the package
30
+ - First version of documentation
31
+ - Basic tests
32
+
33
+ - `BasinMetrics` class to compute basin metris such as basin entropy and boundary dimension.
34
+
35
+ - `TimeSeriesMetrics` class to compute metrics related to time series analysis.
36
+
37
+ - `PlotStyler` utility class to globally configure and apply consistent styling for Matplotlib plots.
38
+
39
+ ---
40
+
41
+ <!-- Dummy heading to avoid ending on a transition -->
42
+
43
+ ##
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pynamicalsys
3
- Version: 1.0.1
4
- Summary: A Python toolkit for chaotic analysis and dynamical systems
3
+ Version: 1.2.2
4
+ Summary: A Python toolkit for the analysis of dynamical systems
5
5
  Author-email: Matheus Rolim Sales <rolim.sales.m@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
7
7
  Version 3, 29 June 2007
@@ -689,6 +689,7 @@ Description-Content-Type: text/markdown
689
689
  Requires-Dist: numpy>=1.21
690
690
  Requires-Dist: matplotlib>=3.4
691
691
  Requires-Dist: numba>=0.55
692
+ Requires-Dist: scipy>=0.6
692
693
 
693
694
  # pynamicalsys: A Python toolkit for the analysis of dynamical systems
694
695
 
@@ -698,28 +699,28 @@ Requires-Dist: numba>=0.55
698
699
 
699
700
  ## Overview
700
701
 
701
- **pynamicalsys** is designed to provide a fast, flexible, and user-friendly environment for analyzing **nonlinear dynamical systems**. It is designed for students, researchers, educators, and enthusiasts who want to explore the world of chaos and dynamical systems. Beyond standard tools like trajectory generation and Lyapunov exponents calculation, pynamicalsys includes advanced features such as
702
+ **pynamicalsys** is designed to provide a fast, flexible, and user-friendly environment for analyzing **nonlinear dynamical systems**. It is intended for students, researchers, educators, and enthusiasts who want to explore the world of chaos and dynamical systems. Beyond standard tools like trajectory generation and Lyapunov exponents calculation, **pynamicalsys** includes advanced features such as
702
703
 
703
- - **Linear dependence index** for chaos detection.
704
- - **Recurrence plots** and recurrence time statistics.
705
- - Chaos indicators based on **weighted Birkhoff averages**.
706
- - Statistical measures of **diffusion and transport** in dynamical systems.
707
- - Computation of **periodic orbits**, their **stability** and their **manifolds**.
708
- - Basin metric for **quantifying** the structure of **basins of attraction**.
709
- - **Plot styling** for consistent and customizable visualizations.
704
+ - **Linear dependence index** for chaos detection.
705
+ - **Recurrence plots** and recurrence time statistics.
706
+ - Chaos indicators based on **weighted Birkhoff averages**.
707
+ - Statistical measures of **diffusion and transport** in dynamical systems.
708
+ - Computation of **periodic orbits**, their **stability** and their **manifolds**.
709
+ - Basin metric for **quantifying** the structure of **basins of attraction**.
710
+ - **Plot styling** for consistent and customizable visualizations.
710
711
 
711
- pynamicalsys is built on top of NumPy and Numba, ensuring high performance and efficiency. Thanks to Numba accelerated computation, pynamicalsys offers speedups up to **130x** compared to the original Python implementation of the algorithms. This makes it suitable for large-scale simulations and analyses.
712
+ **pynamicalsys** is built on top of NumPy and Numba, ensuring high performance and efficiency. Thanks to Numba accelerated computation, **pynamicalsys** offers speedups up to **130x** compared to the original Python implementation of the algorithms. This makes it suitable for large-scale simulations and analyses.
712
713
 
713
714
  ## Installation
714
715
 
715
716
  ### Prerequisites
716
717
 
717
- - Python 3.8 or higher
718
- - pip (Python package installer)
718
+ - Python 3.8 or higher
719
+ - pip (Python package installer)
719
720
 
720
721
  ### Install via PyPI
721
722
 
722
- To install the latest stable release, run:
723
+ To install the latest stable release, run in your command line:
723
724
 
724
725
  ```bash
725
726
  $ pip install pynamicalsys
@@ -727,6 +728,13 @@ $ pip install pynamicalsys
727
728
 
728
729
  > **Note:** On **Windows**, it is **strongly recommended** to use [Anaconda](https://www.anaconda.com). It simplifies dependency management and avoids potential issues with scientific libraries during installation. Be sure to run the command from the **Anaconda Prompt**, not from Command Prompt or PowerShell, to ensure the correct environment is activated.
729
730
 
731
+ ### Upgrade via PyPI
732
+
733
+ To upgrade your current version of **pynamicalsys** to the latest stable release, run in your command line:
734
+
735
+ ```bash
736
+ $ pip install **pynamicalsys** --upgrade
737
+ ```
730
738
 
731
739
  ### Install from source
732
740
 
@@ -757,7 +765,19 @@ $ pip install --upgrade pip build
757
765
 
758
766
  ## Citation
759
767
 
760
- Currently, our research paper is under review, but in the mean time, if you use **pynamicalsys** in your work, you can cite the arXiv version:
768
+ Currently, our research paper is under review, but in the mean time, if you use **pynamicalsys** in your work, you can cite the [arXiv](https://arxiv.org/abs/2506.14044) version:
769
+
770
+ ```bibtex
771
+ @misc{pynamicalsys,
772
+ title={pynamicalsys: A Python toolkit for the analysis of dynamical systems},
773
+ author={Matheus Rolim Sales and Leonardo Costa de Souza and Daniel Borin and Michele Mugnaine and José Danilo Szezech Jr. and Ricardo Luiz Viana and Iberê Luiz Caldas and Edson Denis Leonel and Chris G. Antonopoulos},
774
+ year={2025},
775
+ eprint={2506.14044},
776
+ archivePrefix={arXiv},
777
+ primaryClass={nlin.CD},
778
+ url={https://arxiv.org/abs/2506.14044},
779
+ }
780
+ ```
761
781
 
762
782
  ## Contributing
763
783
 
@@ -6,28 +6,28 @@
6
6
 
7
7
  ## Overview
8
8
 
9
- **pynamicalsys** is designed to provide a fast, flexible, and user-friendly environment for analyzing **nonlinear dynamical systems**. It is designed for students, researchers, educators, and enthusiasts who want to explore the world of chaos and dynamical systems. Beyond standard tools like trajectory generation and Lyapunov exponents calculation, pynamicalsys includes advanced features such as
9
+ **pynamicalsys** is designed to provide a fast, flexible, and user-friendly environment for analyzing **nonlinear dynamical systems**. It is intended for students, researchers, educators, and enthusiasts who want to explore the world of chaos and dynamical systems. Beyond standard tools like trajectory generation and Lyapunov exponents calculation, **pynamicalsys** includes advanced features such as
10
10
 
11
- - **Linear dependence index** for chaos detection.
12
- - **Recurrence plots** and recurrence time statistics.
13
- - Chaos indicators based on **weighted Birkhoff averages**.
14
- - Statistical measures of **diffusion and transport** in dynamical systems.
15
- - Computation of **periodic orbits**, their **stability** and their **manifolds**.
16
- - Basin metric for **quantifying** the structure of **basins of attraction**.
17
- - **Plot styling** for consistent and customizable visualizations.
11
+ - **Linear dependence index** for chaos detection.
12
+ - **Recurrence plots** and recurrence time statistics.
13
+ - Chaos indicators based on **weighted Birkhoff averages**.
14
+ - Statistical measures of **diffusion and transport** in dynamical systems.
15
+ - Computation of **periodic orbits**, their **stability** and their **manifolds**.
16
+ - Basin metric for **quantifying** the structure of **basins of attraction**.
17
+ - **Plot styling** for consistent and customizable visualizations.
18
18
 
19
- pynamicalsys is built on top of NumPy and Numba, ensuring high performance and efficiency. Thanks to Numba accelerated computation, pynamicalsys offers speedups up to **130x** compared to the original Python implementation of the algorithms. This makes it suitable for large-scale simulations and analyses.
19
+ **pynamicalsys** is built on top of NumPy and Numba, ensuring high performance and efficiency. Thanks to Numba accelerated computation, **pynamicalsys** offers speedups up to **130x** compared to the original Python implementation of the algorithms. This makes it suitable for large-scale simulations and analyses.
20
20
 
21
21
  ## Installation
22
22
 
23
23
  ### Prerequisites
24
24
 
25
- - Python 3.8 or higher
26
- - pip (Python package installer)
25
+ - Python 3.8 or higher
26
+ - pip (Python package installer)
27
27
 
28
28
  ### Install via PyPI
29
29
 
30
- To install the latest stable release, run:
30
+ To install the latest stable release, run in your command line:
31
31
 
32
32
  ```bash
33
33
  $ pip install pynamicalsys
@@ -35,6 +35,13 @@ $ pip install pynamicalsys
35
35
 
36
36
  > **Note:** On **Windows**, it is **strongly recommended** to use [Anaconda](https://www.anaconda.com). It simplifies dependency management and avoids potential issues with scientific libraries during installation. Be sure to run the command from the **Anaconda Prompt**, not from Command Prompt or PowerShell, to ensure the correct environment is activated.
37
37
 
38
+ ### Upgrade via PyPI
39
+
40
+ To upgrade your current version of **pynamicalsys** to the latest stable release, run in your command line:
41
+
42
+ ```bash
43
+ $ pip install **pynamicalsys** --upgrade
44
+ ```
38
45
 
39
46
  ### Install from source
40
47
 
@@ -65,7 +72,19 @@ $ pip install --upgrade pip build
65
72
 
66
73
  ## Citation
67
74
 
68
- Currently, our research paper is under review, but in the mean time, if you use **pynamicalsys** in your work, you can cite the arXiv version:
75
+ Currently, our research paper is under review, but in the mean time, if you use **pynamicalsys** in your work, you can cite the [arXiv](https://arxiv.org/abs/2506.14044) version:
76
+
77
+ ```bibtex
78
+ @misc{pynamicalsys,
79
+ title={pynamicalsys: A Python toolkit for the analysis of dynamical systems},
80
+ author={Matheus Rolim Sales and Leonardo Costa de Souza and Daniel Borin and Michele Mugnaine and José Danilo Szezech Jr. and Ricardo Luiz Viana and Iberê Luiz Caldas and Edson Denis Leonel and Chris G. Antonopoulos},
81
+ year={2025},
82
+ eprint={2506.14044},
83
+ archivePrefix={arXiv},
84
+ primaryClass={nlin.CD},
85
+ url={https://arxiv.org/abs/2506.14044},
86
+ }
87
+ ```
69
88
 
70
89
  ## Contributing
71
90
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  dynamic = ["version"]
3
3
  name = "pynamicalsys"
4
- description = "A Python toolkit for chaotic analysis and dynamical systems"
4
+ description = "A Python toolkit for the analysis of dynamical systems"
5
5
  authors = [{ name = "Matheus Rolim Sales", email = "rolim.sales.m@gmail.com" }]
6
6
  readme = "README.md"
7
7
  license = { file = "LICENSE" }
@@ -15,7 +15,7 @@ classifiers = [
15
15
  "Topic :: Software Development :: Libraries :: Python Modules",
16
16
  ]
17
17
 
18
- dependencies = ["numpy >=1.21", "matplotlib >=3.4", "numba >=0.55"]
18
+ dependencies = ["numpy >=1.21", "matplotlib >=3.4", "numba >=0.55", "scipy >=0.6"]
19
19
  requires-python = ">=3.8"
20
20
 
21
21
  [build-system]
@@ -16,9 +16,16 @@
16
16
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
 
18
18
  from pynamicalsys.core.discrete_dynamical_systems import DiscreteDynamicalSystem
19
+ from pynamicalsys.core.continuous_dynamical_systems import ContinuousDynamicalSystem
19
20
  from pynamicalsys.core.basin_metrics import BasinMetrics
20
21
  from pynamicalsys.core.plot_styler import PlotStyler
21
22
  from pynamicalsys.core.time_series_metrics import TimeSeriesMetrics
22
23
  from .__version__ import __version__
23
24
 
24
- __all__ = ["DiscreteDynamicalSystem", "PlotStyler", "TimeSeriesMetrics", "BasinMetrics"]
25
+ __all__ = [
26
+ "DiscreteDynamicalSystem",
27
+ "ContinuousDynamicalSystem",
28
+ "PlotStyler",
29
+ "TimeSeriesMetrics",
30
+ "BasinMetrics",
31
+ ]
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.0.1'
21
- __version_tuple__ = version_tuple = (1, 0, 1)
20
+ __version__ = version = '1.2.2'
21
+ __version_tuple__ = version_tuple = (1, 2, 2)
@@ -0,0 +1,347 @@
1
+ # chaotic_indicators.py
2
+
3
+ # Copyright (C) 2025 Matheus Rolim Sales
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ from typing import Optional, Callable, Union, Tuple, Dict, List, Any, Sequence
19
+ from numpy.typing import NDArray
20
+ import numpy as np
21
+ from numba import njit, prange
22
+
23
+ from pynamicalsys.common.utils import qr
24
+ from pynamicalsys.continuous_time.trajectory_analysis import evolve_system
25
+ from pynamicalsys.continuous_time.numerical_integrators import rk4_step_wrapped
26
+
27
+
28
+ @njit(cache=True)
29
+ def lyapunov_exponents(
30
+ u: NDArray[np.float64],
31
+ parameters: NDArray[np.float64],
32
+ total_time: float,
33
+ equations_of_motion: Callable[
34
+ [np.float64, NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]
35
+ ],
36
+ jacobian: Callable[
37
+ [np.float64, NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]
38
+ ],
39
+ transient_time: Optional[float] = None,
40
+ time_step: float = 0.01,
41
+ atol: float = 1e-6,
42
+ rtol: float = 1e-3,
43
+ integrator=rk4_step_wrapped,
44
+ return_history: bool = False,
45
+ seed: int = 13,
46
+ log_base: float = np.e,
47
+ QR: Callable[
48
+ [NDArray[np.float64]], Tuple[NDArray[np.float64], NDArray[np.float64]]
49
+ ] = qr,
50
+ ) -> NDArray[np.float64]:
51
+
52
+ neq = len(u) # Number of equations of the system
53
+ nt = neq + neq**2 # Total number of equations including variational equations
54
+
55
+ u = u.copy()
56
+
57
+ # Handle transient time
58
+ if transient_time is not None:
59
+ u = evolve_system(
60
+ u,
61
+ parameters,
62
+ transient_time,
63
+ equations_of_motion,
64
+ time_step=time_step,
65
+ atol=atol,
66
+ rtol=rtol,
67
+ integrator=integrator,
68
+ )
69
+ sample_time = total_time - transient_time
70
+ time = transient_time
71
+ else:
72
+ sample_time = total_time
73
+ time = 0
74
+
75
+ # State + deviation vectors
76
+ uv = np.zeros(nt)
77
+ uv[:neq] = u.copy()
78
+
79
+ # Randomly define the deviation vectors and orthonormalize them
80
+ np.random.seed(seed)
81
+ uv[neq:] = -1 + 2 * np.random.rand(nt - neq)
82
+ v = uv[neq:].reshape(neq, neq)
83
+ v, _ = QR(v)
84
+ uv[neq:] = v.reshape(neq**2)
85
+
86
+ exponents = np.zeros(neq, dtype=np.float64)
87
+ history = []
88
+
89
+ while time < total_time:
90
+ if time + time_step > total_time:
91
+ time_step = total_time - time
92
+
93
+ uv_new, time_new, time_step_new, accept = integrator(
94
+ time,
95
+ uv,
96
+ parameters,
97
+ equations_of_motion,
98
+ jacobian=jacobian,
99
+ time_step=time_step,
100
+ )
101
+
102
+ if accept:
103
+ time = time_new
104
+ uv = uv_new.copy()
105
+ # Reshape the deviation vectors into a neq x neq matrix
106
+ v = uv[neq:].reshape(neq, neq).copy()
107
+
108
+ # Perform the QR decomposition
109
+ v, R = QR(v)
110
+
111
+ # Accumulate the log
112
+ exponents += np.log(np.abs(np.diag(R))) / np.log(log_base)
113
+
114
+ if return_history:
115
+ result = [time]
116
+ for i in range(neq):
117
+ result.append(
118
+ exponents[i]
119
+ / (time - (transient_time if transient_time is not None else 0))
120
+ )
121
+ history.append(result)
122
+
123
+ # Reshape v back to uv
124
+ uv[neq:] = v.reshape(neq**2)
125
+
126
+ time_step = time_step_new
127
+
128
+ if return_history:
129
+ return history
130
+ else:
131
+ result = []
132
+ for i in range(neq):
133
+ result.append(
134
+ exponents[i]
135
+ / (time - (transient_time if transient_time is not None else 0))
136
+ )
137
+ return [result]
138
+
139
+
140
+ @njit(cache=True)
141
+ def SALI(
142
+ u: NDArray[np.float64],
143
+ parameters: NDArray[np.float64],
144
+ total_time: float,
145
+ equations_of_motion: Callable[
146
+ [np.float64, NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]
147
+ ],
148
+ jacobian: Callable[
149
+ [np.float64, NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]
150
+ ],
151
+ transient_time: Optional[float] = None,
152
+ time_step: float = 0.01,
153
+ atol: float = 1e-6,
154
+ rtol: float = 1e-3,
155
+ integrator=rk4_step_wrapped,
156
+ return_history: bool = False,
157
+ seed: int = 13,
158
+ threshold: float = 1e-16,
159
+ ) -> NDArray[np.float64]:
160
+
161
+ neq = len(u) # Number of equations of the system
162
+ ndv = 2 # Number of deviation vectors
163
+ nt = neq + neq * ndv # Total number of equations including variational equations
164
+
165
+ u = u.copy()
166
+
167
+ # Handle transient time
168
+ if transient_time is not None:
169
+ u = evolve_system(
170
+ u,
171
+ parameters,
172
+ transient_time,
173
+ equations_of_motion,
174
+ time_step=time_step,
175
+ atol=atol,
176
+ rtol=rtol,
177
+ integrator=integrator,
178
+ )
179
+ time = transient_time
180
+ else:
181
+ time = 0
182
+
183
+ # State + deviation vectors
184
+ uv = np.zeros(nt)
185
+ uv[:neq] = u.copy()
186
+
187
+ # Randomly define the deviation vectors and orthonormalize them
188
+ np.random.seed(seed)
189
+ uv[neq:] = -1 + 2 * np.random.rand(nt - neq)
190
+ v = uv[neq:].reshape(neq, ndv)
191
+ v, _ = qr(v)
192
+ uv[neq:] = v.reshape(neq * ndv)
193
+
194
+ history = []
195
+
196
+ while time < total_time:
197
+ if time + time_step > total_time:
198
+ time_step = total_time - time
199
+
200
+ uv_new, time_new, time_step_new, accept = integrator(
201
+ time,
202
+ uv,
203
+ parameters,
204
+ equations_of_motion,
205
+ jacobian=jacobian,
206
+ time_step=time_step,
207
+ number_of_deviation_vectors=ndv,
208
+ )
209
+
210
+ if accept:
211
+ time = time_new
212
+ uv = uv_new.copy()
213
+
214
+ # Reshape the deviation vectors into a neq x ndv matrix
215
+ v = uv[neq:].reshape(neq, ndv)
216
+
217
+ # Normalize the deviation vectors
218
+ v[:, 0] /= np.linalg.norm(v[:, 0])
219
+ v[:, 1] /= np.linalg.norm(v[:, 1])
220
+
221
+ # Calculate the aligment indexes and SALI
222
+ PAI = np.linalg.norm(v[:, 0] + v[:, 1])
223
+ AAI = np.linalg.norm(v[:, 0] - v[:, 1])
224
+ sali = min(PAI, AAI)
225
+
226
+ if return_history:
227
+ result = [time, sali]
228
+ history.append(result)
229
+
230
+ # Early termination
231
+ if sali <= threshold:
232
+ break
233
+
234
+ # Reshape v back to uv
235
+ uv[neq:] = v.reshape(neq * ndv)
236
+
237
+ time_step = time_step_new
238
+
239
+ if return_history:
240
+ return history
241
+ else:
242
+ return [[time, sali]]
243
+
244
+
245
+ # @njit(cache=True)
246
+ def LDI(
247
+ u: NDArray[np.float64],
248
+ parameters: NDArray[np.float64],
249
+ total_time: float,
250
+ equations_of_motion: Callable[
251
+ [np.float64, NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]
252
+ ],
253
+ jacobian: Callable[
254
+ [np.float64, NDArray[np.float64], NDArray[np.float64]], NDArray[np.float64]
255
+ ],
256
+ number_deviation_vectors: int,
257
+ transient_time: Optional[float] = None,
258
+ time_step: float = 0.01,
259
+ atol: float = 1e-6,
260
+ rtol: float = 1e-3,
261
+ integrator=rk4_step_wrapped,
262
+ return_history: bool = False,
263
+ seed: int = 13,
264
+ threshold: float = 1e-16,
265
+ ) -> NDArray[np.float64]:
266
+
267
+ neq = len(u) # Number of equations of the system
268
+ ndv = number_deviation_vectors # Number of deviation vectors
269
+ nt = neq + neq * ndv # Total number of equations including variational equations
270
+
271
+ u = u.copy()
272
+
273
+ # Handle transient time
274
+ if transient_time is not None:
275
+ u = evolve_system(
276
+ u,
277
+ parameters,
278
+ transient_time,
279
+ equations_of_motion,
280
+ time_step=time_step,
281
+ atol=atol,
282
+ rtol=rtol,
283
+ integrator=integrator,
284
+ )
285
+ time = transient_time
286
+ else:
287
+ time = 0
288
+
289
+ # State + deviation vectors
290
+ uv = np.zeros(nt)
291
+ uv[:neq] = u.copy()
292
+
293
+ # Randomly define the deviation vectors and orthonormalize them
294
+ np.random.seed(seed)
295
+ uv[neq:] = -1 + 2 * np.random.rand(nt - neq)
296
+ v = uv[neq:].reshape(neq, ndv)
297
+ v, _ = qr(v)
298
+ uv[neq:] = v.reshape(neq * ndv)
299
+
300
+ history = []
301
+
302
+ while time < total_time:
303
+ if time + time_step > total_time:
304
+ time_step = total_time - time
305
+
306
+ uv_new, time_new, time_step_new, accept = integrator(
307
+ time,
308
+ uv,
309
+ parameters,
310
+ equations_of_motion,
311
+ jacobian=jacobian,
312
+ time_step=time_step,
313
+ number_of_deviation_vectors=ndv,
314
+ )
315
+
316
+ if accept:
317
+ time = time_new
318
+ uv = uv_new.copy()
319
+
320
+ # Reshape the deviation vectors into a neq x ndv matrix
321
+ v = uv[neq:].reshape(neq, ndv)
322
+
323
+ # Normalize the deviation vectors
324
+ for i in range(ndv):
325
+ v[:, i] /= np.linalg.norm(v[:, i])
326
+
327
+ # Calculate the singular values
328
+ S = np.linalg.svd(v, full_matrices=False, compute_uv=False)
329
+ ldi = np.prod(S)
330
+
331
+ if return_history:
332
+ result = [time, ldi]
333
+ history.append(result)
334
+
335
+ # Early termination
336
+ if ldi <= threshold:
337
+ break
338
+
339
+ # Reshape v back to uv
340
+ uv[neq:] = v.reshape(neq * ndv)
341
+
342
+ time_step = time_step_new
343
+
344
+ if return_history:
345
+ return history
346
+ else:
347
+ return [[time, ldi]]