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,527 @@
|
|
|
1
|
+
"""Soliton-bearing nonlinear field equations: KdV, the nonlinear Schrodinger equation, and Sine-Gordon.
|
|
2
|
+
|
|
3
|
+
Each equation is integrated with a scheme suited to its structure:
|
|
4
|
+
|
|
5
|
+
- **Korteweg-de Vries** -- Strang-split pseudo-spectral: the stiff linear
|
|
6
|
+
dispersion :math:`\\partial_x^3` is advanced exactly via the FFT, and the
|
|
7
|
+
non-stiff advection :math:`6u\\partial_x u` via RK4.
|
|
8
|
+
- **Nonlinear Schrodinger** -- split-step Fourier: exact for the linear
|
|
9
|
+
(kinetic) part and exact for the nonlinear (pointwise phase-rotation) part.
|
|
10
|
+
- **Sine-Gordon** -- explicit leapfrog finite differences on the wave equation.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"kdv_soliton",
|
|
19
|
+
"kdv_step",
|
|
20
|
+
"kdv_evolve",
|
|
21
|
+
"kdv_evolve_frames",
|
|
22
|
+
"nls_bright_soliton",
|
|
23
|
+
"nls_dark_soliton",
|
|
24
|
+
"nls_evolve",
|
|
25
|
+
"nls_evolve_frames",
|
|
26
|
+
"sine_gordon_kink",
|
|
27
|
+
"sine_gordon_evolve",
|
|
28
|
+
"sine_gordon_evolve_frames",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# -- Korteweg-de Vries --------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def kdv_soliton(x: np.ndarray, c: float, x0: float = 0.0) -> np.ndarray:
|
|
36
|
+
"""Exact single-soliton solution of :math:`u_t + 6uu_x + u_{xxx} = 0` at :math:`t=0`.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
x : ndarray
|
|
41
|
+
Spatial grid.
|
|
42
|
+
c : float
|
|
43
|
+
Soliton speed (equal to twice its amplitude: amplitude :math:`=c/2`).
|
|
44
|
+
x0 : float, default=0.0
|
|
45
|
+
Initial center position.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
ndarray
|
|
50
|
+
:math:`u(x, 0) = \\tfrac{c}{2}\\,\\mathrm{sech}^2\\!\\big(\\tfrac{\\sqrt{c}}{2}(x-x_0)\\big)`.
|
|
51
|
+
|
|
52
|
+
See Also
|
|
53
|
+
--------
|
|
54
|
+
kdv_evolve : Propagate this (or any) initial condition forward in time.
|
|
55
|
+
|
|
56
|
+
Examples
|
|
57
|
+
--------
|
|
58
|
+
>>> import numpy as np
|
|
59
|
+
>>> round(float(kdv_soliton(0.0, c=4.0)), 6)
|
|
60
|
+
2.0
|
|
61
|
+
"""
|
|
62
|
+
return (c / 2.0) * (1.0 / np.cosh(np.sqrt(c) / 2.0 * (x - x0))) ** 2
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def kdv_step(u_hat: np.ndarray, k: np.ndarray, dt: float) -> np.ndarray:
|
|
66
|
+
"""Advance the KdV equation in Fourier space by one Strang-split step.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
u_hat : ndarray
|
|
71
|
+
Fourier coefficients of :math:`u` (as from ``numpy.fft.fft``).
|
|
72
|
+
k : ndarray
|
|
73
|
+
Angular wavenumbers matching ``u_hat``.
|
|
74
|
+
dt : float
|
|
75
|
+
Time step.
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
ndarray
|
|
80
|
+
Fourier coefficients after one step of size ``dt``.
|
|
81
|
+
"""
|
|
82
|
+
ik3 = 1j * k**3
|
|
83
|
+
|
|
84
|
+
def nonlinear_rhs(uh):
|
|
85
|
+
u = np.real(np.fft.ifft(uh))
|
|
86
|
+
ux = np.real(np.fft.ifft(1j * k * uh))
|
|
87
|
+
return np.fft.fft(-6 * u * ux)
|
|
88
|
+
|
|
89
|
+
u_hat = u_hat * np.exp(ik3 * dt / 2)
|
|
90
|
+
k1 = nonlinear_rhs(u_hat)
|
|
91
|
+
k2 = nonlinear_rhs(u_hat + dt / 2 * k1)
|
|
92
|
+
k3 = nonlinear_rhs(u_hat + dt / 2 * k2)
|
|
93
|
+
k4 = nonlinear_rhs(u_hat + dt * k3)
|
|
94
|
+
u_hat = u_hat + dt / 6 * (k1 + 2 * k2 + 2 * k3 + k4)
|
|
95
|
+
return u_hat * np.exp(ik3 * dt / 2)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def kdv_evolve(u0: np.ndarray, x: np.ndarray, dt: float, steps: int) -> np.ndarray:
|
|
99
|
+
"""Evolve a KdV initial condition forward in time on a periodic domain.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
u0 : ndarray
|
|
104
|
+
Initial field, sampled on the periodic grid ``x``.
|
|
105
|
+
x : ndarray
|
|
106
|
+
Uniformly spaced periodic spatial grid.
|
|
107
|
+
dt : float
|
|
108
|
+
Time step.
|
|
109
|
+
steps : int
|
|
110
|
+
Number of steps to advance.
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
ndarray
|
|
115
|
+
Field after ``steps * dt`` time units.
|
|
116
|
+
|
|
117
|
+
Notes
|
|
118
|
+
-----
|
|
119
|
+
Because KdV solitons are true solitons, two colliding solitons of
|
|
120
|
+
different speed pass through each other **elastically**: each emerges
|
|
121
|
+
from the collision with its original amplitude and speed, shifted only
|
|
122
|
+
in phase -- unlike generic nonlinear waves, which would break up or
|
|
123
|
+
change shape on collision.
|
|
124
|
+
|
|
125
|
+
Examples
|
|
126
|
+
--------
|
|
127
|
+
A fast, tall soliton launched behind a slower, shorter one overtakes it;
|
|
128
|
+
both retain their original amplitudes after the collision:
|
|
129
|
+
|
|
130
|
+
>>> import numpy as np
|
|
131
|
+
>>> from scipy.signal import find_peaks
|
|
132
|
+
>>> N, L = 512, 60.0
|
|
133
|
+
>>> x = np.linspace(-L / 2, L / 2, N, endpoint=False)
|
|
134
|
+
>>> u0 = kdv_soliton(x, c=9.0, x0=-20) + kdv_soliton(x, c=4.0, x0=-8)
|
|
135
|
+
>>> u = kdv_evolve(u0, x, dt=0.0005, steps=6000)
|
|
136
|
+
>>> peaks, _ = find_peaks(u, height=1.0)
|
|
137
|
+
>>> heights = sorted(u[peaks])
|
|
138
|
+
>>> [round(float(h), 1) for h in heights]
|
|
139
|
+
[2.0, 4.5]
|
|
140
|
+
"""
|
|
141
|
+
k = 2 * np.pi * np.fft.fftfreq(len(x), d=x[1] - x[0])
|
|
142
|
+
u_hat = np.fft.fft(u0)
|
|
143
|
+
for _ in range(steps):
|
|
144
|
+
u_hat = kdv_step(u_hat, k, dt)
|
|
145
|
+
return np.real(np.fft.ifft(u_hat))
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def kdv_evolve_frames(u0: np.ndarray, x: np.ndarray, dt: float, steps_per_frame: int, n_frames: int) -> tuple:
|
|
149
|
+
"""Evolve a KdV field and record a snapshot every ``steps_per_frame`` steps, for animation.
|
|
150
|
+
|
|
151
|
+
A thin looping wrapper around :func:`kdv_evolve` -- no new physics, just
|
|
152
|
+
repeated short calls with each chunk's output fed back in as the next
|
|
153
|
+
chunk's initial condition (valid since :func:`kdv_evolve` is a
|
|
154
|
+
deterministic one-step-at-a-time integrator), so the trajectory can be
|
|
155
|
+
animated frame by frame.
|
|
156
|
+
|
|
157
|
+
Parameters
|
|
158
|
+
----------
|
|
159
|
+
u0 : ndarray
|
|
160
|
+
Initial field.
|
|
161
|
+
x : ndarray
|
|
162
|
+
Uniformly spaced periodic spatial grid.
|
|
163
|
+
dt : float
|
|
164
|
+
Time step.
|
|
165
|
+
steps_per_frame : int
|
|
166
|
+
Number of integration steps between recorded frames.
|
|
167
|
+
n_frames : int
|
|
168
|
+
Number of frames to record after the initial condition.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
frames : ndarray, shape (n_frames + 1, len(x))
|
|
173
|
+
Field at ``t=0`` and after each recorded chunk.
|
|
174
|
+
times : ndarray, shape (n_frames + 1,)
|
|
175
|
+
|
|
176
|
+
See Also
|
|
177
|
+
--------
|
|
178
|
+
physicskit.fields.visualizers.animate_field_1d : Render these frames as a line-plot animation.
|
|
179
|
+
|
|
180
|
+
Examples
|
|
181
|
+
--------
|
|
182
|
+
>>> import numpy as np
|
|
183
|
+
>>> x = np.linspace(-30, 30, 256, endpoint=False)
|
|
184
|
+
>>> u0 = kdv_soliton(x, c=4.0, x0=-15)
|
|
185
|
+
>>> frames, times = kdv_evolve_frames(u0, x, dt=0.001, steps_per_frame=200, n_frames=5)
|
|
186
|
+
>>> frames.shape
|
|
187
|
+
(6, 256)
|
|
188
|
+
"""
|
|
189
|
+
u = np.array(u0, dtype=float, copy=True)
|
|
190
|
+
frames = [u.copy()]
|
|
191
|
+
times = [0.0]
|
|
192
|
+
for i in range(n_frames):
|
|
193
|
+
u = kdv_evolve(u, x, dt, steps_per_frame)
|
|
194
|
+
frames.append(u.copy())
|
|
195
|
+
times.append((i + 1) * steps_per_frame * dt)
|
|
196
|
+
return np.array(frames), np.array(times)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# -- Nonlinear Schrodinger equation -----------------------------------------
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def nls_bright_soliton(x: np.ndarray, t: float, A: float = 1.0, v: float = 0.0, x0: float = 0.0) -> np.ndarray:
|
|
203
|
+
"""Exact bright-soliton solution of the focusing NLS equation.
|
|
204
|
+
|
|
205
|
+
Solves :math:`i\\psi_t + \\tfrac{1}{2}\\psi_{xx} + |\\psi|^2\\psi = 0`.
|
|
206
|
+
|
|
207
|
+
Parameters
|
|
208
|
+
----------
|
|
209
|
+
x : ndarray
|
|
210
|
+
Spatial grid.
|
|
211
|
+
t : float
|
|
212
|
+
Time.
|
|
213
|
+
A : float, default=1.0
|
|
214
|
+
Soliton amplitude.
|
|
215
|
+
v : float, default=0.0
|
|
216
|
+
Soliton velocity.
|
|
217
|
+
x0 : float, default=0.0
|
|
218
|
+
Initial center position.
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
ndarray of complex
|
|
223
|
+
:math:`\\psi(x,t) = A\\,\\mathrm{sech}(A(x-x_0-vt))\\, e^{i[v(x-x_0) + (A^2-v^2)t/2]}`.
|
|
224
|
+
|
|
225
|
+
See Also
|
|
226
|
+
--------
|
|
227
|
+
nls_dark_soliton : The defocusing-equation counterpart.
|
|
228
|
+
nls_evolve : Propagate this (or any) initial condition numerically.
|
|
229
|
+
|
|
230
|
+
Examples
|
|
231
|
+
--------
|
|
232
|
+
>>> import numpy as np
|
|
233
|
+
>>> x = np.array([0.0])
|
|
234
|
+
>>> abs(nls_bright_soliton(x, t=0.0, A=1.0))
|
|
235
|
+
array([1.])
|
|
236
|
+
"""
|
|
237
|
+
envelope = A / np.cosh(A * (x - x0 - v * t))
|
|
238
|
+
phase = v * (x - x0) + (A**2 - v**2) / 2 * t
|
|
239
|
+
return envelope * np.exp(1j * phase)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def nls_dark_soliton(x: np.ndarray, t: float, rho0: float = 1.0, x0: float = 0.0) -> np.ndarray:
|
|
243
|
+
"""Exact stationary dark (black) soliton solution of the defocusing NLS equation.
|
|
244
|
+
|
|
245
|
+
Solves :math:`i\\psi_t + \\tfrac{1}{2}\\psi_{xx} - |\\psi|^2\\psi = 0`: a
|
|
246
|
+
density notch that vanishes at its center, sitting on a uniform
|
|
247
|
+
background of density ``rho0``.
|
|
248
|
+
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
x : ndarray
|
|
252
|
+
Spatial grid.
|
|
253
|
+
t : float
|
|
254
|
+
Time.
|
|
255
|
+
rho0 : float, default=1.0
|
|
256
|
+
Background density far from the soliton.
|
|
257
|
+
x0 : float, default=0.0
|
|
258
|
+
Center position.
|
|
259
|
+
|
|
260
|
+
Returns
|
|
261
|
+
-------
|
|
262
|
+
ndarray of complex
|
|
263
|
+
:math:`\\psi(x,t) = \\sqrt{\\rho_0}\\,\\tanh\\!\\big(\\sqrt{\\rho_0/2}\\,(x-x_0)\\big)\\, e^{-i\\rho_0 t}`,
|
|
264
|
+
with healing length :math:`\\xi = 1/\\sqrt{\\rho_0}`.
|
|
265
|
+
|
|
266
|
+
See Also
|
|
267
|
+
--------
|
|
268
|
+
nls_bright_soliton : The focusing-equation counterpart.
|
|
269
|
+
|
|
270
|
+
Examples
|
|
271
|
+
--------
|
|
272
|
+
>>> import numpy as np
|
|
273
|
+
>>> x = np.array([0.0])
|
|
274
|
+
>>> abs(nls_dark_soliton(x, t=0.0, rho0=1.0))
|
|
275
|
+
array([0.])
|
|
276
|
+
"""
|
|
277
|
+
envelope = np.sqrt(rho0) * np.tanh(np.sqrt(rho0 / 2) * (x - x0))
|
|
278
|
+
return envelope * np.exp(-1j * rho0 * t)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def nls_evolve(psi0: np.ndarray, x: np.ndarray, dt: float, steps: int, g: float = 1.0) -> np.ndarray:
|
|
282
|
+
"""Evolve a nonlinear Schrodinger initial condition via split-step Fourier.
|
|
283
|
+
|
|
284
|
+
Solves :math:`i\\psi_t + \\tfrac{1}{2}\\psi_{xx} + g|\\psi|^2\\psi = 0`
|
|
285
|
+
on a periodic domain: ``g > 0`` is focusing (bright solitons),
|
|
286
|
+
``g < 0`` is defocusing (dark solitons).
|
|
287
|
+
|
|
288
|
+
Parameters
|
|
289
|
+
----------
|
|
290
|
+
psi0 : ndarray of complex
|
|
291
|
+
Initial wavefunction, sampled on the periodic grid ``x``.
|
|
292
|
+
x : ndarray
|
|
293
|
+
Uniformly spaced periodic spatial grid.
|
|
294
|
+
dt : float
|
|
295
|
+
Time step.
|
|
296
|
+
steps : int
|
|
297
|
+
Number of steps to advance.
|
|
298
|
+
g : float, default=1.0
|
|
299
|
+
Nonlinearity strength and sign.
|
|
300
|
+
|
|
301
|
+
Returns
|
|
302
|
+
-------
|
|
303
|
+
ndarray of complex
|
|
304
|
+
Field after ``steps * dt`` time units.
|
|
305
|
+
|
|
306
|
+
Examples
|
|
307
|
+
--------
|
|
308
|
+
A bright soliton propagates without dispersing -- its envelope
|
|
309
|
+
:math:`|\\psi|` is unchanged after 2 time units of evolution:
|
|
310
|
+
|
|
311
|
+
>>> import numpy as np
|
|
312
|
+
>>> N, L = 1024, 80.0
|
|
313
|
+
>>> x = np.linspace(-L / 2, L / 2, N, endpoint=False)
|
|
314
|
+
>>> psi0 = nls_bright_soliton(x, t=0.0, A=1.0)
|
|
315
|
+
>>> psi = nls_evolve(psi0, x, dt=0.001, steps=2000, g=1.0)
|
|
316
|
+
>>> shape_error = np.max(np.abs(np.abs(psi) - np.abs(psi0)))
|
|
317
|
+
>>> bool(shape_error < 1e-3)
|
|
318
|
+
True
|
|
319
|
+
"""
|
|
320
|
+
k = 2 * np.pi * np.fft.fftfreq(len(x), d=x[1] - x[0])
|
|
321
|
+
lin_prop = np.exp(-1j * 0.5 * k**2 * dt)
|
|
322
|
+
psi = np.array(psi0, dtype=complex, copy=True)
|
|
323
|
+
for _ in range(steps):
|
|
324
|
+
psi_hat = np.fft.fft(psi)
|
|
325
|
+
psi_hat *= lin_prop
|
|
326
|
+
psi = np.fft.ifft(psi_hat)
|
|
327
|
+
psi *= np.exp(1j * g * np.abs(psi) ** 2 * dt)
|
|
328
|
+
return psi
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def nls_evolve_frames(psi0: np.ndarray, x: np.ndarray, dt: float, steps_per_frame: int, n_frames: int, g: float = 1.0) -> tuple:
|
|
332
|
+
"""Evolve an NLS field and record a snapshot every ``steps_per_frame`` steps, for animation.
|
|
333
|
+
|
|
334
|
+
A thin looping wrapper around :func:`nls_evolve`, analogous to
|
|
335
|
+
:func:`kdv_evolve_frames`: no new physics, just repeated chunked calls
|
|
336
|
+
with the state carried forward, to produce an animatable sequence of frames.
|
|
337
|
+
|
|
338
|
+
Parameters
|
|
339
|
+
----------
|
|
340
|
+
psi0 : ndarray of complex
|
|
341
|
+
Initial wavefunction.
|
|
342
|
+
x : ndarray
|
|
343
|
+
Uniformly spaced periodic spatial grid.
|
|
344
|
+
dt : float
|
|
345
|
+
Time step.
|
|
346
|
+
steps_per_frame : int
|
|
347
|
+
Number of integration steps between recorded frames.
|
|
348
|
+
n_frames : int
|
|
349
|
+
Number of frames to record after the initial condition.
|
|
350
|
+
g : float, default=1.0
|
|
351
|
+
Nonlinearity strength and sign.
|
|
352
|
+
|
|
353
|
+
Returns
|
|
354
|
+
-------
|
|
355
|
+
frames : ndarray of complex, shape (n_frames + 1, len(x))
|
|
356
|
+
Field at ``t=0`` and after each recorded chunk.
|
|
357
|
+
times : ndarray, shape (n_frames + 1,)
|
|
358
|
+
|
|
359
|
+
See Also
|
|
360
|
+
--------
|
|
361
|
+
physicskit.fields.visualizers.animate_field_1d : Render these frames as a line-plot animation.
|
|
362
|
+
|
|
363
|
+
Examples
|
|
364
|
+
--------
|
|
365
|
+
>>> import numpy as np
|
|
366
|
+
>>> x = np.linspace(-40, 40, 512, endpoint=False)
|
|
367
|
+
>>> psi0 = nls_bright_soliton(x, t=0.0, A=1.0)
|
|
368
|
+
>>> frames, times = nls_evolve_frames(psi0, x, dt=0.001, steps_per_frame=200, n_frames=5, g=1.0)
|
|
369
|
+
>>> frames.shape
|
|
370
|
+
(6, 512)
|
|
371
|
+
"""
|
|
372
|
+
psi = np.array(psi0, dtype=complex, copy=True)
|
|
373
|
+
frames = [psi.copy()]
|
|
374
|
+
times = [0.0]
|
|
375
|
+
for i in range(n_frames):
|
|
376
|
+
psi = nls_evolve(psi, x, dt, steps_per_frame, g)
|
|
377
|
+
frames.append(psi.copy())
|
|
378
|
+
times.append((i + 1) * steps_per_frame * dt)
|
|
379
|
+
return np.array(frames), np.array(times)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
# -- Sine-Gordon --------------------------------------------------------------
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def sine_gordon_kink(x: np.ndarray, t: float, v: float = 0.0, x0: float = 0.0, polarity: int = 1) -> np.ndarray:
|
|
386
|
+
"""Exact kink (or antikink) solution of the Sine-Gordon equation :math:`u_{tt} - u_{xx} + \\sin u = 0`.
|
|
387
|
+
|
|
388
|
+
Parameters
|
|
389
|
+
----------
|
|
390
|
+
x : ndarray
|
|
391
|
+
Spatial grid.
|
|
392
|
+
t : float
|
|
393
|
+
Time.
|
|
394
|
+
v : float, default=0.0
|
|
395
|
+
Kink velocity (:math:`|v| < 1`, the wave speed of the linearized equation).
|
|
396
|
+
x0 : float, default=0.0
|
|
397
|
+
Initial center position.
|
|
398
|
+
polarity : {1, -1}, default=1
|
|
399
|
+
``1`` for a kink (field jumps by :math:`2\\pi`), ``-1`` for an antikink.
|
|
400
|
+
|
|
401
|
+
Returns
|
|
402
|
+
-------
|
|
403
|
+
ndarray
|
|
404
|
+
:math:`u(x,t) = 4\\arctan\\!\\big(\\exp[\\text{polarity}\\cdot\\gamma(x-x_0-vt)]\\big)`,
|
|
405
|
+
with :math:`\\gamma = 1/\\sqrt{1-v^2}`.
|
|
406
|
+
|
|
407
|
+
See Also
|
|
408
|
+
--------
|
|
409
|
+
sine_gordon_evolve : Propagate this (or any) initial condition numerically.
|
|
410
|
+
|
|
411
|
+
Examples
|
|
412
|
+
--------
|
|
413
|
+
>>> import numpy as np
|
|
414
|
+
>>> round(float(sine_gordon_kink(0.0, t=0.0)), 6)
|
|
415
|
+
3.141593
|
|
416
|
+
"""
|
|
417
|
+
gamma = 1.0 / np.sqrt(1 - v**2)
|
|
418
|
+
return 4 * np.arctan(np.exp(polarity * gamma * (x - x0 - v * t)))
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def sine_gordon_evolve(u0: np.ndarray, u0_prev: np.ndarray, x: np.ndarray, dt: float, steps: int) -> tuple:
|
|
422
|
+
"""Evolve the Sine-Gordon equation with explicit leapfrog finite differences.
|
|
423
|
+
|
|
424
|
+
Parameters
|
|
425
|
+
----------
|
|
426
|
+
u0 : ndarray
|
|
427
|
+
Field at the starting time.
|
|
428
|
+
u0_prev : ndarray
|
|
429
|
+
Field one step *before* the starting time (needed to seed the
|
|
430
|
+
two-level leapfrog scheme); for a traveling-wave initial condition,
|
|
431
|
+
use the exact solution evaluated at ``t=-dt``.
|
|
432
|
+
x : ndarray
|
|
433
|
+
Uniformly spaced spatial grid, with fixed (Dirichlet) boundaries.
|
|
434
|
+
dt : float
|
|
435
|
+
Time step; must satisfy the CFL condition ``dt <= dx`` (wave speed 1).
|
|
436
|
+
steps : int
|
|
437
|
+
Number of steps to advance.
|
|
438
|
+
|
|
439
|
+
Returns
|
|
440
|
+
-------
|
|
441
|
+
u, u_prev : ndarray
|
|
442
|
+
The field at the final step and the step before it (the pair
|
|
443
|
+
needed to continue the integration further).
|
|
444
|
+
|
|
445
|
+
Examples
|
|
446
|
+
--------
|
|
447
|
+
A kink launched at speed :math:`v=0.5` arrives at the expected
|
|
448
|
+
Lorentz-contracted position after propagating:
|
|
449
|
+
|
|
450
|
+
>>> import numpy as np
|
|
451
|
+
>>> N, L, v, x0 = 4000, 200.0, 0.5, -50.0
|
|
452
|
+
>>> x = np.linspace(-L / 2, L / 2, N)
|
|
453
|
+
>>> dx = x[1] - x[0]
|
|
454
|
+
>>> dt = 0.4 * dx
|
|
455
|
+
>>> u_prev = sine_gordon_kink(x, -dt, v, x0)
|
|
456
|
+
>>> u0 = sine_gordon_kink(x, 0.0, v, x0)
|
|
457
|
+
>>> steps = 1000
|
|
458
|
+
>>> u, _ = sine_gordon_evolve(u0, u_prev, x, dt, steps)
|
|
459
|
+
>>> expected = sine_gordon_kink(x, steps * dt, v, x0)
|
|
460
|
+
>>> bool(np.max(np.abs(u - expected)) < 0.01)
|
|
461
|
+
True
|
|
462
|
+
"""
|
|
463
|
+
dx = x[1] - x[0]
|
|
464
|
+
u_prev = np.array(u0_prev, dtype=float, copy=True)
|
|
465
|
+
u = np.array(u0, dtype=float, copy=True)
|
|
466
|
+
for _ in range(steps):
|
|
467
|
+
lap = np.zeros_like(u)
|
|
468
|
+
lap[1:-1] = (u[2:] - 2 * u[1:-1] + u[:-2]) / dx**2
|
|
469
|
+
u_next = 2 * u - u_prev + dt**2 * (lap - np.sin(u))
|
|
470
|
+
u_next[0] = u[0]
|
|
471
|
+
u_next[-1] = u[-1]
|
|
472
|
+
u_prev, u = u, u_next
|
|
473
|
+
return u, u_prev
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
def sine_gordon_evolve_frames(u0: np.ndarray, u0_prev: np.ndarray, x: np.ndarray, dt: float, steps_per_frame: int, n_frames: int) -> tuple:
|
|
477
|
+
"""Evolve a Sine-Gordon field and record a snapshot every ``steps_per_frame`` steps, for animation.
|
|
478
|
+
|
|
479
|
+
A thin looping wrapper around :func:`sine_gordon_evolve`, analogous to
|
|
480
|
+
:func:`kdv_evolve_frames`: the ``(u, u_prev)`` leapfrog pair is carried
|
|
481
|
+
forward chunk to chunk, with no change to the underlying physics.
|
|
482
|
+
|
|
483
|
+
Parameters
|
|
484
|
+
----------
|
|
485
|
+
u0 : ndarray
|
|
486
|
+
Field at the starting time.
|
|
487
|
+
u0_prev : ndarray
|
|
488
|
+
Field one step before the starting time (see :func:`sine_gordon_evolve`).
|
|
489
|
+
x : ndarray
|
|
490
|
+
Uniformly spaced spatial grid.
|
|
491
|
+
dt : float
|
|
492
|
+
Time step.
|
|
493
|
+
steps_per_frame : int
|
|
494
|
+
Number of integration steps between recorded frames.
|
|
495
|
+
n_frames : int
|
|
496
|
+
Number of frames to record after the initial condition.
|
|
497
|
+
|
|
498
|
+
Returns
|
|
499
|
+
-------
|
|
500
|
+
frames : ndarray, shape (n_frames + 1, len(x))
|
|
501
|
+
Field at ``t=0`` and after each recorded chunk.
|
|
502
|
+
times : ndarray, shape (n_frames + 1,)
|
|
503
|
+
|
|
504
|
+
See Also
|
|
505
|
+
--------
|
|
506
|
+
physicskit.fields.visualizers.animate_field_1d : Render these frames as a line-plot animation.
|
|
507
|
+
|
|
508
|
+
Examples
|
|
509
|
+
--------
|
|
510
|
+
>>> import numpy as np
|
|
511
|
+
>>> x = np.linspace(-50, 50, 800)
|
|
512
|
+
>>> dt = 0.4 * (x[1] - x[0])
|
|
513
|
+
>>> u_prev = sine_gordon_kink(x, -dt, v=0.5, x0=-20)
|
|
514
|
+
>>> u0 = sine_gordon_kink(x, 0.0, v=0.5, x0=-20)
|
|
515
|
+
>>> frames, times = sine_gordon_evolve_frames(u0, u_prev, x, dt, steps_per_frame=100, n_frames=4)
|
|
516
|
+
>>> frames.shape
|
|
517
|
+
(5, 800)
|
|
518
|
+
"""
|
|
519
|
+
u = np.array(u0, dtype=float, copy=True)
|
|
520
|
+
u_prev = np.array(u0_prev, dtype=float, copy=True)
|
|
521
|
+
frames = [u.copy()]
|
|
522
|
+
times = [0.0]
|
|
523
|
+
for i in range(n_frames):
|
|
524
|
+
u, u_prev = sine_gordon_evolve(u, u_prev, x, dt, steps_per_frame)
|
|
525
|
+
frames.append(u.copy())
|
|
526
|
+
times.append((i + 1) * steps_per_frame * dt)
|
|
527
|
+
return np.array(frames), np.array(times)
|
|
File without changes
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Animation smoke tests for physicskit.fields.visualizers: build each animation and save it
|
|
2
|
+
to a GIF, following the pattern in physicskit/classical/tests/test_visualizers.py."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pytest
|
|
8
|
+
from matplotlib.animation import PillowWriter
|
|
9
|
+
|
|
10
|
+
from physicskit.fields.electrodynamics import (
|
|
11
|
+
courant_limit_2d,
|
|
12
|
+
dielectric_slab,
|
|
13
|
+
fdtd_2d_tmz_evolve,
|
|
14
|
+
oscillating_dipole_source,
|
|
15
|
+
tmz_cavity_mode,
|
|
16
|
+
)
|
|
17
|
+
from physicskit.fields.quantum_fields import gpe_evolve, gpe_imprint_vortex, gpe_relax, harmonic_trap_grid
|
|
18
|
+
from physicskit.fields.solitons import (
|
|
19
|
+
kdv_evolve_frames,
|
|
20
|
+
kdv_soliton,
|
|
21
|
+
nls_bright_soliton,
|
|
22
|
+
nls_evolve_frames,
|
|
23
|
+
sine_gordon_evolve_frames,
|
|
24
|
+
sine_gordon_kink,
|
|
25
|
+
)
|
|
26
|
+
from physicskit.fields.visualizers import (
|
|
27
|
+
animate_casimir_modes,
|
|
28
|
+
animate_density_2d,
|
|
29
|
+
animate_field_1d,
|
|
30
|
+
animate_field_2d,
|
|
31
|
+
animate_flux_tube,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _save(anim, tmp_path, name):
|
|
36
|
+
out = tmp_path / name
|
|
37
|
+
anim.save(out, writer=PillowWriter(fps=10))
|
|
38
|
+
assert out.exists() and out.stat().st_size > 0
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TestSolitonAnimations:
|
|
42
|
+
@pytest.mark.slow
|
|
43
|
+
def test_kdv_animation(self, tmp_path):
|
|
44
|
+
x = np.linspace(-30, 30, 200, endpoint=False)
|
|
45
|
+
u0 = kdv_soliton(x, c=4.0, x0=-15)
|
|
46
|
+
frames, times = kdv_evolve_frames(u0, x, dt=0.001, steps_per_frame=100, n_frames=4)
|
|
47
|
+
anim = animate_field_1d(x, frames, times, ylabel="u(x, t)")
|
|
48
|
+
_save(anim, tmp_path, "kdv.gif")
|
|
49
|
+
|
|
50
|
+
@pytest.mark.slow
|
|
51
|
+
def test_nls_animation(self, tmp_path):
|
|
52
|
+
x = np.linspace(-40, 40, 256, endpoint=False)
|
|
53
|
+
psi0 = nls_bright_soliton(x, t=0.0, A=1.0)
|
|
54
|
+
frames, times = nls_evolve_frames(psi0, x, dt=0.001, steps_per_frame=100, n_frames=4, g=1.0)
|
|
55
|
+
anim = animate_field_1d(x, frames, times, ylabel=r"$|\psi|$")
|
|
56
|
+
_save(anim, tmp_path, "nls.gif")
|
|
57
|
+
|
|
58
|
+
@pytest.mark.slow
|
|
59
|
+
def test_sine_gordon_animation(self, tmp_path):
|
|
60
|
+
x = np.linspace(-50, 50, 400)
|
|
61
|
+
dt = 0.4 * (x[1] - x[0])
|
|
62
|
+
u_prev = sine_gordon_kink(x, -dt, v=0.5, x0=-20)
|
|
63
|
+
u0 = sine_gordon_kink(x, 0.0, v=0.5, x0=-20)
|
|
64
|
+
frames, times = sine_gordon_evolve_frames(u0, u_prev, x, dt, steps_per_frame=50, n_frames=4)
|
|
65
|
+
anim = animate_field_1d(x, frames, times, ylabel="u(x, t)")
|
|
66
|
+
_save(anim, tmp_path, "sine_gordon.gif")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestFDTDAnimations:
|
|
70
|
+
@pytest.mark.slow
|
|
71
|
+
def test_dipole_radiation_animation(self, tmp_path):
|
|
72
|
+
N = 40
|
|
73
|
+
dx = dy = 2e-3
|
|
74
|
+
dt = 0.5 * courant_limit_2d(dx, dy)
|
|
75
|
+
eps_r = mu_r = np.ones((N, N))
|
|
76
|
+
Ez0 = Hx0 = Hy0 = np.zeros((N, N))
|
|
77
|
+
source = oscillating_dipole_source(N // 2, N // 2, amplitude=1.0, freq=3e10)
|
|
78
|
+
frames, times = fdtd_2d_tmz_evolve(Ez0, Hx0, Hy0, eps_r, mu_r, steps=40, dt=dt, dx=dx, dy=dy, source=source, snapshot_stride=5)
|
|
79
|
+
x = np.arange(N) * dx
|
|
80
|
+
y = np.arange(N) * dy
|
|
81
|
+
X, Y = np.meshgrid(x, y, indexing="ij")
|
|
82
|
+
anim = animate_field_2d(X, Y, frames, times)
|
|
83
|
+
_save(anim, tmp_path, "dipole.gif")
|
|
84
|
+
|
|
85
|
+
@pytest.mark.slow
|
|
86
|
+
def test_dielectric_slab_animation(self, tmp_path):
|
|
87
|
+
Nx, Ny = 60, 30
|
|
88
|
+
dx = dy = 1e-3
|
|
89
|
+
dt = 0.5 * courant_limit_2d(dx, dy)
|
|
90
|
+
eps_r = dielectric_slab((Nx, Ny), i_start=35, i_end=50, eps_r_slab=4.0)
|
|
91
|
+
mu_r = np.ones((Nx, Ny))
|
|
92
|
+
xs = np.arange(Nx)
|
|
93
|
+
Ez0 = np.exp(-((xs[:, None] - 15) ** 2) / (2 * 4.0**2)) * np.ones((1, Ny))
|
|
94
|
+
Hx0 = Hy0 = np.zeros((Nx, Ny))
|
|
95
|
+
frames, times = fdtd_2d_tmz_evolve(Ez0, Hx0, Hy0, eps_r, mu_r, steps=40, dt=dt, dx=dx, dy=dy, snapshot_stride=5)
|
|
96
|
+
x = np.arange(Nx) * dx
|
|
97
|
+
y = np.arange(Ny) * dy
|
|
98
|
+
X, Y = np.meshgrid(x, y, indexing="ij")
|
|
99
|
+
anim = animate_field_2d(X, Y, frames, times)
|
|
100
|
+
_save(anim, tmp_path, "slab.gif")
|
|
101
|
+
# the wave should have visibly entered the slab region, not just reflected away
|
|
102
|
+
assert np.max(np.abs(frames[:, 35:50, :])) > 0.0
|
|
103
|
+
|
|
104
|
+
@pytest.mark.slow
|
|
105
|
+
def test_cavity_mode_animation(self, tmp_path):
|
|
106
|
+
N = 25
|
|
107
|
+
dx = dy = 1e-3
|
|
108
|
+
dt = 0.5 * courant_limit_2d(dx, dy)
|
|
109
|
+
Ez0, omega = tmz_cavity_mode((N, N), dx, dy, m=1, n=1)
|
|
110
|
+
Hx0 = Hy0 = np.zeros((N, N))
|
|
111
|
+
eps_r = mu_r = np.ones((N, N))
|
|
112
|
+
frames, times = fdtd_2d_tmz_evolve(Ez0, Hx0, Hy0, eps_r, mu_r, steps=40, dt=dt, dx=dx, dy=dy, snapshot_stride=4)
|
|
113
|
+
x = np.arange(N) * dx
|
|
114
|
+
y = np.arange(N) * dy
|
|
115
|
+
X, Y = np.meshgrid(x, y, indexing="ij")
|
|
116
|
+
anim = animate_field_2d(X, Y, frames, times)
|
|
117
|
+
_save(anim, tmp_path, "cavity.gif")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class TestGPEAnimations:
|
|
121
|
+
@pytest.mark.slow
|
|
122
|
+
def test_vortex_precession_animation(self, tmp_path):
|
|
123
|
+
n, length, g = 40, 12.0, 4.0
|
|
124
|
+
X, Y, _, _, K2 = harmonic_trap_grid(n, length)
|
|
125
|
+
V = 0.5 * (X**2 + Y**2)
|
|
126
|
+
psi_gs = gpe_relax(np.exp(-0.5 * (X**2 + Y**2)).astype(complex), V, g, dtau=5e-4, steps=1500, X=X, Y=Y, K2=K2)
|
|
127
|
+
psi_v = gpe_imprint_vortex(psi_gs, X, Y, [(1.0, 0.03)])
|
|
128
|
+
frames, times = gpe_evolve(psi_v, V, g, dt=2e-3, steps=200, K2=K2, snapshot_stride=25)
|
|
129
|
+
extent = (X.min(), X.max(), Y.min(), Y.max())
|
|
130
|
+
anim = animate_density_2d(frames, extent=extent, times=times)
|
|
131
|
+
_save(anim, tmp_path, "vortex.gif")
|
|
132
|
+
|
|
133
|
+
@pytest.mark.slow
|
|
134
|
+
def test_self_focusing_animation(self, tmp_path):
|
|
135
|
+
n, length = 64, 16.0
|
|
136
|
+
X, Y, _, _, K2 = harmonic_trap_grid(n, length)
|
|
137
|
+
V = np.zeros((n, n))
|
|
138
|
+
psi0 = 3.0 * np.exp(-0.5 * (X**2 + Y**2)).astype(complex)
|
|
139
|
+
frames, times = gpe_evolve(psi0, V, g=-1.0, dt=2e-4, steps=200, K2=K2, snapshot_stride=25)
|
|
140
|
+
extent = (X.min(), X.max(), Y.min(), Y.max())
|
|
141
|
+
anim = animate_density_2d(frames, extent=extent, times=times)
|
|
142
|
+
_save(anim, tmp_path, "collapse.gif")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class TestFluxTubeAndCasimirAnimations:
|
|
146
|
+
@pytest.mark.slow
|
|
147
|
+
def test_flux_tube_animation(self, tmp_path):
|
|
148
|
+
anim = animate_flux_tube((80, 20), dx=0.25, dy=0.25, separations=np.linspace(4.0, 16.0, 5))
|
|
149
|
+
_save(anim, tmp_path, "flux_tube.gif")
|
|
150
|
+
|
|
151
|
+
@pytest.mark.slow
|
|
152
|
+
def test_casimir_animation(self, tmp_path):
|
|
153
|
+
anim = animate_casimir_modes(np.linspace(1.0, 5.0, 5))
|
|
154
|
+
_save(anim, tmp_path, "casimir.gif")
|