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,142 @@
|
|
|
1
|
+
"""Turbulent kinetic energy spectra and the Kolmogorov -5/3 law.
|
|
2
|
+
|
|
3
|
+
A turbulent velocity field is usefully summarized not by its detailed
|
|
4
|
+
pointwise structure but by how its kinetic energy is distributed across
|
|
5
|
+
length scales -- the energy spectrum :math:`E(k)`, defined so that
|
|
6
|
+
:math:`\\int E(k)\\,dk` is the total kinetic energy per unit mass.
|
|
7
|
+
Kolmogorov's 1941 theory predicts a universal power law,
|
|
8
|
+
:math:`E(k)\\propto k^{-5/3}`, in the "inertial range" of scales small
|
|
9
|
+
enough to have forgotten how the turbulence was forced but large enough not
|
|
10
|
+
to feel viscosity yet -- one of the most-tested predictions in all of
|
|
11
|
+
classical physics, and the standard first check that a simulated 2D or 3D
|
|
12
|
+
flow (e.g. the output of
|
|
13
|
+
:class:`physicskit.fluids.systems.navier_stokes.NavierStokes2D`) is
|
|
14
|
+
resolving a genuine turbulent cascade.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
from numpy.typing import NDArray
|
|
21
|
+
|
|
22
|
+
from physicskit.fluids.exceptions import InvalidParameterError
|
|
23
|
+
|
|
24
|
+
__all__ = ["energy_spectrum", "kolmogorov_reference_slope"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def energy_spectrum(u: NDArray[np.float64], v: NDArray[np.float64], length: float) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
|
|
28
|
+
"""Isotropic (azimuthally averaged) kinetic energy spectrum of a 2D velocity field.
|
|
29
|
+
|
|
30
|
+
Computes :math:`\\hat{u}(\\mathbf{k})` and :math:`\\hat{v}(\\mathbf{k})`
|
|
31
|
+
by FFT, forms the kinetic energy density
|
|
32
|
+
:math:`\\tfrac{1}{2}(|\\hat{u}|^2+|\\hat{v}|^2)` at each wavevector, and
|
|
33
|
+
sums it over the discrete annulus of wavevectors with
|
|
34
|
+
:math:`k \\le |\\mathbf{k}| < k+1` (in grid-index units) to give
|
|
35
|
+
:math:`E(k)`, normalized so that :math:`\\sum_k E(k) \\approx` the
|
|
36
|
+
domain-averaged kinetic energy per unit mass (Parseval's theorem).
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
u, v : ndarray of float, shape (n, n)
|
|
41
|
+
Velocity components on a doubly periodic grid, e.g. from
|
|
42
|
+
:meth:`physicskit.fluids.systems.navier_stokes.NavierStokes2D.velocity`.
|
|
43
|
+
length : float
|
|
44
|
+
Physical domain size.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
k : ndarray of float, shape (n // 2,)
|
|
49
|
+
Wavenumber bins (angular, :math:`2\\pi/\\lambda` convention).
|
|
50
|
+
E : ndarray of float, shape (n // 2,)
|
|
51
|
+
Kinetic energy spectral density at each wavenumber bin.
|
|
52
|
+
|
|
53
|
+
Raises
|
|
54
|
+
------
|
|
55
|
+
InvalidParameterError
|
|
56
|
+
If `u` and `v` are not the same shape, or are not square.
|
|
57
|
+
|
|
58
|
+
See Also
|
|
59
|
+
--------
|
|
60
|
+
kolmogorov_reference_slope : The -5/3 reference line to compare `E` against.
|
|
61
|
+
|
|
62
|
+
Examples
|
|
63
|
+
--------
|
|
64
|
+
>>> import numpy as np
|
|
65
|
+
>>> n, length = 64, 2 * np.pi
|
|
66
|
+
>>> x = np.linspace(0, length, n, endpoint=False)
|
|
67
|
+
>>> X, Y = np.meshgrid(x, x, indexing="ij")
|
|
68
|
+
>>> u, v = np.sin(Y), np.sin(X) # a single-mode flow
|
|
69
|
+
>>> k, E = energy_spectrum(u, v, length)
|
|
70
|
+
>>> bool(np.argmax(E) == 1) # all the energy sits at the single k=1 mode
|
|
71
|
+
True
|
|
72
|
+
"""
|
|
73
|
+
if u.shape != v.shape:
|
|
74
|
+
raise InvalidParameterError("u and v must have the same shape")
|
|
75
|
+
if u.shape[0] != u.shape[1]:
|
|
76
|
+
raise InvalidParameterError("u and v must be square (n, n) arrays")
|
|
77
|
+
n = u.shape[0]
|
|
78
|
+
u_hat = np.fft.fft2(u) / n**2
|
|
79
|
+
v_hat = np.fft.fft2(v) / n**2
|
|
80
|
+
energy_density = 0.5 * (np.abs(u_hat) ** 2 + np.abs(v_hat) ** 2) * n**2
|
|
81
|
+
|
|
82
|
+
kfreq = np.fft.fftfreq(n, d=length / n) * 2.0 * np.pi
|
|
83
|
+
KX, KY = np.meshgrid(kfreq, kfreq, indexing="ij")
|
|
84
|
+
kmag_index = np.round(np.sqrt(KX**2 + KY**2) / (2.0 * np.pi / length)).astype(int)
|
|
85
|
+
|
|
86
|
+
n_bins = n // 2
|
|
87
|
+
E = np.zeros(n_bins)
|
|
88
|
+
for shell in range(n_bins):
|
|
89
|
+
mask = kmag_index == shell
|
|
90
|
+
E[shell] = energy_density[mask].sum()
|
|
91
|
+
k = np.arange(n_bins) * (2.0 * np.pi / length)
|
|
92
|
+
return k, E
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def kolmogorov_reference_slope(k: NDArray[np.float64], k0: float, E0: float) -> NDArray[np.float64]:
|
|
96
|
+
"""A Kolmogorov :math:`k^{-5/3}` reference line, anchored at one point.
|
|
97
|
+
|
|
98
|
+
Kolmogorov's K41 theory predicts that, in the inertial range, the
|
|
99
|
+
energy spectrum depends only on the wavenumber `k` and the (scale-independent)
|
|
100
|
+
energy dissipation rate, and dimensional analysis alone then fixes the
|
|
101
|
+
power law:
|
|
102
|
+
|
|
103
|
+
.. math::
|
|
104
|
+
|
|
105
|
+
E(k) = E_0 \\left(\\frac{k}{k_0}\\right)^{-5/3}.
|
|
106
|
+
|
|
107
|
+
Plotting this line through one point ``(k0, E0)`` of a measured
|
|
108
|
+
spectrum (see :func:`energy_spectrum`) on log-log axes is the standard
|
|
109
|
+
visual check for an inertial range: a genuine turbulent cascade runs
|
|
110
|
+
parallel to this line over at least a decade of `k`.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
k : ndarray of float
|
|
115
|
+
Wavenumbers at which to evaluate the reference line.
|
|
116
|
+
k0 : float
|
|
117
|
+
Anchor wavenumber; must be positive.
|
|
118
|
+
E0 : float
|
|
119
|
+
Spectral energy density at `k0`.
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
ndarray of float
|
|
124
|
+
Reference spectral density :math:`E_0(k/k_0)^{-5/3}` at each `k`.
|
|
125
|
+
|
|
126
|
+
Raises
|
|
127
|
+
------
|
|
128
|
+
InvalidParameterError
|
|
129
|
+
If `k0` is not positive.
|
|
130
|
+
|
|
131
|
+
Examples
|
|
132
|
+
--------
|
|
133
|
+
>>> import numpy as np
|
|
134
|
+
>>> k = np.array([1.0, 2.0, 4.0])
|
|
135
|
+
>>> ref = kolmogorov_reference_slope(k, k0=1.0, E0=1.0)
|
|
136
|
+
>>> round(float(ref[1]), 4)
|
|
137
|
+
0.315
|
|
138
|
+
"""
|
|
139
|
+
if k0 <= 0:
|
|
140
|
+
raise InvalidParameterError(f"k0 must be positive, got {k0}")
|
|
141
|
+
k = np.asarray(k, dtype=np.float64)
|
|
142
|
+
return E0 * (k / k0) ** (-5.0 / 3.0)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from physicskit.fluids.visualizers import theme
|
|
2
|
+
from physicskit.fluids.visualizers.compressible import plot_shock_tube_profiles
|
|
3
|
+
from physicskit.fluids.visualizers.flow_fields import plot_streamlines, plot_vorticity_field
|
|
4
|
+
from physicskit.fluids.visualizers.potential_flow import plot_pressure_coefficient
|
|
5
|
+
from physicskit.fluids.visualizers.spectra import plot_energy_spectrum
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"plot_energy_spectrum",
|
|
9
|
+
"plot_pressure_coefficient",
|
|
10
|
+
"plot_shock_tube_profiles",
|
|
11
|
+
"plot_streamlines",
|
|
12
|
+
"plot_vorticity_field",
|
|
13
|
+
"theme",
|
|
14
|
+
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Shock-tube profile plots."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import numpy as np
|
|
7
|
+
from matplotlib.figure import Figure
|
|
8
|
+
from numpy.typing import NDArray
|
|
9
|
+
|
|
10
|
+
from physicskit.fluids.visualizers import theme
|
|
11
|
+
|
|
12
|
+
__all__ = ["plot_shock_tube_profiles"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def plot_shock_tube_profiles(x: NDArray[np.float64], rho: NDArray[np.float64], u: NDArray[np.float64], p: NDArray[np.float64]) -> tuple[Figure, NDArray]:
|
|
16
|
+
"""Plot density, velocity, and pressure profiles from a shock-tube solution.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
x : ndarray of float
|
|
21
|
+
Spatial grid.
|
|
22
|
+
rho, u, p : ndarray of float
|
|
23
|
+
Density, velocity, and pressure profiles, e.g. from
|
|
24
|
+
:func:`physicskit.fluids.systems.compressible_flow.sod_shock_tube`.
|
|
25
|
+
|
|
26
|
+
Returns
|
|
27
|
+
-------
|
|
28
|
+
fig : matplotlib.figure.Figure
|
|
29
|
+
axes : ndarray of matplotlib.axes.Axes, shape (3,)
|
|
30
|
+
"""
|
|
31
|
+
fig, axes = plt.subplots(3, 1, figsize=(7, 8), sharex=True)
|
|
32
|
+
for ax, field, label in zip(axes, (rho, u, p), (r"$\rho$", "u", "p")):
|
|
33
|
+
ax.plot(x, field, color=theme.PRIMARY, lw=1.2)
|
|
34
|
+
ax.set_ylabel(label)
|
|
35
|
+
ax.grid(alpha=0.3)
|
|
36
|
+
axes[-1].set_xlabel("x")
|
|
37
|
+
fig.suptitle("Sod shock tube")
|
|
38
|
+
fig.tight_layout()
|
|
39
|
+
return fig, axes
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Streamline and vorticity-field plots, the workhorse visualizations of this package."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, cast
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
import numpy as np
|
|
9
|
+
from matplotlib.animation import FuncAnimation
|
|
10
|
+
from matplotlib.axes import Axes
|
|
11
|
+
from matplotlib.figure import Figure
|
|
12
|
+
from numpy.typing import NDArray
|
|
13
|
+
|
|
14
|
+
from physicskit.fluids.systems.instabilities import simulate_kelvin_helmholtz, simulate_rayleigh_taylor
|
|
15
|
+
from physicskit.fluids.visualizers import theme
|
|
16
|
+
|
|
17
|
+
__all__ = ["plot_streamlines", "plot_vorticity_field", "animate_kelvin_helmholtz", "animate_rayleigh_taylor"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def plot_streamlines(
|
|
21
|
+
X: NDArray[np.float64], Y: NDArray[np.float64], u: NDArray[np.float64], v: NDArray[np.float64], ax: Axes | None = None, **streamplot_kwargs: Any
|
|
22
|
+
) -> tuple[Figure, Axes]:
|
|
23
|
+
"""Plot velocity-field streamlines.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
X, Y : ndarray of float, shape (n, n)
|
|
28
|
+
Real-space coordinate grids.
|
|
29
|
+
u, v : ndarray of float, shape (n, n)
|
|
30
|
+
Velocity components.
|
|
31
|
+
ax : matplotlib.axes.Axes, optional
|
|
32
|
+
Axes to draw into; a new figure is created if omitted.
|
|
33
|
+
**streamplot_kwargs
|
|
34
|
+
Additional keyword arguments forwarded to ``ax.streamplot``.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
fig : matplotlib.figure.Figure
|
|
39
|
+
ax : matplotlib.axes.Axes
|
|
40
|
+
"""
|
|
41
|
+
if ax is None:
|
|
42
|
+
fig, ax = plt.subplots(figsize=(6, 6))
|
|
43
|
+
else:
|
|
44
|
+
fig = cast(Figure, ax.figure)
|
|
45
|
+
kwargs: dict[str, Any] = {"color": theme.STRUCTURE, "linewidth": 0.8, "density": 1.2}
|
|
46
|
+
kwargs.update(streamplot_kwargs)
|
|
47
|
+
ax.streamplot(X.T, Y.T, u.T, v.T, **kwargs)
|
|
48
|
+
ax.set_xlabel("x")
|
|
49
|
+
ax.set_ylabel("y")
|
|
50
|
+
ax.set_aspect("equal")
|
|
51
|
+
return fig, ax
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def plot_vorticity_field(
|
|
55
|
+
X: NDArray[np.float64],
|
|
56
|
+
Y: NDArray[np.float64],
|
|
57
|
+
omega: NDArray[np.float64],
|
|
58
|
+
u: NDArray[np.float64] | None = None,
|
|
59
|
+
v: NDArray[np.float64] | None = None,
|
|
60
|
+
ax: Axes | None = None,
|
|
61
|
+
**pcolormesh_kwargs: Any,
|
|
62
|
+
) -> tuple[Figure, Axes]:
|
|
63
|
+
"""Plot a vorticity field as a heatmap, optionally overlaid with velocity streamlines.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
X, Y : ndarray of float, shape (n, n)
|
|
68
|
+
Real-space coordinate grids.
|
|
69
|
+
omega : ndarray of float, shape (n, n)
|
|
70
|
+
Vorticity field.
|
|
71
|
+
u, v : ndarray of float, shape (n, n), optional
|
|
72
|
+
Velocity components; if given, streamlines are overlaid on the heatmap.
|
|
73
|
+
ax : matplotlib.axes.Axes, optional
|
|
74
|
+
Axes to draw into; a new figure is created if omitted.
|
|
75
|
+
**pcolormesh_kwargs
|
|
76
|
+
Additional keyword arguments forwarded to ``ax.pcolormesh``.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
fig : matplotlib.figure.Figure
|
|
81
|
+
ax : matplotlib.axes.Axes
|
|
82
|
+
"""
|
|
83
|
+
if ax is None:
|
|
84
|
+
fig, ax = plt.subplots(figsize=(6, 6))
|
|
85
|
+
else:
|
|
86
|
+
fig = cast(Figure, ax.figure)
|
|
87
|
+
vmax = np.max(np.abs(omega)) or 1.0
|
|
88
|
+
kwargs: dict[str, Any] = {"cmap": theme.VORTICITY_CMAP, "shading": "auto", "vmin": -vmax, "vmax": vmax}
|
|
89
|
+
kwargs.update(pcolormesh_kwargs)
|
|
90
|
+
im = ax.pcolormesh(X, Y, omega, **kwargs)
|
|
91
|
+
fig.colorbar(im, ax=ax, label="vorticity")
|
|
92
|
+
if u is not None and v is not None:
|
|
93
|
+
ax.streamplot(X.T, Y.T, u.T, v.T, color=theme.STRUCTURE, linewidth=0.6, density=1.0)
|
|
94
|
+
ax.set_xlabel("x")
|
|
95
|
+
ax.set_ylabel("y")
|
|
96
|
+
ax.set_aspect("equal")
|
|
97
|
+
return fig, ax
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _animate_vorticity_snapshots(
|
|
101
|
+
X: NDArray[np.float64], Y: NDArray[np.float64], snapshots: list[NDArray[np.float64]], title: str, interval: int, label: str = "vorticity"
|
|
102
|
+
) -> FuncAnimation:
|
|
103
|
+
"""Shared heatmap animator: redraws a vorticity-like (signed, diverging) field over a sequence of snapshots."""
|
|
104
|
+
fig, ax = plt.subplots(figsize=(6, 6))
|
|
105
|
+
vmax = max(float(np.max(np.abs(s))) for s in snapshots) or 1.0
|
|
106
|
+
im = ax.pcolormesh(X, Y, snapshots[0], cmap=theme.VORTICITY_CMAP, shading="auto", vmin=-vmax, vmax=vmax)
|
|
107
|
+
fig.colorbar(im, ax=ax, label=label)
|
|
108
|
+
ax.set_xlabel("x")
|
|
109
|
+
ax.set_ylabel("y")
|
|
110
|
+
ax.set_aspect("equal")
|
|
111
|
+
ax.set_title(title)
|
|
112
|
+
|
|
113
|
+
def update(frame):
|
|
114
|
+
im.set_array(snapshots[frame].ravel())
|
|
115
|
+
return (im,)
|
|
116
|
+
|
|
117
|
+
return FuncAnimation(fig, update, frames=len(snapshots), interval=interval, blit=True)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def animate_kelvin_helmholtz(
|
|
121
|
+
omega0: NDArray[np.float64], nu: float, dt: float, steps_per_frame: int, n_frames: int, length: float, interval: int = 60
|
|
122
|
+
) -> FuncAnimation:
|
|
123
|
+
"""Animate a Kelvin-Helmholtz shear layer rolling up into its characteristic vortex row.
|
|
124
|
+
|
|
125
|
+
Repeatedly calls
|
|
126
|
+
:func:`physicskit.fluids.systems.instabilities.simulate_kelvin_helmholtz`
|
|
127
|
+
for ``steps_per_frame`` RK4 steps at a time, using each call's final
|
|
128
|
+
vorticity as the next call's initial condition, and animates the
|
|
129
|
+
resulting vorticity-field snapshots.
|
|
130
|
+
|
|
131
|
+
Parameters
|
|
132
|
+
----------
|
|
133
|
+
omega0 : ndarray of float, shape (n, n)
|
|
134
|
+
Initial vorticity field, e.g. from
|
|
135
|
+
:func:`physicskit.fluids.systems.instabilities.kelvin_helmholtz_ic`.
|
|
136
|
+
nu : float
|
|
137
|
+
Kinematic viscosity; must be positive.
|
|
138
|
+
dt : float
|
|
139
|
+
Time step per sub-step.
|
|
140
|
+
steps_per_frame : int
|
|
141
|
+
Number of RK4 steps advanced between animation frames.
|
|
142
|
+
n_frames : int
|
|
143
|
+
Number of animation frames.
|
|
144
|
+
length : float
|
|
145
|
+
Physical domain size.
|
|
146
|
+
interval : int, default=60
|
|
147
|
+
Delay between frames in milliseconds.
|
|
148
|
+
|
|
149
|
+
Returns
|
|
150
|
+
-------
|
|
151
|
+
matplotlib.animation.FuncAnimation
|
|
152
|
+
|
|
153
|
+
See Also
|
|
154
|
+
--------
|
|
155
|
+
physicskit.fluids.systems.instabilities.simulate_kelvin_helmholtz : Supplies the vorticity snapshots animated here.
|
|
156
|
+
animate_rayleigh_taylor : The companion buoyancy-driven instability animator.
|
|
157
|
+
|
|
158
|
+
Examples
|
|
159
|
+
--------
|
|
160
|
+
>>> import numpy as np
|
|
161
|
+
>>> from physicskit.fluids.systems.instabilities import kelvin_helmholtz_ic
|
|
162
|
+
>>> n, length = 64, 2 * np.pi
|
|
163
|
+
>>> omega0 = kelvin_helmholtz_ic(n, length, shear_width=0.1, perturbation_amplitude=0.05)
|
|
164
|
+
>>> anim = animate_kelvin_helmholtz(omega0, nu=0.001, dt=0.0025, steps_per_frame=10, n_frames=4, length=length)
|
|
165
|
+
>>> len(list(anim.new_frame_seq()))
|
|
166
|
+
4
|
|
167
|
+
"""
|
|
168
|
+
n = omega0.shape[0]
|
|
169
|
+
x = np.linspace(0, length, n, endpoint=False)
|
|
170
|
+
X, Y = np.meshgrid(x, x, indexing="ij")
|
|
171
|
+
omega = np.asarray(omega0, dtype=float)
|
|
172
|
+
snapshots = [omega.copy()]
|
|
173
|
+
for _ in range(n_frames - 1):
|
|
174
|
+
result = simulate_kelvin_helmholtz(omega, nu, dt, steps_per_frame, length)
|
|
175
|
+
omega = result["omega"]
|
|
176
|
+
snapshots.append(omega.copy())
|
|
177
|
+
return _animate_vorticity_snapshots(X, Y, snapshots, title="Kelvin-Helmholtz instability", interval=interval)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def animate_rayleigh_taylor(
|
|
181
|
+
omega0: NDArray[np.float64],
|
|
182
|
+
buoyancy0: NDArray[np.float64],
|
|
183
|
+
nu: float,
|
|
184
|
+
kappa: float,
|
|
185
|
+
g: float,
|
|
186
|
+
dt: float,
|
|
187
|
+
steps_per_frame: int,
|
|
188
|
+
n_frames: int,
|
|
189
|
+
length: float,
|
|
190
|
+
interval: int = 60,
|
|
191
|
+
) -> FuncAnimation:
|
|
192
|
+
"""Animate the Rayleigh-Taylor instability's mushroom plumes growing from a rippled density interface.
|
|
193
|
+
|
|
194
|
+
Repeatedly calls
|
|
195
|
+
:func:`physicskit.fluids.systems.instabilities.simulate_rayleigh_taylor`
|
|
196
|
+
for ``steps_per_frame`` RK4 steps at a time, using each call's final
|
|
197
|
+
state as the next call's initial condition, and animates the resulting
|
|
198
|
+
buoyancy-field snapshots (the field in which the rising light plumes
|
|
199
|
+
and falling heavy fingers are most visually distinct).
|
|
200
|
+
|
|
201
|
+
Parameters
|
|
202
|
+
----------
|
|
203
|
+
omega0, buoyancy0 : ndarray of float, shape (n, n)
|
|
204
|
+
Initial vorticity and buoyancy fields, e.g. from
|
|
205
|
+
:func:`physicskit.fluids.systems.instabilities.rayleigh_taylor_ic`.
|
|
206
|
+
nu : float
|
|
207
|
+
Kinematic viscosity; must be positive.
|
|
208
|
+
kappa : float
|
|
209
|
+
Buoyancy diffusivity; must be positive.
|
|
210
|
+
g : float
|
|
211
|
+
Gravitational acceleration; must be positive.
|
|
212
|
+
dt : float
|
|
213
|
+
Time step per sub-step.
|
|
214
|
+
steps_per_frame : int
|
|
215
|
+
Number of RK4 steps advanced between animation frames.
|
|
216
|
+
n_frames : int
|
|
217
|
+
Number of animation frames.
|
|
218
|
+
length : float
|
|
219
|
+
Physical domain size.
|
|
220
|
+
interval : int, default=60
|
|
221
|
+
Delay between frames in milliseconds.
|
|
222
|
+
|
|
223
|
+
Returns
|
|
224
|
+
-------
|
|
225
|
+
matplotlib.animation.FuncAnimation
|
|
226
|
+
|
|
227
|
+
See Also
|
|
228
|
+
--------
|
|
229
|
+
physicskit.fluids.systems.instabilities.simulate_rayleigh_taylor : Supplies the buoyancy snapshots animated here.
|
|
230
|
+
animate_kelvin_helmholtz : The companion shear-driven instability animator.
|
|
231
|
+
|
|
232
|
+
Examples
|
|
233
|
+
--------
|
|
234
|
+
>>> import numpy as np
|
|
235
|
+
>>> from physicskit.fluids.systems.instabilities import rayleigh_taylor_ic
|
|
236
|
+
>>> n, length = 64, 2 * np.pi
|
|
237
|
+
>>> omega0, buoyancy0 = rayleigh_taylor_ic(n, length, atwood_number=0.3, perturbation_amplitude=0.01)
|
|
238
|
+
>>> anim = animate_rayleigh_taylor(omega0, buoyancy0, nu=0.002, kappa=0.002, g=1.0, dt=0.01, steps_per_frame=10, n_frames=4, length=length)
|
|
239
|
+
>>> len(list(anim.new_frame_seq()))
|
|
240
|
+
4
|
|
241
|
+
"""
|
|
242
|
+
n = omega0.shape[0]
|
|
243
|
+
x = np.linspace(0, length, n, endpoint=False)
|
|
244
|
+
X, Y = np.meshgrid(x, x, indexing="ij")
|
|
245
|
+
omega = np.asarray(omega0, dtype=float)
|
|
246
|
+
buoyancy = np.asarray(buoyancy0, dtype=float)
|
|
247
|
+
snapshots = [buoyancy.copy()]
|
|
248
|
+
for _ in range(n_frames - 1):
|
|
249
|
+
result = simulate_rayleigh_taylor(omega, buoyancy, nu, kappa, g, dt, steps_per_frame, length)
|
|
250
|
+
omega, buoyancy = result["omega"], result["buoyancy"]
|
|
251
|
+
snapshots.append(buoyancy.copy())
|
|
252
|
+
return _animate_vorticity_snapshots(X, Y, snapshots, title="Rayleigh-Taylor instability (buoyancy)", interval=interval, label="buoyancy")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Pressure-coefficient plots for potential flow."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, cast
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
import numpy as np
|
|
9
|
+
from matplotlib.axes import Axes
|
|
10
|
+
from matplotlib.figure import Figure
|
|
11
|
+
from numpy.typing import NDArray
|
|
12
|
+
|
|
13
|
+
from physicskit.fluids.visualizers import theme
|
|
14
|
+
|
|
15
|
+
__all__ = ["plot_pressure_coefficient"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def plot_pressure_coefficient(theta: NDArray[np.float64], Cp: NDArray[np.float64], ax: Axes | None = None, **plot_kwargs: Any) -> tuple[Figure, Axes]:
|
|
19
|
+
"""Plot the surface pressure coefficient :math:`C_p(\\theta)` around a body.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
theta : ndarray of float
|
|
24
|
+
Angular position around the body (radians), typically ``[0, 2*pi]``.
|
|
25
|
+
Cp : ndarray of float
|
|
26
|
+
Pressure coefficient at each `theta`, e.g. from
|
|
27
|
+
:func:`physicskit.fluids.systems.potential_flow.pressure_coefficient`
|
|
28
|
+
evaluated on a circle.
|
|
29
|
+
ax : matplotlib.axes.Axes, optional
|
|
30
|
+
Axes to draw into; a new figure is created if omitted.
|
|
31
|
+
**plot_kwargs
|
|
32
|
+
Additional keyword arguments forwarded to ``ax.plot``.
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
fig : matplotlib.figure.Figure
|
|
37
|
+
ax : matplotlib.axes.Axes
|
|
38
|
+
"""
|
|
39
|
+
if ax is None:
|
|
40
|
+
fig, ax = plt.subplots(figsize=(6, 4))
|
|
41
|
+
else:
|
|
42
|
+
fig = cast(Figure, ax.figure)
|
|
43
|
+
kwargs: dict[str, Any] = {"color": theme.PRIMARY}
|
|
44
|
+
kwargs.update(plot_kwargs)
|
|
45
|
+
ax.plot(np.degrees(theta), Cp, **kwargs)
|
|
46
|
+
ax.axhline(0.0, color=theme.MUTED, lw=0.8, ls="--")
|
|
47
|
+
ax.invert_yaxis()
|
|
48
|
+
ax.set_xlabel(r"$\theta$ (degrees)")
|
|
49
|
+
ax.set_ylabel(r"$C_p$")
|
|
50
|
+
ax.set_title("Surface pressure coefficient")
|
|
51
|
+
return fig, ax
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Turbulent energy-spectrum plots."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, cast
|
|
6
|
+
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
import numpy as np
|
|
9
|
+
from matplotlib.axes import Axes
|
|
10
|
+
from matplotlib.figure import Figure
|
|
11
|
+
from numpy.typing import NDArray
|
|
12
|
+
|
|
13
|
+
from physicskit.fluids.utils.spectral_analysis import kolmogorov_reference_slope
|
|
14
|
+
from physicskit.fluids.visualizers import theme
|
|
15
|
+
|
|
16
|
+
__all__ = ["plot_energy_spectrum"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def plot_energy_spectrum(
|
|
20
|
+
k: NDArray[np.float64], E: NDArray[np.float64], ax: Axes | None = None, show_kolmogorov: bool = True, **plot_kwargs: Any
|
|
21
|
+
) -> tuple[Figure, Axes]:
|
|
22
|
+
"""Log-log plot of a kinetic energy spectrum, with an optional Kolmogorov -5/3 reference line.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
k : ndarray of float
|
|
27
|
+
Wavenumbers, e.g. from :func:`physicskit.fluids.utils.spectral_analysis.energy_spectrum`.
|
|
28
|
+
E : ndarray of float
|
|
29
|
+
Spectral energy density at each `k`.
|
|
30
|
+
ax : matplotlib.axes.Axes, optional
|
|
31
|
+
Axes to draw into; a new figure is created if omitted.
|
|
32
|
+
show_kolmogorov : bool, default True
|
|
33
|
+
If True, overlay a :math:`k^{-5/3}` reference line anchored at the
|
|
34
|
+
lowest plotted (nonzero-energy) wavenumber.
|
|
35
|
+
**plot_kwargs
|
|
36
|
+
Additional keyword arguments forwarded to ``ax.loglog`` for the
|
|
37
|
+
measured spectrum.
|
|
38
|
+
|
|
39
|
+
Returns
|
|
40
|
+
-------
|
|
41
|
+
fig : matplotlib.figure.Figure
|
|
42
|
+
ax : matplotlib.axes.Axes
|
|
43
|
+
"""
|
|
44
|
+
if ax is None:
|
|
45
|
+
fig, ax = plt.subplots(figsize=(6, 5))
|
|
46
|
+
else:
|
|
47
|
+
fig = cast(Figure, ax.figure)
|
|
48
|
+
k = np.asarray(k, dtype=np.float64)
|
|
49
|
+
E = np.asarray(E, dtype=np.float64)
|
|
50
|
+
mask = (k > 0) & (E > 0)
|
|
51
|
+
kwargs: dict[str, Any] = {"color": theme.PRIMARY, "marker": "o", "markersize": 3, "label": "E(k)"}
|
|
52
|
+
kwargs.update(plot_kwargs)
|
|
53
|
+
ax.loglog(k[mask], E[mask], **kwargs)
|
|
54
|
+
if show_kolmogorov and np.any(mask):
|
|
55
|
+
k0 = k[mask][0]
|
|
56
|
+
E0 = E[mask][0]
|
|
57
|
+
ax.loglog(k[mask], kolmogorov_reference_slope(k[mask], k0, E0), color=theme.ACCENT, ls="--", label=r"$k^{-5/3}$")
|
|
58
|
+
ax.set_xlabel("k")
|
|
59
|
+
ax.set_ylabel("E(k)")
|
|
60
|
+
ax.set_title("Kinetic energy spectrum")
|
|
61
|
+
ax.legend()
|
|
62
|
+
return fig, ax
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Shared color constants for physicskit.fluids's Matplotlib visualizers.
|
|
2
|
+
|
|
3
|
+
Re-exports the same palette :mod:`physicskit.chaos.visualizers.theme` defines,
|
|
4
|
+
so a plot moving between the two packages (e.g. a von Karman street built
|
|
5
|
+
from :mod:`physicskit.fluids.systems.vortex_dynamics` next to a chaotic
|
|
6
|
+
trajectory) reads as one consistent visual language rather than two
|
|
7
|
+
accidentally different ones. Every visualizer still accepts its own
|
|
8
|
+
color/colormap keyword arguments to override these, so nothing here is
|
|
9
|
+
load-bearing.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from physicskit.chaos.visualizers.theme import (
|
|
15
|
+
ACCENT,
|
|
16
|
+
DIVERGING_CMAP,
|
|
17
|
+
MUTED,
|
|
18
|
+
PRIMARY,
|
|
19
|
+
QUALITATIVE_CMAP,
|
|
20
|
+
SEQUENTIAL_CMAP,
|
|
21
|
+
STRUCTURE,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"PRIMARY",
|
|
26
|
+
"ACCENT",
|
|
27
|
+
"STRUCTURE",
|
|
28
|
+
"MUTED",
|
|
29
|
+
"QUALITATIVE_CMAP",
|
|
30
|
+
"SEQUENTIAL_CMAP",
|
|
31
|
+
"DIVERGING_CMAP",
|
|
32
|
+
"VORTICITY_CMAP",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
#: Diverging colormap for vorticity fields (signed, centered at zero): an
|
|
36
|
+
#: alias for :data:`DIVERGING_CMAP`, named for its most common use in this
|
|
37
|
+
#: package.
|
|
38
|
+
VORTICITY_CMAP: str = DIVERGING_CMAP
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Numba-accelerated ODE integrators shared across physicskit subpackages.
|
|
2
|
+
|
|
3
|
+
Right-hand-side / force callbacks use the ``f(state_or_pos, t, params) ->
|
|
4
|
+
ndarray`` convention throughout, so a single compiled callback can be reused
|
|
5
|
+
across systems with different parameter values without recompiling (see
|
|
6
|
+
:mod:`physicskit.integrators.fixed_step`).
|
|
7
|
+
|
|
8
|
+
* :func:`rk4_integrate` -- classical 4th-order Runge-Kutta (not
|
|
9
|
+
energy-preserving).
|
|
10
|
+
* :func:`leapfrog_integrate` (alias :func:`velocity_verlet_integrate`) --
|
|
11
|
+
2nd-order symplectic Stormer-Verlet, for separable systems
|
|
12
|
+
``pos'' = force(pos, t)``.
|
|
13
|
+
* :func:`yoshida4_integrate` -- 4th-order symplectic, built from three
|
|
14
|
+
leapfrog sub-steps.
|
|
15
|
+
* :func:`dopri5_integrate` -- adaptive-step-size embedded Dormand-Prince
|
|
16
|
+
RK5(4), for non-conservative or accuracy-sensitive systems (see
|
|
17
|
+
:mod:`physicskit.integrators.adaptive` for why this isn't offered for the
|
|
18
|
+
symplectic integrators).
|
|
19
|
+
|
|
20
|
+
:mod:`physicskit.classical.core.integrators` uses its own closure-based
|
|
21
|
+
calling convention (``force_func(q, t)`` plus a per-instance ``mass_inv``)
|
|
22
|
+
and :mod:`physicskit.statphys.core.md_engine` its own periodic-boundary,
|
|
23
|
+
force-caching variant; both are documented at their own definitions rather
|
|
24
|
+
than adapted to the convention here.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from physicskit.integrators.adaptive import dopri5_integrate, dopri5_step
|
|
28
|
+
from physicskit.integrators.fixed_step import (
|
|
29
|
+
RHSFunc,
|
|
30
|
+
leapfrog_integrate,
|
|
31
|
+
leapfrog_step,
|
|
32
|
+
rk4_integrate,
|
|
33
|
+
rk4_step,
|
|
34
|
+
velocity_verlet_integrate,
|
|
35
|
+
velocity_verlet_step,
|
|
36
|
+
yoshida4_integrate,
|
|
37
|
+
yoshida4_step,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"RHSFunc",
|
|
42
|
+
"rk4_step",
|
|
43
|
+
"rk4_integrate",
|
|
44
|
+
"leapfrog_step",
|
|
45
|
+
"leapfrog_integrate",
|
|
46
|
+
"velocity_verlet_step",
|
|
47
|
+
"velocity_verlet_integrate",
|
|
48
|
+
"yoshida4_step",
|
|
49
|
+
"yoshida4_integrate",
|
|
50
|
+
"dopri5_step",
|
|
51
|
+
"dopri5_integrate",
|
|
52
|
+
]
|