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,308 @@
|
|
|
1
|
+
r"""1D WKB wavefunctions, classical turning points, and Bohr-Sommerfeld (EBK) quantization.
|
|
2
|
+
|
|
3
|
+
The Wentzel-Kramers-Brillouin (WKB) approximation writes the wavefunction
|
|
4
|
+
as :math:`\psi(x) \sim p(x)^{-1/2}\exp(\pm i\int p\,dx/\hbar)` -- an
|
|
5
|
+
:math:`\hbar\to 0` asymptotic expansion valid wherever the local
|
|
6
|
+
de Broglie wavelength :math:`2\pi\hbar/p(x)` varies slowly compared to
|
|
7
|
+
itself. The prefactor :math:`p(x)^{-1/2}` is exactly the classical
|
|
8
|
+
probability density of a particle oscillating in the potential (it spends
|
|
9
|
+
more time, and so is more likely to be found, where it moves slowest);
|
|
10
|
+
this is the one-dimensional seed of every semiclassical idea in
|
|
11
|
+
:mod:`physicskit.semiclassical` -- the Van Vleck-Morette
|
|
12
|
+
determinant in :mod:`~physicskit.semiclassical.core.propagators` is
|
|
13
|
+
the same classical-probability prefactor for a propagator instead of a
|
|
14
|
+
stationary state, and the periodic-orbit sum in
|
|
15
|
+
:mod:`~physicskit.semiclassical.core.gutzwiller` is built from the
|
|
16
|
+
same action integral used here for Bohr-Sommerfeld quantization.
|
|
17
|
+
|
|
18
|
+
At each classical turning point the WKB approximation itself breaks down
|
|
19
|
+
(:math:`p(x)\to 0`); matching the oscillatory interior solution through
|
|
20
|
+
that breakdown region (via the Airy function connection formulas) costs
|
|
21
|
+
each *soft* (linear) turning point a phase of :math:`\pi/4`. For a bound
|
|
22
|
+
state with two such turning points, the round-trip quantization condition
|
|
23
|
+
:math:`\oint p\,dx = 2\pi\hbar(n+\tfrac12)` -- equivalently
|
|
24
|
+
:math:`\int_{x_1}^{x_2}p\,dx=(n+\tfrac12)\pi\hbar` -- is the
|
|
25
|
+
one-dimensional Einstein-Brillouin-Keller (EBK) rule implemented by
|
|
26
|
+
:func:`bohr_sommerfeld_energies`.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import numpy as np
|
|
32
|
+
from scipy.integrate import cumulative_trapezoid, quad
|
|
33
|
+
from scipy.optimize import brentq
|
|
34
|
+
|
|
35
|
+
from .._compat import trapz
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"classical_momentum",
|
|
39
|
+
"turning_points",
|
|
40
|
+
"wkb_action",
|
|
41
|
+
"bohr_sommerfeld_energies",
|
|
42
|
+
"wkb_wavefunction",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def classical_momentum(E: float, V, x: np.ndarray, m: float = 1.0) -> np.ndarray:
|
|
47
|
+
r"""Classical momentum :math:`p(x) = \sqrt{2m(E-V(x))}` in the allowed region.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
E : float
|
|
52
|
+
Total energy.
|
|
53
|
+
V : callable
|
|
54
|
+
Potential energy function ``V(x)``.
|
|
55
|
+
x : ndarray
|
|
56
|
+
Positions at which to evaluate :math:`p(x)`.
|
|
57
|
+
m : float, default=1.0
|
|
58
|
+
Particle mass.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
ndarray
|
|
63
|
+
:math:`p(x)`, same shape as ``x``; ``nan`` wherever :math:`V(x)>E`
|
|
64
|
+
(the classically forbidden region, where WKB oscillates into a
|
|
65
|
+
real exponential instead).
|
|
66
|
+
|
|
67
|
+
Examples
|
|
68
|
+
--------
|
|
69
|
+
>>> import numpy as np
|
|
70
|
+
>>> V = lambda x: 0.5 * x ** 2
|
|
71
|
+
>>> p = classical_momentum(E=2.0, V=V, x=np.array([0.0, 1.0, 3.0]))
|
|
72
|
+
>>> np.round(p, 4)
|
|
73
|
+
array([2. , 1.7321, nan])
|
|
74
|
+
"""
|
|
75
|
+
x = np.asarray(x, dtype=float)
|
|
76
|
+
diff = 2.0 * m * (E - V(x))
|
|
77
|
+
return np.sqrt(np.where(diff >= 0, diff, np.nan))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def turning_points(E: float, V, x_min: float, x_max: float, n_search: int = 4000) -> list:
|
|
81
|
+
r"""Locate the classical turning points (roots of :math:`E=V(x)`) in :math:`[x_{min},x_{max}]`.
|
|
82
|
+
|
|
83
|
+
Scans a fine grid for sign changes of :math:`E-V(x)` and refines each
|
|
84
|
+
with Brent's method; returns every turning point found, not just the
|
|
85
|
+
innermost pair, so multi-well potentials are handled correctly.
|
|
86
|
+
|
|
87
|
+
Parameters
|
|
88
|
+
----------
|
|
89
|
+
E : float
|
|
90
|
+
Total energy.
|
|
91
|
+
V : callable
|
|
92
|
+
Potential energy function ``V(x)``.
|
|
93
|
+
x_min, x_max : float
|
|
94
|
+
Search domain (should extend into the classically forbidden
|
|
95
|
+
region on both sides of the state of interest).
|
|
96
|
+
n_search : int, default=4000
|
|
97
|
+
Number of grid points used to bracket the roots; increase for
|
|
98
|
+
potentials with closely spaced turning points.
|
|
99
|
+
|
|
100
|
+
Returns
|
|
101
|
+
-------
|
|
102
|
+
list of float
|
|
103
|
+
Turning points, ascending.
|
|
104
|
+
|
|
105
|
+
See Also
|
|
106
|
+
--------
|
|
107
|
+
wkb_action : Integrates :func:`classical_momentum` between two turning points.
|
|
108
|
+
|
|
109
|
+
Examples
|
|
110
|
+
--------
|
|
111
|
+
>>> V = lambda x: 0.5 * x ** 2
|
|
112
|
+
>>> [round(t, 4) for t in turning_points(E=2.0, V=V, x_min=-10, x_max=10)]
|
|
113
|
+
[-2.0, 2.0]
|
|
114
|
+
"""
|
|
115
|
+
xs = np.linspace(x_min, x_max, n_search)
|
|
116
|
+
f = E - V(xs)
|
|
117
|
+
roots = []
|
|
118
|
+
for i in range(n_search - 1):
|
|
119
|
+
if f[i] == 0:
|
|
120
|
+
roots.append(float(xs[i]))
|
|
121
|
+
elif f[i] * f[i + 1] < 0:
|
|
122
|
+
roots.append(brentq(lambda x: E - V(x), xs[i], xs[i + 1]))
|
|
123
|
+
return roots
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def wkb_action(E: float, V, m: float, x1: float, x2: float, hbar: float = 1.0) -> float:
|
|
127
|
+
r"""WKB action integral :math:`S(E)=\int_{x_1}^{x_2} p(x)\,dx` between two turning points.
|
|
128
|
+
|
|
129
|
+
This is the classical action accumulated on one traversal of the
|
|
130
|
+
classically allowed region -- half of the full round-trip action
|
|
131
|
+
:math:`\oint p\,dx`, and (as a function of :math:`E`) exactly the
|
|
132
|
+
Hamilton principal function whose energy derivative gives the
|
|
133
|
+
classical period, :math:`T(E)=dS/dE`, used by
|
|
134
|
+
:func:`physicskit.semiclassical.core.gutzwiller.classical_period`.
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
E : float
|
|
139
|
+
Total energy.
|
|
140
|
+
V : callable
|
|
141
|
+
Potential energy function ``V(x)``.
|
|
142
|
+
m : float
|
|
143
|
+
Particle mass.
|
|
144
|
+
x1, x2 : float
|
|
145
|
+
The two turning points (e.g. from :func:`turning_points`).
|
|
146
|
+
hbar : float, default=1.0
|
|
147
|
+
Value of :math:`\hbar` to use (only needed by callers converting
|
|
148
|
+
this to a phase; the integral itself is :math:`\hbar`-independent).
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
float
|
|
153
|
+
The action :math:`S(E)`.
|
|
154
|
+
|
|
155
|
+
Examples
|
|
156
|
+
--------
|
|
157
|
+
For the harmonic oscillator, :math:`S(E)=\pi E/\omega` exactly:
|
|
158
|
+
|
|
159
|
+
>>> V = lambda x: 0.5 * x ** 2
|
|
160
|
+
>>> x1, x2 = turning_points(E=2.0, V=V, x_min=-10, x_max=10)
|
|
161
|
+
>>> round(wkb_action(E=2.0, V=V, m=1.0, x1=x1, x2=x2), 6)
|
|
162
|
+
6.283185
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
def integrand(x):
|
|
166
|
+
return float(np.nan_to_num(classical_momentum(E, V, np.array([x]), m)[0], nan=0.0))
|
|
167
|
+
|
|
168
|
+
result, _ = quad(integrand, x1, x2, limit=200)
|
|
169
|
+
return result
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def bohr_sommerfeld_energies(V, m: float, x_min: float, x_max: float, n_max: int, hbar: float = 1.0, E_min: float = 1e-3, E_max: float = 100.0) -> np.ndarray:
|
|
173
|
+
r"""Bohr-Sommerfeld (EBK) bound-state energies from the WKB quantization condition.
|
|
174
|
+
|
|
175
|
+
Solves :math:`\int_{x_1(E_n)}^{x_2(E_n)}p(x)\,dx=(n+\tfrac12)\pi\hbar`
|
|
176
|
+
for each :math:`n=0,\dots,n_{max}-1` by root-finding on :math:`E`,
|
|
177
|
+
re-locating the turning points at every trial energy. For the
|
|
178
|
+
harmonic oscillator this reproduces the exact spectrum
|
|
179
|
+
:math:`E_n=(n+\tfrac12)\hbar\omega` to machine precision, since the
|
|
180
|
+
WKB approximation is exact whenever the potential is exactly
|
|
181
|
+
quadratic.
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
V : callable
|
|
186
|
+
Potential energy function ``V(x)``, with a single classically
|
|
187
|
+
allowed region containing its minimum for every energy searched.
|
|
188
|
+
m : float
|
|
189
|
+
Particle mass.
|
|
190
|
+
x_min, x_max : float
|
|
191
|
+
Search domain for :func:`turning_points`; must extend well into
|
|
192
|
+
the classically forbidden region at ``E_max``.
|
|
193
|
+
n_max : int
|
|
194
|
+
Number of levels to compute (:math:`n=0,\dots,n_{max}-1`).
|
|
195
|
+
hbar : float, default=1.0
|
|
196
|
+
Value of :math:`\hbar` to use.
|
|
197
|
+
E_min : float, default=1e-3
|
|
198
|
+
Lower bracket for the ground-state root search; must be small
|
|
199
|
+
enough that its turning points still resolve on the
|
|
200
|
+
:func:`turning_points` search grid.
|
|
201
|
+
E_max : float, default=100.0
|
|
202
|
+
Upper bracket for the highest level's root search.
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
ndarray, shape (n_max,)
|
|
207
|
+
Quantized energies, ascending.
|
|
208
|
+
|
|
209
|
+
See Also
|
|
210
|
+
--------
|
|
211
|
+
wkb_action : The action integral this quantizes.
|
|
212
|
+
wkb_wavefunction : The corresponding approximate wavefunctions.
|
|
213
|
+
|
|
214
|
+
Examples
|
|
215
|
+
--------
|
|
216
|
+
>>> import numpy as np
|
|
217
|
+
>>> V = lambda x: 0.5 * x ** 2
|
|
218
|
+
>>> energies = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=5)
|
|
219
|
+
>>> np.round(energies, 6)
|
|
220
|
+
array([0.5, 1.5, 2.5, 3.5, 4.5])
|
|
221
|
+
"""
|
|
222
|
+
energies = np.empty(n_max)
|
|
223
|
+
for n in range(n_max):
|
|
224
|
+
|
|
225
|
+
def condition(E, n=n):
|
|
226
|
+
tp = turning_points(E, V, x_min, x_max)
|
|
227
|
+
x1, x2 = tp[0], tp[-1]
|
|
228
|
+
return wkb_action(E, V, m, x1, x2, hbar) - (n + 0.5) * np.pi * hbar
|
|
229
|
+
|
|
230
|
+
energies[n] = brentq(condition, E_min, E_max)
|
|
231
|
+
return energies
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def wkb_wavefunction(x: np.ndarray, E: float, V, m: float = 1.0, hbar: float = 1.0) -> np.ndarray:
|
|
235
|
+
r"""The (real-valued, standing-wave) WKB wavefunction in the classically allowed region.
|
|
236
|
+
|
|
237
|
+
.. math::
|
|
238
|
+
|
|
239
|
+
\psi(x) \approx \frac{C}{\sqrt{p(x)}}
|
|
240
|
+
\cos\!\left(\frac{1}{\hbar}\int_{x_1}^{x}p(x')\,dx' - \frac{\pi}{4}\right),
|
|
241
|
+
|
|
242
|
+
with the :math:`\pi/4` phase set by the Airy connection formula at
|
|
243
|
+
the left (soft) turning point :math:`x_1`, and :math:`C` fixed by
|
|
244
|
+
numerical normalization over the allowed region. Diverges (is not
|
|
245
|
+
valid) within a few de Broglie wavelengths of either turning point;
|
|
246
|
+
zero is returned in the classically forbidden region rather than the
|
|
247
|
+
(also invalid) naive imaginary-momentum continuation.
|
|
248
|
+
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
x : ndarray
|
|
252
|
+
Positions at which to evaluate the wavefunction.
|
|
253
|
+
E : float
|
|
254
|
+
Energy (e.g. from :func:`bohr_sommerfeld_energies`, for a properly
|
|
255
|
+
quantized bound state).
|
|
256
|
+
V : callable
|
|
257
|
+
Potential energy function ``V(x)``.
|
|
258
|
+
m : float, default=1.0
|
|
259
|
+
Particle mass.
|
|
260
|
+
hbar : float, default=1.0
|
|
261
|
+
Value of :math:`\hbar` to use.
|
|
262
|
+
|
|
263
|
+
Returns
|
|
264
|
+
-------
|
|
265
|
+
ndarray
|
|
266
|
+
:math:`\psi(x)`, same shape as ``x``, normalized so
|
|
267
|
+
:math:`\int|\psi|^2\,dx=1` over ``x``'s range.
|
|
268
|
+
|
|
269
|
+
See Also
|
|
270
|
+
--------
|
|
271
|
+
bohr_sommerfeld_energies : Quantized energies this is evaluated at.
|
|
272
|
+
|
|
273
|
+
Examples
|
|
274
|
+
--------
|
|
275
|
+
The WKB wavefunction at the Bohr-Sommerfeld energy for quantum number
|
|
276
|
+
``n`` has exactly ``n`` nodes, the standard node-counting theorem:
|
|
277
|
+
|
|
278
|
+
>>> import numpy as np
|
|
279
|
+
>>> V = lambda x: 0.5 * x ** 2
|
|
280
|
+
>>> E5 = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=6)[5]
|
|
281
|
+
>>> x = np.linspace(-10, 10, 4000)
|
|
282
|
+
>>> psi = wkb_wavefunction(x, E5, V, m=1.0)
|
|
283
|
+
>>> nonzero = psi[psi != 0]
|
|
284
|
+
>>> int(np.sum(np.diff(np.sign(nonzero)) != 0))
|
|
285
|
+
5
|
|
286
|
+
"""
|
|
287
|
+
x = np.asarray(x, dtype=float)
|
|
288
|
+
tp = turning_points(E, V, float(np.min(x)), float(np.max(x)))
|
|
289
|
+
x1, x2 = tp[0], tp[-1]
|
|
290
|
+
allowed = (x > x1) & (x < x2)
|
|
291
|
+
|
|
292
|
+
psi = np.zeros_like(x)
|
|
293
|
+
xa = x[allowed]
|
|
294
|
+
p = classical_momentum(E, V, xa, m)
|
|
295
|
+
order = np.argsort(xa)
|
|
296
|
+
xa_sorted = xa[order]
|
|
297
|
+
p_sorted = p[order]
|
|
298
|
+
phase_sorted = cumulative_trapezoid(p_sorted, xa_sorted, initial=0.0) / hbar
|
|
299
|
+
unsort = np.argsort(order)
|
|
300
|
+
phase = phase_sorted[unsort]
|
|
301
|
+
|
|
302
|
+
psi_allowed = np.cos(phase - np.pi / 4.0) / np.sqrt(p)
|
|
303
|
+
psi[allowed] = psi_allowed
|
|
304
|
+
|
|
305
|
+
norm = np.sqrt(trapz(psi**2, x))
|
|
306
|
+
if norm > 0:
|
|
307
|
+
psi = psi / norm
|
|
308
|
+
return psi
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from physicskit.semiclassical.systems.scarring import (
|
|
2
|
+
bouncing_ball_energies,
|
|
3
|
+
bouncing_ball_orbit_points,
|
|
4
|
+
husimi_projection_1d,
|
|
5
|
+
scar_enhancement,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"bouncing_ball_energies",
|
|
10
|
+
"bouncing_ball_orbit_points",
|
|
11
|
+
"scar_enhancement",
|
|
12
|
+
"husimi_projection_1d",
|
|
13
|
+
]
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
r"""Quantum scars: eigenstate density concentrated on unstable classical periodic orbits.
|
|
2
|
+
|
|
3
|
+
Heller (1984) discovered that individual eigenstates of a classically
|
|
4
|
+
chaotic system are not always the featureless, ergodically-spread blobs
|
|
5
|
+
random-matrix intuition suggests: a small but robust fraction instead
|
|
6
|
+
show enhanced probability density in a tube around one particular
|
|
7
|
+
unstable classical periodic orbit -- a *scar* -- even though almost
|
|
8
|
+
every orbit nearby diverges from it exponentially fast. The bridge to
|
|
9
|
+
:mod:`physicskit.semiclassical.core.gutzwiller` is direct: the same
|
|
10
|
+
unstable periodic orbits that weight the Gutzwiller trace formula's
|
|
11
|
+
oscillating sum are exactly the orbits that scar individual eigenstates,
|
|
12
|
+
since eigenstates are (schematically) superpositions of trace-formula
|
|
13
|
+
terms.
|
|
14
|
+
|
|
15
|
+
:func:`bouncing_ball_energies` and :func:`bouncing_ball_orbit_points`
|
|
16
|
+
concern the single most famous scarred family in the Bunimovich stadium
|
|
17
|
+
billiard (:class:`physicskit.quantum.chapters.potentials.StadiumBilliard2D`):
|
|
18
|
+
the "bouncing ball" orbits bouncing straight up and down between the
|
|
19
|
+
flat top and bottom walls, which -- unlike a generic stadium orbit --
|
|
20
|
+
are only marginally unstable, so many low-lying eigenstates concentrate
|
|
21
|
+
along them. :func:`scar_enhancement` quantifies that concentration for
|
|
22
|
+
any eigenstate density, and :func:`husimi_projection_1d` builds a
|
|
23
|
+
non-periodic analog of :func:`physicskit.chaos.quantum.husimi.husimi_function`
|
|
24
|
+
for viewing a 1D wavefunction slice (e.g. along the billiard's flat
|
|
25
|
+
wall) in phase space.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import numpy as np
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
"bouncing_ball_energies",
|
|
34
|
+
"bouncing_ball_orbit_points",
|
|
35
|
+
"scar_enhancement",
|
|
36
|
+
"husimi_projection_1d",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def bouncing_ball_energies(R: float, hbar: float = 1.0, m: float = 1.0, n_max: int = 6) -> np.ndarray:
|
|
41
|
+
r"""Predicted energies of the "bouncing ball" orbit family in a stadium billiard of cap radius ``R``.
|
|
42
|
+
|
|
43
|
+
A trajectory launched perpendicular to the flat top and bottom walls
|
|
44
|
+
of a Bunimovich stadium (see
|
|
45
|
+
:class:`physicskit.quantum.chapters.potentials.StadiumBilliard2D`)
|
|
46
|
+
bounces straight up and down forever, blind to the length ``L`` of
|
|
47
|
+
the central rectangle -- exactly the motion of a particle in a 1D
|
|
48
|
+
infinite square well of width :math:`2R`. Quantizing that 1D motion
|
|
49
|
+
gives a leading-order prediction for where "bouncing ball" states
|
|
50
|
+
(eigenstates concentrated on this orbit family) appear in the full
|
|
51
|
+
2D spectrum:
|
|
52
|
+
|
|
53
|
+
.. math::
|
|
54
|
+
|
|
55
|
+
E_n = \frac{(n\pi\hbar)^2}{2m(2R)^2}, \qquad n=1,2,3,\dots
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
R : float
|
|
60
|
+
Radius of the stadium's semicircular end-caps (half-height of
|
|
61
|
+
the billiard).
|
|
62
|
+
hbar : float, default=1.0
|
|
63
|
+
Value of :math:`\hbar` to use.
|
|
64
|
+
m : float, default=1.0
|
|
65
|
+
Particle mass.
|
|
66
|
+
n_max : int, default=6
|
|
67
|
+
Number of levels to compute.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
ndarray, shape (n_max,)
|
|
72
|
+
Predicted bouncing-ball energies, ascending.
|
|
73
|
+
|
|
74
|
+
See Also
|
|
75
|
+
--------
|
|
76
|
+
bouncing_ball_orbit_points : The classical orbit these energies quantize.
|
|
77
|
+
|
|
78
|
+
Examples
|
|
79
|
+
--------
|
|
80
|
+
This is exactly the ordinary infinite-square-well spectrum for a
|
|
81
|
+
well of width :math:`2R`:
|
|
82
|
+
|
|
83
|
+
>>> import numpy as np
|
|
84
|
+
>>> R = 0.5
|
|
85
|
+
>>> energies = bouncing_ball_energies(R, n_max=3)
|
|
86
|
+
>>> exact = (np.arange(1, 4) * np.pi) ** 2 / (2 * (2 * R) ** 2)
|
|
87
|
+
>>> bool(np.allclose(energies, exact))
|
|
88
|
+
True
|
|
89
|
+
"""
|
|
90
|
+
n = np.arange(1, n_max + 1)
|
|
91
|
+
return (n * np.pi * hbar) ** 2 / (2.0 * m * (2.0 * R) ** 2)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def bouncing_ball_orbit_points(x0: float, R: float, n_bounces: int = 4) -> tuple:
|
|
95
|
+
r"""Trace the classical "bouncing ball" orbit at horizontal position ``x0`` in a stadium billiard.
|
|
96
|
+
|
|
97
|
+
A perpendicular launch from the bottom wall at :math:`(x_0,-R)`
|
|
98
|
+
reflects straight back and forth off the flat top (:math:`y=R`) and
|
|
99
|
+
bottom (:math:`y=-R`) walls, tracing the same vertical segment
|
|
100
|
+
forever -- returned here as a zig-zag list of points suitable for
|
|
101
|
+
overlaying on a density plot.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
x0 : float
|
|
106
|
+
Horizontal position of the orbit, with :math:`|x_0| < L/2`
|
|
107
|
+
(strictly inside the flat central section of the stadium).
|
|
108
|
+
R : float
|
|
109
|
+
Radius of the stadium's semicircular end-caps.
|
|
110
|
+
n_bounces : int, default=4
|
|
111
|
+
Number of full up-down traversals to trace.
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
x, y : ndarray
|
|
116
|
+
Coordinates tracing the orbit, shape ``(2 * n_bounces + 1,)``.
|
|
117
|
+
|
|
118
|
+
See Also
|
|
119
|
+
--------
|
|
120
|
+
bouncing_ball_energies : Quantized energies of this orbit family.
|
|
121
|
+
|
|
122
|
+
Examples
|
|
123
|
+
--------
|
|
124
|
+
>>> x, y = bouncing_ball_orbit_points(x0=0.2, R=0.5, n_bounces=2)
|
|
125
|
+
>>> x
|
|
126
|
+
array([0.2, 0.2, 0.2, 0.2, 0.2])
|
|
127
|
+
>>> y
|
|
128
|
+
array([-0.5, 0.5, -0.5, 0.5, -0.5])
|
|
129
|
+
"""
|
|
130
|
+
y = np.array([-R if i % 2 == 0 else R for i in range(2 * n_bounces + 1)])
|
|
131
|
+
x = np.full_like(y, x0)
|
|
132
|
+
return x, y
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def scar_enhancement(density: np.ndarray, X: np.ndarray, Y: np.ndarray, mask: np.ndarray, x0: float, half_width: float) -> float:
|
|
136
|
+
r"""Density enhancement in a tube around a vertical bouncing-ball orbit, relative to the billiard average.
|
|
137
|
+
|
|
138
|
+
.. math::
|
|
139
|
+
|
|
140
|
+
\eta = \frac{\langle|\psi|^2\rangle_{\text{tube}}}{\langle|\psi|^2\rangle_{\text{billiard}}},
|
|
141
|
+
\qquad \text{tube} = \{(x,y)\in\text{billiard} : |x-x_0|\le w\},
|
|
142
|
+
|
|
143
|
+
a simple, direct measure of scarring: :math:`\eta\approx1` for an
|
|
144
|
+
ergodically-spread (unscarred) state, since the tube then just
|
|
145
|
+
samples a representative fraction of the whole density, while
|
|
146
|
+
:math:`\eta\gg1` signals density piled up specifically along the
|
|
147
|
+
orbit at :math:`x_0`.
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
density : ndarray
|
|
152
|
+
Probability density :math:`|\psi(x,y)|^2` on a grid.
|
|
153
|
+
X, Y : ndarray
|
|
154
|
+
Coordinate meshgrid matching ``density``.
|
|
155
|
+
mask : ndarray of bool
|
|
156
|
+
``True`` inside the billiard (e.g. from
|
|
157
|
+
:meth:`physicskit.quantum.chapters.potentials.StadiumBilliard2D.mask`).
|
|
158
|
+
x0 : float
|
|
159
|
+
Horizontal position of the bouncing-ball orbit to test.
|
|
160
|
+
half_width : float
|
|
161
|
+
Half-width of the tube around ``x0``.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
float
|
|
166
|
+
The enhancement factor :math:`\eta`.
|
|
167
|
+
|
|
168
|
+
Examples
|
|
169
|
+
--------
|
|
170
|
+
A density sharply concentrated in a narrow ridge at ``x0`` is
|
|
171
|
+
strongly enhanced inside a tube covering that ridge:
|
|
172
|
+
|
|
173
|
+
>>> import numpy as np
|
|
174
|
+
>>> x = np.linspace(-2, 2, 400)
|
|
175
|
+
>>> y = np.linspace(-1, 1, 200)
|
|
176
|
+
>>> X, Y = np.meshgrid(x, y, indexing="ij")
|
|
177
|
+
>>> mask = np.ones_like(X, dtype=bool)
|
|
178
|
+
>>> density = np.exp(-(X - 0.3) ** 2 / (2 * 0.05 ** 2))
|
|
179
|
+
>>> eta = scar_enhancement(density, X, Y, mask, x0=0.3, half_width=0.15)
|
|
180
|
+
>>> bool(12.0 < eta < 14.0)
|
|
181
|
+
True
|
|
182
|
+
|
|
183
|
+
An (exactly) uniform density is not enhanced anywhere:
|
|
184
|
+
|
|
185
|
+
>>> uniform = np.ones_like(X)
|
|
186
|
+
>>> round(scar_enhancement(uniform, X, Y, mask, x0=0.3, half_width=0.15), 8)
|
|
187
|
+
1.0
|
|
188
|
+
"""
|
|
189
|
+
tube = mask & (np.abs(X - x0) <= half_width)
|
|
190
|
+
return float(np.mean(density[tube]) / np.mean(density[mask]))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def husimi_projection_1d(
|
|
194
|
+
psi: np.ndarray,
|
|
195
|
+
s: np.ndarray,
|
|
196
|
+
hbar: float = 1.0,
|
|
197
|
+
sigma: float | None = None,
|
|
198
|
+
resolution: int = 60,
|
|
199
|
+
s0_range: tuple | None = None,
|
|
200
|
+
p0_range: tuple | None = None,
|
|
201
|
+
) -> tuple:
|
|
202
|
+
r"""Husimi (coherent-state) phase-space projection of a 1D wavefunction slice on an open interval.
|
|
203
|
+
|
|
204
|
+
The non-periodic counterpart of
|
|
205
|
+
:func:`physicskit.chaos.quantum.husimi.husimi_function`: overlaps
|
|
206
|
+
``psi`` with ordinary (non-periodized) coherent states
|
|
207
|
+
:math:`g_{s_0,p_0}(s)=\exp[-(s-s_0)^2/2\sigma^2+ip_0(s-s_0)/\hbar]`
|
|
208
|
+
at every point of an :math:`(s_0,p_0)` grid, suited to a slice taken
|
|
209
|
+
along an open boundary -- e.g. the flat top wall of a stadium
|
|
210
|
+
billiard, where :func:`bouncing_ball_orbit_points` lives -- rather
|
|
211
|
+
than a periodic domain.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
psi : ndarray of complex
|
|
216
|
+
Wavefunction values sampled on ``s``.
|
|
217
|
+
s : ndarray
|
|
218
|
+
Uniform 1D coordinate grid ``psi`` is sampled on.
|
|
219
|
+
hbar : float, default=1.0
|
|
220
|
+
Value of :math:`\hbar` to use.
|
|
221
|
+
sigma : float, optional
|
|
222
|
+
Coherent-state position width. Defaults to :math:`\sqrt{\hbar}`
|
|
223
|
+
(the minimum-uncertainty, equal-spread-in-natural-units choice).
|
|
224
|
+
resolution : int, default=60
|
|
225
|
+
Number of grid points along each of the :math:`s_0`, :math:`p_0` axes.
|
|
226
|
+
s0_range : (float, float), optional
|
|
227
|
+
Range of :math:`s_0` to scan. Defaults to ``(s.min(), s.max())``.
|
|
228
|
+
p0_range : (float, float), optional
|
|
229
|
+
Range of :math:`p_0` to scan. Defaults to
|
|
230
|
+
:math:`\pm\pi\hbar/\Delta s` (the grid's Nyquist momentum).
|
|
231
|
+
|
|
232
|
+
Returns
|
|
233
|
+
-------
|
|
234
|
+
S0, P0 : ndarray, shape (resolution, resolution)
|
|
235
|
+
Phase-space grid (``indexing="ij"``).
|
|
236
|
+
husimi : ndarray, shape (resolution, resolution)
|
|
237
|
+
The Husimi distribution, normalized to a peak value of 1.
|
|
238
|
+
|
|
239
|
+
See Also
|
|
240
|
+
--------
|
|
241
|
+
scar_enhancement : A simpler, single-number scarring diagnostic in
|
|
242
|
+
position space rather than phase space.
|
|
243
|
+
|
|
244
|
+
Examples
|
|
245
|
+
--------
|
|
246
|
+
A Gaussian wave packet's Husimi projection peaks at its own
|
|
247
|
+
position and momentum:
|
|
248
|
+
|
|
249
|
+
>>> import numpy as np
|
|
250
|
+
>>> s = np.linspace(-10, 10, 2000)
|
|
251
|
+
>>> s0_true, p0_true, w = 2.0, 3.0, 1.0
|
|
252
|
+
>>> psi = np.exp(-(s - s0_true) ** 2 / (2 * w ** 2)) * np.exp(1j * p0_true * s / 1.0)
|
|
253
|
+
>>> S0, P0, H = husimi_projection_1d(psi, s, hbar=1.0, sigma=w, resolution=80, s0_range=(-2, 6), p0_range=(-2, 8))
|
|
254
|
+
>>> i, j = np.unravel_index(np.argmax(H), H.shape)
|
|
255
|
+
>>> bool(abs(S0[i, j] - s0_true) < 0.2 and abs(P0[i, j] - p0_true) < 0.2)
|
|
256
|
+
True
|
|
257
|
+
"""
|
|
258
|
+
s = np.asarray(s, dtype=float)
|
|
259
|
+
ds = s[1] - s[0]
|
|
260
|
+
if sigma is None:
|
|
261
|
+
sigma = np.sqrt(hbar)
|
|
262
|
+
if s0_range is None:
|
|
263
|
+
s0_range = (float(s.min()), float(s.max()))
|
|
264
|
+
if p0_range is None:
|
|
265
|
+
p_max = np.pi * hbar / ds
|
|
266
|
+
p0_range = (-p_max, p_max)
|
|
267
|
+
|
|
268
|
+
s0 = np.linspace(s0_range[0], s0_range[1], resolution)
|
|
269
|
+
p0 = np.linspace(p0_range[0], p0_range[1], resolution)
|
|
270
|
+
S0, P0 = np.meshgrid(s0, p0, indexing="ij")
|
|
271
|
+
|
|
272
|
+
ds_grid = s[None, None, :] - S0[:, :, None]
|
|
273
|
+
coherent = np.exp(-(ds_grid**2) / (2.0 * sigma**2) + 1j * P0[:, :, None] * ds_grid / hbar)
|
|
274
|
+
overlap = np.tensordot(np.conj(coherent), psi, axes=([2], [0])) * ds
|
|
275
|
+
|
|
276
|
+
husimi = np.abs(overlap) ** 2
|
|
277
|
+
husimi /= husimi.max()
|
|
278
|
+
return S0, P0, husimi
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Physics-correctness tests for physicskit.semiclassical.core.gutzwiller."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pytest
|
|
7
|
+
from scipy.signal import find_peaks
|
|
8
|
+
|
|
9
|
+
from physicskit.semiclassical.core.gutzwiller import (
|
|
10
|
+
classical_period,
|
|
11
|
+
gutzwiller_amplitude_from_monodromy,
|
|
12
|
+
gutzwiller_density_of_states,
|
|
13
|
+
)
|
|
14
|
+
from physicskit.semiclassical.core.wkb import bohr_sommerfeld_energies
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.mark.slow
|
|
18
|
+
def test_gutzwiller_trace_formula_peaks_match_bohr_sommerfeld_spectrum():
|
|
19
|
+
V = lambda x: 0.5 * x**2
|
|
20
|
+
E_grid = np.linspace(0.2, 4.5, 200)
|
|
21
|
+
dos = gutzwiller_density_of_states(E_grid, V, m=1.0, x_min=-20, x_max=20)
|
|
22
|
+
peak_idx, _ = find_peaks(dos, height=0.3 * dos.max())
|
|
23
|
+
exact = bohr_sommerfeld_energies(V, m=1.0, x_min=-20, x_max=20, n_max=4)
|
|
24
|
+
assert np.allclose(E_grid[peak_idx], exact, atol=0.05)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_classical_period_matches_harmonic_oscillator():
|
|
28
|
+
V = lambda x: 0.5 * x**2
|
|
29
|
+
T = classical_period(E=3.0, V=V, m=1.0, x_min=-20, x_max=20)
|
|
30
|
+
assert abs(T - 2 * np.pi) < 1e-4
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_gutzwiller_amplitude_from_monodromy():
|
|
34
|
+
M = np.array([[2.0, 0.0], [0.0, 0.5]])
|
|
35
|
+
assert abs(gutzwiller_amplitude_from_monodromy(M) - 1.0 / np.sqrt(0.5)) < 1e-10
|