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,198 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from physicskit.astro.stellar_dynamo import (
|
|
5
|
+
_spectral_grid_2d,
|
|
6
|
+
alpha_omega_growth_rate,
|
|
7
|
+
alpha_omega_wave_frequency,
|
|
8
|
+
convective_roll_rhs,
|
|
9
|
+
dominant_mode_growth_rate,
|
|
10
|
+
kinetic_energy,
|
|
11
|
+
simulate_alpha_omega_dynamo,
|
|
12
|
+
simulate_stellar_convection,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
# Part 2: alpha-omega mean-field dynamo -- the core dispersion-relation check
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_alpha_omega_growth_rate_matches_simulation_for_unstable_mode():
|
|
21
|
+
"""The single most important correctness guarantee in this module:
|
|
22
|
+
seed a pure Fourier mode, evolve it, and check the numerically
|
|
23
|
+
observed growth rate against the closed-form dispersion relation."""
|
|
24
|
+
Lx = 2 * np.pi
|
|
25
|
+
nx = 64
|
|
26
|
+
x = np.linspace(0, Lx, nx, endpoint=False)
|
|
27
|
+
k0 = 1.0 # m = 1: k0 = 2*pi*m/Lx with Lx = 2*pi
|
|
28
|
+
alpha, shear, eta = 1.0, 5.0, 0.05
|
|
29
|
+
|
|
30
|
+
A0 = 1e-3 * np.cos(k0 * x)
|
|
31
|
+
B0 = np.zeros_like(A0)
|
|
32
|
+
|
|
33
|
+
sigma_predicted = alpha_omega_growth_rate(alpha, shear, k0, eta)
|
|
34
|
+
assert sigma_predicted > 0 # this test is specifically the unstable/growing case
|
|
35
|
+
|
|
36
|
+
dt = 0.01
|
|
37
|
+
n_steps = 600
|
|
38
|
+
save_every = 5
|
|
39
|
+
times, A_snapshots, B_snapshots = simulate_alpha_omega_dynamo(A0, B0, alpha, shear, eta, Lx, dt, n_steps, save_every)
|
|
40
|
+
|
|
41
|
+
sigma_observed = dominant_mode_growth_rate(B_snapshots, dt_save=dt * save_every)
|
|
42
|
+
assert sigma_observed == pytest.approx(sigma_predicted, rel=0.02)
|
|
43
|
+
|
|
44
|
+
# Cross-check against A too, and against the module's independent
|
|
45
|
+
# frequency formula (same magnitude as the growth rate, by construction
|
|
46
|
+
# of the dispersion relation s^2 = i*alpha*shear*k).
|
|
47
|
+
sigma_observed_A = dominant_mode_growth_rate(A_snapshots, dt_save=dt * save_every)
|
|
48
|
+
assert sigma_observed_A == pytest.approx(sigma_predicted, rel=0.02)
|
|
49
|
+
omega_freq = alpha_omega_wave_frequency(alpha, shear, k0)
|
|
50
|
+
assert omega_freq == pytest.approx(np.sqrt(alpha * shear * k0 / 2.0), rel=1e-10)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_alpha_omega_dispersion_relation_holds_for_several_wavenumbers():
|
|
54
|
+
"""The closed-form growth rate and wave-frequency magnitude must agree
|
|
55
|
+
(they're the real and imaginary parts of the same complex root)."""
|
|
56
|
+
alpha, shear, eta = 0.8, 3.0, 0.1
|
|
57
|
+
k = np.array([0.5, 1.0, 2.0, 3.0])
|
|
58
|
+
sigma = alpha_omega_growth_rate(alpha, shear, k, eta)
|
|
59
|
+
freq = alpha_omega_wave_frequency(alpha, shear, k)
|
|
60
|
+
assert freq == pytest.approx(sigma + eta * k**2, rel=1e-10)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_alpha_omega_dynamo_decays_in_stable_regime():
|
|
64
|
+
"""Large diffusivity relative to alpha*shear*k should make the
|
|
65
|
+
dispersion relation predict decay, and the simulated field energy
|
|
66
|
+
should actually decay."""
|
|
67
|
+
Lx = 2 * np.pi
|
|
68
|
+
nx = 64
|
|
69
|
+
x = np.linspace(0, Lx, nx, endpoint=False)
|
|
70
|
+
k0 = 1.0
|
|
71
|
+
alpha, shear, eta = 1.0, 1.0, 2.0
|
|
72
|
+
|
|
73
|
+
sigma_predicted = alpha_omega_growth_rate(alpha, shear, k0, eta)
|
|
74
|
+
assert sigma_predicted < 0 # this test is specifically the stable/decaying case
|
|
75
|
+
|
|
76
|
+
A0 = 1e-3 * np.cos(k0 * x)
|
|
77
|
+
B0 = np.zeros_like(A0)
|
|
78
|
+
dt = 0.01
|
|
79
|
+
n_steps = 600
|
|
80
|
+
save_every = 5
|
|
81
|
+
times, A_snapshots, B_snapshots = simulate_alpha_omega_dynamo(A0, B0, alpha, shear, eta, Lx, dt, n_steps, save_every)
|
|
82
|
+
|
|
83
|
+
initial_energy = np.sum(A_snapshots[0] ** 2 + B_snapshots[0] ** 2)
|
|
84
|
+
final_energy = np.sum(A_snapshots[-1] ** 2 + B_snapshots[-1] ** 2)
|
|
85
|
+
assert final_energy < initial_energy
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_simulate_alpha_omega_dynamo_shapes_and_finiteness():
|
|
89
|
+
Lx = 2 * np.pi
|
|
90
|
+
nx = 40
|
|
91
|
+
x = np.linspace(0, Lx, nx, endpoint=False)
|
|
92
|
+
A0 = 1e-3 * np.cos(2 * x)
|
|
93
|
+
B0 = np.zeros_like(A0)
|
|
94
|
+
times, A_snapshots, B_snapshots = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=2.0, eta=0.1, Lx=Lx, dt=0.02, n_steps=30, save_every=3)
|
|
95
|
+
n_saved = 30 // 3 + 1
|
|
96
|
+
assert times.shape == (n_saved,)
|
|
97
|
+
assert A_snapshots.shape == (n_saved, nx)
|
|
98
|
+
assert B_snapshots.shape == (n_saved, nx)
|
|
99
|
+
assert np.all(np.isfinite(A_snapshots))
|
|
100
|
+
assert np.all(np.isfinite(B_snapshots))
|
|
101
|
+
assert A_snapshots[0] == pytest.approx(A0)
|
|
102
|
+
assert B_snapshots[0] == pytest.approx(B0)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_alpha_omega_growth_rate_vectorizes_over_k():
|
|
106
|
+
k = np.array([0.0, 1.0, 2.0, 4.0])
|
|
107
|
+
sigma = alpha_omega_growth_rate(alpha=1.0, shear=2.0, k=k, eta=0.1)
|
|
108
|
+
assert sigma.shape == (4,)
|
|
109
|
+
# k=0: no alpha-omega drive at all, growth rate is exactly zero (no diffusion either, at k=0).
|
|
110
|
+
assert sigma[0] == pytest.approx(0.0)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_dominant_mode_growth_rate_recovers_known_slope():
|
|
114
|
+
t = np.arange(20) * 0.1
|
|
115
|
+
sigma_true = 1.7
|
|
116
|
+
A_snapshots = np.exp(sigma_true * t)[:, None] * np.ones((20, 6))
|
|
117
|
+
sigma_fit = dominant_mode_growth_rate(A_snapshots, dt_save=0.1)
|
|
118
|
+
assert sigma_fit == pytest.approx(sigma_true, rel=1e-6)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
# Part 1: 2D convective rolls
|
|
123
|
+
# ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@pytest.mark.slow
|
|
127
|
+
@pytest.mark.parametrize("seed", [0, 1])
|
|
128
|
+
def test_convection_grows_and_stays_finite(seed):
|
|
129
|
+
"""Small random noise should grow into sustained convective motion
|
|
130
|
+
(kinetic energy at the end of the run meaningfully larger than at the
|
|
131
|
+
start) without ever producing NaN/Inf, for at least two random seeds."""
|
|
132
|
+
nx = ny = 32
|
|
133
|
+
Lx = Ly = 2 * np.pi
|
|
134
|
+
times, omega_snapshots, T_snapshots = simulate_stellar_convection(nx, ny, Lx, Ly, n_steps=2000, seed=seed)
|
|
135
|
+
|
|
136
|
+
assert np.all(np.isfinite(omega_snapshots))
|
|
137
|
+
assert np.all(np.isfinite(T_snapshots))
|
|
138
|
+
|
|
139
|
+
_, _, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
|
|
140
|
+
KE_initial = kinetic_energy(omega_snapshots[0], KX, KY, K2)
|
|
141
|
+
KE_final = kinetic_energy(omega_snapshots[-1], KX, KY, K2)
|
|
142
|
+
assert KE_final > 100.0 * KE_initial
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def test_convective_roll_rhs_shapes():
|
|
146
|
+
nx = ny = 32
|
|
147
|
+
Lx = Ly = 2 * np.pi
|
|
148
|
+
_, Y, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
|
|
149
|
+
rng = np.random.default_rng(0)
|
|
150
|
+
omega = 1e-3 * rng.standard_normal((ny, nx))
|
|
151
|
+
T = 1e-3 * rng.standard_normal((ny, nx))
|
|
152
|
+
domega_dt, dT_dt = convective_roll_rhs(omega, T, Y, KX, KY, K2, nu=0.05, kappa=0.05, g_alpha=1.0, beta=1.0, Ly=Ly, tau_relax=0.5)
|
|
153
|
+
assert domega_dt.shape == (ny, nx)
|
|
154
|
+
assert dT_dt.shape == (ny, nx)
|
|
155
|
+
assert np.all(np.isfinite(domega_dt))
|
|
156
|
+
assert np.all(np.isfinite(dT_dt))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_convective_roll_rhs_relaxation_pulls_uniform_zero_field_toward_teq():
|
|
160
|
+
"""With zero velocity and zero perturbation temperature, the only
|
|
161
|
+
surviving term in dT'/dt is the Newtonian-cooling relaxation toward
|
|
162
|
+
Teq(y); check its sign and magnitude directly against the formula."""
|
|
163
|
+
nx = ny = 16
|
|
164
|
+
Lx = Ly = 2 * np.pi
|
|
165
|
+
_, Y, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
|
|
166
|
+
omega = np.zeros((ny, nx))
|
|
167
|
+
T = np.zeros((ny, nx))
|
|
168
|
+
beta, tau_relax = 2.0, 0.5
|
|
169
|
+
_, dT_dt = convective_roll_rhs(omega, T, Y, KX, KY, K2, nu=0.05, kappa=0.05, g_alpha=1.0, beta=beta, Ly=Ly, tau_relax=tau_relax)
|
|
170
|
+
Teq = -beta * np.cos(2 * np.pi * Y / Ly)
|
|
171
|
+
expected = Teq / tau_relax
|
|
172
|
+
assert dT_dt == pytest.approx(expected, abs=1e-10)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_simulate_stellar_convection_shapes():
|
|
176
|
+
nx, ny = 24, 32
|
|
177
|
+
Lx, Ly = 2 * np.pi, 3.0
|
|
178
|
+
n_steps, save_every = 20, 5
|
|
179
|
+
times, omega_snapshots, T_snapshots = simulate_stellar_convection(nx, ny, Lx, Ly, n_steps=n_steps, save_every=save_every, seed=0)
|
|
180
|
+
n_saved = n_steps // save_every + 1
|
|
181
|
+
assert times.shape == (n_saved,)
|
|
182
|
+
assert omega_snapshots.shape == (n_saved, ny, nx)
|
|
183
|
+
assert T_snapshots.shape == (n_saved, ny, nx)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def test_kinetic_energy_of_zero_vorticity_is_zero():
|
|
187
|
+
nx = ny = 32
|
|
188
|
+
Lx = Ly = 2 * np.pi
|
|
189
|
+
_, _, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
|
|
190
|
+
assert kinetic_energy(np.zeros((ny, nx)), KX, KY, K2) == 0.0
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_kinetic_energy_positive_for_nonzero_vorticity():
|
|
194
|
+
nx = ny = 32
|
|
195
|
+
Lx = Ly = 2 * np.pi
|
|
196
|
+
X, Y, KX, KY, K2 = _spectral_grid_2d(nx, ny, Lx, Ly)
|
|
197
|
+
omega = np.sin(X) * np.cos(Y)
|
|
198
|
+
assert kinetic_energy(omega, KX, KY, K2) > 0.0
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pytest
|
|
3
|
+
|
|
4
|
+
from physicskit.astro.stellar_structure import (
|
|
5
|
+
PolytropicStar,
|
|
6
|
+
chandrasekhar_mass,
|
|
7
|
+
lane_emden,
|
|
8
|
+
main_sequence_luminosity,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_lane_emden_n0_matches_analytic_solution():
|
|
13
|
+
xi, theta = lane_emden(0.0)
|
|
14
|
+
assert xi[-1] == pytest.approx(np.sqrt(6.0), rel=1e-3)
|
|
15
|
+
# analytic: theta(xi) = 1 - xi^2/6
|
|
16
|
+
analytic = 1.0 - xi**2 / 6.0
|
|
17
|
+
assert theta == pytest.approx(analytic, abs=2e-3)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_lane_emden_n1_matches_analytic_solution():
|
|
21
|
+
xi, theta = lane_emden(1.0)
|
|
22
|
+
assert xi[-1] == pytest.approx(np.pi, rel=1e-3)
|
|
23
|
+
# analytic: theta(xi) = sin(xi)/xi
|
|
24
|
+
analytic = np.sin(xi) / xi
|
|
25
|
+
assert theta == pytest.approx(analytic, abs=2e-3)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_polytropic_star_n0_matches_uniform_sphere_mass():
|
|
29
|
+
star = PolytropicStar(n=0.0, K=2.5, rho_c=3.0)
|
|
30
|
+
uniform_mass = 4.0 / 3.0 * np.pi * star.radius**3 * star.rho_c
|
|
31
|
+
assert star.mass == pytest.approx(uniform_mass, rel=1e-2)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_polytropic_star_positive_physical_quantities():
|
|
35
|
+
star = PolytropicStar(n=1.5, K=1.0, rho_c=1.0)
|
|
36
|
+
assert star.radius > 0
|
|
37
|
+
assert star.mass > 0
|
|
38
|
+
assert star.xi1 > 0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_chandrasekhar_mass_near_known_value():
|
|
42
|
+
M = chandrasekhar_mass(2.0)
|
|
43
|
+
assert 1.2 < M < 1.5
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_chandrasekhar_mass_scales_as_inverse_mu_e_squared():
|
|
47
|
+
assert chandrasekhar_mass(4.0) == pytest.approx(chandrasekhar_mass(2.0) / 4.0)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_main_sequence_luminosity_power_law():
|
|
51
|
+
assert main_sequence_luminosity(2.0) == pytest.approx(2.0**3.5)
|
|
52
|
+
assert main_sequence_luminosity(1.0) == pytest.approx(1.0)
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pytest
|
|
4
|
+
from matplotlib.animation import PillowWriter
|
|
5
|
+
from matplotlib.collections import LineCollection
|
|
6
|
+
|
|
7
|
+
from physicskit.astro.cosmic_web import lagrangian_grid, random_displacement_potential
|
|
8
|
+
from physicskit.astro.galactic_dynamics import circular_velocity
|
|
9
|
+
from physicskit.astro.nbody import NBodySystem, figure_eight_initial_conditions
|
|
10
|
+
from physicskit.astro.stellar_dynamo import simulate_alpha_omega_dynamo, simulate_stellar_convection
|
|
11
|
+
from physicskit.astro.stellar_structure import lane_emden
|
|
12
|
+
from physicskit.astro.visualizers import (
|
|
13
|
+
animate_dynamo_wave,
|
|
14
|
+
animate_nbody_trajectories,
|
|
15
|
+
animate_stellar_convection,
|
|
16
|
+
animate_zeldovich_collapse,
|
|
17
|
+
plot_dynamo_butterfly_diagram,
|
|
18
|
+
plot_lane_emden,
|
|
19
|
+
plot_nbody_trajectories,
|
|
20
|
+
plot_rotation_curve,
|
|
21
|
+
plot_zeldovich_snapshot,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.slow
|
|
26
|
+
def test_animate_nbody_trajectories_figure_eight_saves_gif(tmp_path):
|
|
27
|
+
positions, velocities, masses = figure_eight_initial_conditions()
|
|
28
|
+
system = NBodySystem(positions, velocities, masses)
|
|
29
|
+
history = system.simulate(dt=0.002, n_steps=300)
|
|
30
|
+
|
|
31
|
+
anim = animate_nbody_trajectories(history, skip=5)
|
|
32
|
+
out = tmp_path / "nbody_figure_eight.gif"
|
|
33
|
+
anim.save(out, writer=PillowWriter(fps=10))
|
|
34
|
+
assert out.exists() and out.stat().st_size > 0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_animate_nbody_trajectories_uses_one_collection_and_marker_per_body():
|
|
38
|
+
history = np.random.default_rng(1).normal(size=(50, 3, 3))
|
|
39
|
+
|
|
40
|
+
anim = animate_nbody_trajectories(history, title="N-body test")
|
|
41
|
+
ax = anim._fig.axes[0]
|
|
42
|
+
collections = [c for c in ax.collections if isinstance(c, LineCollection)]
|
|
43
|
+
assert len(collections) == 3
|
|
44
|
+
assert len(ax.lines) == 3
|
|
45
|
+
assert ax.get_title() == "N-body test"
|
|
46
|
+
|
|
47
|
+
anim._draw_frame(0) # a single point per body: the <2-point trail branch
|
|
48
|
+
assert collections[0].get_segments() == []
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_animate_nbody_trajectories_trail_fades_with_alpha():
|
|
52
|
+
"""The trail must actually fade: older segments more transparent than
|
|
53
|
+
the most recent one."""
|
|
54
|
+
history = np.cumsum(np.random.default_rng(2).normal(size=(100, 3, 3)), axis=0)
|
|
55
|
+
|
|
56
|
+
anim = animate_nbody_trajectories(history, trail=100)
|
|
57
|
+
anim._draw_frame(99)
|
|
58
|
+
ax = anim._fig.axes[0]
|
|
59
|
+
lc = next(c for c in ax.collections if isinstance(c, LineCollection))
|
|
60
|
+
alphas = np.asarray(lc.get_colors())[:, 3]
|
|
61
|
+
assert alphas[0] < alphas[-1]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_plot_nbody_trajectories_returns_one_line_per_body():
|
|
65
|
+
# A synthetic array is enough here -- plot_nbody_trajectories only
|
|
66
|
+
# cares about (n_steps+1, N, 3) shape, not real dynamics.
|
|
67
|
+
history = np.random.default_rng(0).normal(size=(10, 3, 3))
|
|
68
|
+
|
|
69
|
+
fig, ax = plot_nbody_trajectories(history)
|
|
70
|
+
assert isinstance(fig, plt.Figure)
|
|
71
|
+
assert len(ax.lines) == 3
|
|
72
|
+
|
|
73
|
+
_, ax_given = plot_nbody_trajectories(history, ax=ax)
|
|
74
|
+
assert ax_given is ax # reuses the supplied axes rather than creating a new figure
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_plot_lane_emden_returns_figure():
|
|
78
|
+
xi, theta = lane_emden(1.5, n_points=50)
|
|
79
|
+
fig, ax = plot_lane_emden(xi, theta)
|
|
80
|
+
assert isinstance(fig, plt.Figure)
|
|
81
|
+
assert len(ax.lines) == 2 # theta(xi) curve + the axhline(0) reference line
|
|
82
|
+
assert len(ax.collections) == 1 # the surface-point scatter
|
|
83
|
+
|
|
84
|
+
_, ax_given = plot_lane_emden(xi, theta, ax=ax)
|
|
85
|
+
assert ax_given is ax
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_plot_rotation_curve_with_and_without_observed_data():
|
|
89
|
+
r = np.linspace(1.0, 10.0, 10)
|
|
90
|
+
v_model = circular_velocity(r, lambda rr: 1.0)
|
|
91
|
+
|
|
92
|
+
fig1, ax1 = plot_rotation_curve(r, v_model)
|
|
93
|
+
assert isinstance(fig1, plt.Figure)
|
|
94
|
+
assert len(ax1.collections) == 0 # no scatter without observed data
|
|
95
|
+
|
|
96
|
+
fig2, ax2 = plot_rotation_curve(r, v_model, v_observed=v_model * 1.1)
|
|
97
|
+
assert isinstance(fig2, plt.Figure)
|
|
98
|
+
assert len(ax2.collections) == 1 # scatter added for observed data
|
|
99
|
+
|
|
100
|
+
_, ax_given = plot_rotation_curve(r, v_model, ax=ax1)
|
|
101
|
+
assert ax_given is ax1
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _small_zeldovich_field():
|
|
105
|
+
q = lagrangian_grid(5, 1.0)
|
|
106
|
+
k_vectors, amplitudes, phases = random_displacement_potential(4, k_min=2 * np.pi, k_max=6 * np.pi, amplitude_scale=0.02, seed=0)
|
|
107
|
+
return q, k_vectors, amplitudes, phases
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def test_animate_zeldovich_collapse_builds_and_draws_a_frame():
|
|
111
|
+
q, k_vectors, amplitudes, phases = _small_zeldovich_field()
|
|
112
|
+
D_values = np.linspace(0.0, 0.1, 3)
|
|
113
|
+
anim = animate_zeldovich_collapse(q, D_values, k_vectors, amplitudes, phases)
|
|
114
|
+
anim._draw_frame(1)
|
|
115
|
+
assert anim._fig.axes[0].collections # the density-colored scatter exists
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_plot_zeldovich_snapshot_returns_figure():
|
|
119
|
+
q, k_vectors, amplitudes, phases = _small_zeldovich_field()
|
|
120
|
+
fig, ax = plot_zeldovich_snapshot(q, 0.05, k_vectors, amplitudes, phases)
|
|
121
|
+
assert isinstance(fig, plt.Figure)
|
|
122
|
+
assert ax.collections
|
|
123
|
+
|
|
124
|
+
_, ax_given = plot_zeldovich_snapshot(q, 0.05, k_vectors, amplitudes, phases, ax=ax)
|
|
125
|
+
assert ax_given is ax
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@pytest.mark.slow
|
|
129
|
+
def test_animate_stellar_convection_builds_and_draws_a_frame():
|
|
130
|
+
times, omega_snaps, T_snaps = simulate_stellar_convection(16, 16, 2 * np.pi, 2 * np.pi, n_steps=20, save_every=10, seed=0)
|
|
131
|
+
anim = animate_stellar_convection(times, omega_snaps, T_snaps)
|
|
132
|
+
anim._draw_frame(1)
|
|
133
|
+
ax_omega, ax_T = anim._fig.axes[0], anim._fig.axes[1]
|
|
134
|
+
assert len(ax_omega.images) == 1 and len(ax_T.images) == 1
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_animate_dynamo_wave_builds_and_draws_a_frame():
|
|
138
|
+
Lx = 2 * np.pi
|
|
139
|
+
x = np.linspace(0, Lx, 16, endpoint=False)
|
|
140
|
+
A0 = 1e-3 * np.cos(x)
|
|
141
|
+
B0 = np.zeros_like(A0)
|
|
142
|
+
times, A_snaps, B_snaps = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=5.0, eta=0.05, Lx=Lx, dt=0.01, n_steps=20, save_every=5)
|
|
143
|
+
anim = animate_dynamo_wave(times, A_snaps, B_snaps, x)
|
|
144
|
+
anim._draw_frame(1)
|
|
145
|
+
assert len(anim._fig.axes[0].lines) == 2 # A(x) and B(x)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def test_plot_dynamo_butterfly_diagram_returns_figure():
|
|
149
|
+
Lx = 2 * np.pi
|
|
150
|
+
x = np.linspace(0, Lx, 16, endpoint=False)
|
|
151
|
+
A0 = 1e-3 * np.cos(x)
|
|
152
|
+
B0 = np.zeros_like(A0)
|
|
153
|
+
times, A_snaps, B_snaps = simulate_alpha_omega_dynamo(A0, B0, alpha=1.0, shear=5.0, eta=0.05, Lx=Lx, dt=0.01, n_steps=20, save_every=5)
|
|
154
|
+
fig, ax = plot_dynamo_butterfly_diagram(times, B_snaps, x)
|
|
155
|
+
assert isinstance(fig, plt.Figure)
|
|
156
|
+
assert ax.collections
|
|
157
|
+
|
|
158
|
+
_, ax_given = plot_dynamo_butterfly_diagram(times, B_snaps, x, ax=ax)
|
|
159
|
+
assert ax_given is ax
|