physicskit 0.1.0__py3-none-any.whl
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.
- physicskit/__init__.py +51 -0
- physicskit/astro/__init__.py +66 -0
- physicskit/astro/cosmic_web.py +395 -0
- physicskit/astro/galactic_dynamics.py +137 -0
- physicskit/astro/nbody.py +208 -0
- physicskit/astro/orbital_mechanics.py +220 -0
- physicskit/astro/stellar_dynamo.py +628 -0
- physicskit/astro/stellar_structure.py +198 -0
- physicskit/astro/tests/__init__.py +0 -0
- physicskit/astro/tests/conftest.py +7 -0
- physicskit/astro/tests/test_cosmic_web.py +159 -0
- physicskit/astro/tests/test_galactic_dynamics.py +46 -0
- physicskit/astro/tests/test_nbody.py +81 -0
- physicskit/astro/tests/test_orbital_mechanics.py +73 -0
- physicskit/astro/tests/test_stellar_dynamo.py +198 -0
- physicskit/astro/tests/test_stellar_structure.py +52 -0
- physicskit/astro/tests/test_visualizers.py +159 -0
- physicskit/astro/visualizers.py +628 -0
- physicskit/chaos/__init__.py +55 -0
- physicskit/chaos/core/__init__.py +3 -0
- physicskit/chaos/core/base_system.py +342 -0
- physicskit/chaos/core/integrators.py +40 -0
- physicskit/chaos/exceptions.py +24 -0
- physicskit/chaos/quantum/__init__.py +38 -0
- physicskit/chaos/quantum/billiards.py +274 -0
- physicskit/chaos/quantum/husimi.py +85 -0
- physicskit/chaos/quantum/maps.py +366 -0
- physicskit/chaos/systems/__init__.py +38 -0
- physicskit/chaos/systems/billiards.py +1131 -0
- physicskit/chaos/systems/continuous.py +1276 -0
- physicskit/chaos/systems/maps.py +557 -0
- physicskit/chaos/tests/__init__.py +0 -0
- physicskit/chaos/tests/test_basins.py +76 -0
- physicskit/chaos/tests/test_bifurcation.py +132 -0
- physicskit/chaos/tests/test_billiards.py +115 -0
- physicskit/chaos/tests/test_continuous.py +224 -0
- physicskit/chaos/tests/test_dimension.py +69 -0
- physicskit/chaos/tests/test_divergence.py +90 -0
- physicskit/chaos/tests/test_dynamic_plots.py +269 -0
- physicskit/chaos/tests/test_integrators.py +96 -0
- physicskit/chaos/tests/test_io.py +41 -0
- physicskit/chaos/tests/test_maps.py +110 -0
- physicskit/chaos/tests/test_metrics.py +115 -0
- physicskit/chaos/tests/test_phase_space.py +73 -0
- physicskit/chaos/tests/test_properties.py +116 -0
- physicskit/chaos/tests/test_quantum_billiards.py +94 -0
- physicskit/chaos/tests/test_quantum_maps.py +144 -0
- physicskit/chaos/tests/test_recurrence.py +51 -0
- physicskit/chaos/tests/test_repr_and_api_consistency.py +134 -0
- physicskit/chaos/tests/test_section.py +49 -0
- physicskit/chaos/tests/test_spectral.py +48 -0
- physicskit/chaos/tests/test_streamlit_app.py +45 -0
- physicskit/chaos/tests/test_timeseries.py +131 -0
- physicskit/chaos/tests/test_viewer3d.py +41 -0
- physicskit/chaos/utils/__init__.py +46 -0
- physicskit/chaos/utils/dimension.py +139 -0
- physicskit/chaos/utils/io.py +95 -0
- physicskit/chaos/utils/metrics.py +304 -0
- physicskit/chaos/utils/recurrence.py +122 -0
- physicskit/chaos/utils/spectral.py +69 -0
- physicskit/chaos/utils/timeseries.py +303 -0
- physicskit/chaos/visualizers/__init__.py +85 -0
- physicskit/chaos/visualizers/basins.py +185 -0
- physicskit/chaos/visualizers/bifurcation.py +273 -0
- physicskit/chaos/visualizers/divergence.py +374 -0
- physicskit/chaos/visualizers/dynamic_plots.py +1372 -0
- physicskit/chaos/visualizers/phase_space.py +133 -0
- physicskit/chaos/visualizers/quantum.py +299 -0
- physicskit/chaos/visualizers/recurrence.py +91 -0
- physicskit/chaos/visualizers/section.py +161 -0
- physicskit/chaos/visualizers/theme.py +31 -0
- physicskit/chaos/visualizers/viewer3d.py +82 -0
- physicskit/classical/__init__.py +55 -0
- physicskit/classical/core/__init__.py +17 -0
- physicskit/classical/core/base_system.py +510 -0
- physicskit/classical/core/integrators.py +397 -0
- physicskit/classical/systems/__init__.py +32 -0
- physicskit/classical/systems/chains.py +334 -0
- physicskit/classical/systems/hamiltonian.py +215 -0
- physicskit/classical/systems/lagrangian.py +308 -0
- physicskit/classical/systems/newtonian.py +536 -0
- physicskit/classical/systems/rotations.py +614 -0
- physicskit/classical/tests/__init__.py +0 -0
- physicskit/classical/tests/conftest.py +7 -0
- physicskit/classical/tests/test_base_system.py +113 -0
- physicskit/classical/tests/test_chains.py +84 -0
- physicskit/classical/tests/test_conservation.py +244 -0
- physicskit/classical/tests/test_conservation_utils.py +47 -0
- physicskit/classical/tests/test_hamiltonian.py +44 -0
- physicskit/classical/tests/test_integrators.py +123 -0
- physicskit/classical/tests/test_lagrangian.py +69 -0
- physicskit/classical/tests/test_newtonian.py +45 -0
- physicskit/classical/tests/test_rotations.py +160 -0
- physicskit/classical/tests/test_stepsize.py +149 -0
- physicskit/classical/tests/test_symbolic.py +125 -0
- physicskit/classical/tests/test_visualizers.py +172 -0
- physicskit/classical/utils/__init__.py +20 -0
- physicskit/classical/utils/conservation.py +126 -0
- physicskit/classical/utils/stepsize.py +187 -0
- physicskit/classical/utils/symbolic.py +235 -0
- physicskit/classical/visualizers/__init__.py +25 -0
- physicskit/classical/visualizers/animations.py +508 -0
- physicskit/classical/visualizers/interactive.py +113 -0
- physicskit/classical/visualizers/modal_analysis.py +97 -0
- physicskit/classical/visualizers/phase_space.py +214 -0
- physicskit/condensed/__init__.py +122 -0
- physicskit/condensed/anderson_localization.py +155 -0
- physicskit/condensed/correlated.py +284 -0
- physicskit/condensed/ginzburg_landau.py +220 -0
- physicskit/condensed/landau_levels.py +246 -0
- physicskit/condensed/laughlin.py +229 -0
- physicskit/condensed/models.py +627 -0
- physicskit/condensed/tests/__init__.py +0 -0
- physicskit/condensed/tests/test_condensed.py +518 -0
- physicskit/condensed/tests/test_visualizers.py +87 -0
- physicskit/condensed/tight_binding.py +445 -0
- physicskit/condensed/topological_insulator_3d.py +178 -0
- physicskit/condensed/topology.py +217 -0
- physicskit/condensed/visualizers.py +296 -0
- physicskit/condensed/weyl.py +180 -0
- physicskit/constants.py +184 -0
- physicskit/fields/__init__.py +111 -0
- physicskit/fields/electrodynamics.py +671 -0
- physicskit/fields/quantum_fields.py +510 -0
- physicskit/fields/solitons.py +527 -0
- physicskit/fields/tests/__init__.py +0 -0
- physicskit/fields/tests/conftest.py +7 -0
- physicskit/fields/tests/test_field_animations.py +154 -0
- physicskit/fields/tests/test_fields.py +439 -0
- physicskit/fields/tests/test_visualizers.py +101 -0
- physicskit/fields/visualizers.py +503 -0
- physicskit/fluids/__init__.py +134 -0
- physicskit/fluids/core/__init__.py +23 -0
- physicskit/fluids/core/grid.py +165 -0
- physicskit/fluids/core/timestepping.py +231 -0
- physicskit/fluids/exceptions.py +26 -0
- physicskit/fluids/systems/__init__.py +70 -0
- physicskit/fluids/systems/compressible_flow.py +281 -0
- physicskit/fluids/systems/instabilities.py +343 -0
- physicskit/fluids/systems/navier_stokes.py +221 -0
- physicskit/fluids/systems/potential_flow.py +440 -0
- physicskit/fluids/systems/viscous_flow.py +425 -0
- physicskit/fluids/systems/vortex_dynamics.py +304 -0
- physicskit/fluids/tests/__init__.py +0 -0
- physicskit/fluids/tests/conftest.py +7 -0
- physicskit/fluids/tests/test_compressible_flow.py +66 -0
- physicskit/fluids/tests/test_instabilities.py +115 -0
- physicskit/fluids/tests/test_navier_stokes.py +67 -0
- physicskit/fluids/tests/test_potential_flow.py +92 -0
- physicskit/fluids/tests/test_static_visualizers.py +91 -0
- physicskit/fluids/tests/test_utils.py +100 -0
- physicskit/fluids/tests/test_viscous_flow.py +110 -0
- physicskit/fluids/tests/test_visualizers.py +34 -0
- physicskit/fluids/tests/test_vortex_dynamics.py +88 -0
- physicskit/fluids/utils/__init__.py +18 -0
- physicskit/fluids/utils/dimensionless.py +239 -0
- physicskit/fluids/utils/spectral_analysis.py +142 -0
- physicskit/fluids/visualizers/__init__.py +14 -0
- physicskit/fluids/visualizers/compressible.py +39 -0
- physicskit/fluids/visualizers/flow_fields.py +252 -0
- physicskit/fluids/visualizers/potential_flow.py +51 -0
- physicskit/fluids/visualizers/spectra.py +62 -0
- physicskit/fluids/visualizers/theme.py +38 -0
- physicskit/integrators/__init__.py +52 -0
- physicskit/integrators/adaptive.py +199 -0
- physicskit/integrators/fixed_step.py +360 -0
- physicskit/integrators/tests/__init__.py +0 -0
- physicskit/integrators/tests/test_integrators.py +101 -0
- physicskit/optics/__init__.py +124 -0
- physicskit/optics/_compat.py +5 -0
- physicskit/optics/gaussian.py +382 -0
- physicskit/optics/quantum_optics.py +428 -0
- physicskit/optics/ray.py +469 -0
- physicskit/optics/tests/__init__.py +0 -0
- physicskit/optics/tests/test_diffraction_animation.py +38 -0
- physicskit/optics/tests/test_gaussian.py +170 -0
- physicskit/optics/tests/test_quantum_optics.py +147 -0
- physicskit/optics/tests/test_ray.py +177 -0
- physicskit/optics/tests/test_visualizers.py +58 -0
- physicskit/optics/tests/test_wave.py +146 -0
- physicskit/optics/visualizers.py +264 -0
- physicskit/optics/wave.py +365 -0
- physicskit/particle/__init__.py +152 -0
- physicskit/particle/collider.py +382 -0
- physicskit/particle/confinement.py +125 -0
- physicskit/particle/decays.py +357 -0
- physicskit/particle/electroweak.py +300 -0
- physicskit/particle/kinematics.py +271 -0
- physicskit/particle/neutrinos.py +84 -0
- physicskit/particle/nuclear.py +100 -0
- physicskit/particle/scattering.py +159 -0
- physicskit/particle/tests/__init__.py +0 -0
- physicskit/particle/tests/conftest.py +7 -0
- physicskit/particle/tests/test_collider.py +119 -0
- physicskit/particle/tests/test_confinement.py +42 -0
- physicskit/particle/tests/test_decays.py +112 -0
- physicskit/particle/tests/test_electroweak.py +97 -0
- physicskit/particle/tests/test_kinematics.py +138 -0
- physicskit/particle/tests/test_neutrinos.py +36 -0
- physicskit/particle/tests/test_nuclear.py +45 -0
- physicskit/particle/tests/test_scattering.py +64 -0
- physicskit/particle/tests/test_visualizers.py +214 -0
- physicskit/particle/visualizers/__init__.py +38 -0
- physicskit/particle/visualizers/animations.py +705 -0
- physicskit/particle/visualizers/static.py +101 -0
- physicskit/plasma/__init__.py +176 -0
- physicskit/plasma/acceleration.py +152 -0
- physicskit/plasma/instabilities.py +417 -0
- physicskit/plasma/kinetic.py +588 -0
- physicskit/plasma/mhd.py +463 -0
- physicskit/plasma/single_particle.py +562 -0
- physicskit/plasma/tests/__init__.py +0 -0
- physicskit/plasma/tests/conftest.py +7 -0
- physicskit/plasma/tests/test_new_time_domain_features.py +222 -0
- physicskit/plasma/tests/test_plasma.py +232 -0
- physicskit/plasma/tests/test_visualizers.py +79 -0
- physicskit/plasma/turbulence.py +219 -0
- physicskit/plasma/visualizers.py +868 -0
- physicskit/plasma/waves.py +549 -0
- physicskit/quantum/__init__.py +180 -0
- physicskit/quantum/_compat.py +20 -0
- physicskit/quantum/chapters/__init__.py +0 -0
- physicskit/quantum/chapters/entanglement.py +489 -0
- physicskit/quantum/chapters/harmonic_spin.py +517 -0
- physicskit/quantum/chapters/hydrogen_am.py +292 -0
- physicskit/quantum/chapters/perturbation.py +350 -0
- physicskit/quantum/chapters/potentials.py +997 -0
- physicskit/quantum/chapters/spin.py +306 -0
- physicskit/quantum/chapters/wave_packets.py +541 -0
- physicskit/quantum/core/__init__.py +0 -0
- physicskit/quantum/core/eigensolvers.py +311 -0
- physicskit/quantum/core/operators.py +296 -0
- physicskit/quantum/core/solvers.py +271 -0
- physicskit/quantum/tests/__init__.py +0 -0
- physicskit/quantum/tests/conftest.py +7 -0
- physicskit/quantum/tests/test_animations.py +225 -0
- physicskit/quantum/tests/test_compat.py +43 -0
- physicskit/quantum/tests/test_eigensolvers.py +24 -0
- physicskit/quantum/tests/test_entanglement.py +127 -0
- physicskit/quantum/tests/test_harmonic_spin.py +140 -0
- physicskit/quantum/tests/test_hydrogen_am.py +48 -0
- physicskit/quantum/tests/test_measure.py +110 -0
- physicskit/quantum/tests/test_operators.py +105 -0
- physicskit/quantum/tests/test_perturbation.py +112 -0
- physicskit/quantum/tests/test_physics_checks.py +131 -0
- physicskit/quantum/tests/test_potentials.py +191 -0
- physicskit/quantum/tests/test_solvers.py +70 -0
- physicskit/quantum/tests/test_spin.py +22 -0
- physicskit/quantum/tests/test_unitarity.py +84 -0
- physicskit/quantum/tests/test_wave_packets.py +53 -0
- physicskit/quantum/utils/__init__.py +0 -0
- physicskit/quantum/utils/measure.py +253 -0
- physicskit/quantum/visualizers/__init__.py +0 -0
- physicskit/quantum/visualizers/bloch_sphere.py +205 -0
- physicskit/quantum/visualizers/entanglement.py +58 -0
- physicskit/quantum/visualizers/orbitals.py +187 -0
- physicskit/quantum/visualizers/phase_space.py +179 -0
- physicskit/quantum/visualizers/wavefunctions.py +230 -0
- physicskit/relativity/__init__.py +61 -0
- physicskit/relativity/chapters/__init__.py +33 -0
- physicskit/relativity/chapters/cosmology.py +190 -0
- physicskit/relativity/chapters/gw_merger.py +399 -0
- physicskit/relativity/chapters/kerr.py +371 -0
- physicskit/relativity/chapters/lensing.py +196 -0
- physicskit/relativity/chapters/neutron_star.py +149 -0
- physicskit/relativity/chapters/schwarzschild.py +412 -0
- physicskit/relativity/chapters/timekeeping.py +133 -0
- physicskit/relativity/core/__init__.py +12 -0
- physicskit/relativity/core/geodesics.py +216 -0
- physicskit/relativity/core/kerr_raytracer.py +259 -0
- physicskit/relativity/core/raytracer.py +241 -0
- physicskit/relativity/core/tensors.py +468 -0
- physicskit/relativity/tests/__init__.py +0 -0
- physicskit/relativity/tests/test_conservations.py +54 -0
- physicskit/relativity/tests/test_constants.py +34 -0
- physicskit/relativity/tests/test_cosmology.py +61 -0
- physicskit/relativity/tests/test_gw_merger.py +117 -0
- physicskit/relativity/tests/test_kerr.py +116 -0
- physicskit/relativity/tests/test_kerr_raytracer.py +103 -0
- physicskit/relativity/tests/test_lensing.py +75 -0
- physicskit/relativity/tests/test_neutron_star.py +48 -0
- physicskit/relativity/tests/test_raytracer.py +67 -0
- physicskit/relativity/tests/test_schwarzschild.py +126 -0
- physicskit/relativity/tests/test_shadow_render.py +81 -0
- physicskit/relativity/tests/test_tensors.py +86 -0
- physicskit/relativity/tests/test_timekeeping.py +51 -0
- physicskit/relativity/tests/test_visualizers_misc.py +115 -0
- physicskit/relativity/utils/__init__.py +1 -0
- physicskit/relativity/utils/constants.py +232 -0
- physicskit/relativity/visualizers/__init__.py +46 -0
- physicskit/relativity/visualizers/interactive.py +127 -0
- physicskit/relativity/visualizers/shadow_render.py +367 -0
- physicskit/relativity/visualizers/spacetime_3d.py +92 -0
- physicskit/relativity/visualizers/spacetime_diagrams.py +198 -0
- physicskit/relativity/visualizers/wave_plots.py +185 -0
- physicskit/rmt/__init__.py +8 -0
- physicskit/rmt/ensembles/__init__.py +108 -0
- physicskit/rmt/ensembles/banded.py +114 -0
- physicskit/rmt/ensembles/base.py +135 -0
- physicskit/rmt/ensembles/bdg.py +218 -0
- physicskit/rmt/ensembles/chiral.py +308 -0
- physicskit/rmt/ensembles/circular.py +104 -0
- physicskit/rmt/ensembles/crossover.py +82 -0
- physicskit/rmt/ensembles/density_matrix.py +148 -0
- physicskit/rmt/ensembles/effective_hamiltonian.py +230 -0
- physicskit/rmt/ensembles/embedded.py +207 -0
- physicskit/rmt/ensembles/gaussian.py +153 -0
- physicskit/rmt/ensembles/ginibre.py +110 -0
- physicskit/rmt/ensembles/girko.py +190 -0
- physicskit/rmt/ensembles/graph_laplacian.py +92 -0
- physicskit/rmt/ensembles/haar.py +57 -0
- physicskit/rmt/ensembles/jacobi.py +182 -0
- physicskit/rmt/ensembles/poisson.py +77 -0
- physicskit/rmt/ensembles/polynomial.py +139 -0
- physicskit/rmt/ensembles/pt_symmetric.py +120 -0
- physicskit/rmt/ensembles/single_ring.py +170 -0
- physicskit/rmt/ensembles/sparse.py +95 -0
- physicskit/rmt/ensembles/syk.py +170 -0
- physicskit/rmt/ensembles/truncated_unitary.py +80 -0
- physicskit/rmt/ensembles/universality.py +92 -0
- physicskit/rmt/ensembles/wishart.py +88 -0
- physicskit/rmt/py.typed +0 -0
- physicskit/rmt/spectrum.py +82 -0
- physicskit/rmt/stats/__init__.py +160 -0
- physicskit/rmt/stats/characteristic_polynomial.py +77 -0
- physicskit/rmt/stats/circular_law.py +54 -0
- physicskit/rmt/stats/correlations.py +162 -0
- physicskit/rmt/stats/density.py +70 -0
- physicskit/rmt/stats/entanglement.py +36 -0
- physicskit/rmt/stats/free_probability.py +202 -0
- physicskit/rmt/stats/localization.py +338 -0
- physicskit/rmt/stats/marchenko_pastur.py +55 -0
- physicskit/rmt/stats/pt_symmetric.py +265 -0
- physicskit/rmt/stats/ratios.py +110 -0
- physicskit/rmt/stats/real_ginibre.py +134 -0
- physicskit/rmt/stats/rigidity.py +272 -0
- physicskit/rmt/stats/single_ring.py +95 -0
- physicskit/rmt/stats/spacing.py +150 -0
- physicskit/rmt/stats/tracy_widom.py +175 -0
- physicskit/rmt/stats/truncated_unitary.py +40 -0
- physicskit/rmt/stats/unfolding.py +37 -0
- physicskit/rmt/stats/wachter.py +67 -0
- physicskit/rmt/tests/__init__.py +0 -0
- physicskit/rmt/tests/cache_utils.py +107 -0
- physicskit/rmt/tests/conftest.py +8 -0
- physicskit/rmt/tests/test_banded.py +86 -0
- physicskit/rmt/tests/test_base.py +29 -0
- physicskit/rmt/tests/test_bdg.py +133 -0
- physicskit/rmt/tests/test_characteristic_polynomial.py +50 -0
- physicskit/rmt/tests/test_chiral.py +273 -0
- physicskit/rmt/tests/test_circular.py +225 -0
- physicskit/rmt/tests/test_crossover.py +72 -0
- physicskit/rmt/tests/test_density.py +23 -0
- physicskit/rmt/tests/test_density_matrix.py +181 -0
- physicskit/rmt/tests/test_effective_hamiltonian.py +140 -0
- physicskit/rmt/tests/test_embedded.py +169 -0
- physicskit/rmt/tests/test_free_probability.py +81 -0
- physicskit/rmt/tests/test_gaussian_ensembles.py +22 -0
- physicskit/rmt/tests/test_gaussian_semicircle.py +127 -0
- physicskit/rmt/tests/test_ginibre_circular_law.py +131 -0
- physicskit/rmt/tests/test_girko.py +178 -0
- physicskit/rmt/tests/test_graph_laplacian.py +102 -0
- physicskit/rmt/tests/test_haar.py +118 -0
- physicskit/rmt/tests/test_jacobi_wachter.py +136 -0
- physicskit/rmt/tests/test_localization.py +240 -0
- physicskit/rmt/tests/test_poisson.py +149 -0
- physicskit/rmt/tests/test_polynomial.py +107 -0
- physicskit/rmt/tests/test_pt_symmetric.py +178 -0
- physicskit/rmt/tests/test_random_state.py +19 -0
- physicskit/rmt/tests/test_real_ginibre.py +112 -0
- physicskit/rmt/tests/test_rigidity_universality.py +167 -0
- physicskit/rmt/tests/test_single_ring.py +132 -0
- physicskit/rmt/tests/test_spacing_and_ratios.py +122 -0
- physicskit/rmt/tests/test_sparse.py +71 -0
- physicskit/rmt/tests/test_spectrum.py +27 -0
- physicskit/rmt/tests/test_syk.py +136 -0
- physicskit/rmt/tests/test_tracy_widom.py +113 -0
- physicskit/rmt/tests/test_tridiagonal.py +41 -0
- physicskit/rmt/tests/test_truncated_unitary.py +80 -0
- physicskit/rmt/tests/test_validation_base.py +25 -0
- physicskit/rmt/tests/test_validation_misc.py +67 -0
- physicskit/rmt/tests/test_wishart_marchenko_pastur.py +120 -0
- physicskit/rmt/utils/__init__.py +0 -0
- physicskit/rmt/utils/haar.py +128 -0
- physicskit/rmt/utils/random_state.py +24 -0
- physicskit/rmt/utils/tridiagonal.py +167 -0
- physicskit/rmt/validation/__init__.py +36 -0
- physicskit/rmt/validation/base.py +126 -0
- physicskit/rmt/validation/circular_law.py +80 -0
- physicskit/rmt/validation/marchenko_pastur.py +53 -0
- physicskit/rmt/validation/ratio_distribution.py +53 -0
- physicskit/rmt/validation/real_ginibre.py +60 -0
- physicskit/rmt/validation/sine_kernel.py +57 -0
- physicskit/rmt/validation/single_ring.py +68 -0
- physicskit/rmt/validation/tracy_widom.py +89 -0
- physicskit/rmt/validation/universality.py +100 -0
- physicskit/rmt/validation/wachter.py +52 -0
- physicskit/rmt/validation/wigner_semicircle.py +40 -0
- physicskit/rmt/validation/wigner_surmise.py +58 -0
- physicskit/semiclassical/__init__.py +94 -0
- physicskit/semiclassical/_compat.py +5 -0
- physicskit/semiclassical/core/__init__.py +41 -0
- physicskit/semiclassical/core/gutzwiller.py +215 -0
- physicskit/semiclassical/core/path_integral.py +594 -0
- physicskit/semiclassical/core/propagators.py +579 -0
- physicskit/semiclassical/core/wkb.py +308 -0
- physicskit/semiclassical/systems/__init__.py +13 -0
- physicskit/semiclassical/systems/scarring.py +278 -0
- physicskit/semiclassical/tests/__init__.py +0 -0
- physicskit/semiclassical/tests/test_gutzwiller.py +35 -0
- physicskit/semiclassical/tests/test_path_integral.py +194 -0
- physicskit/semiclassical/tests/test_propagators.py +82 -0
- physicskit/semiclassical/tests/test_scarring.py +43 -0
- physicskit/semiclassical/tests/test_visualizers.py +89 -0
- physicskit/semiclassical/tests/test_wkb.py +30 -0
- physicskit/semiclassical/visualizers/__init__.py +17 -0
- physicskit/semiclassical/visualizers/gutzwiller.py +55 -0
- physicskit/semiclassical/visualizers/path_integral.py +195 -0
- physicskit/semiclassical/visualizers/propagators.py +89 -0
- physicskit/semiclassical/visualizers/scarring.py +146 -0
- physicskit/semiclassical/visualizers/wkb.py +55 -0
- physicskit/statphys/__init__.py +80 -0
- physicskit/statphys/chapters/__init__.py +43 -0
- physicskit/statphys/chapters/ehrenfest_urn.py +112 -0
- physicskit/statphys/chapters/ising_lattice.py +431 -0
- physicskit/statphys/chapters/kpz_growth.py +129 -0
- physicskit/statphys/chapters/molecular_dynamics.py +258 -0
- physicskit/statphys/chapters/nonequilibrium_work.py +146 -0
- physicskit/statphys/chapters/percolation.py +305 -0
- physicskit/statphys/chapters/random_walk.py +142 -0
- physicskit/statphys/chapters/renormalization.py +148 -0
- physicskit/statphys/chapters/sandpile.py +109 -0
- physicskit/statphys/chapters/spin_glass.py +275 -0
- physicskit/statphys/core/__init__.py +10 -0
- physicskit/statphys/core/kpz_engine.py +53 -0
- physicskit/statphys/core/md_engine.py +157 -0
- physicskit/statphys/core/monte_carlo.py +462 -0
- physicskit/statphys/core/random_walk_engine.py +68 -0
- physicskit/statphys/core/sandpile_engine.py +52 -0
- physicskit/statphys/tests/__init__.py +0 -0
- physicskit/statphys/tests/test_dynamics.py +66 -0
- physicskit/statphys/tests/test_ehrenfest_urn.py +44 -0
- physicskit/statphys/tests/test_finite_size_scaling.py +62 -0
- physicskit/statphys/tests/test_interactive.py +33 -0
- physicskit/statphys/tests/test_ising.py +68 -0
- physicskit/statphys/tests/test_kpz.py +55 -0
- physicskit/statphys/tests/test_landau_theory.py +49 -0
- physicskit/statphys/tests/test_md_engine.py +31 -0
- physicskit/statphys/tests/test_molecular_dynamics.py +72 -0
- physicskit/statphys/tests/test_nonequilibrium_work.py +33 -0
- physicskit/statphys/tests/test_partition_function.py +26 -0
- physicskit/statphys/tests/test_percolation.py +116 -0
- physicskit/statphys/tests/test_potts_model.py +46 -0
- physicskit/statphys/tests/test_random_walk.py +50 -0
- physicskit/statphys/tests/test_renormalization.py +44 -0
- physicskit/statphys/tests/test_sandpile.py +44 -0
- physicskit/statphys/tests/test_spin_glass.py +73 -0
- physicskit/statphys/tests/test_thermodynamics.py +121 -0
- physicskit/statphys/tests/test_xy_model.py +45 -0
- physicskit/statphys/utils/__init__.py +1 -0
- physicskit/statphys/utils/dynamics.py +100 -0
- physicskit/statphys/utils/finite_size_scaling.py +171 -0
- physicskit/statphys/utils/landau_theory.py +151 -0
- physicskit/statphys/utils/partition_function.py +109 -0
- physicskit/statphys/utils/thermodynamics.py +356 -0
- physicskit/statphys/visualizers/__init__.py +87 -0
- physicskit/statphys/visualizers/interactive.py +161 -0
- physicskit/statphys/visualizers/jarzynski_render.py +44 -0
- physicskit/statphys/visualizers/kpz_render.py +65 -0
- physicskit/statphys/visualizers/lattice_render.py +212 -0
- physicskit/statphys/visualizers/particle_render.py +121 -0
- physicskit/statphys/visualizers/random_walk_render.py +106 -0
- physicskit/statphys/visualizers/rg_render.py +45 -0
- physicskit/statphys/visualizers/sandpile_render.py +65 -0
- physicskit/statphys/visualizers/spin_glass_render.py +40 -0
- physicskit/statphys/visualizers/urn_render.py +38 -0
- physicskit/statphys/visualizers/vortex_render.py +84 -0
- physicskit/tests/__init__.py +0 -0
- physicskit/tests/test_constants.py +38 -0
- physicskit-0.1.0.dist-info/METADATA +196 -0
- physicskit-0.1.0.dist-info/RECORD +484 -0
- physicskit-0.1.0.dist-info/WHEEL +5 -0
- physicskit-0.1.0.dist-info/licenses/LICENSE +21 -0
- physicskit-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Poincare sections and boundary phase-space (s, sin phi) plots for billiards."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, cast
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
import numpy as np
|
|
9
|
+
from matplotlib.axes import Axes
|
|
10
|
+
from matplotlib.figure import Figure
|
|
11
|
+
from numpy.typing import ArrayLike
|
|
12
|
+
|
|
13
|
+
from physicskit.chaos.core.base_system import BilliardSystem
|
|
14
|
+
from physicskit.chaos.visualizers import theme
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def plot_poincare_section(
|
|
18
|
+
billiard: BilliardSystem,
|
|
19
|
+
n_rays: int = 50,
|
|
20
|
+
n_bounces: int = 200,
|
|
21
|
+
pos: ArrayLike | None = None,
|
|
22
|
+
ax: Axes | None = None,
|
|
23
|
+
seed: int | None = None,
|
|
24
|
+
**scatter_kwargs: Any,
|
|
25
|
+
) -> tuple[Figure, Axes]:
|
|
26
|
+
"""Scatter-plot the boundary phase space ``(s, sin(phi))`` of a billiard.
|
|
27
|
+
|
|
28
|
+
Launches `n_rays` trajectories from an interior point at random angles
|
|
29
|
+
and collects `n_bounces` reflections from each, pooling all the resulting
|
|
30
|
+
boundary hits into one Poincare section. Integrable billiards (Circle,
|
|
31
|
+
Rectangle) trace out smooth invariant curves; chaotic (defocusing)
|
|
32
|
+
billiards (Sinai, Stadium) fill the section with a dense chaotic sea.
|
|
33
|
+
Rays are traced in a single call to
|
|
34
|
+
:meth:`~physicskit.chaos.systems.billiards._RayTracingBilliard.simulate_many_rays`,
|
|
35
|
+
which parallelizes across rays internally (Numba ``prange``).
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
billiard : BilliardSystem
|
|
40
|
+
Billiard to sample.
|
|
41
|
+
n_rays : int, default 50
|
|
42
|
+
Number of independent trajectories to launch.
|
|
43
|
+
n_bounces : int, default 200
|
|
44
|
+
Number of reflections to trace per trajectory.
|
|
45
|
+
pos : array_like of float, shape (2,), optional
|
|
46
|
+
Shared launch position ``(x, y)`` for every ray; defaults to
|
|
47
|
+
``billiard.sample_interior_point()``. Worth overriding for a billiard
|
|
48
|
+
whose default interior point is a point of special symmetry -- e.g.
|
|
49
|
+
:class:`~physicskit.chaos.systems.billiards.CircleBilliard`'s is its exact
|
|
50
|
+
center, from which *every* ray hits the boundary head-on
|
|
51
|
+
(``sin(phi) = 0``), collapsing the whole section onto a single line
|
|
52
|
+
instead of the family of invariant curves an off-center point traces
|
|
53
|
+
out.
|
|
54
|
+
ax : matplotlib.axes.Axes, optional
|
|
55
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
56
|
+
seed : int, optional
|
|
57
|
+
Seed for the random angle generator, for reproducibility.
|
|
58
|
+
**scatter_kwargs
|
|
59
|
+
Additional keyword arguments forwarded to ``ax.scatter``.
|
|
60
|
+
|
|
61
|
+
Returns
|
|
62
|
+
-------
|
|
63
|
+
fig : matplotlib.figure.Figure
|
|
64
|
+
ax : matplotlib.axes.Axes
|
|
65
|
+
"""
|
|
66
|
+
rng = np.random.default_rng(seed)
|
|
67
|
+
interior = billiard.sample_interior_point() if pos is None else np.asarray(pos, dtype=np.float64)
|
|
68
|
+
angles = rng.uniform(0.0, 2.0 * np.pi, size=n_rays)
|
|
69
|
+
result = billiard.simulate_many_rays(interior, angles, n_bounces)
|
|
70
|
+
s, sin_phi = result["s"], result["sin_phi"]
|
|
71
|
+
|
|
72
|
+
if ax is None:
|
|
73
|
+
fig, ax = plt.subplots(figsize=(7, 5))
|
|
74
|
+
else:
|
|
75
|
+
fig = cast(Figure, ax.figure)
|
|
76
|
+
|
|
77
|
+
kwargs: dict[str, Any] = {"s": 0.6, "c": theme.PRIMARY, "alpha": 0.6}
|
|
78
|
+
kwargs.update(scatter_kwargs)
|
|
79
|
+
ax.scatter(s, sin_phi, **kwargs)
|
|
80
|
+
ax.set_xlim(0.0, billiard.perimeter())
|
|
81
|
+
ax.set_ylim(-1.0, 1.0)
|
|
82
|
+
ax.set_xlabel("s (boundary arclength)")
|
|
83
|
+
ax.set_ylabel(r"$\sin\varphi$")
|
|
84
|
+
ax.set_title(f"{billiard.__class__.__name__} Poincare section")
|
|
85
|
+
return fig, ax
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def plot_billiard_trajectory(
|
|
89
|
+
billiard: BilliardSystem,
|
|
90
|
+
pos: ArrayLike,
|
|
91
|
+
vel: ArrayLike,
|
|
92
|
+
n_bounces: int = 50,
|
|
93
|
+
ax: Axes | None = None,
|
|
94
|
+
**plot_kwargs: Any,
|
|
95
|
+
) -> tuple[Figure, Axes]:
|
|
96
|
+
"""Plot a single trajectory bouncing inside the billiard's boundary.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
billiard : BilliardSystem
|
|
101
|
+
Billiard to trace the trajectory within.
|
|
102
|
+
pos : array_like of float, shape (2,)
|
|
103
|
+
Initial position ``(x, y)``; must lie in the billiard's interior.
|
|
104
|
+
vel : array_like of float, shape (2,)
|
|
105
|
+
Initial velocity direction ``(vx, vy)``; normalized internally.
|
|
106
|
+
n_bounces : int, default 50
|
|
107
|
+
Number of reflections to trace.
|
|
108
|
+
ax : matplotlib.axes.Axes, optional
|
|
109
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
110
|
+
**plot_kwargs
|
|
111
|
+
Additional keyword arguments forwarded to ``ax.plot`` for the
|
|
112
|
+
trajectory line.
|
|
113
|
+
|
|
114
|
+
Returns
|
|
115
|
+
-------
|
|
116
|
+
fig : matplotlib.figure.Figure
|
|
117
|
+
ax : matplotlib.axes.Axes
|
|
118
|
+
"""
|
|
119
|
+
boundary = billiard.boundary_polyline()
|
|
120
|
+
path, _ = billiard.trajectory_segments(pos, vel, n_bounces)
|
|
121
|
+
|
|
122
|
+
if ax is None:
|
|
123
|
+
fig, ax = plt.subplots(figsize=(6, 6))
|
|
124
|
+
else:
|
|
125
|
+
fig = cast(Figure, ax.figure)
|
|
126
|
+
|
|
127
|
+
ax.plot(boundary[:, 0], boundary[:, 1], color=theme.STRUCTURE, lw=1.5)
|
|
128
|
+
kwargs: dict[str, Any] = {"color": theme.ACCENT, "lw": 0.8}
|
|
129
|
+
kwargs.update(plot_kwargs)
|
|
130
|
+
ax.plot(path[:, 0], path[:, 1], **kwargs)
|
|
131
|
+
ax.set_aspect("equal")
|
|
132
|
+
ax.set_title(f"{billiard.__class__.__name__} trajectory")
|
|
133
|
+
return fig, ax
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""Plotting helpers for quantum maps and quantum billiards.
|
|
2
|
+
|
|
3
|
+
Plots the objects :mod:`physicskit.chaos.quantum` produces -- Floquet eigenphases,
|
|
4
|
+
Husimi phase-space distributions, and billiard eigenfunctions -- following
|
|
5
|
+
the same ``(fig, ax)``-returning, ``ax=`` -accepting convention as the rest
|
|
6
|
+
of :mod:`physicskit.chaos.visualizers`. Deliberately absent: any plot of spectral
|
|
7
|
+
*statistics* (level-spacing histograms, spectral rigidity, and the like) --
|
|
8
|
+
that analysis, and the random-matrix-theory context for it, belongs to the
|
|
9
|
+
separate ``physicskit.rmt`` package, which can consume
|
|
10
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.eigenphases`,
|
|
11
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.eigenphases`, or
|
|
12
|
+
:meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.wavenumbers` directly.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import Any, cast
|
|
18
|
+
|
|
19
|
+
import matplotlib.pyplot as plt
|
|
20
|
+
import numpy as np
|
|
21
|
+
from matplotlib.animation import FuncAnimation
|
|
22
|
+
from matplotlib.axes import Axes
|
|
23
|
+
from matplotlib.figure import Figure
|
|
24
|
+
from numpy.typing import ArrayLike
|
|
25
|
+
|
|
26
|
+
from physicskit.chaos.quantum.billiards import QuantumBilliard
|
|
27
|
+
from physicskit.chaos.quantum.maps import QuantumBakersMap, QuantumKickedRotor
|
|
28
|
+
from physicskit.chaos.visualizers import theme
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def plot_quantum_spectrum(eigenphases: ArrayLike, ax: Axes | None = None, **scatter_kwargs: Any) -> tuple[Figure, Axes]:
|
|
32
|
+
"""Scatter a quantum map's Floquet eigenphases on the unit circle.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
eigenphases : array_like of float, shape (n,)
|
|
37
|
+
Eigenphases in radians, e.g. from
|
|
38
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.eigenphases` or
|
|
39
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.eigenphases`.
|
|
40
|
+
ax : matplotlib.axes.Axes, optional
|
|
41
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
42
|
+
**scatter_kwargs
|
|
43
|
+
Additional keyword arguments forwarded to ``ax.scatter``.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
fig : matplotlib.figure.Figure
|
|
48
|
+
ax : matplotlib.axes.Axes
|
|
49
|
+
"""
|
|
50
|
+
eigenphases = np.asarray(eigenphases, dtype=np.float64)
|
|
51
|
+
|
|
52
|
+
if ax is None:
|
|
53
|
+
fig, ax = plt.subplots(figsize=(6, 6))
|
|
54
|
+
else:
|
|
55
|
+
fig = cast(Figure, ax.figure)
|
|
56
|
+
|
|
57
|
+
circle = np.linspace(0.0, 2.0 * np.pi, 400)
|
|
58
|
+
ax.plot(np.cos(circle), np.sin(circle), color=theme.MUTED, lw=0.8, zorder=1)
|
|
59
|
+
kwargs: dict[str, Any] = {"s": 12, "color": theme.PRIMARY, "zorder": 2}
|
|
60
|
+
kwargs.update(scatter_kwargs)
|
|
61
|
+
ax.scatter(np.cos(eigenphases), np.sin(eigenphases), **kwargs)
|
|
62
|
+
ax.set_aspect("equal")
|
|
63
|
+
ax.set_xlabel(r"$\cos(\phi)$")
|
|
64
|
+
ax.set_ylabel(r"$\sin(\phi)$")
|
|
65
|
+
ax.set_title("Floquet eigenphases")
|
|
66
|
+
return fig, ax
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def plot_husimi(
|
|
70
|
+
q_grid: ArrayLike,
|
|
71
|
+
p_grid: ArrayLike,
|
|
72
|
+
husimi: ArrayLike,
|
|
73
|
+
ax: Axes | None = None,
|
|
74
|
+
cmap: str = theme.SEQUENTIAL_CMAP,
|
|
75
|
+
q_label: str = "q",
|
|
76
|
+
p_label: str = "p",
|
|
77
|
+
title: str | None = None,
|
|
78
|
+
) -> tuple[Figure, Axes]:
|
|
79
|
+
"""Plot a Husimi phase-space distribution.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
q_grid, p_grid : array_like of float, shape (resolution, resolution)
|
|
84
|
+
Phase-space grid, as returned by
|
|
85
|
+
:func:`~physicskit.chaos.quantum.husimi.husimi_function` (or
|
|
86
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.husimi` /
|
|
87
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.husimi`).
|
|
88
|
+
husimi : array_like of float, shape (resolution, resolution)
|
|
89
|
+
The Husimi distribution.
|
|
90
|
+
ax : matplotlib.axes.Axes, optional
|
|
91
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
92
|
+
cmap : str, default theme.SEQUENTIAL_CMAP
|
|
93
|
+
Colormap name.
|
|
94
|
+
q_label, p_label : str, default "q", "p"
|
|
95
|
+
Axis labels.
|
|
96
|
+
title : str, optional
|
|
97
|
+
Axes title.
|
|
98
|
+
|
|
99
|
+
Returns
|
|
100
|
+
-------
|
|
101
|
+
fig : matplotlib.figure.Figure
|
|
102
|
+
ax : matplotlib.axes.Axes
|
|
103
|
+
"""
|
|
104
|
+
q_grid = np.asarray(q_grid, dtype=np.float64)
|
|
105
|
+
p_grid = np.asarray(p_grid, dtype=np.float64)
|
|
106
|
+
husimi = np.asarray(husimi, dtype=np.float64)
|
|
107
|
+
|
|
108
|
+
if ax is None:
|
|
109
|
+
fig, ax = plt.subplots(figsize=(6.5, 6))
|
|
110
|
+
else:
|
|
111
|
+
fig = cast(Figure, ax.figure)
|
|
112
|
+
|
|
113
|
+
mesh = ax.pcolormesh(q_grid, p_grid, husimi, cmap=cmap, shading="gouraud")
|
|
114
|
+
fig.colorbar(mesh, ax=ax, label="Husimi intensity")
|
|
115
|
+
ax.set_xlabel(q_label)
|
|
116
|
+
ax.set_ylabel(p_label)
|
|
117
|
+
if title:
|
|
118
|
+
ax.set_title(title)
|
|
119
|
+
return fig, ax
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def plot_billiard_eigenstate(
|
|
123
|
+
quantum_billiard: QuantumBilliard,
|
|
124
|
+
eigenfunction: ArrayLike,
|
|
125
|
+
ax: Axes | None = None,
|
|
126
|
+
density: bool = False,
|
|
127
|
+
show_boundary: bool = True,
|
|
128
|
+
) -> tuple[Figure, Axes]:
|
|
129
|
+
"""Plot one eigenfunction of a :class:`~physicskit.chaos.quantum.billiards.QuantumBilliard`.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
quantum_billiard : QuantumBilliard
|
|
134
|
+
The quantized billiard the eigenfunction belongs to (used for its
|
|
135
|
+
grid and boundary outline).
|
|
136
|
+
eigenfunction : array_like of float, shape (nx, ny)
|
|
137
|
+
One eigenfunction, e.g. a single row of the array returned by
|
|
138
|
+
:meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.eigenstates`; grid
|
|
139
|
+
points outside the billiard should be ``nan``.
|
|
140
|
+
ax : matplotlib.axes.Axes, optional
|
|
141
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
142
|
+
density : bool, default False
|
|
143
|
+
If False (the default), plot the signed wavefunction ``psi`` itself
|
|
144
|
+
with a diverging colormap, showing nodal lines directly; this is
|
|
145
|
+
always available since :meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.eigenstates`
|
|
146
|
+
solves a real symmetric eigenproblem, so prefer it for a consistent
|
|
147
|
+
look across regular and chaotic billiards alike. If True, plot the
|
|
148
|
+
probability density ``|psi|^2`` instead, with a sequential colormap.
|
|
149
|
+
show_boundary : bool, default True
|
|
150
|
+
Whether to overlay the billiard's boundary outline.
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
fig : matplotlib.figure.Figure
|
|
155
|
+
ax : matplotlib.axes.Axes
|
|
156
|
+
"""
|
|
157
|
+
eigenfunction = np.asarray(eigenfunction, dtype=np.float64)
|
|
158
|
+
x_grid, y_grid = quantum_billiard.grid()
|
|
159
|
+
|
|
160
|
+
if ax is None:
|
|
161
|
+
fig, ax = plt.subplots(figsize=(6.5, 6))
|
|
162
|
+
else:
|
|
163
|
+
fig = cast(Figure, ax.figure)
|
|
164
|
+
|
|
165
|
+
if density:
|
|
166
|
+
field = eigenfunction**2
|
|
167
|
+
cmap = theme.SEQUENTIAL_CMAP
|
|
168
|
+
vmin, vmax = 0.0, np.nanmax(field)
|
|
169
|
+
label = r"$|\psi|^2$"
|
|
170
|
+
else:
|
|
171
|
+
field = eigenfunction
|
|
172
|
+
cmap = theme.DIVERGING_CMAP
|
|
173
|
+
vmax = np.nanmax(np.abs(field))
|
|
174
|
+
vmin = -vmax
|
|
175
|
+
label = r"$\psi$"
|
|
176
|
+
|
|
177
|
+
mesh = ax.pcolormesh(x_grid, y_grid, field, cmap=cmap, vmin=vmin, vmax=vmax, shading="auto")
|
|
178
|
+
fig.colorbar(mesh, ax=ax, label=label)
|
|
179
|
+
|
|
180
|
+
if show_boundary:
|
|
181
|
+
boundary = quantum_billiard.billiard.boundary_polyline()
|
|
182
|
+
ax.plot(boundary[:, 0], boundary[:, 1], color=theme.STRUCTURE, lw=1.2)
|
|
183
|
+
|
|
184
|
+
ax.set_aspect("equal")
|
|
185
|
+
ax.set_xlabel("x")
|
|
186
|
+
ax.set_ylabel("y")
|
|
187
|
+
return fig, ax
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def plot_weyl_law(quantum_billiard: QuantumBilliard, n_states: int = 30, ax: Axes | None = None) -> tuple[Figure, Axes]:
|
|
191
|
+
"""Compare a billiard's actual eigenvalue counting function to Weyl's law.
|
|
192
|
+
|
|
193
|
+
Draws the exact (staircase) count of eigenvalues below each wavenumber
|
|
194
|
+
alongside the smooth prediction from
|
|
195
|
+
:meth:`~physicskit.chaos.quantum.billiards.QuantumBilliard.weyl_counting_function`.
|
|
196
|
+
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
quantum_billiard : QuantumBilliard
|
|
200
|
+
The quantized billiard to check.
|
|
201
|
+
n_states : int, default 30
|
|
202
|
+
Number of lowest eigenstates to compute and count.
|
|
203
|
+
ax : matplotlib.axes.Axes, optional
|
|
204
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
fig : matplotlib.figure.Figure
|
|
209
|
+
ax : matplotlib.axes.Axes
|
|
210
|
+
"""
|
|
211
|
+
wavenumbers = quantum_billiard.wavenumbers(n_states)
|
|
212
|
+
|
|
213
|
+
if ax is None:
|
|
214
|
+
fig, ax = plt.subplots(figsize=(7, 5))
|
|
215
|
+
else:
|
|
216
|
+
fig = cast(Figure, ax.figure)
|
|
217
|
+
|
|
218
|
+
counts = np.arange(1, n_states + 1)
|
|
219
|
+
ax.step(wavenumbers, counts, where="post", color=theme.PRIMARY, label="actual $N(k)$")
|
|
220
|
+
k_smooth = np.linspace(0.0, wavenumbers[-1] * 1.05, 400)
|
|
221
|
+
ax.plot(
|
|
222
|
+
k_smooth,
|
|
223
|
+
quantum_billiard.weyl_counting_function(k_smooth),
|
|
224
|
+
color=theme.ACCENT,
|
|
225
|
+
ls="--",
|
|
226
|
+
label="Weyl's law",
|
|
227
|
+
)
|
|
228
|
+
ax.set_xlabel("k")
|
|
229
|
+
ax.set_ylabel("N(k)")
|
|
230
|
+
ax.set_title(f"{quantum_billiard.billiard.__class__.__name__}: eigenvalue counting function")
|
|
231
|
+
ax.legend(loc="upper left")
|
|
232
|
+
return fig, ax
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def animate_husimi_evolution(
|
|
236
|
+
quantum_map: QuantumKickedRotor | QuantumBakersMap,
|
|
237
|
+
states: ArrayLike,
|
|
238
|
+
resolution: int = 80,
|
|
239
|
+
n_wraps: int = 3,
|
|
240
|
+
interval: int = 350,
|
|
241
|
+
cmap: str = theme.SEQUENTIAL_CMAP,
|
|
242
|
+
title: str | None = None,
|
|
243
|
+
) -> FuncAnimation:
|
|
244
|
+
"""Animate a quantum map state's Husimi distribution evolving, step by step.
|
|
245
|
+
|
|
246
|
+
Watching a coherent wavepacket's Husimi distribution spread across phase
|
|
247
|
+
space -- staying compact and orbit-like where the classical map is
|
|
248
|
+
regular, filling in a chaotic sea where it is not -- is one of the most
|
|
249
|
+
direct illustrations of quantum chaos: it shows the quantum-classical
|
|
250
|
+
correspondence visibly *breaking down*.
|
|
251
|
+
|
|
252
|
+
Parameters
|
|
253
|
+
----------
|
|
254
|
+
quantum_map : QuantumKickedRotor or QuantumBakersMap
|
|
255
|
+
The quantum map `states` were generated from (used for its `husimi`
|
|
256
|
+
method).
|
|
257
|
+
states : array_like of complex, shape (n_steps + 1, dim)
|
|
258
|
+
State at each step, e.g. from
|
|
259
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.evolve` or
|
|
260
|
+
:meth:`~physicskit.chaos.quantum.maps.QuantumBakersMap.evolve`.
|
|
261
|
+
resolution : int, default 80
|
|
262
|
+
Number of grid points along each phase-space axis.
|
|
263
|
+
n_wraps : int, default 3
|
|
264
|
+
Number of periodic images summed to periodize the coherent states
|
|
265
|
+
used by :meth:`~physicskit.chaos.quantum.maps.QuantumKickedRotor.husimi`.
|
|
266
|
+
interval : int, default 350
|
|
267
|
+
Delay between animation frames, in milliseconds.
|
|
268
|
+
cmap : str, default theme.SEQUENTIAL_CMAP
|
|
269
|
+
Colormap name.
|
|
270
|
+
title : str, optional
|
|
271
|
+
Base title; each frame appends its step number.
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
matplotlib.animation.FuncAnimation
|
|
276
|
+
Assign it to a variable to keep it alive, and display it with
|
|
277
|
+
``plt.show()`` or save it with ``anim.save(...)``.
|
|
278
|
+
"""
|
|
279
|
+
states = np.asarray(states, dtype=np.complex128)
|
|
280
|
+
n_steps = states.shape[0]
|
|
281
|
+
|
|
282
|
+
q_grid, p_grid, husimi0 = quantum_map.husimi(states[0], resolution=resolution, n_wraps=n_wraps)
|
|
283
|
+
|
|
284
|
+
fig, ax = plt.subplots(figsize=(6.5, 6))
|
|
285
|
+
mesh = ax.pcolormesh(q_grid, p_grid, husimi0, cmap=cmap, shading="gouraud", vmin=0.0, vmax=1.0)
|
|
286
|
+
fig.colorbar(mesh, ax=ax, label="Husimi intensity")
|
|
287
|
+
ax.set_xlabel("q")
|
|
288
|
+
ax.set_ylabel("p")
|
|
289
|
+
base_title = title or f"{type(quantum_map).__name__} Husimi distribution"
|
|
290
|
+
title_artist = ax.set_title(f"{base_title} (step 0)")
|
|
291
|
+
|
|
292
|
+
def update(frame: int) -> tuple:
|
|
293
|
+
_, _, husimi = quantum_map.husimi(states[frame], resolution=resolution, n_wraps=n_wraps)
|
|
294
|
+
mesh.set_array(husimi.ravel())
|
|
295
|
+
title_artist.set_text(f"{base_title} (step {frame})")
|
|
296
|
+
return mesh, title_artist
|
|
297
|
+
|
|
298
|
+
anim = FuncAnimation(fig, update, frames=n_steps, interval=interval, blit=False)
|
|
299
|
+
return anim
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Visualizations of Poincare recurrence: recurrence plots and return-time histograms."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import cast
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from matplotlib.axes import Axes
|
|
9
|
+
from matplotlib.figure import Figure
|
|
10
|
+
from numpy.typing import ArrayLike
|
|
11
|
+
|
|
12
|
+
from physicskit.chaos.utils.recurrence import recurrence_matrix, recurrence_times
|
|
13
|
+
from physicskit.chaos.visualizers import theme
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def plot_recurrence_matrix(states: ArrayLike, epsilon: float, ax: Axes | None = None) -> tuple[Figure, Axes]:
|
|
17
|
+
"""Plot the classic black-and-white recurrence plot of a trajectory.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
states : array_like of float, shape (n, dim)
|
|
22
|
+
Trajectory samples.
|
|
23
|
+
epsilon : float
|
|
24
|
+
Neighborhood radius defining a "recurrence".
|
|
25
|
+
ax : matplotlib.axes.Axes, optional
|
|
26
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
fig : matplotlib.figure.Figure
|
|
31
|
+
ax : matplotlib.axes.Axes
|
|
32
|
+
"""
|
|
33
|
+
matrix = recurrence_matrix(states, epsilon)
|
|
34
|
+
|
|
35
|
+
if ax is None:
|
|
36
|
+
fig, ax = plt.subplots(figsize=(6, 6))
|
|
37
|
+
else:
|
|
38
|
+
fig = cast(Figure, ax.figure)
|
|
39
|
+
|
|
40
|
+
ax.imshow(matrix, cmap="Greys", origin="lower", interpolation="nearest")
|
|
41
|
+
ax.set_xlabel("i")
|
|
42
|
+
ax.set_ylabel("j")
|
|
43
|
+
ax.set_title(f"Recurrence plot ($\\epsilon$ = {epsilon:g})")
|
|
44
|
+
return fig, ax
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def plot_recurrence_times(
|
|
48
|
+
states: ArrayLike,
|
|
49
|
+
epsilon: float,
|
|
50
|
+
reference_idx: int = 0,
|
|
51
|
+
dt: float = 1.0,
|
|
52
|
+
bins: int = 40,
|
|
53
|
+
ax: Axes | None = None,
|
|
54
|
+
) -> tuple[Figure, Axes]:
|
|
55
|
+
"""Plot a histogram of the recurrence-time distribution to a reference point.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
states : array_like of float, shape (n, dim)
|
|
60
|
+
Trajectory samples.
|
|
61
|
+
epsilon : float
|
|
62
|
+
Neighborhood radius defining a "return".
|
|
63
|
+
reference_idx : int, default 0
|
|
64
|
+
Index into `states` of the reference point to measure returns to.
|
|
65
|
+
dt : float, default 1.0
|
|
66
|
+
Time between consecutive rows of `states`.
|
|
67
|
+
bins : int, default 40
|
|
68
|
+
Number of histogram bins.
|
|
69
|
+
ax : matplotlib.axes.Axes, optional
|
|
70
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
71
|
+
|
|
72
|
+
Returns
|
|
73
|
+
-------
|
|
74
|
+
fig : matplotlib.figure.Figure
|
|
75
|
+
ax : matplotlib.axes.Axes
|
|
76
|
+
"""
|
|
77
|
+
times = recurrence_times(states, epsilon, reference_idx=reference_idx, dt=dt)
|
|
78
|
+
|
|
79
|
+
if ax is None:
|
|
80
|
+
fig, ax = plt.subplots(figsize=(7, 5))
|
|
81
|
+
else:
|
|
82
|
+
fig = cast(Figure, ax.figure)
|
|
83
|
+
|
|
84
|
+
ax.hist(times, bins=bins, color=theme.PRIMARY, alpha=0.8)
|
|
85
|
+
if times.size:
|
|
86
|
+
ax.axvline(times.mean(), color=theme.ACCENT, linestyle="--", label=f"mean = {times.mean():.3g}")
|
|
87
|
+
ax.legend()
|
|
88
|
+
ax.set_xlabel("recurrence time")
|
|
89
|
+
ax.set_ylabel("count")
|
|
90
|
+
ax.set_title(f"Recurrence-time distribution ($\\epsilon$ = {epsilon:g})")
|
|
91
|
+
return fig, ax
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""Poincare sections (surface-of-section crossings) for continuous-time flows.
|
|
2
|
+
|
|
3
|
+
Unlike :mod:`physicskit.chaos.visualizers.phase_space` (which builds a billiard's
|
|
4
|
+
boundary phase space from its ray-tracing bounces), this module implements
|
|
5
|
+
the original form of the technique Poincare introduced while studying the
|
|
6
|
+
restricted three-body problem: sample a continuous flow only at the instants
|
|
7
|
+
it pierces a fixed surface in state space, turning the ODE's trajectory into
|
|
8
|
+
a lower-dimensional map whose structure -- smooth invariant curves (or a
|
|
9
|
+
handful of points) for regular motion, a scattered "chaotic sea" otherwise --
|
|
10
|
+
is far easier to read than the raw, tangled trajectory.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import Any, cast
|
|
16
|
+
|
|
17
|
+
import matplotlib.pyplot as plt
|
|
18
|
+
import numpy as np
|
|
19
|
+
from matplotlib.axes import Axes
|
|
20
|
+
from matplotlib.figure import Figure
|
|
21
|
+
from numpy.typing import ArrayLike, NDArray
|
|
22
|
+
|
|
23
|
+
from physicskit.chaos.core.base_system import DynamicalSystem
|
|
24
|
+
from physicskit.chaos.visualizers import theme
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def poincare_crossings(
|
|
28
|
+
system: DynamicalSystem,
|
|
29
|
+
state0: ArrayLike,
|
|
30
|
+
coord: int,
|
|
31
|
+
value: float = 0.0,
|
|
32
|
+
direction: float = 1.0,
|
|
33
|
+
t_max: float = 200.0,
|
|
34
|
+
dt: float = 0.001,
|
|
35
|
+
) -> NDArray[np.float64]:
|
|
36
|
+
"""Integrate one trajectory and record its state at every crossing of a
|
|
37
|
+
fixed surface ``state[coord] == value``.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
system : DynamicalSystem
|
|
42
|
+
System to integrate, via its own ``trajectory(state0, dt, n_steps)``.
|
|
43
|
+
state0 : array_like of float, shape (dim,)
|
|
44
|
+
Initial state.
|
|
45
|
+
coord : int
|
|
46
|
+
Index of the state component that defines the section surface.
|
|
47
|
+
value : float, default 0.0
|
|
48
|
+
Value of ``state[coord]`` the surface sits at.
|
|
49
|
+
direction : float, default 1.0
|
|
50
|
+
Sign of ``d(state[coord])/dt`` required to keep a crossing (e.g. the
|
|
51
|
+
default ``1.0`` keeps only crossings where `coord` is increasing,
|
|
52
|
+
discarding the return crossing on the way back, so each pass through
|
|
53
|
+
the surface is counted once instead of twice).
|
|
54
|
+
t_max : float, default 200.0
|
|
55
|
+
Total integration time.
|
|
56
|
+
dt : float, default 0.001
|
|
57
|
+
Fixed integration step size.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
ndarray of float, shape (n_crossings, dim)
|
|
62
|
+
The full state at each qualifying crossing, linearly interpolated
|
|
63
|
+
between the two bracketing integration steps.
|
|
64
|
+
"""
|
|
65
|
+
n_steps = int(round(t_max / dt))
|
|
66
|
+
_, states = system.trajectory(state0=np.asarray(state0, dtype=np.float64), dt=dt, n_steps=n_steps)
|
|
67
|
+
|
|
68
|
+
f = states[:, coord] - value
|
|
69
|
+
crosses = (np.sign(f[:-1]) != np.sign(f[1:])) & (f[:-1] != 0.0)
|
|
70
|
+
if direction > 0:
|
|
71
|
+
crosses &= f[1:] > f[:-1]
|
|
72
|
+
elif direction < 0:
|
|
73
|
+
crosses &= f[1:] < f[:-1]
|
|
74
|
+
idx = np.flatnonzero(crosses)
|
|
75
|
+
if idx.size == 0:
|
|
76
|
+
return np.empty((0, states.shape[1]))
|
|
77
|
+
|
|
78
|
+
f0, f1 = f[idx], f[idx + 1]
|
|
79
|
+
frac = f0 / (f0 - f1)
|
|
80
|
+
return states[idx] + frac[:, None] * (states[idx + 1] - states[idx])
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def plot_poincare_map(
|
|
84
|
+
system: DynamicalSystem,
|
|
85
|
+
initial_states: ArrayLike,
|
|
86
|
+
coord: int = 1,
|
|
87
|
+
value: float = 0.0,
|
|
88
|
+
direction: float = 1.0,
|
|
89
|
+
plot_coords: tuple[int, int] = (0, 2),
|
|
90
|
+
t_max: float = 200.0,
|
|
91
|
+
dt: float = 0.001,
|
|
92
|
+
labels: list[str] | None = None,
|
|
93
|
+
ax: Axes | None = None,
|
|
94
|
+
**scatter_kwargs: Any,
|
|
95
|
+
) -> tuple[Figure, Axes]:
|
|
96
|
+
"""Overlay Poincare-section crossings from several initial conditions.
|
|
97
|
+
|
|
98
|
+
Each initial condition in `initial_states` is integrated independently
|
|
99
|
+
and its :func:`poincare_crossings` plotted as its own scatter series
|
|
100
|
+
(colored from :data:`~physicskit.chaos.visualizers.theme.QUALITATIVE_CMAP`), so
|
|
101
|
+
a regular orbit's crossings -- collapsing onto a smooth curve, or even a
|
|
102
|
+
handful of points, for a periodic orbit -- can be compared directly
|
|
103
|
+
against a chaotic orbit's crossings, which scatter to fill a 2D patch.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
system : DynamicalSystem
|
|
108
|
+
System to integrate.
|
|
109
|
+
initial_states : array_like of float, shape (n_series, dim)
|
|
110
|
+
Initial states, one per series to overlay.
|
|
111
|
+
coord : int, default 1
|
|
112
|
+
Index of the state component that defines the section surface
|
|
113
|
+
(default ``1``, i.e. ``y`` for a state ``(x, y, vx, vy)``).
|
|
114
|
+
value : float, default 0.0
|
|
115
|
+
Value of ``state[coord]`` the surface sits at.
|
|
116
|
+
direction : float, default 1.0
|
|
117
|
+
Sign of ``d(state[coord])/dt`` required to keep a crossing; see
|
|
118
|
+
:func:`poincare_crossings`.
|
|
119
|
+
plot_coords : tuple of int, default (0, 2)
|
|
120
|
+
Indices of the two state components to scatter against each other
|
|
121
|
+
(default: ``x`` vs. ``vx`` for a state ``(x, y, vx, vy)``).
|
|
122
|
+
t_max : float, default 200.0
|
|
123
|
+
Total integration time per series.
|
|
124
|
+
dt : float, default 0.001
|
|
125
|
+
Fixed integration step size.
|
|
126
|
+
labels : list of str, optional
|
|
127
|
+
Legend label for each series; the legend is omitted entirely if not
|
|
128
|
+
given.
|
|
129
|
+
ax : matplotlib.axes.Axes, optional
|
|
130
|
+
Axes to draw into; a new figure and axes are created if omitted.
|
|
131
|
+
**scatter_kwargs
|
|
132
|
+
Additional keyword arguments forwarded to every ``ax.scatter`` call.
|
|
133
|
+
|
|
134
|
+
Returns
|
|
135
|
+
-------
|
|
136
|
+
fig : matplotlib.figure.Figure
|
|
137
|
+
ax : matplotlib.axes.Axes
|
|
138
|
+
"""
|
|
139
|
+
initial_states = np.atleast_2d(np.asarray(initial_states, dtype=np.float64))
|
|
140
|
+
|
|
141
|
+
if ax is None:
|
|
142
|
+
fig, ax = plt.subplots(figsize=(7, 6))
|
|
143
|
+
else:
|
|
144
|
+
fig = cast(Figure, ax.figure)
|
|
145
|
+
|
|
146
|
+
cmap = plt.get_cmap(theme.QUALITATIVE_CMAP)
|
|
147
|
+
i0, i1 = plot_coords
|
|
148
|
+
for i, s0 in enumerate(initial_states):
|
|
149
|
+
crossings = poincare_crossings(system, s0, coord=coord, value=value, direction=direction, t_max=t_max, dt=dt)
|
|
150
|
+
if crossings.shape[0] == 0:
|
|
151
|
+
continue
|
|
152
|
+
kwargs: dict[str, Any] = {"s": 6, "alpha": 0.7, "color": cmap(i % cmap.N)}
|
|
153
|
+
if labels is not None:
|
|
154
|
+
kwargs["label"] = labels[i]
|
|
155
|
+
kwargs.update(scatter_kwargs)
|
|
156
|
+
ax.scatter(crossings[:, i0], crossings[:, i1], **kwargs)
|
|
157
|
+
|
|
158
|
+
if labels is not None:
|
|
159
|
+
ax.legend(fontsize=8)
|
|
160
|
+
ax.set_title(f"{system.__class__.__name__} Poincare section")
|
|
161
|
+
return fig, ax
|