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,131 @@
|
|
|
1
|
+
"""Spot-check each chapter against known analytic results, so regressions in
|
|
2
|
+
the underlying physics (not just raw unitarity) get caught."""
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from physicskit.quantum.chapters.entanglement import AharonovBohmRing, BellCorrelations
|
|
7
|
+
from physicskit.quantum.chapters.harmonic_spin import HarmonicOscillator, ThermalState
|
|
8
|
+
from physicskit.quantum.chapters.hydrogen_am import HydrogenOrbital
|
|
9
|
+
from physicskit.quantum.chapters.potentials import FiniteSquareWell, StadiumBilliard2D
|
|
10
|
+
from physicskit.quantum.chapters.wave_packets import QuantumRevival
|
|
11
|
+
from physicskit.quantum.core.eigensolvers import NumerovSolver, harmonic_well, infinite_well
|
|
12
|
+
from physicskit.quantum.visualizers.phase_space import wigner_transform
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_numerov_matches_infinite_well_and_harmonic_oscillator():
|
|
16
|
+
x = np.linspace(0, 1, 400)
|
|
17
|
+
energies = NumerovSolver(x, infinite_well()).solve(5).energies
|
|
18
|
+
analytic = (np.arange(1, 6) ** 2 * np.pi**2) / 2
|
|
19
|
+
assert np.allclose(energies, analytic, rtol=1e-3)
|
|
20
|
+
|
|
21
|
+
x2 = np.linspace(-10, 10, 800)
|
|
22
|
+
energies2 = NumerovSolver(x2, harmonic_well()).solve(5).energies
|
|
23
|
+
assert np.allclose(energies2, np.arange(5) + 0.5, atol=1e-4)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_coherent_state_tracks_classical_trajectory():
|
|
27
|
+
ho = HarmonicOscillator()
|
|
28
|
+
x = np.linspace(-15, 15, 3000)
|
|
29
|
+
alpha = 3 + 1j
|
|
30
|
+
for t in (0.0, 1.3, 4.0):
|
|
31
|
+
psi_t = ho.coherent_wavefunction(alpha, x, t=t)
|
|
32
|
+
x_mean = np.real(np.trapezoid(x * np.abs(psi_t) ** 2, x))
|
|
33
|
+
x_classical, _ = ho.coherent_trajectory(alpha, np.array([t]))
|
|
34
|
+
assert abs(x_mean - x_classical[0]) < 1e-6
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_thermal_state_broadens_with_temperature():
|
|
38
|
+
ho = HarmonicOscillator()
|
|
39
|
+
var_cold = ThermalState(ho, T=0.1).variance()
|
|
40
|
+
var_hot = ThermalState(ho, T=5.0).variance()
|
|
41
|
+
assert var_hot > var_cold
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_hydrogen_orbitals_normalized_with_correct_energy():
|
|
45
|
+
for n, l, m in [(1, 0, 0), (2, 1, 0), (3, 2, 1)]:
|
|
46
|
+
orb = HydrogenOrbital(n, l, m)
|
|
47
|
+
assert abs(orb.check_normalization() - 1.0) < 1e-6
|
|
48
|
+
assert abs(orb.energy - (-1 / (2 * n**2))) < 1e-12
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_quantum_revival_reassembles_at_revival_time():
|
|
52
|
+
qr = QuantumRevival(L=1.0, n_max=250)
|
|
53
|
+
x = np.linspace(0, qr.L, 1500)
|
|
54
|
+
psi0_func = qr.gaussian_initial_state(x0=0.3, sigma=0.03)
|
|
55
|
+
psi0 = psi0_func(x)
|
|
56
|
+
c = qr.eigenbasis_coefficients(psi0_func)
|
|
57
|
+
|
|
58
|
+
fidelity_scrambled = qr.fidelity_to_initial(x, 0.1 * qr.revival_time, c, psi0)
|
|
59
|
+
fidelity_revived = qr.fidelity_to_initial(x, qr.revival_time, c, psi0)
|
|
60
|
+
|
|
61
|
+
assert fidelity_revived > 0.999
|
|
62
|
+
assert fidelity_scrambled < 0.5
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_wigner_transform_matches_ground_state_analytic_form():
|
|
66
|
+
ho = HarmonicOscillator()
|
|
67
|
+
x = np.linspace(-8, 8, 250)
|
|
68
|
+
psi0 = ho.eigenfunction(0, x)
|
|
69
|
+
xg, p, W = wigner_transform(x, psi0, hbar=1.0, n_p=120)
|
|
70
|
+
X, P = np.meshgrid(x, p, indexing="ij")
|
|
71
|
+
analytic = (1 / np.pi) * np.exp(-(X**2) - P**2)
|
|
72
|
+
assert np.max(np.abs(W - analytic)) < 1e-10
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_bell_singlet_violates_chsh_bound():
|
|
76
|
+
bc = BellCorrelations()
|
|
77
|
+
assert abs(bc.chsh_optimal() - 2 * np.sqrt(2)) < 1e-10
|
|
78
|
+
assert bc.chsh_optimal() > 2.0 # violates the classical (local hidden-variable) bound
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_aharonov_bohm_energy_periodic_in_flux_quantum():
|
|
82
|
+
ring = AharonovBohmRing(R=1.0)
|
|
83
|
+
Phi0 = ring.flux_quantum
|
|
84
|
+
n = np.arange(-3, 4)
|
|
85
|
+
e0 = ring.energy(n, 0.0)
|
|
86
|
+
e_shifted = ring.energy(n + 1, Phi0) # shifting both n and Phi by one quantum is a relabeling
|
|
87
|
+
assert np.allclose(e0, e_shifted)
|
|
88
|
+
assert abs(ring.aharonov_bohm_phase(Phi0) - 2 * np.pi) < 1e-12
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_barrier_scattering_matches_sub_barrier_tunneling_formula():
|
|
92
|
+
# A "well" with negative V0 is a barrier of height |V0|; below the
|
|
93
|
+
# barrier (E < |V0|) this is the classically forbidden, sub-barrier
|
|
94
|
+
# tunneling regime, where k2 is purely imaginary.
|
|
95
|
+
E, Vb, a = 4.5, 6.0, 1.0
|
|
96
|
+
barrier = FiniteSquareWell(V0=-Vb, width=a)
|
|
97
|
+
result = barrier.scattering(E)
|
|
98
|
+
|
|
99
|
+
kappa = np.sqrt(2 * (Vb - E))
|
|
100
|
+
T_expected = 1 / (1 + Vb**2 * np.sinh(kappa * a) ** 2 / (4 * E * (Vb - E)))
|
|
101
|
+
assert abs(result.T - T_expected) < 1e-12
|
|
102
|
+
assert abs(result.k2.real) < 1e-12 # purely imaginary in the forbidden region
|
|
103
|
+
assert 0 < result.T < 1
|
|
104
|
+
|
|
105
|
+
# Above the barrier (E > |V0|), T should match the ordinary real-k2 formula.
|
|
106
|
+
E_above = 10.0
|
|
107
|
+
result_above = barrier.scattering(E_above)
|
|
108
|
+
k2_expected = np.sqrt(2 * (E_above - Vb))
|
|
109
|
+
T_expected_above = 1 / (1 + Vb**2 * np.sin(k2_expected * a) ** 2 / (4 * E_above * (E_above - Vb)))
|
|
110
|
+
assert abs(result_above.T - T_expected_above) < 1e-10
|
|
111
|
+
assert abs(result_above.k2.imag) < 1e-12
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_stadium_billiard_grid_is_isotropic_and_states_are_normalized():
|
|
115
|
+
# A mismatched dx/dy staircases the semicircular caps as ellipses
|
|
116
|
+
# rather than circles, giving resolution-dependent, non-monotonically
|
|
117
|
+
# converging eigenvalues -- grid() must keep dx == dy.
|
|
118
|
+
sb = StadiumBilliard2D(L=1.0, R=0.5)
|
|
119
|
+
for n_points in (50, 90, 150):
|
|
120
|
+
(X, Y), x, y = sb.grid(n_points)
|
|
121
|
+
dx, dy = x[1] - x[0], y[1] - y[0]
|
|
122
|
+
# dy matches dx up to the rounding of n_y to an integer point count
|
|
123
|
+
assert abs(dx - dy) / dx < 0.02
|
|
124
|
+
|
|
125
|
+
energies, wavefunctions, X, Y, mask = sb.solve(n_points=90, n_states=4)
|
|
126
|
+
assert np.all(np.diff(energies) > 0)
|
|
127
|
+
assert np.all(energies > 0)
|
|
128
|
+
dx, dy = X[1, 0] - X[0, 0], Y[0, 1] - Y[0, 0]
|
|
129
|
+
for psi in wavefunctions:
|
|
130
|
+
assert abs(np.sum(psi**2) * dx * dy - 1.0) < 1e-6
|
|
131
|
+
assert np.all(psi[~mask] == 0.0)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"""Tests for physicskit.quantum.chapters.potentials: the parts
|
|
2
|
+
test_physics_checks.py and test_animations.py don't already exercise --
|
|
3
|
+
the asymmetric step well, the gravitational bouncer (both the Numerov
|
|
4
|
+
solver and its closed-form Airy-function check), DoubleWellSimulator's
|
|
5
|
+
localized_state, FiniteSquareWell's bound_states/transmission_spectrum/
|
|
6
|
+
evanescent_wavefunction, and the 2D rectangular/circular boxes.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from physicskit.quantum._compat import trapz
|
|
15
|
+
from physicskit.quantum.chapters.potentials import (
|
|
16
|
+
Box2DEigenstate,
|
|
17
|
+
CircularBox2D,
|
|
18
|
+
DoubleWellSimulator,
|
|
19
|
+
FiniteSquareWell,
|
|
20
|
+
RectangularBox2D,
|
|
21
|
+
airy_bouncer_energies,
|
|
22
|
+
airy_wavefunction,
|
|
23
|
+
asymmetric_well_states,
|
|
24
|
+
gravitational_bouncer_states,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# --- Asymmetric step well -----------------------------------------------------
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_asymmetric_well_states_are_bound_below_the_lower_wall():
|
|
32
|
+
res = asymmetric_well_states(width=2.0, V_left=40.0, V_right=15.0, n_points=800, n_states=3)
|
|
33
|
+
assert np.all(np.diff(res.energies) > 0) # ascending
|
|
34
|
+
assert np.all(res.energies < 15.0) # below the lower (right) wall
|
|
35
|
+
for psi in res.wavefunctions:
|
|
36
|
+
assert trapz(psi**2, res.x) == pytest.approx(1.0, abs=1e-2)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# --- Gravitational bouncer -----------------------------------------------------
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_gravitational_bouncer_numerov_matches_airy_analytic_energies():
|
|
43
|
+
n_states = 4
|
|
44
|
+
numeric = gravitational_bouncer_states(alpha=1.0, x_extent=12.0, n_points=1500, n_states=n_states)
|
|
45
|
+
analytic = airy_bouncer_energies(alpha=1.0, n_states=n_states)
|
|
46
|
+
np.testing.assert_allclose(numeric.energies, analytic, rtol=2e-2)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_airy_bouncer_energies_are_ascending_and_positive():
|
|
50
|
+
energies = airy_bouncer_energies(alpha=2.0, n_states=5)
|
|
51
|
+
assert np.all(energies > 0)
|
|
52
|
+
assert np.all(np.diff(energies) > 0)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_airy_wavefunction_is_normalized_and_vanishes_below_floor():
|
|
56
|
+
x = np.linspace(-2, 30, 4000)
|
|
57
|
+
psi = airy_wavefunction(x, alpha=1.0, n=0)
|
|
58
|
+
assert trapz(psi**2, x) == pytest.approx(1.0, abs=1e-3)
|
|
59
|
+
np.testing.assert_allclose(psi[x < 0], 0.0)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_airy_wavefunction_overlaps_numerov_ground_state():
|
|
63
|
+
numeric = gravitational_bouncer_states(alpha=1.0, x_extent=12.0, n_points=1500, n_states=1)
|
|
64
|
+
analytic_psi = airy_wavefunction(numeric.x, alpha=1.0, n=0)
|
|
65
|
+
overlap = abs(trapz(analytic_psi * numeric.wavefunctions[0], numeric.x))
|
|
66
|
+
assert overlap == pytest.approx(1.0, abs=1e-2)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# --- Double well: localized_state ---------------------------------------------
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_double_well_localized_state_is_normalized_and_side_asymmetric():
|
|
73
|
+
dw = DoubleWellSimulator(lam=0.3, a=2.0, n_points=800)
|
|
74
|
+
result = dw.solve(n_states=2)
|
|
75
|
+
left = dw.localized_state(result, side="left")
|
|
76
|
+
right = dw.localized_state(result, side="right")
|
|
77
|
+
assert trapz(left**2, result.x) == pytest.approx(1.0, abs=1e-2)
|
|
78
|
+
assert trapz(right**2, result.x) == pytest.approx(1.0, abs=1e-2)
|
|
79
|
+
left_mask = result.x < 0
|
|
80
|
+
# a state built to localize on the left should weight the left lobe more
|
|
81
|
+
assert trapz(left[left_mask] ** 2, result.x[left_mask]) > trapz(right[left_mask] ** 2, result.x[left_mask])
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# --- Finite square well: bound_states / transmission_spectrum / evanescent ----
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_finite_square_well_bound_states_are_all_negative_energy():
|
|
88
|
+
well = FiniteSquareWell(V0=20.0, width=2.0)
|
|
89
|
+
res = well.bound_states(n_points=800, n_states=6)
|
|
90
|
+
assert res.energies.size > 0
|
|
91
|
+
assert np.all(res.energies < 0)
|
|
92
|
+
assert np.all(np.diff(res.energies) > 0)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def test_finite_square_well_evanescent_wavefunction_matches_bound_states_entry():
|
|
96
|
+
well = FiniteSquareWell(V0=20.0, width=2.0)
|
|
97
|
+
res = well.bound_states(n_points=800, n_states=3)
|
|
98
|
+
np.testing.assert_allclose(well.evanescent_wavefunction(res, n=1), res.wavefunctions[1])
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_transmission_spectrum_matches_pointwise_scattering():
|
|
102
|
+
well = FiniteSquareWell(V0=10.0, width=1.0)
|
|
103
|
+
E_values = np.array([1.0, 5.0, 12.0])
|
|
104
|
+
spectrum = well.transmission_spectrum(E_values)
|
|
105
|
+
expected = np.array([well.scattering(E).T for E in E_values])
|
|
106
|
+
np.testing.assert_allclose(spectrum, expected)
|
|
107
|
+
assert np.all((spectrum >= 0) & (spectrum <= 1))
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# --- 2D rectangular box ---------------------------------------------------------
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_rectangular_box_energy_matches_formula():
|
|
114
|
+
box = RectangularBox2D(Lx=2.0, Ly=3.0, hbar=1.0, m=1.0)
|
|
115
|
+
nx, ny = 2, 3
|
|
116
|
+
expected = (np.pi**2 * box.hbar**2 / (2 * box.m)) * ((nx / box.Lx) ** 2 + (ny / box.Ly) ** 2)
|
|
117
|
+
assert box.energy(nx, ny) == pytest.approx(expected)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_rectangular_box_spectrum_is_sorted_by_energy():
|
|
121
|
+
box = RectangularBox2D(Lx=1.0, Ly=1.7)
|
|
122
|
+
states = box.spectrum(n_max=4)
|
|
123
|
+
energies = [s.energy for s in states]
|
|
124
|
+
assert energies == sorted(energies)
|
|
125
|
+
assert len(states) == 16
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_rectangular_box_square_has_degeneracies():
|
|
129
|
+
box = RectangularBox2D(Lx=1.0, Ly=1.0)
|
|
130
|
+
degeneracies = box.degeneracies(n_max=4)
|
|
131
|
+
# (1,2) and (2,1) are exactly degenerate for a square box (E ~ nx^2+ny^2)
|
|
132
|
+
assert any({(1, 2), (2, 1)} <= set(pairs) for pairs in degeneracies.values())
|
|
133
|
+
for pairs in degeneracies.values():
|
|
134
|
+
assert len(pairs) >= 2
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def test_rectangular_box_grid_has_expected_shape_and_bounds():
|
|
138
|
+
box = RectangularBox2D(Lx=2.0, Ly=3.0)
|
|
139
|
+
X, Y = box.grid(n_points=10)
|
|
140
|
+
assert X.shape == (10, 10)
|
|
141
|
+
assert X.min() == pytest.approx(0.0)
|
|
142
|
+
assert X.max() == pytest.approx(2.0)
|
|
143
|
+
assert Y.max() == pytest.approx(3.0)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def test_box2d_eigenstate_psi_is_normalized_over_the_box():
|
|
147
|
+
box = RectangularBox2D(Lx=1.0, Ly=1.0)
|
|
148
|
+
state = Box2DEigenstate(nx=2, ny=1, energy=box.energy(2, 1))
|
|
149
|
+
X, Y = box.grid(n_points=200)
|
|
150
|
+
psi = state.psi(X, Y, box.Lx, box.Ly)
|
|
151
|
+
integral = trapz(trapz(psi**2, Y[0], axis=1), X[:, 0])
|
|
152
|
+
assert integral == pytest.approx(1.0, abs=1e-2)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# --- 2D circular quantum dot ------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_circular_box_eigenstate_energy_matches_bessel_zero_formula():
|
|
159
|
+
from scipy.special import jn_zeros
|
|
160
|
+
|
|
161
|
+
dot = CircularBox2D(R=1.5, hbar=1.0, m_mass=1.0)
|
|
162
|
+
state = dot.eigenstate(m=1, n=2)
|
|
163
|
+
expected_k = jn_zeros(1, 2)[-1] / dot.R
|
|
164
|
+
assert state.k == pytest.approx(expected_k)
|
|
165
|
+
assert state.energy == pytest.approx(dot.hbar**2 * state.k**2 / (2 * dot.m_mass))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_circular_box_spectrum_is_sorted_and_ground_state_is_m_zero_n_one():
|
|
169
|
+
dot = CircularBox2D(R=1.0)
|
|
170
|
+
states = dot.spectrum(m_max=3, n_max=3)
|
|
171
|
+
energies = [s.energy for s in states]
|
|
172
|
+
assert energies == sorted(energies)
|
|
173
|
+
assert states[0].m == 0
|
|
174
|
+
assert states[0].n == 1
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_circular_box_polar_grid_spans_radius_and_full_turn():
|
|
178
|
+
dot = CircularBox2D(R=2.0)
|
|
179
|
+
r, phi = dot.polar_grid(n_r=20, n_phi=30)
|
|
180
|
+
assert r.shape == (20, 30)
|
|
181
|
+
assert r.max() == pytest.approx(2.0)
|
|
182
|
+
assert phi.max() == pytest.approx(2 * np.pi)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_circular_eigenstate_psi_vanishes_at_the_boundary():
|
|
186
|
+
dot = CircularBox2D(R=1.0)
|
|
187
|
+
state = dot.eigenstate(m=0, n=1)
|
|
188
|
+
phi = np.linspace(0, 2 * np.pi, 16)
|
|
189
|
+
r_boundary = np.full_like(phi, dot.R)
|
|
190
|
+
psi_boundary = state.psi(r_boundary, phi, dot.R)
|
|
191
|
+
np.testing.assert_allclose(psi_boundary, 0.0, atol=1e-8)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Tests for physicskit.quantum.core.solvers: the time-dependent-potential
|
|
2
|
+
branch of SplitOperatorSolver2D (test_unitarity.py only exercises the
|
|
3
|
+
static-potential path) and _accepts_time's non-introspectable-callable
|
|
4
|
+
fallback.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from physicskit.quantum.core.solvers import SplitOperatorSolver2D, _accepts_time
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _gaussian_2d(X, Y, x0=0.0, y0=0.0, sigma=1.0):
|
|
16
|
+
norm = (2 * np.pi * sigma**2) ** (-0.5)
|
|
17
|
+
return norm * np.exp(-((X - x0) ** 2 + (Y - y0) ** 2) / (2 * sigma**2))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_accepts_time_detects_three_argument_signature():
|
|
21
|
+
def V_static(x, y):
|
|
22
|
+
return x + y
|
|
23
|
+
|
|
24
|
+
def V_time_dependent(x, y, t):
|
|
25
|
+
return x + y + t
|
|
26
|
+
|
|
27
|
+
assert _accepts_time(V_static, n_spatial_args=2) is False
|
|
28
|
+
assert _accepts_time(V_time_dependent, n_spatial_args=2) is True
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_accepts_time_falls_back_to_false_for_non_introspectable_callable():
|
|
32
|
+
# inspect.signature(min) raises ValueError (no signature metadata for
|
|
33
|
+
# this builtin), and _accepts_time should fall back to False rather
|
|
34
|
+
# than propagating the exception.
|
|
35
|
+
assert _accepts_time(min, n_spatial_args=2) is False
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_split_operator_2d_with_time_dependent_potential_conserves_norm():
|
|
39
|
+
x = np.linspace(-8, 8, 64)
|
|
40
|
+
y = np.linspace(-8, 8, 64)
|
|
41
|
+
|
|
42
|
+
def V(X, Y, t):
|
|
43
|
+
return 0.5 * (X**2 + Y**2) * (1.0 + 0.1 * np.sin(t))
|
|
44
|
+
|
|
45
|
+
solver = SplitOperatorSolver2D(x, y, V, dt=1e-3)
|
|
46
|
+
assert solver._time_dependent is True
|
|
47
|
+
|
|
48
|
+
X, Y = np.meshgrid(x, y, indexing="ij")
|
|
49
|
+
psi = _gaussian_2d(X, Y).astype(complex)
|
|
50
|
+
psi /= np.sqrt(solver.norm(psi))
|
|
51
|
+
|
|
52
|
+
t = 0.0
|
|
53
|
+
for _ in range(50):
|
|
54
|
+
psi = solver.step(psi, t)
|
|
55
|
+
t += solver.dt
|
|
56
|
+
|
|
57
|
+
assert solver.norm(psi) == pytest.approx(1.0, abs=1e-6)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_split_operator_2d_time_dependent_potential_actually_varies_with_time():
|
|
61
|
+
x = np.linspace(-8, 8, 32)
|
|
62
|
+
y = np.linspace(-8, 8, 32)
|
|
63
|
+
|
|
64
|
+
def V(X, Y, t):
|
|
65
|
+
return t * (X**2 + Y**2)
|
|
66
|
+
|
|
67
|
+
solver = SplitOperatorSolver2D(x, y, V, dt=1e-3)
|
|
68
|
+
phase_t0 = solver._half_potential_phase(0.0)
|
|
69
|
+
phase_t1 = solver._half_potential_phase(1.0)
|
|
70
|
+
assert not np.allclose(phase_t0, phase_t1)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Tests for physicskit.quantum.chapters.spin: RabiProblem's Omega_R=0
|
|
2
|
+
edge case (no drive, no detuning), not exercised by test_animations.py.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from physicskit.quantum.chapters.spin import RabiProblem
|
|
10
|
+
from physicskit.quantum.core.operators import identity2
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_rabi_propagator_is_identity_when_undriven_and_on_resonance():
|
|
14
|
+
rabi = RabiProblem(omega0=1.0, omega_d=1.0, Omega=0.0)
|
|
15
|
+
assert rabi.generalized_rabi_frequency == 0.0
|
|
16
|
+
np.testing.assert_allclose(rabi.propagator(t=2.5), identity2)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_rabi_excited_state_population_stays_zero_when_undriven():
|
|
20
|
+
rabi = RabiProblem(omega0=1.0, omega_d=1.0, Omega=0.0)
|
|
21
|
+
t = np.linspace(0, 10, 20)
|
|
22
|
+
np.testing.assert_allclose(rabi.excited_state_population(t), np.zeros_like(t))
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Verify probability conservation integral |psi(x,t)|^2 dx = 1 +/- 1e-6 over
|
|
2
|
+
10^4 timesteps of the split-operator FFT propagator, across a variety of
|
|
3
|
+
potential shapes (harmonic, double well, finite well, asymmetric well,
|
|
4
|
+
gravitational bouncer, soft infinite box, and a 2D rectangular box).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from physicskit.quantum.core.eigensolvers import (
|
|
11
|
+
asymmetric_step_well,
|
|
12
|
+
double_well,
|
|
13
|
+
finite_well,
|
|
14
|
+
harmonic_well,
|
|
15
|
+
linear_gravitational_well,
|
|
16
|
+
)
|
|
17
|
+
from physicskit.quantum.core.solvers import SplitOperatorSolver1D, SplitOperatorSolver2D
|
|
18
|
+
|
|
19
|
+
N_STEPS = 10_000
|
|
20
|
+
TOL = 1e-6
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _gaussian(x, x0=0.0, sigma=1.0, k0=0.0):
|
|
24
|
+
norm = (2 * np.pi * sigma**2) ** (-0.25)
|
|
25
|
+
return norm * np.exp(-((x - x0) ** 2) / (4 * sigma**2)) * np.exp(1j * k0 * x)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _run_1d(V, x, psi0, dt):
|
|
29
|
+
solver = SplitOperatorSolver1D(x, V, dt=dt)
|
|
30
|
+
psi = psi0.astype(complex)
|
|
31
|
+
psi /= np.sqrt(solver.norm(psi))
|
|
32
|
+
for _ in range(N_STEPS):
|
|
33
|
+
psi = solver.step(psi)
|
|
34
|
+
return solver.norm(psi)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.mark.parametrize(
|
|
38
|
+
"name,V,x_range,x0,sigma,dt",
|
|
39
|
+
[
|
|
40
|
+
("harmonic", harmonic_well(), (-15, 15), 2.0, 1.0, 1e-3),
|
|
41
|
+
("double_well", double_well(lam=0.5, a=2.5), (-8, 8), 2.5, 0.5, 5e-4),
|
|
42
|
+
("finite_well", finite_well(V0=30.0, width=3.0), (-10, 10), 0.0, 0.5, 5e-4),
|
|
43
|
+
("asymmetric_well", asymmetric_step_well(width=3.0, V_left=40.0, V_right=15.0), (-8, 8), 0.0, 0.5, 5e-4),
|
|
44
|
+
("gravitational_bouncer", linear_gravitational_well(alpha=2.0), (-12, 12), 3.0, 0.5, 2e-4),
|
|
45
|
+
],
|
|
46
|
+
)
|
|
47
|
+
def test_1d_unitarity(name, V, x_range, x0, sigma, dt):
|
|
48
|
+
x = np.linspace(*x_range, 2048)
|
|
49
|
+
psi0 = _gaussian(x, x0=x0, sigma=sigma)
|
|
50
|
+
final_norm = _run_1d(V, x, psi0, dt)
|
|
51
|
+
assert abs(final_norm - 1.0) < TOL, f"{name}: norm drifted to {final_norm}"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_1d_unitarity_soft_infinite_box():
|
|
55
|
+
L, wall = 1.0, 4000.0
|
|
56
|
+
|
|
57
|
+
def V(x):
|
|
58
|
+
return np.where((x >= 0) & (x <= L), 0.0, wall)
|
|
59
|
+
|
|
60
|
+
x = np.linspace(-0.3, 1.3, 2048)
|
|
61
|
+
psi0 = _gaussian(x, x0=0.5, sigma=0.08)
|
|
62
|
+
final_norm = _run_1d(V, x, psi0, dt=2e-5)
|
|
63
|
+
assert abs(final_norm - 1.0) < TOL
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_2d_unitarity_rectangular_box():
|
|
67
|
+
Lx, Ly, wall = 1.0, 1.0, 3000.0
|
|
68
|
+
|
|
69
|
+
def V(x, y):
|
|
70
|
+
return np.where((x >= 0) & (x <= Lx) & (y >= 0) & (y <= Ly), 0.0, wall)
|
|
71
|
+
|
|
72
|
+
x = np.linspace(-0.3, 1.3, 160)
|
|
73
|
+
y = np.linspace(-0.3, 1.3, 160)
|
|
74
|
+
solver = SplitOperatorSolver2D(x, y, V, dt=5e-5)
|
|
75
|
+
|
|
76
|
+
X, Y = solver.X, solver.Y
|
|
77
|
+
psi0 = np.exp(-((X - 0.5) ** 2 + (Y - 0.5) ** 2) / (4 * 0.05**2)).astype(complex)
|
|
78
|
+
psi0 /= np.sqrt(solver.norm(psi0))
|
|
79
|
+
|
|
80
|
+
psi = psi0
|
|
81
|
+
for _ in range(2000):
|
|
82
|
+
psi = solver.step(psi)
|
|
83
|
+
|
|
84
|
+
assert abs(solver.norm(psi) - 1.0) < TOL
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Tests for physicskit.quantum.chapters.wave_packets: the parts of
|
|
2
|
+
GaussianDispersion (center, density) and TwinSlit not already exercised
|
|
3
|
+
by test_physics_checks.py/test_animations.py.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from physicskit.quantum._compat import trapz
|
|
12
|
+
from physicskit.quantum.chapters.wave_packets import GaussianDispersion, TwinSlit
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_gaussian_dispersion_center_moves_ballistically():
|
|
16
|
+
gd = GaussianDispersion(x0=1.0, k0=3.0, hbar=1.0, m=2.0)
|
|
17
|
+
t = np.array([0.0, 1.0, 2.5])
|
|
18
|
+
np.testing.assert_allclose(gd.center(t), gd.x0 + (gd.hbar * gd.k0 / gd.m) * t)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_gaussian_dispersion_density_matches_abs_psi_squared():
|
|
22
|
+
gd = GaussianDispersion()
|
|
23
|
+
x = np.linspace(-10, 10, 200)
|
|
24
|
+
np.testing.assert_allclose(gd.density(x, t=0.7), np.abs(gd.psi(x, 0.7)) ** 2)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_gaussian_dispersion_density_stays_normalized_over_time():
|
|
28
|
+
gd = GaussianDispersion(sigma0=1.0, k0=0.0) # k0=0 keeps the packet centered at x0
|
|
29
|
+
x = np.linspace(-40, 40, 4000)
|
|
30
|
+
for t in (0.0, 5.0, 20.0):
|
|
31
|
+
assert trapz(gd.density(x, t), x) == pytest.approx(1.0, abs=1e-3)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_twin_slit_intensity_is_normalized():
|
|
35
|
+
ts = TwinSlit(slit_separation=4.0, slit_width=0.4, k0=10.0)
|
|
36
|
+
x = np.linspace(-20, 20, 4000)
|
|
37
|
+
I = ts.intensity(x, screen_distance=50.0)
|
|
38
|
+
assert trapz(I, x) == pytest.approx(1.0, abs=1e-6)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_twin_slit_intensity_is_symmetric_about_the_axis():
|
|
42
|
+
ts = TwinSlit(slit_separation=4.0, slit_width=0.4, k0=10.0)
|
|
43
|
+
x = np.linspace(-20, 20, 501) # ascending and symmetric, so trapz normalization matches
|
|
44
|
+
I = ts.intensity(x, screen_distance=50.0)
|
|
45
|
+
np.testing.assert_allclose(I, I[::-1], rtol=1e-10)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_twin_slit_amplitude_is_complex_and_finite():
|
|
49
|
+
ts = TwinSlit()
|
|
50
|
+
x = np.linspace(-10, 10, 50)
|
|
51
|
+
amp = ts.amplitude(x, screen_distance=30.0)
|
|
52
|
+
assert np.iscomplexobj(amp)
|
|
53
|
+
assert np.all(np.isfinite(amp))
|
|
File without changes
|