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,194 @@
|
|
|
1
|
+
"""Physics-correctness tests for physicskit.semiclassical.core.path_integral."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from physicskit.semiclassical.core.path_integral import (
|
|
9
|
+
build_phasor_diagram,
|
|
10
|
+
discretized_action,
|
|
11
|
+
feynman_phasor_partial_sums,
|
|
12
|
+
free_particle_classical_action,
|
|
13
|
+
free_particle_classical_path,
|
|
14
|
+
harmonic_oscillator_classical_action,
|
|
15
|
+
harmonic_oscillator_classical_path,
|
|
16
|
+
sample_random_paths,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_discretized_action_matches_free_particle_closed_form_exactly():
|
|
21
|
+
# The free-particle classical path is a straight line, so the midpoint-rule
|
|
22
|
+
# discretization is exact (constant velocity, zero potential) for any n_slices.
|
|
23
|
+
x0, xf, T, m = 0.0, 2.0, 1.0, 1.0
|
|
24
|
+
_, x = free_particle_classical_path(x0, xf, T, m, n_slices=200)
|
|
25
|
+
S_discrete = discretized_action(x, dt=T / 200, m=m, V=lambda x: 0.0 * x)
|
|
26
|
+
S_exact = free_particle_classical_action(x0, xf, T, m)
|
|
27
|
+
assert S_discrete == pytest.approx(S_exact, rel=1e-10)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_discretized_action_converges_to_harmonic_oscillator_closed_form():
|
|
31
|
+
# Unlike the free particle, the classical path here is curved, so the midpoint
|
|
32
|
+
# rule has O(dt^2) discretization error. At n_slices=200 the achieved relative
|
|
33
|
+
# error is ~2.5e-4 (checked empirically), well inside the 1% tolerance used here.
|
|
34
|
+
x0, xf, T, m, omega = 0.3, -0.7, 2.3, 1.0, 1.1
|
|
35
|
+
n_slices = 200
|
|
36
|
+
_, x = harmonic_oscillator_classical_path(x0, xf, T, m, omega, n_slices)
|
|
37
|
+
V = lambda x: 0.5 * m * omega**2 * x**2
|
|
38
|
+
S_discrete = discretized_action(x, dt=T / n_slices, m=m, V=V)
|
|
39
|
+
S_exact = harmonic_oscillator_classical_action(x0, xf, T, m, omega)
|
|
40
|
+
assert S_discrete == pytest.approx(S_exact, rel=1e-2)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_free_particle_classical_path_minimizes_action_among_random_paths():
|
|
44
|
+
# For a free particle the classical (straight-line) path is a true minimum of
|
|
45
|
+
# the action, not merely a stationary point, so every randomly sampled path
|
|
46
|
+
# must have action >= the classical action (within numerical tolerance).
|
|
47
|
+
x0, xf, T, m, n_slices = 0.0, 1.5, 1.0, 1.0, 40
|
|
48
|
+
S_cl = free_particle_classical_action(x0, xf, T, m)
|
|
49
|
+
paths = sample_random_paths(x0, xf, T, n_slices, n_paths=50, sigma=0.4, seed=1)
|
|
50
|
+
dt = T / n_slices
|
|
51
|
+
actions = np.array([discretized_action(p, dt, m, lambda x: 0.0 * x) for p in paths])
|
|
52
|
+
assert np.all(actions >= S_cl - 1e-8)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_harmonic_oscillator_classical_action_closer_than_random_perturbation():
|
|
56
|
+
# Unlike the free particle, the harmonic-oscillator classical path is only a
|
|
57
|
+
# stationary point of the action (not necessarily a minimum), so we only check
|
|
58
|
+
# that it is closer to the exact classical action than a randomly perturbed
|
|
59
|
+
# path -- a weaker but still meaningful sanity check.
|
|
60
|
+
x0, xf, T, m, omega, n_slices = 0.2, 0.8, 1.0, 1.0, 1.3, 60
|
|
61
|
+
S_cl = harmonic_oscillator_classical_action(x0, xf, T, m, omega)
|
|
62
|
+
_, x_cl = harmonic_oscillator_classical_path(x0, xf, T, m, omega, n_slices)
|
|
63
|
+
V = lambda x: 0.5 * m * omega**2 * x**2
|
|
64
|
+
dt = T / n_slices
|
|
65
|
+
S_cl_discrete = discretized_action(x_cl, dt, m, V)
|
|
66
|
+
|
|
67
|
+
random_paths = sample_random_paths(x0, xf, T, n_slices, n_paths=1, sigma=0.5, seed=3)
|
|
68
|
+
S_random = discretized_action(random_paths[0], dt, m, V)
|
|
69
|
+
|
|
70
|
+
assert abs(S_cl_discrete - S_cl) < abs(S_random - S_cl)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@pytest.mark.parametrize(
|
|
74
|
+
"target,func,kwargs",
|
|
75
|
+
[
|
|
76
|
+
("path", harmonic_oscillator_classical_path, dict(x0=0.0, xf=1.0, m=1.0, omega=1.0, n_slices=10)),
|
|
77
|
+
("action", harmonic_oscillator_classical_action, dict(x0=0.0, xf=1.0, m=1.0, omega=1.0)),
|
|
78
|
+
],
|
|
79
|
+
)
|
|
80
|
+
def test_harmonic_oscillator_raises_at_conjugate_point(target, func, kwargs):
|
|
81
|
+
# omega*T = pi exactly is a conjugate point: the classical path is non-unique.
|
|
82
|
+
T = np.pi / kwargs["omega"]
|
|
83
|
+
with pytest.raises(ValueError):
|
|
84
|
+
func(T=T, **kwargs)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_feynman_phasor_partial_sums_matches_hand_computation():
|
|
88
|
+
actions = np.array([0.3, -1.2, 5.0, 0.0])
|
|
89
|
+
hbar = 0.5
|
|
90
|
+
classical_action = 0.1
|
|
91
|
+
paths = np.zeros((actions.shape[0], 3)) # only shape[0] is used by the function
|
|
92
|
+
|
|
93
|
+
partial = feynman_phasor_partial_sums(paths, actions, hbar, classical_action=classical_action)
|
|
94
|
+
|
|
95
|
+
# Independent hand computation: sort by |action - classical_action| ascending,
|
|
96
|
+
# then cumulatively sum exp(i*action/hbar) in that order, starting from 0.
|
|
97
|
+
order = np.argsort(np.abs(actions - classical_action))
|
|
98
|
+
expected = np.concatenate([[0.0 + 0.0j], np.cumsum(np.exp(1j * actions[order] / hbar))])
|
|
99
|
+
|
|
100
|
+
assert np.allclose(partial, expected)
|
|
101
|
+
assert partial.shape == (actions.shape[0] + 1,)
|
|
102
|
+
assert partial[0] == 0.0
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_phasor_sum_concentrates_near_classical_path_as_hbar_shrinks():
|
|
106
|
+
# The core physics claim of this module: shrinking hbar makes the propagator's
|
|
107
|
+
# support concentrate ever more tightly around the classical path. Quantify
|
|
108
|
+
# this by comparing, at two very different hbar values, what fraction of the
|
|
109
|
+
# final (all-paths) partial-sum magnitude is already captured by just the
|
|
110
|
+
# closest 10% of paths (sorted by proximity to the classical action).
|
|
111
|
+
def frac_from_closest_10_percent(hbar, seed):
|
|
112
|
+
_, _, _, _, partial = build_phasor_diagram(
|
|
113
|
+
x0=0.0,
|
|
114
|
+
xf=1.0,
|
|
115
|
+
T=1.0,
|
|
116
|
+
m=1.0,
|
|
117
|
+
hbar=hbar,
|
|
118
|
+
potential="free",
|
|
119
|
+
n_slices=40,
|
|
120
|
+
n_paths=400,
|
|
121
|
+
sigma=0.5,
|
|
122
|
+
seed=seed,
|
|
123
|
+
)
|
|
124
|
+
n_total = partial.shape[0] - 1
|
|
125
|
+
idx = max(1, round(0.1 * n_total))
|
|
126
|
+
return abs(partial[idx]) / abs(partial[-1])
|
|
127
|
+
|
|
128
|
+
# hbar=20 is much larger than the typical |S - S_cl| spread of this ensemble
|
|
129
|
+
# (tens at most), so phases barely wind and the closest 10% contributes about
|
|
130
|
+
# the "trivial" 10% share. hbar=1.0 is much smaller than that spread, so the
|
|
131
|
+
# closest paths reinforce while distant ones increasingly cancel.
|
|
132
|
+
large_hbar, small_hbar = 20.0, 1.0
|
|
133
|
+
seed = 42
|
|
134
|
+
|
|
135
|
+
frac_large = frac_from_closest_10_percent(large_hbar, seed)
|
|
136
|
+
frac_small = frac_from_closest_10_percent(small_hbar, seed)
|
|
137
|
+
|
|
138
|
+
assert frac_small > frac_large
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_free_particle_functions_reject_nonpositive_t_and_bad_n_slices():
|
|
142
|
+
with pytest.raises(ValueError):
|
|
143
|
+
free_particle_classical_path(x0=0.0, xf=1.0, T=0.0, m=1.0, n_slices=4)
|
|
144
|
+
with pytest.raises(ValueError):
|
|
145
|
+
free_particle_classical_path(x0=0.0, xf=1.0, T=1.0, m=1.0, n_slices=0)
|
|
146
|
+
with pytest.raises(ValueError):
|
|
147
|
+
free_particle_classical_action(x0=0.0, xf=1.0, T=0.0, m=1.0)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_harmonic_oscillator_functions_reject_nonpositive_t_and_bad_n_slices():
|
|
151
|
+
with pytest.raises(ValueError):
|
|
152
|
+
harmonic_oscillator_classical_path(x0=0.0, xf=1.0, T=0.0, m=1.0, omega=1.0, n_slices=4)
|
|
153
|
+
with pytest.raises(ValueError):
|
|
154
|
+
harmonic_oscillator_classical_path(x0=0.0, xf=1.0, T=1.0, m=1.0, omega=1.0, n_slices=0)
|
|
155
|
+
with pytest.raises(ValueError):
|
|
156
|
+
harmonic_oscillator_classical_action(x0=0.0, xf=1.0, T=0.0, m=1.0, omega=1.0)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_sample_random_paths_rejects_nonpositive_t_and_bad_counts():
|
|
160
|
+
with pytest.raises(ValueError):
|
|
161
|
+
sample_random_paths(x0=0.0, xf=1.0, T=0.0, n_slices=4, n_paths=2, sigma=0.1, seed=0)
|
|
162
|
+
with pytest.raises(ValueError):
|
|
163
|
+
sample_random_paths(x0=0.0, xf=1.0, T=1.0, n_slices=0, n_paths=2, sigma=0.1, seed=0)
|
|
164
|
+
with pytest.raises(ValueError):
|
|
165
|
+
sample_random_paths(x0=0.0, xf=1.0, T=1.0, n_slices=4, n_paths=0, sigma=0.1, seed=0)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_feynman_phasor_partial_sums_rejects_empty_actions_and_zero_hbar():
|
|
169
|
+
with pytest.raises(ValueError):
|
|
170
|
+
feynman_phasor_partial_sums(paths=np.empty((0, 1)), actions=np.array([]), hbar=0.5)
|
|
171
|
+
with pytest.raises(ValueError):
|
|
172
|
+
feynman_phasor_partial_sums(paths=np.zeros((2, 1)), actions=np.array([0.1, 0.2]), hbar=0.0)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_build_phasor_diagram_harmonic_potential_matches_classical_path_and_action():
|
|
176
|
+
omega = 1.5
|
|
177
|
+
paths, actions, x_cl, S_cl, partial = build_phasor_diagram(
|
|
178
|
+
x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="harmonic", omega=omega, n_slices=10, n_paths=5, sigma=0.1, seed=0
|
|
179
|
+
)
|
|
180
|
+
expected_path = harmonic_oscillator_classical_path(x0=0.0, xf=1.0, T=1.0, m=1.0, omega=omega, n_slices=10)[1]
|
|
181
|
+
expected_action = harmonic_oscillator_classical_action(x0=0.0, xf=1.0, T=1.0, m=1.0, omega=omega)
|
|
182
|
+
assert np.allclose(x_cl, expected_path)
|
|
183
|
+
assert S_cl == pytest.approx(expected_action)
|
|
184
|
+
assert paths.shape[0] == actions.shape[0] == 6
|
|
185
|
+
assert partial.shape == (7,)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def test_build_phasor_diagram_rejects_nonpositive_t_missing_omega_and_bad_potential():
|
|
189
|
+
with pytest.raises(ValueError):
|
|
190
|
+
build_phasor_diagram(x0=0.0, xf=1.0, T=0.0, m=1.0, hbar=0.1, potential="free", n_slices=10, n_paths=5, sigma=0.1, seed=0)
|
|
191
|
+
with pytest.raises(ValueError):
|
|
192
|
+
build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="harmonic", n_slices=10, n_paths=5, sigma=0.1, seed=0)
|
|
193
|
+
with pytest.raises(ValueError):
|
|
194
|
+
build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="quartic", n_slices=10, n_paths=5, sigma=0.1, seed=0)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Physics-correctness tests for physicskit.semiclassical.core.propagators."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numba import njit
|
|
7
|
+
|
|
8
|
+
from physicskit.semiclassical.core.propagators import (
|
|
9
|
+
coherent_state_overlap,
|
|
10
|
+
frozen_gaussian_1d,
|
|
11
|
+
herman_kluk_propagate_wavepacket,
|
|
12
|
+
propagate_trajectory_monodromy_action,
|
|
13
|
+
van_vleck_propagator_1d,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
_ZERO = njit(lambda q, params: 0.0, cache=False)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _harmonic_potential(m=1.0, omega=1.0):
|
|
20
|
+
params = np.array([m * omega**2])
|
|
21
|
+
dVdx = njit(lambda q, params: params[0] * q, cache=False)
|
|
22
|
+
d2Vdx2 = njit(lambda q, params: params[0], cache=False)
|
|
23
|
+
V = njit(lambda q, params: 0.5 * params[0] * q**2, cache=False)
|
|
24
|
+
return dVdx, d2Vdx2, V, params
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_monodromy_matches_harmonic_oscillator_and_preserves_liouville():
|
|
28
|
+
dVdx, d2Vdx2, V, params = _harmonic_potential()
|
|
29
|
+
t = 2.1
|
|
30
|
+
_q, _p, M, _S, _hist = propagate_trajectory_monodromy_action(1.0, 0.4, dVdx, d2Vdx2, V, m=1.0, dt=t / 3000, steps=3000, params=params)
|
|
31
|
+
M_exact = np.array([[np.cos(t), np.sin(t)], [-np.sin(t), np.cos(t)]])
|
|
32
|
+
assert np.max(np.abs(M - M_exact)) < 1e-5
|
|
33
|
+
assert abs(np.linalg.det(M) - 1.0) < 1e-8
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_van_vleck_propagator_matches_free_particle_exact():
|
|
37
|
+
q_t, K = van_vleck_propagator_1d(q0=0.0, p0=1.0, dVdx=_ZERO, d2Vdx2=_ZERO, V=_ZERO, m=1.0, dt=1.0 / 2000, steps=2000)
|
|
38
|
+
K_exact = np.sqrt(1.0 / (2j * np.pi)) * np.exp(1j * q_t**2 / 2.0)
|
|
39
|
+
assert abs(K - K_exact) < 1e-6
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_van_vleck_propagator_matches_harmonic_oscillator_exact():
|
|
43
|
+
dVdx, d2Vdx2, V, params = _harmonic_potential()
|
|
44
|
+
q0, p0, t = 1.0, 0.3, 1.3
|
|
45
|
+
q_t, K = van_vleck_propagator_1d(q0, p0, dVdx, d2Vdx2, V, m=1.0, dt=t / 4000, steps=4000, hbar=1.0, params=params)
|
|
46
|
+
K_exact = np.sqrt(1.0 / (2j * np.pi * np.sin(t))) * np.exp(1j / (2 * np.sin(t)) * ((q_t**2 + q0**2) * np.cos(t) - 2 * q_t * q0))
|
|
47
|
+
assert abs(K - K_exact) < 1e-5
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_coherent_state_overlap_matches_numerical_integration():
|
|
51
|
+
x = np.linspace(-40, 40, 20000)
|
|
52
|
+
gamma = 1.0
|
|
53
|
+
psi1 = frozen_gaussian_1d(x, qc=0.3, pc=0.7, gamma=gamma)
|
|
54
|
+
psi2 = frozen_gaussian_1d(x, qc=-0.2, pc=1.1, gamma=gamma)
|
|
55
|
+
numeric = np.trapezoid(np.conj(psi1) * psi2, x)
|
|
56
|
+
closed_form = coherent_state_overlap(0.3, 0.7, -0.2, 1.1, gamma)
|
|
57
|
+
assert abs(numeric - closed_form) < 1e-6
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_herman_kluk_reconstructs_initial_state_at_short_time():
|
|
61
|
+
dVdx, d2Vdx2, V, params = _harmonic_potential()
|
|
62
|
+
x = np.linspace(-6, 6, 400)
|
|
63
|
+
psi = herman_kluk_propagate_wavepacket(
|
|
64
|
+
1.0, 0.0, gamma=1.0, dVdx=dVdx, d2Vdx2=d2Vdx2, V=V, m=1.0, dt=1e-6, steps=1, x_eval=x, n_grid=61, n_sigma=7.0, params=params
|
|
65
|
+
)
|
|
66
|
+
psi0 = frozen_gaussian_1d(x, qc=1.0, pc=0.0, gamma=1.0)
|
|
67
|
+
fidelity = abs(np.trapezoid(np.conj(psi0) * psi, x)) ** 2
|
|
68
|
+
assert fidelity > 0.999
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_herman_kluk_defaults_params_to_an_empty_array_when_unused():
|
|
72
|
+
# dVdx/d2Vdx2/V here never index into params, so params=None (->
|
|
73
|
+
# np.empty(0) internally) is fine and should behave like the
|
|
74
|
+
# explicit-params harmonic oscillator above (m=omega=1).
|
|
75
|
+
dVdx = njit(lambda q, params: q, cache=False)
|
|
76
|
+
d2Vdx2 = njit(lambda q, params: 1.0, cache=False)
|
|
77
|
+
V = njit(lambda q, params: 0.5 * q**2, cache=False)
|
|
78
|
+
x = np.linspace(-6, 6, 400)
|
|
79
|
+
psi = herman_kluk_propagate_wavepacket(1.0, 0.0, gamma=1.0, dVdx=dVdx, d2Vdx2=d2Vdx2, V=V, m=1.0, dt=1e-6, steps=1, x_eval=x, n_grid=61, n_sigma=7.0)
|
|
80
|
+
psi0 = frozen_gaussian_1d(x, qc=1.0, pc=0.0, gamma=1.0)
|
|
81
|
+
fidelity = abs(np.trapezoid(np.conj(psi0) * psi, x)) ** 2
|
|
82
|
+
assert fidelity > 0.999
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Physics-correctness tests for physicskit.semiclassical.systems.scarring."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from physicskit.semiclassical.systems.scarring import bouncing_ball_energies, husimi_projection_1d, scar_enhancement
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_bouncing_ball_energies_match_infinite_well_of_width_2R():
|
|
11
|
+
R = 0.7
|
|
12
|
+
energies = bouncing_ball_energies(R, n_max=4)
|
|
13
|
+
exact = (np.arange(1, 5) * np.pi) ** 2 / (2 * (2 * R) ** 2)
|
|
14
|
+
assert np.allclose(energies, exact)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def test_scar_enhancement_of_uniform_density_is_one():
|
|
18
|
+
x = np.linspace(-2, 2, 200)
|
|
19
|
+
y = np.linspace(-1, 1, 100)
|
|
20
|
+
X, Y = np.meshgrid(x, y, indexing="ij")
|
|
21
|
+
mask = np.ones_like(X, dtype=bool)
|
|
22
|
+
uniform = np.ones_like(X)
|
|
23
|
+
eta = scar_enhancement(uniform, X, Y, mask, x0=0.3, half_width=0.2)
|
|
24
|
+
assert abs(eta - 1.0) < 1e-10
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_scar_enhancement_detects_concentrated_ridge():
|
|
28
|
+
x = np.linspace(-2, 2, 400)
|
|
29
|
+
y = np.linspace(-1, 1, 200)
|
|
30
|
+
X, Y = np.meshgrid(x, y, indexing="ij")
|
|
31
|
+
mask = np.ones_like(X, dtype=bool)
|
|
32
|
+
density = np.exp(-((X - 0.3) ** 2) / (2 * 0.05**2))
|
|
33
|
+
eta = scar_enhancement(density, X, Y, mask, x0=0.3, half_width=0.15)
|
|
34
|
+
assert eta > 5.0
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_husimi_projection_1d_default_sigma_and_ranges_peaks_near_source():
|
|
38
|
+
s = np.linspace(-10, 10, 500)
|
|
39
|
+
s0_true, p0_true, w = 2.0, 3.0, 1.0
|
|
40
|
+
psi = np.exp(-((s - s0_true) ** 2) / (2 * w**2)) * np.exp(1j * p0_true * s / 1.0)
|
|
41
|
+
S0, P0, H = husimi_projection_1d(psi, s, hbar=1.0, resolution=30)
|
|
42
|
+
i, j = np.unravel_index(np.argmax(H), H.shape)
|
|
43
|
+
assert abs(S0[i, j] - s0_true) < 1.0
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Coverage for physicskit.semiclassical.visualizers's ax=<given> branch
|
|
2
|
+
(previously untested for every function here): plot_density_of_states,
|
|
3
|
+
plot_wkb_wavefunction, plot_classical_trajectory_on_wigner, plot_scar_map,
|
|
4
|
+
plot_husimi_1d. All pure matplotlib, small inputs -- fast."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from physicskit.semiclassical.core.gutzwiller import gutzwiller_density_of_states
|
|
12
|
+
from physicskit.semiclassical.core.path_integral import build_phasor_diagram
|
|
13
|
+
from physicskit.semiclassical.core.propagators import frozen_gaussian_1d
|
|
14
|
+
from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies, wkb_wavefunction
|
|
15
|
+
from physicskit.semiclassical.systems.scarring import bouncing_ball_orbit_points, husimi_projection_1d
|
|
16
|
+
from physicskit.semiclassical.visualizers.gutzwiller import plot_density_of_states
|
|
17
|
+
from physicskit.semiclassical.visualizers.path_integral import animate_feynman_phasor_spiral, plot_phasor_convergence
|
|
18
|
+
from physicskit.semiclassical.visualizers.propagators import plot_classical_trajectory_on_wigner
|
|
19
|
+
from physicskit.semiclassical.visualizers.scarring import plot_husimi_1d, plot_scar_map
|
|
20
|
+
from physicskit.semiclassical.visualizers.wkb import plot_wkb_wavefunction
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_plot_density_of_states_given_ax():
|
|
24
|
+
V = lambda x: 0.5 * x**2
|
|
25
|
+
E_grid = np.linspace(0.2, 3.5, 50)
|
|
26
|
+
dos = gutzwiller_density_of_states(E_grid, V, m=1.0, x_min=-20, x_max=20)
|
|
27
|
+
fig, ax = plt.subplots()
|
|
28
|
+
_, ax_given = plot_density_of_states(E_grid, dos, ax=ax)
|
|
29
|
+
assert ax_given is ax
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_plot_wkb_wavefunction_given_ax():
|
|
33
|
+
V = lambda x: 0.5 * x**2
|
|
34
|
+
E2 = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=3)[2]
|
|
35
|
+
x = np.linspace(-6, 6, 200)
|
|
36
|
+
psi = wkb_wavefunction(x, E2, V)
|
|
37
|
+
fig, ax = plt.subplots()
|
|
38
|
+
_, ax_given = plot_wkb_wavefunction(x, psi, V=V, ax=ax)
|
|
39
|
+
assert ax_given is ax
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_plot_classical_trajectory_on_wigner_given_ax():
|
|
43
|
+
x = np.linspace(-8, 8, 100)
|
|
44
|
+
psi = frozen_gaussian_1d(x, qc=1.0, pc=0.5, gamma=1.0)
|
|
45
|
+
theta = np.linspace(0, 2 * np.pi, 30)
|
|
46
|
+
q_hist, p_hist = np.cos(theta), np.sin(theta)
|
|
47
|
+
fig, ax = plt.subplots()
|
|
48
|
+
_, ax_given = plot_classical_trajectory_on_wigner(x, psi, q_hist, p_hist, ax=ax)
|
|
49
|
+
assert ax_given is ax
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_plot_scar_map_given_ax():
|
|
53
|
+
x = np.linspace(-2, 2, 30)
|
|
54
|
+
y = np.linspace(-1, 1, 20)
|
|
55
|
+
X, Y = np.meshgrid(x, y, indexing="ij")
|
|
56
|
+
density = np.exp(-((X - 0.3) ** 2) / (2 * 0.2**2))
|
|
57
|
+
orbit_x, orbit_y = bouncing_ball_orbit_points(x0=0.3, R=1.0)
|
|
58
|
+
fig, ax = plt.subplots()
|
|
59
|
+
_, ax_given = plot_scar_map(X, Y, density, orbit_x=orbit_x, orbit_y=orbit_y, ax=ax)
|
|
60
|
+
assert ax_given is ax
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_plot_husimi_1d_given_ax():
|
|
64
|
+
s = np.linspace(-10, 10, 200)
|
|
65
|
+
psi = np.exp(-((s - 2.0) ** 2) / 2.0) * np.exp(1j * 3.0 * s)
|
|
66
|
+
S0, P0, H = husimi_projection_1d(psi, s, sigma=1.0, resolution=20, s0_range=(-2, 6), p0_range=(-2, 8))
|
|
67
|
+
fig, ax = plt.subplots()
|
|
68
|
+
_, ax_given = plot_husimi_1d(S0, P0, H, ax=ax)
|
|
69
|
+
assert ax_given is ax
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_animate_feynman_phasor_spiral_builds_and_draws_a_frame():
|
|
73
|
+
paths, actions, x_cl, S_cl, _ = build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=0.1, potential="free", n_slices=20, n_paths=10, sigma=0.3, seed=0)
|
|
74
|
+
t = np.linspace(0.0, 1.0, x_cl.shape[0])
|
|
75
|
+
anim = animate_feynman_phasor_spiral(paths, actions, x_cl, S_cl, hbar=0.1, t_array=t)
|
|
76
|
+
anim._init_draw()
|
|
77
|
+
anim._draw_frame(0)
|
|
78
|
+
anim._draw_frame(1) # a second frame exercises removing the previous frame's path lines
|
|
79
|
+
assert "2/" in anim._fig.axes[1].get_title()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_plot_phasor_convergence_given_ax():
|
|
83
|
+
sums, hbars = [], [0.5, 0.05]
|
|
84
|
+
for hbar in hbars:
|
|
85
|
+
_, _, _, _, partial = build_phasor_diagram(x0=0.0, xf=1.0, T=1.0, m=1.0, hbar=hbar, potential="free", n_slices=10, n_paths=20, sigma=0.3, seed=0)
|
|
86
|
+
sums.append(partial)
|
|
87
|
+
fig, ax = plt.subplots()
|
|
88
|
+
_, ax_given = plot_phasor_convergence(sums, hbars, ax=ax)
|
|
89
|
+
assert ax_given is ax
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Physics-correctness tests for physicskit.semiclassical.core.wkb."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies, turning_points, wkb_wavefunction
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_bohr_sommerfeld_matches_harmonic_oscillator_exact_spectrum():
|
|
11
|
+
V = lambda x: 0.5 * x**2
|
|
12
|
+
energies = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=6)
|
|
13
|
+
assert np.allclose(energies, np.arange(6) + 0.5, atol=1e-8)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_turning_points_finds_root_landing_exactly_on_a_search_grid_point():
|
|
17
|
+
# n_search=3 puts a grid point exactly at x=0, where E - V(x) = 0 - 0 = 0.
|
|
18
|
+
roots = turning_points(E=0.0, V=lambda x: x, x_min=-1.0, x_max=1.0, n_search=3)
|
|
19
|
+
assert roots == [0.0]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_wkb_wavefunction_has_n_nodes():
|
|
23
|
+
V = lambda x: 0.5 * x**2
|
|
24
|
+
for n in range(4):
|
|
25
|
+
E_n = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=n + 1)[n]
|
|
26
|
+
x = np.linspace(-10, 10, 4000)
|
|
27
|
+
psi = wkb_wavefunction(x, E_n, V, m=1.0)
|
|
28
|
+
nonzero = psi[psi != 0]
|
|
29
|
+
n_nodes = np.sum(np.diff(np.sign(nonzero)) != 0)
|
|
30
|
+
assert n_nodes == n
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from physicskit.semiclassical.visualizers.gutzwiller import plot_density_of_states
|
|
2
|
+
from physicskit.semiclassical.visualizers.propagators import plot_classical_trajectory_on_wigner
|
|
3
|
+
from physicskit.semiclassical.visualizers.scarring import (
|
|
4
|
+
plot_husimi_1d,
|
|
5
|
+
plot_scar_map,
|
|
6
|
+
plot_scar_map_interactive,
|
|
7
|
+
)
|
|
8
|
+
from physicskit.semiclassical.visualizers.wkb import plot_wkb_wavefunction
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"plot_wkb_wavefunction",
|
|
12
|
+
"plot_classical_trajectory_on_wigner",
|
|
13
|
+
"plot_density_of_states",
|
|
14
|
+
"plot_scar_map",
|
|
15
|
+
"plot_husimi_1d",
|
|
16
|
+
"plot_scar_map_interactive",
|
|
17
|
+
]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
r"""Plotting helpers for the Gutzwiller trace-formula density of states."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
__all__ = ["plot_density_of_states"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def plot_density_of_states(E_grid: np.ndarray, dos: np.ndarray, exact_energies: np.ndarray | None = None, ax=None):
|
|
12
|
+
r"""Plot the Gutzwiller trace-formula density of states, with exact levels marked.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
E_grid : ndarray
|
|
17
|
+
Energy grid.
|
|
18
|
+
dos : ndarray
|
|
19
|
+
Density of states, e.g. from
|
|
20
|
+
:func:`physicskit.semiclassical.core.gutzwiller.gutzwiller_density_of_states`.
|
|
21
|
+
exact_energies : ndarray, optional
|
|
22
|
+
Exact (or Bohr-Sommerfeld) energy levels to mark with vertical
|
|
23
|
+
dashed lines.
|
|
24
|
+
ax : matplotlib.axes.Axes, optional
|
|
25
|
+
Axes to draw into; a new figure is created if omitted.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
fig : matplotlib.figure.Figure
|
|
30
|
+
ax : matplotlib.axes.Axes
|
|
31
|
+
|
|
32
|
+
Examples
|
|
33
|
+
--------
|
|
34
|
+
>>> import numpy as np
|
|
35
|
+
>>> from physicskit.semiclassical.core.gutzwiller import gutzwiller_density_of_states
|
|
36
|
+
>>> from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies
|
|
37
|
+
>>> V = lambda x: 0.5 * x ** 2
|
|
38
|
+
>>> E_grid = np.linspace(0.2, 3.5, 200)
|
|
39
|
+
>>> dos = gutzwiller_density_of_states(E_grid, V, m=1.0, x_min=-20, x_max=20)
|
|
40
|
+
>>> energies = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=3)
|
|
41
|
+
>>> fig, ax = plot_density_of_states(E_grid, dos, exact_energies=energies)
|
|
42
|
+
>>> isinstance(fig, plt.Figure)
|
|
43
|
+
True
|
|
44
|
+
"""
|
|
45
|
+
if ax is None:
|
|
46
|
+
fig, ax = plt.subplots()
|
|
47
|
+
else:
|
|
48
|
+
fig = ax.figure
|
|
49
|
+
ax.plot(E_grid, dos, color="C0")
|
|
50
|
+
if exact_energies is not None:
|
|
51
|
+
for E_n in exact_energies:
|
|
52
|
+
ax.axvline(E_n, color="C3", linestyle="--", linewidth=0.8)
|
|
53
|
+
ax.set_xlabel("E")
|
|
54
|
+
ax.set_ylabel("g(E)")
|
|
55
|
+
return fig, ax
|