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,705 @@
|
|
|
1
|
+
r"""Animations for the ten toy "collider physics" demonstrations built on
|
|
2
|
+
top of :mod:`physicskit.particle`'s decay, scattering, shower,
|
|
3
|
+
confinement, electroweak, and neutrino-oscillation models.
|
|
4
|
+
|
|
5
|
+
Every function here returns a :class:`matplotlib.animation.FuncAnimation`
|
|
6
|
+
(built with ``blit=False`` throughout, since several of these redraw
|
|
7
|
+
variable-length or variable-count artists each frame); save it with
|
|
8
|
+
e.g. ``anim.save(path, writer=PillowWriter(fps=10))``.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import matplotlib.pyplot as plt
|
|
14
|
+
import numpy as np
|
|
15
|
+
from matplotlib.animation import FuncAnimation
|
|
16
|
+
from matplotlib.patches import Circle
|
|
17
|
+
|
|
18
|
+
from physicskit.particle.collider import charged_track_points, cluster_into_jets, flatten_shower, shower_leaves
|
|
19
|
+
from physicskit.particle.decays import michel_spectrum
|
|
20
|
+
from physicskit.particle.electroweak import cp_asymmetry, higgs_potential
|
|
21
|
+
from physicskit.particle.electroweak import qed_dsigma_domega_mumu as _qed_dsigma_domega_mumu
|
|
22
|
+
from physicskit.particle.neutrinos import oscillation_probability
|
|
23
|
+
from physicskit.particle.scattering import ALPHA_FS
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"animate_particle_cascade",
|
|
27
|
+
"animate_parton_shower",
|
|
28
|
+
"animate_detector_event",
|
|
29
|
+
"animate_string_breaking",
|
|
30
|
+
"animate_higgs_rollover",
|
|
31
|
+
"animate_decay_chain_bars",
|
|
32
|
+
"animate_neutrino_oscillation",
|
|
33
|
+
"animate_qed_angular_distribution",
|
|
34
|
+
"animate_michel_histogram",
|
|
35
|
+
"animate_cp_asymmetry",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# Items 1 & 7: shower / parton-shower tree animation (shared machinery)
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _layout_shower_positions(root, track_length):
|
|
45
|
+
"""Map each non-root node to a (start, end) 2D transverse-plane segment,
|
|
46
|
+
walking outward from the collision vertex at the origin."""
|
|
47
|
+
positions = {}
|
|
48
|
+
|
|
49
|
+
def walk(node, start):
|
|
50
|
+
for child in node.children:
|
|
51
|
+
px, py = child.four_vector.px, child.four_vector.py
|
|
52
|
+
pt = float(np.hypot(px, py))
|
|
53
|
+
direction = np.array([px, py]) / pt if pt > 1e-9 else np.array([1.0, 0.0])
|
|
54
|
+
end = start + track_length * direction
|
|
55
|
+
positions[id(child)] = (start, end)
|
|
56
|
+
walk(child, end)
|
|
57
|
+
|
|
58
|
+
walk(root, np.array([0.0, 0.0]))
|
|
59
|
+
return positions
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _animate_shower_tree(root, detector_radii, track_length, interval, ax, color_func, extra_static=None):
|
|
63
|
+
positions = _layout_shower_positions(root, track_length)
|
|
64
|
+
nodes = [n for n in flatten_shower(root) if n.parent is not None]
|
|
65
|
+
nodes.sort(key=lambda n: n.generation)
|
|
66
|
+
|
|
67
|
+
if ax is None:
|
|
68
|
+
fig, ax = plt.subplots()
|
|
69
|
+
else:
|
|
70
|
+
fig = ax.figure
|
|
71
|
+
R_track, R_calo = detector_radii
|
|
72
|
+
ax.add_patch(Circle((0, 0), R_track, fill=False, linestyle="--", color="steelblue"))
|
|
73
|
+
ax.add_patch(Circle((0, 0), R_calo, fill=False, linestyle="-", color="firebrick"))
|
|
74
|
+
if extra_static is not None:
|
|
75
|
+
extra_static(ax, R_calo)
|
|
76
|
+
ax.set_xlim(-R_calo * 1.15, R_calo * 1.15)
|
|
77
|
+
ax.set_ylim(-R_calo * 1.15, R_calo * 1.15)
|
|
78
|
+
ax.set_aspect("equal")
|
|
79
|
+
ax.plot(0, 0, "k*", markersize=10)
|
|
80
|
+
|
|
81
|
+
lines = [ax.plot([], [], lw=1.6, color=color_func(n))[0] for n in nodes]
|
|
82
|
+
(markers,) = ax.plot([], [], "o", color="black", markersize=3)
|
|
83
|
+
|
|
84
|
+
def update(frame):
|
|
85
|
+
visible = nodes[: frame + 1]
|
|
86
|
+
for line, node in zip(lines, nodes):
|
|
87
|
+
if node in visible:
|
|
88
|
+
s, e = positions[id(node)]
|
|
89
|
+
line.set_data([s[0], e[0]], [s[1], e[1]])
|
|
90
|
+
ends = np.array([positions[id(n)][1] for n in visible]) if visible else np.empty((0, 2))
|
|
91
|
+
if len(ends):
|
|
92
|
+
markers.set_data(ends[:, 0], ends[:, 1])
|
|
93
|
+
return [*lines, markers]
|
|
94
|
+
|
|
95
|
+
return FuncAnimation(fig, update, frames=max(len(nodes), 1), interval=interval, blit=False)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def animate_particle_cascade(root, detector_radii=(3.0, 6.0), track_length=0.6, interval=150, ax=None):
|
|
99
|
+
"""Animate a toy shower cascade (:func:`physicskit.particle.collider.simple_shower`)
|
|
100
|
+
propagating outward from the collision vertex through a schematic detector.
|
|
101
|
+
|
|
102
|
+
Concentric circles mark a "tracker" (inner) and "calorimeter" (outer)
|
|
103
|
+
region; each branch of the shower tree appears as one more track
|
|
104
|
+
segment per frame, in order of production (generation).
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
root : physicskit.particle.collider.ShowerParticle
|
|
109
|
+
Root of the shower tree, e.g. from
|
|
110
|
+
:func:`physicskit.particle.collider.simple_shower`.
|
|
111
|
+
detector_radii : (float, float), default=(3.0, 6.0)
|
|
112
|
+
Radii of the schematic tracker and calorimeter circles.
|
|
113
|
+
track_length : float, default=0.6
|
|
114
|
+
Schematic (not physically derived) drawn length of each track
|
|
115
|
+
segment -- purely a layout choice, not a decay-length calculation.
|
|
116
|
+
interval : int, default=150
|
|
117
|
+
Delay between frames, in milliseconds.
|
|
118
|
+
ax : matplotlib.axes.Axes, optional
|
|
119
|
+
Axes to draw into; a new figure is created if omitted.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
matplotlib.animation.FuncAnimation
|
|
124
|
+
|
|
125
|
+
Examples
|
|
126
|
+
--------
|
|
127
|
+
>>> import numpy as np
|
|
128
|
+
>>> from physicskit.particle.collider import simple_shower
|
|
129
|
+
>>> root = simple_shower(50.0, E_threshold=5.0, rng=np.random.default_rng(0))
|
|
130
|
+
>>> anim = animate_particle_cascade(root)
|
|
131
|
+
>>> anim.__class__.__name__
|
|
132
|
+
'FuncAnimation'
|
|
133
|
+
"""
|
|
134
|
+
return _animate_shower_tree(
|
|
135
|
+
root,
|
|
136
|
+
detector_radii,
|
|
137
|
+
track_length,
|
|
138
|
+
interval,
|
|
139
|
+
ax,
|
|
140
|
+
color_func=lambda n: plt.cm.plasma(min(n.generation / 6.0, 1.0)),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def animate_parton_shower(root, detector_radii=(3.0, 6.0), track_length=0.6, n_jets=2, interval=150, ax=None):
|
|
145
|
+
"""Animate a toy parton shower (:func:`physicskit.particle.collider.parton_shower`)
|
|
146
|
+
developing into jets.
|
|
147
|
+
|
|
148
|
+
Reuses the tree-reveal machinery of :func:`animate_particle_cascade`,
|
|
149
|
+
color-coding branches by parton flavor (quark/antiquark vs. gluon)
|
|
150
|
+
and overlaying the final jet-axis directions found by
|
|
151
|
+
:func:`physicskit.particle.collider.cluster_into_jets`.
|
|
152
|
+
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
root : physicskit.particle.collider.ShowerParticle
|
|
156
|
+
Root of the parton shower tree.
|
|
157
|
+
detector_radii, track_length, interval, ax
|
|
158
|
+
See :func:`animate_particle_cascade`.
|
|
159
|
+
n_jets : int, default=2
|
|
160
|
+
Number of jet cones to cluster the final state into and overlay.
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
matplotlib.animation.FuncAnimation
|
|
165
|
+
|
|
166
|
+
Examples
|
|
167
|
+
--------
|
|
168
|
+
>>> import numpy as np
|
|
169
|
+
>>> from physicskit.particle.collider import parton_shower
|
|
170
|
+
>>> root = parton_shower(50.0, E_threshold=5.0, rng=np.random.default_rng(0))
|
|
171
|
+
>>> anim = animate_parton_shower(root)
|
|
172
|
+
>>> anim.__class__.__name__
|
|
173
|
+
'FuncAnimation'
|
|
174
|
+
"""
|
|
175
|
+
flavor_colors = {"q": "royalblue", "qbar": "seagreen", "g": "firebrick", "": "gray"}
|
|
176
|
+
leaves = shower_leaves(root)
|
|
177
|
+
jets = cluster_into_jets(leaves, n_jets=n_jets) if len(leaves) >= n_jets else []
|
|
178
|
+
|
|
179
|
+
def extra_static(ax, R_calo):
|
|
180
|
+
for jet in jets:
|
|
181
|
+
if not jet:
|
|
182
|
+
continue
|
|
183
|
+
px = np.mean([leaf.four_vector.px for leaf in jet])
|
|
184
|
+
py = np.mean([leaf.four_vector.py for leaf in jet])
|
|
185
|
+
pt = np.hypot(px, py)
|
|
186
|
+
if pt > 1e-9:
|
|
187
|
+
ax.plot([0, R_calo * px / pt], [0, R_calo * py / pt], "--", color="black", alpha=0.4, lw=1.0)
|
|
188
|
+
|
|
189
|
+
return _animate_shower_tree(
|
|
190
|
+
root,
|
|
191
|
+
detector_radii,
|
|
192
|
+
track_length,
|
|
193
|
+
interval,
|
|
194
|
+
ax,
|
|
195
|
+
color_func=lambda n: flavor_colors.get(n.flavor, "gray"),
|
|
196
|
+
extra_static=extra_static,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# ---------------------------------------------------------------------------
|
|
201
|
+
# Item 10: detector event display
|
|
202
|
+
# ---------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def animate_detector_event(four_vectors, charges, B, detector_radii=(3.0, 6.0), n_frames=60, interval=100, ax=None):
|
|
206
|
+
r"""Animate final-state tracks growing outward from the vertex and
|
|
207
|
+
landing in a schematic calorimeter.
|
|
208
|
+
|
|
209
|
+
Charged particles curve (radius :math:`r=p_T/(qB)`, see
|
|
210
|
+
:func:`physicskit.particle.collider.charged_track_points`); neutral
|
|
211
|
+
particles fly in straight lines. Each frame reveals one more step
|
|
212
|
+
along every track; a marker is drawn at each track's current
|
|
213
|
+
endpoint, standing in for a calorimeter energy deposit once the
|
|
214
|
+
track reaches the outer radius.
|
|
215
|
+
|
|
216
|
+
Parameters
|
|
217
|
+
----------
|
|
218
|
+
four_vectors : sequence of physicskit.particle.kinematics.FourVector
|
|
219
|
+
Final-state particles.
|
|
220
|
+
charges : sequence of float
|
|
221
|
+
Charge of each particle, in units of the elementary charge.
|
|
222
|
+
B : float
|
|
223
|
+
Magnetic field strength (see
|
|
224
|
+
:func:`~physicskit.particle.collider.charged_track_points`).
|
|
225
|
+
detector_radii : (float, float), default=(3.0, 6.0)
|
|
226
|
+
Radii of the schematic tracker and calorimeter circles.
|
|
227
|
+
n_frames : int, default=60
|
|
228
|
+
Number of animation frames (and points sampled along each track).
|
|
229
|
+
interval : int, default=100
|
|
230
|
+
Delay between frames, in milliseconds.
|
|
231
|
+
ax : matplotlib.axes.Axes, optional
|
|
232
|
+
Axes to draw into; a new figure is created if omitted.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
matplotlib.animation.FuncAnimation
|
|
237
|
+
|
|
238
|
+
Examples
|
|
239
|
+
--------
|
|
240
|
+
>>> from physicskit.particle.kinematics import FourVector
|
|
241
|
+
>>> ps = [FourVector(5.0, 3.0, 0.0, 3.0), FourVector(4.0, 0.0, 3.0, 2.0)]
|
|
242
|
+
>>> anim = animate_detector_event(ps, charges=[1.0, -1.0], B=1.0)
|
|
243
|
+
>>> anim.__class__.__name__
|
|
244
|
+
'FuncAnimation'
|
|
245
|
+
"""
|
|
246
|
+
R_track, R_calo = detector_radii
|
|
247
|
+
tracks = [charged_track_points(p, q, B, n_points=n_frames, path_length=R_calo * 1.3) for p, q in zip(four_vectors, charges)]
|
|
248
|
+
|
|
249
|
+
if ax is None:
|
|
250
|
+
fig, ax = plt.subplots()
|
|
251
|
+
else:
|
|
252
|
+
fig = ax.figure
|
|
253
|
+
ax.add_patch(Circle((0, 0), R_track, fill=False, linestyle="--", color="steelblue"))
|
|
254
|
+
ax.add_patch(Circle((0, 0), R_calo, fill=False, color="firebrick"))
|
|
255
|
+
ax.set_xlim(-R_calo * 1.15, R_calo * 1.15)
|
|
256
|
+
ax.set_ylim(-R_calo * 1.15, R_calo * 1.15)
|
|
257
|
+
ax.set_aspect("equal")
|
|
258
|
+
ax.plot(0, 0, "k*", markersize=10)
|
|
259
|
+
|
|
260
|
+
colors = ["crimson" if q > 0 else ("royalblue" if q < 0 else "gray") for q in charges]
|
|
261
|
+
lines = [ax.plot([], [], lw=1.8, color=c)[0] for c in colors]
|
|
262
|
+
(deposits,) = ax.plot([], [], "s", color="darkorange", markersize=7)
|
|
263
|
+
|
|
264
|
+
def update(frame):
|
|
265
|
+
ends = []
|
|
266
|
+
for line, track in zip(lines, tracks):
|
|
267
|
+
pts = track[: frame + 2]
|
|
268
|
+
line.set_data(pts[:, 0], pts[:, 1])
|
|
269
|
+
ends.append(pts[-1])
|
|
270
|
+
ends = np.array(ends)
|
|
271
|
+
deposits.set_data(ends[:, 0], ends[:, 1])
|
|
272
|
+
return [*lines, deposits]
|
|
273
|
+
|
|
274
|
+
return FuncAnimation(fig, update, frames=n_frames, interval=interval, blit=False)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
# ---------------------------------------------------------------------------
|
|
278
|
+
# Item 2: quark confinement / string breaking
|
|
279
|
+
# ---------------------------------------------------------------------------
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def animate_string_breaking(sim, interval=120, ax=None):
|
|
283
|
+
r"""Animate a receding quark pair's confining string stretching and
|
|
284
|
+
breaking, from :func:`physicskit.particle.confinement.string_break_chain`.
|
|
285
|
+
|
|
286
|
+
A thick line (whose width and color track the stored tension,
|
|
287
|
+
``energy_per_segment``) stretches between the two receding quark
|
|
288
|
+
markers; each time the simulation records a break, it snaps into
|
|
289
|
+
one more, shorter segment, with a new marker appearing at each
|
|
290
|
+
newly created quark-antiquark endpoint. (The endpoints of the
|
|
291
|
+
``n_segments(t)`` current strings are drawn evenly spaced across the
|
|
292
|
+
current total extent -- a schematic simplification, see
|
|
293
|
+
:func:`~physicskit.particle.confinement.string_break_chain`'s
|
|
294
|
+
docstring, rather than tracking each new pair's exact, individually
|
|
295
|
+
frozen creation position.)
|
|
296
|
+
|
|
297
|
+
Parameters
|
|
298
|
+
----------
|
|
299
|
+
sim : dict
|
|
300
|
+
Output of :func:`physicskit.particle.confinement.string_break_chain`.
|
|
301
|
+
interval : int, default=120
|
|
302
|
+
Delay between frames, in milliseconds.
|
|
303
|
+
ax : matplotlib.axes.Axes, optional
|
|
304
|
+
Axes to draw into; a new figure is created if omitted.
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
matplotlib.animation.FuncAnimation
|
|
309
|
+
|
|
310
|
+
Examples
|
|
311
|
+
--------
|
|
312
|
+
>>> import numpy as np
|
|
313
|
+
>>> from physicskit.particle.confinement import string_break_chain
|
|
314
|
+
>>> sim = string_break_chain(np.linspace(0, 10, 40), v=0.3, kappa=1.0, m_q=1.0, n_breaks=2)
|
|
315
|
+
>>> anim = animate_string_breaking(sim)
|
|
316
|
+
>>> anim.__class__.__name__
|
|
317
|
+
'FuncAnimation'
|
|
318
|
+
"""
|
|
319
|
+
t, r, n_segments, energy_per_segment = sim["t"], sim["r"], sim["n_segments"], sim["energy_per_segment"]
|
|
320
|
+
m_q = sim["m_q"]
|
|
321
|
+
max_segments = int(n_segments.max())
|
|
322
|
+
|
|
323
|
+
if ax is None:
|
|
324
|
+
fig, ax = plt.subplots(figsize=(7, 2.5))
|
|
325
|
+
else:
|
|
326
|
+
fig = ax.figure
|
|
327
|
+
rmax = r.max() * 0.55 + 1e-9
|
|
328
|
+
ax.set_xlim(-rmax, rmax)
|
|
329
|
+
ax.set_ylim(-1.0, 1.0)
|
|
330
|
+
ax.set_yticks([])
|
|
331
|
+
ax.set_xlabel("separation")
|
|
332
|
+
ax.set_title("QCD string breaking")
|
|
333
|
+
|
|
334
|
+
lines = [ax.plot([], [], lw=3, solid_capstyle="round", color="darkorange")[0] for _ in range(max_segments)]
|
|
335
|
+
(endpoints,) = ax.plot([], [], "o", color="black", markersize=7)
|
|
336
|
+
|
|
337
|
+
def update(frame):
|
|
338
|
+
n = int(n_segments[frame])
|
|
339
|
+
half = r[frame] / 2.0
|
|
340
|
+
xs = np.linspace(-half, half, n + 1)
|
|
341
|
+
tension = min(energy_per_segment[frame] / (2.0 * m_q), 1.0)
|
|
342
|
+
for i, line in enumerate(lines):
|
|
343
|
+
if i < n:
|
|
344
|
+
line.set_data([xs[i], xs[i + 1]], [0.0, 0.0])
|
|
345
|
+
line.set_color(plt.cm.inferno(0.2 + 0.6 * tension))
|
|
346
|
+
line.set_linewidth(1.0 + 4.0 * tension)
|
|
347
|
+
else:
|
|
348
|
+
line.set_data([], [])
|
|
349
|
+
endpoints.set_data(xs, np.zeros_like(xs))
|
|
350
|
+
return [*lines, endpoints]
|
|
351
|
+
|
|
352
|
+
return FuncAnimation(fig, update, frames=len(t), interval=interval, blit=False)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
# ---------------------------------------------------------------------------
|
|
356
|
+
# Item 3: Higgs mechanism (classical rollover)
|
|
357
|
+
# ---------------------------------------------------------------------------
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def animate_higgs_rollover(phi_t, a, b, interval=30, ax=None):
|
|
361
|
+
r"""Animate a scalar field rolling from the unstable symmetric point
|
|
362
|
+
into a broken-symmetry vacuum, from
|
|
363
|
+
:func:`physicskit.particle.electroweak.higgs_field_rollover`.
|
|
364
|
+
|
|
365
|
+
The static curve is :func:`physicskit.particle.electroweak.higgs_potential`;
|
|
366
|
+
a point (with a fading trail) traces :math:`(\phi(t), V(\phi(t)))` as
|
|
367
|
+
the field rolls down one side of the double well.
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
----------
|
|
371
|
+
phi_t : ndarray
|
|
372
|
+
Field trajectory :math:`\phi(t)`, e.g. the first output of
|
|
373
|
+
:func:`~physicskit.particle.electroweak.higgs_field_rollover`.
|
|
374
|
+
a, b : float
|
|
375
|
+
Potential parameters, see
|
|
376
|
+
:func:`~physicskit.particle.electroweak.higgs_potential`.
|
|
377
|
+
interval : int, default=30
|
|
378
|
+
Delay between frames, in milliseconds.
|
|
379
|
+
ax : matplotlib.axes.Axes, optional
|
|
380
|
+
Axes to draw into; a new figure is created if omitted.
|
|
381
|
+
|
|
382
|
+
Returns
|
|
383
|
+
-------
|
|
384
|
+
matplotlib.animation.FuncAnimation
|
|
385
|
+
|
|
386
|
+
Examples
|
|
387
|
+
--------
|
|
388
|
+
>>> import numpy as np
|
|
389
|
+
>>> from physicskit.particle.electroweak import higgs_field_rollover
|
|
390
|
+
>>> t = np.linspace(0, 40, 100)
|
|
391
|
+
>>> phi, _ = higgs_field_rollover(1e-3, 0.0, a=1.0, b=1.0, t_eval=t, damping=0.05)
|
|
392
|
+
>>> anim = animate_higgs_rollover(phi, a=1.0, b=1.0)
|
|
393
|
+
>>> anim.__class__.__name__
|
|
394
|
+
'FuncAnimation'
|
|
395
|
+
"""
|
|
396
|
+
span = 1.3 * np.max(np.abs(phi_t)) + 0.1
|
|
397
|
+
phi_range = np.linspace(-span, span, 400)
|
|
398
|
+
V = higgs_potential(phi_range, a, b)
|
|
399
|
+
|
|
400
|
+
if ax is None:
|
|
401
|
+
fig, ax = plt.subplots()
|
|
402
|
+
else:
|
|
403
|
+
fig = ax.figure
|
|
404
|
+
ax.plot(phi_range, V, color="gray", lw=1.5)
|
|
405
|
+
ax.set_xlabel(r"$\phi$")
|
|
406
|
+
ax.set_ylabel(r"$V(\phi)$")
|
|
407
|
+
ax.set_title("Classical symmetry breaking")
|
|
408
|
+
(point,) = ax.plot([], [], "o", color="crimson", markersize=8)
|
|
409
|
+
(trace,) = ax.plot([], [], color="crimson", lw=1.0, alpha=0.5)
|
|
410
|
+
|
|
411
|
+
def update(frame):
|
|
412
|
+
phi = phi_t[: frame + 1]
|
|
413
|
+
V_phi = higgs_potential(phi, a, b)
|
|
414
|
+
trace.set_data(phi, V_phi)
|
|
415
|
+
point.set_data([phi[-1]], [V_phi[-1]])
|
|
416
|
+
return [point, trace]
|
|
417
|
+
|
|
418
|
+
return FuncAnimation(fig, update, frames=len(phi_t), interval=interval, blit=False)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
# ---------------------------------------------------------------------------
|
|
422
|
+
# Item 4: decay chain population animation
|
|
423
|
+
# ---------------------------------------------------------------------------
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def animate_decay_chain_bars(t, populations, labels=None, interval=150, ax=None):
|
|
427
|
+
"""Animate each species' population evolving over time in a decay chain.
|
|
428
|
+
|
|
429
|
+
Parameters
|
|
430
|
+
----------
|
|
431
|
+
t : ndarray of shape (n_t,)
|
|
432
|
+
Times.
|
|
433
|
+
populations : ndarray of shape (n_species, n_t)
|
|
434
|
+
Population of each species over time, e.g. from
|
|
435
|
+
:func:`physicskit.particle.decays.bateman_decay_chain`.
|
|
436
|
+
labels : sequence of str, optional
|
|
437
|
+
Bar labels; defaults to ``"species 1"``, ``"species 2"``, ...
|
|
438
|
+
interval : int, default=150
|
|
439
|
+
Delay between frames, in milliseconds.
|
|
440
|
+
ax : matplotlib.axes.Axes, optional
|
|
441
|
+
Axes to draw into; a new figure is created if omitted.
|
|
442
|
+
|
|
443
|
+
Returns
|
|
444
|
+
-------
|
|
445
|
+
matplotlib.animation.FuncAnimation
|
|
446
|
+
|
|
447
|
+
Examples
|
|
448
|
+
--------
|
|
449
|
+
>>> import numpy as np
|
|
450
|
+
>>> from physicskit.particle.decays import bateman_decay_chain
|
|
451
|
+
>>> t = np.linspace(0, 10, 30)
|
|
452
|
+
>>> N = bateman_decay_chain(1000.0, [0.5, 0.2], t)
|
|
453
|
+
>>> anim = animate_decay_chain_bars(t, N)
|
|
454
|
+
>>> anim.__class__.__name__
|
|
455
|
+
'FuncAnimation'
|
|
456
|
+
"""
|
|
457
|
+
populations = np.asarray(populations)
|
|
458
|
+
n_species = populations.shape[0]
|
|
459
|
+
if labels is None:
|
|
460
|
+
labels = [f"species {i + 1}" for i in range(n_species)]
|
|
461
|
+
if ax is None:
|
|
462
|
+
fig, ax = plt.subplots()
|
|
463
|
+
else:
|
|
464
|
+
fig = ax.figure
|
|
465
|
+
bars = ax.bar(labels, populations[:, 0], color=plt.cm.viridis(np.linspace(0, 1, n_species)))
|
|
466
|
+
ax.set_ylim(0, populations.max() * 1.05 + 1e-12)
|
|
467
|
+
ax.set_ylabel("population")
|
|
468
|
+
title = ax.set_title(f"t = {t[0]:.2f}")
|
|
469
|
+
|
|
470
|
+
def update(frame):
|
|
471
|
+
for bar, h in zip(bars, populations[:, frame]):
|
|
472
|
+
bar.set_height(h)
|
|
473
|
+
title.set_text(f"t = {t[frame]:.2f}")
|
|
474
|
+
return [*bars, title]
|
|
475
|
+
|
|
476
|
+
return FuncAnimation(fig, update, frames=len(t), interval=interval, blit=False)
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
# ---------------------------------------------------------------------------
|
|
480
|
+
# Item 5: neutrino oscillations
|
|
481
|
+
# ---------------------------------------------------------------------------
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def animate_neutrino_oscillation(L, E, theta, delta_m2, interval=60, ax=None):
|
|
485
|
+
r"""Animate :math:`P(\nu_e)` and :math:`P(\nu_\mu)` growing as a
|
|
486
|
+
function of distance traveled, from
|
|
487
|
+
:func:`physicskit.particle.neutrinos.oscillation_probability`.
|
|
488
|
+
|
|
489
|
+
Parameters
|
|
490
|
+
----------
|
|
491
|
+
L : ndarray
|
|
492
|
+
Baselines (distance traveled), in km, in increasing order.
|
|
493
|
+
E : float
|
|
494
|
+
Neutrino energy, in GeV.
|
|
495
|
+
theta : float
|
|
496
|
+
Mixing angle, radians.
|
|
497
|
+
delta_m2 : float
|
|
498
|
+
Mass-squared splitting, in :math:`{\rm eV}^2`.
|
|
499
|
+
interval : int, default=60
|
|
500
|
+
Delay between frames, in milliseconds.
|
|
501
|
+
ax : matplotlib.axes.Axes, optional
|
|
502
|
+
Axes to draw into; a new figure is created if omitted.
|
|
503
|
+
|
|
504
|
+
Returns
|
|
505
|
+
-------
|
|
506
|
+
matplotlib.animation.FuncAnimation
|
|
507
|
+
|
|
508
|
+
Examples
|
|
509
|
+
--------
|
|
510
|
+
>>> import numpy as np
|
|
511
|
+
>>> L = np.linspace(0, 1000, 100)
|
|
512
|
+
>>> anim = animate_neutrino_oscillation(L, E=1.0, theta=0.6, delta_m2=2.5e-3)
|
|
513
|
+
>>> anim.__class__.__name__
|
|
514
|
+
'FuncAnimation'
|
|
515
|
+
"""
|
|
516
|
+
L = np.asarray(L, dtype=float)
|
|
517
|
+
P_mu = oscillation_probability(L, E, theta, delta_m2)
|
|
518
|
+
P_e = 1.0 - P_mu
|
|
519
|
+
|
|
520
|
+
if ax is None:
|
|
521
|
+
fig, ax = plt.subplots()
|
|
522
|
+
else:
|
|
523
|
+
fig = ax.figure
|
|
524
|
+
ax.set_xlim(L.min(), L.max())
|
|
525
|
+
ax.set_ylim(0.0, 1.05)
|
|
526
|
+
ax.set_xlabel("L [km]")
|
|
527
|
+
ax.set_ylabel("probability")
|
|
528
|
+
(line_e,) = ax.plot([], [], color="steelblue", label=r"$P(\nu_e)$")
|
|
529
|
+
(line_mu,) = ax.plot([], [], color="firebrick", label=r"$P(\nu_\mu)$")
|
|
530
|
+
ax.legend(loc="upper right")
|
|
531
|
+
|
|
532
|
+
def update(frame):
|
|
533
|
+
line_e.set_data(L[: frame + 1], P_e[: frame + 1])
|
|
534
|
+
line_mu.set_data(L[: frame + 1], P_mu[: frame + 1])
|
|
535
|
+
return [line_e, line_mu]
|
|
536
|
+
|
|
537
|
+
return FuncAnimation(fig, update, frames=len(L), interval=interval, blit=False)
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
# ---------------------------------------------------------------------------
|
|
541
|
+
# Item 6: QED angular distribution vs. sqrt(s)
|
|
542
|
+
# ---------------------------------------------------------------------------
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def animate_qed_angular_distribution(sqrt_s_values, alpha=ALPHA_FS, n_theta=200, interval=200, ax=None):
|
|
546
|
+
r"""Animate the :math:`e^+e^-\to\mu^+\mu^-` angular distribution's
|
|
547
|
+
shape as :math:`\sqrt s` is swept, from
|
|
548
|
+
:func:`physicskit.particle.electroweak.qed_dsigma_domega_mumu`.
|
|
549
|
+
|
|
550
|
+
Parameters
|
|
551
|
+
----------
|
|
552
|
+
sqrt_s_values : ndarray
|
|
553
|
+
Center-of-mass energies to sweep through (one per frame).
|
|
554
|
+
alpha : float, default=ALPHA_FS
|
|
555
|
+
Fine-structure constant.
|
|
556
|
+
n_theta : int, default=200
|
|
557
|
+
Number of polar-angle samples per frame.
|
|
558
|
+
interval : int, default=200
|
|
559
|
+
Delay between frames, in milliseconds.
|
|
560
|
+
ax : matplotlib.axes.Axes, optional
|
|
561
|
+
Polar axes to draw into; new polar axes are created if omitted.
|
|
562
|
+
|
|
563
|
+
Returns
|
|
564
|
+
-------
|
|
565
|
+
matplotlib.animation.FuncAnimation
|
|
566
|
+
|
|
567
|
+
Examples
|
|
568
|
+
--------
|
|
569
|
+
>>> import numpy as np
|
|
570
|
+
>>> sqrt_s = np.linspace(5.0, 20.0, 20)
|
|
571
|
+
>>> anim = animate_qed_angular_distribution(sqrt_s)
|
|
572
|
+
>>> anim.__class__.__name__
|
|
573
|
+
'FuncAnimation'
|
|
574
|
+
"""
|
|
575
|
+
theta = np.linspace(0.0, np.pi, n_theta)
|
|
576
|
+
if ax is None:
|
|
577
|
+
fig = plt.figure()
|
|
578
|
+
ax = fig.add_subplot(projection="polar")
|
|
579
|
+
else:
|
|
580
|
+
fig = ax.figure
|
|
581
|
+
(line,) = ax.plot([], [])
|
|
582
|
+
title = ax.set_title("")
|
|
583
|
+
|
|
584
|
+
def update(frame):
|
|
585
|
+
s = sqrt_s_values[frame]
|
|
586
|
+
vals = _qed_dsigma_domega_mumu(np.cos(theta), s, alpha=alpha)
|
|
587
|
+
line.set_data(theta, vals)
|
|
588
|
+
ax.set_ylim(0.0, max(float(vals.max()) * 1.1, 1e-30))
|
|
589
|
+
title.set_text(rf"$\sqrt{{s}}={s:.2f}$")
|
|
590
|
+
return [line, title]
|
|
591
|
+
|
|
592
|
+
return FuncAnimation(fig, update, frames=len(sqrt_s_values), interval=interval, blit=False)
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
# ---------------------------------------------------------------------------
|
|
596
|
+
# Item 8: muon decay / Michel spectrum
|
|
597
|
+
# ---------------------------------------------------------------------------
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def animate_michel_histogram(x_samples, batch_size=20, n_bins=30, interval=100, ax=None):
|
|
601
|
+
r"""Animate a histogram of sampled Michel-spectrum electron energies
|
|
602
|
+
building up event-by-event, converging to
|
|
603
|
+
:func:`physicskit.particle.decays.michel_spectrum`.
|
|
604
|
+
|
|
605
|
+
Parameters
|
|
606
|
+
----------
|
|
607
|
+
x_samples : ndarray
|
|
608
|
+
Sampled scaled electron energies, e.g. from
|
|
609
|
+
:func:`physicskit.particle.decays.sample_michel_electron_energies`.
|
|
610
|
+
batch_size : int, default=20
|
|
611
|
+
Number of additional samples revealed per frame.
|
|
612
|
+
n_bins : int, default=30
|
|
613
|
+
Number of histogram bins.
|
|
614
|
+
interval : int, default=100
|
|
615
|
+
Delay between frames, in milliseconds.
|
|
616
|
+
ax : matplotlib.axes.Axes, optional
|
|
617
|
+
Axes to draw into; a new figure is created if omitted.
|
|
618
|
+
|
|
619
|
+
Returns
|
|
620
|
+
-------
|
|
621
|
+
matplotlib.animation.FuncAnimation
|
|
622
|
+
|
|
623
|
+
Examples
|
|
624
|
+
--------
|
|
625
|
+
>>> import numpy as np
|
|
626
|
+
>>> from physicskit.particle.decays import sample_michel_electron_energies
|
|
627
|
+
>>> xs = sample_michel_electron_energies(500, rng=np.random.default_rng(0))
|
|
628
|
+
>>> anim = animate_michel_histogram(xs, batch_size=100)
|
|
629
|
+
>>> anim.__class__.__name__
|
|
630
|
+
'FuncAnimation'
|
|
631
|
+
"""
|
|
632
|
+
if ax is None:
|
|
633
|
+
fig, ax = plt.subplots()
|
|
634
|
+
else:
|
|
635
|
+
fig = ax.figure
|
|
636
|
+
x_theory = np.linspace(0.0, 1.0, 200)
|
|
637
|
+
y_theory = michel_spectrum(x_theory)
|
|
638
|
+
n_frames = int(np.ceil(len(x_samples) / batch_size))
|
|
639
|
+
|
|
640
|
+
def update(frame):
|
|
641
|
+
ax.cla()
|
|
642
|
+
ax.plot(x_theory, y_theory, color="black", lw=2, label="Michel spectrum")
|
|
643
|
+
n = min((frame + 1) * batch_size, len(x_samples))
|
|
644
|
+
ax.hist(x_samples[:n], bins=n_bins, range=(0.0, 1.0), density=True, color="steelblue", alpha=0.7, label=f"N={n}")
|
|
645
|
+
ax.set_xlabel(r"$x=2E_e/m_\mu$")
|
|
646
|
+
ax.set_ylabel(r"$d\Gamma/dx$")
|
|
647
|
+
ax.set_ylim(0.0, max(2.2, y_theory.max() * 1.2))
|
|
648
|
+
ax.legend(loc="upper left")
|
|
649
|
+
return []
|
|
650
|
+
|
|
651
|
+
return FuncAnimation(fig, update, frames=n_frames, interval=interval, blit=False)
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
# ---------------------------------------------------------------------------
|
|
655
|
+
# Item 9: CP violation
|
|
656
|
+
# ---------------------------------------------------------------------------
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
def animate_cp_asymmetry(t, delta_m, gamma_s, gamma_l, epsilon, interval=60, ax=None):
|
|
660
|
+
r"""Animate the neutral-meson decay-rate CP asymmetry :math:`A(t)`
|
|
661
|
+
building up, from :func:`physicskit.particle.electroweak.cp_asymmetry`.
|
|
662
|
+
|
|
663
|
+
Parameters
|
|
664
|
+
----------
|
|
665
|
+
t : ndarray
|
|
666
|
+
Times.
|
|
667
|
+
delta_m, gamma_s, gamma_l, epsilon
|
|
668
|
+
See :func:`physicskit.particle.electroweak.meson_decay_rates_cp_eigenstate`.
|
|
669
|
+
interval : int, default=60
|
|
670
|
+
Delay between frames, in milliseconds.
|
|
671
|
+
ax : matplotlib.axes.Axes, optional
|
|
672
|
+
Axes to draw into; a new figure is created if omitted.
|
|
673
|
+
|
|
674
|
+
Returns
|
|
675
|
+
-------
|
|
676
|
+
matplotlib.animation.FuncAnimation
|
|
677
|
+
|
|
678
|
+
Examples
|
|
679
|
+
--------
|
|
680
|
+
>>> import numpy as np
|
|
681
|
+
>>> t = np.linspace(0, 20, 100)
|
|
682
|
+
>>> anim = animate_cp_asymmetry(t, delta_m=0.5, gamma_s=1.0, gamma_l=0.1, epsilon=0.002 + 0.001j)
|
|
683
|
+
>>> anim.__class__.__name__
|
|
684
|
+
'FuncAnimation'
|
|
685
|
+
"""
|
|
686
|
+
t = np.asarray(t, dtype=float)
|
|
687
|
+
A = cp_asymmetry(t, delta_m, gamma_s, gamma_l, epsilon)
|
|
688
|
+
|
|
689
|
+
if ax is None:
|
|
690
|
+
fig, ax = plt.subplots()
|
|
691
|
+
else:
|
|
692
|
+
fig = ax.figure
|
|
693
|
+
amax = float(np.max(np.abs(A))) + 1e-12
|
|
694
|
+
ax.set_xlim(t.min(), t.max())
|
|
695
|
+
ax.set_ylim(-1.15 * amax, 1.15 * amax)
|
|
696
|
+
ax.set_xlabel("t")
|
|
697
|
+
ax.set_ylabel("A(t)")
|
|
698
|
+
ax.set_title("CP-violating decay-rate asymmetry")
|
|
699
|
+
(line,) = ax.plot([], [], color="darkorange", lw=1.6)
|
|
700
|
+
|
|
701
|
+
def update(frame):
|
|
702
|
+
line.set_data(t[: frame + 1], A[: frame + 1])
|
|
703
|
+
return [line]
|
|
704
|
+
|
|
705
|
+
return FuncAnimation(fig, update, frames=len(t), interval=interval, blit=False)
|