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,112 @@
|
|
|
1
|
+
"""The Ehrenfest urn model: the simplest illustration of statistical irreversibility.
|
|
2
|
+
|
|
3
|
+
Loschmidt and Zermelo objected that Boltzmann's H-theorem could not be
|
|
4
|
+
right, since microscopically reversible dynamics cannot produce genuinely
|
|
5
|
+
irreversible macroscopic behavior (Loschmidt), and any bounded mechanical
|
|
6
|
+
system must eventually return arbitrarily close to its initial state
|
|
7
|
+
(Zermelo, via Poincare recurrence). The Ehrenfests' 1907 urn model resolves
|
|
8
|
+
both objections in the simplest possible setting: the dynamics is exactly
|
|
9
|
+
reversible and does recur exactly, yet for any macroscopic number of balls
|
|
10
|
+
the expected recurrence time is astronomically long, while the approach to
|
|
11
|
+
equilibrium is essentially instantaneous -- reconciling reversible
|
|
12
|
+
microphysics with an observed arrow of time.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from scipy.special import gammaln
|
|
19
|
+
|
|
20
|
+
__all__ = ["EhrenfestUrn"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class EhrenfestUrn:
|
|
24
|
+
"""The Ehrenfest urn model of N labeled balls exchanged between two boxes.
|
|
25
|
+
|
|
26
|
+
At each time step, one of the ``n_balls`` balls (chosen uniformly at
|
|
27
|
+
random) is moved from whichever box it currently occupies to the other.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
n_balls : int, default=100
|
|
32
|
+
Total number of balls, N.
|
|
33
|
+
n_left_init : int, optional
|
|
34
|
+
Initial number of balls in the left box. Defaults to ``n_balls``
|
|
35
|
+
(all balls start in one box, a maximally non-equilibrium state).
|
|
36
|
+
seed : int, optional
|
|
37
|
+
Seed for the ball-selection sequence.
|
|
38
|
+
|
|
39
|
+
Attributes
|
|
40
|
+
----------
|
|
41
|
+
n_left : int
|
|
42
|
+
Current number of balls in the left box.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, n_balls=100, n_left_init=None, seed=None):
|
|
46
|
+
self.n_balls = n_balls
|
|
47
|
+
self.n_left = n_balls if n_left_init is None else n_left_init
|
|
48
|
+
self._rng = np.random.default_rng(seed)
|
|
49
|
+
|
|
50
|
+
def step(self):
|
|
51
|
+
"""Move one uniformly random ball to the other box.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
int
|
|
56
|
+
The updated :attr:`n_left`.
|
|
57
|
+
"""
|
|
58
|
+
chosen = self._rng.integers(0, self.n_balls)
|
|
59
|
+
if chosen < self.n_left:
|
|
60
|
+
self.n_left -= 1
|
|
61
|
+
else:
|
|
62
|
+
self.n_left += 1
|
|
63
|
+
return self.n_left
|
|
64
|
+
|
|
65
|
+
def entropy(self):
|
|
66
|
+
"""Boltzmann entropy :math:`S/k_B = \\ln W` of the current macrostate.
|
|
67
|
+
|
|
68
|
+
:math:`W = \\binom{N}{n_{\\text{left}}}` counts the ball-labelings
|
|
69
|
+
consistent with the current left-box occupancy; the binomial
|
|
70
|
+
coefficient is evaluated via the log-gamma function
|
|
71
|
+
(``scipy.special.gammaln``) to stay numerically stable for large
|
|
72
|
+
:math:`N`.
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
float
|
|
77
|
+
"""
|
|
78
|
+
N, n = self.n_balls, self.n_left
|
|
79
|
+
return float(gammaln(N + 1) - gammaln(n + 1) - gammaln(N - n + 1))
|
|
80
|
+
|
|
81
|
+
def run(self, n_steps):
|
|
82
|
+
"""Run the urn for ``n_steps`` and record its history.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
n_steps : int
|
|
87
|
+
Number of steps to simulate.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
dict of str -> ndarray
|
|
92
|
+
Keys ``"t"``, ``"n_left"``, ``"entropy"``, each of length
|
|
93
|
+
``n_steps + 1`` (including the initial state).
|
|
94
|
+
|
|
95
|
+
Examples
|
|
96
|
+
--------
|
|
97
|
+
>>> urn = EhrenfestUrn(n_balls=50, seed=0)
|
|
98
|
+
>>> history = urn.run(200)
|
|
99
|
+
>>> history["n_left"].shape
|
|
100
|
+
(201,)
|
|
101
|
+
>>> int(history["n_left"][0])
|
|
102
|
+
50
|
|
103
|
+
"""
|
|
104
|
+
n_left = np.empty(n_steps + 1, dtype=np.int64)
|
|
105
|
+
entropy = np.empty(n_steps + 1, dtype=np.float64)
|
|
106
|
+
n_left[0] = self.n_left
|
|
107
|
+
entropy[0] = self.entropy()
|
|
108
|
+
for t in range(1, n_steps + 1):
|
|
109
|
+
self.step()
|
|
110
|
+
n_left[t] = self.n_left
|
|
111
|
+
entropy[t] = self.entropy()
|
|
112
|
+
return {"t": np.arange(n_steps + 1), "n_left": n_left, "entropy": entropy}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
"""Lattice spin models: the 2D Ising model, the q-state Potts model, and the XY model.
|
|
2
|
+
|
|
3
|
+
Three user-facing classes wrap the Numba kernels in
|
|
4
|
+
:mod:`physicskit.statphys.core.monte_carlo`:
|
|
5
|
+
|
|
6
|
+
- :class:`Ising2D` -- the archetypal discrete ferromagnet, with an exactly
|
|
7
|
+
known critical temperature and both Metropolis and Wolff dynamics.
|
|
8
|
+
- :class:`PottsModel2D` -- its :math:`q`-state generalization, whose
|
|
9
|
+
transition sharpens from second order (:math:`q \\le 4`) to first order
|
|
10
|
+
(:math:`q > 4`) on the square lattice.
|
|
11
|
+
- :class:`XYModel2D` -- continuous planar spins hosting the topological
|
|
12
|
+
Kosterlitz-Thouless transition, driven by vortex-antivortex unbinding
|
|
13
|
+
rather than symmetry breaking.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
from physicskit.statphys.core.monte_carlo import (
|
|
21
|
+
ising_total_energy,
|
|
22
|
+
ising_total_magnetization,
|
|
23
|
+
metropolis_sweep_ising,
|
|
24
|
+
metropolis_sweep_potts,
|
|
25
|
+
metropolis_sweep_xy,
|
|
26
|
+
potts_total_energy,
|
|
27
|
+
seed_numba_random,
|
|
28
|
+
wolff_step_ising,
|
|
29
|
+
xy_plaquette_vorticity,
|
|
30
|
+
xy_total_energy,
|
|
31
|
+
)
|
|
32
|
+
from physicskit.statphys.utils.thermodynamics import specific_heat, susceptibility
|
|
33
|
+
|
|
34
|
+
__all__ = ["Ising2D", "PottsModel2D", "XYModel2D"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Ising2D:
|
|
38
|
+
"""The 2D ferromagnetic Ising model on a periodic :math:`L \\times L` lattice.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
L : int, default=32
|
|
43
|
+
Linear lattice size.
|
|
44
|
+
J : float, default=1.0
|
|
45
|
+
Ferromagnetic coupling constant.
|
|
46
|
+
kB : float, default=1.0
|
|
47
|
+
Boltzmann constant, in whatever unit system ``J`` and ``T`` are
|
|
48
|
+
expressed in.
|
|
49
|
+
seed : int, optional
|
|
50
|
+
Seed for reproducible initial spin configurations and Metropolis
|
|
51
|
+
dynamics.
|
|
52
|
+
|
|
53
|
+
Attributes
|
|
54
|
+
----------
|
|
55
|
+
spins : ndarray of shape (L, L)
|
|
56
|
+
Current spin configuration, values in ``{-1, +1}``.
|
|
57
|
+
|
|
58
|
+
Examples
|
|
59
|
+
--------
|
|
60
|
+
>>> model = Ising2D(L=16, seed=0)
|
|
61
|
+
>>> model.sweep(beta=1.0, n_sweeps=50)
|
|
62
|
+
>>> -1.0 <= model.magnetization() / model.n_sites <= 1.0
|
|
63
|
+
True
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(self, L=32, J=1.0, kB=1.0, seed=None):
|
|
67
|
+
self.L = L
|
|
68
|
+
self.J = J
|
|
69
|
+
self.kB = kB
|
|
70
|
+
self.n_sites = L * L
|
|
71
|
+
self._rng = np.random.default_rng(seed)
|
|
72
|
+
if seed is not None:
|
|
73
|
+
seed_numba_random(seed)
|
|
74
|
+
self.spins = self._rng.choice(np.array([-1, 1], dtype=np.int64), size=(L, L))
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def T_C(self):
|
|
78
|
+
"""Onsager's exact critical temperature, :math:`2J / (k_B \\ln(1 + \\sqrt{2})) \\approx 2.269 J / k_B`."""
|
|
79
|
+
return 2.0 * self.J / (self.kB * np.log(1.0 + np.sqrt(2.0)))
|
|
80
|
+
|
|
81
|
+
def reset(self, ordered=False):
|
|
82
|
+
"""Reinitialize the spin configuration.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
ordered : bool, default=False
|
|
87
|
+
If True, start from a fully aligned (all ``+1``) configuration
|
|
88
|
+
(a low-temperature / :math:`T=0` state). Otherwise draw an
|
|
89
|
+
independent random ``\\pm 1`` configuration (a :math:`T=\\infty`
|
|
90
|
+
state).
|
|
91
|
+
"""
|
|
92
|
+
if ordered:
|
|
93
|
+
self.spins = np.ones((self.L, self.L), dtype=np.int64)
|
|
94
|
+
else:
|
|
95
|
+
self.spins = self._rng.choice(np.array([-1, 1], dtype=np.int64), size=(self.L, self.L))
|
|
96
|
+
|
|
97
|
+
def sweep(self, beta, algorithm="metropolis", n_sweeps=1):
|
|
98
|
+
"""Advance the lattice by one or more Monte Carlo sweeps.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
beta : float
|
|
103
|
+
Inverse temperature :math:`1/(k_B T)`.
|
|
104
|
+
algorithm : {"metropolis", "wolff"}, default="metropolis"
|
|
105
|
+
Update rule. Metropolis flips single spins; Wolff grows and flips
|
|
106
|
+
whole clusters, which decorrelates much faster near :math:`T_c`.
|
|
107
|
+
n_sweeps : int, default=1
|
|
108
|
+
Number of sweeps (Metropolis) or cluster updates (Wolff) to
|
|
109
|
+
perform.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
int or None
|
|
114
|
+
For ``"wolff"``, the size of the last cluster flipped; ``None``
|
|
115
|
+
for ``"metropolis"``.
|
|
116
|
+
"""
|
|
117
|
+
last_cluster = None
|
|
118
|
+
for _ in range(n_sweeps):
|
|
119
|
+
if algorithm == "metropolis":
|
|
120
|
+
metropolis_sweep_ising(self.spins, beta, self.J)
|
|
121
|
+
elif algorithm == "wolff":
|
|
122
|
+
last_cluster = wolff_step_ising(self.spins, beta, self.J)
|
|
123
|
+
else:
|
|
124
|
+
raise ValueError("algorithm must be 'metropolis' or 'wolff'")
|
|
125
|
+
return last_cluster
|
|
126
|
+
|
|
127
|
+
def energy(self):
|
|
128
|
+
"""Total energy of the current configuration, :math:`-J \\sum_{\\langle i,j\\rangle} s_i s_j`."""
|
|
129
|
+
return ising_total_energy(self.spins, self.J)
|
|
130
|
+
|
|
131
|
+
def magnetization(self):
|
|
132
|
+
"""Total magnetization :math:`M = \\sum_i s_i` of the current configuration."""
|
|
133
|
+
return ising_total_magnetization(self.spins)
|
|
134
|
+
|
|
135
|
+
def run_temperature_sweep(self, temperatures, n_equil=200, n_measure=500, algorithm="metropolis", measure_every=1):
|
|
136
|
+
"""Sweep over a range of temperatures, measuring equilibrium thermodynamics at each.
|
|
137
|
+
|
|
138
|
+
At every temperature the lattice is first equilibrated for
|
|
139
|
+
``n_equil`` sweeps, then sampled every ``measure_every`` sweeps for
|
|
140
|
+
``n_measure`` measurements, from which the specific heat and magnetic
|
|
141
|
+
susceptibility are estimated via their fluctuation-dissipation
|
|
142
|
+
relations. The final configuration at each temperature seeds the next
|
|
143
|
+
(simulated annealing), which shortens equilibration as the sweep
|
|
144
|
+
proceeds.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
temperatures : array_like
|
|
149
|
+
Temperatures to sample, typically ordered from high to low to
|
|
150
|
+
exploit annealing.
|
|
151
|
+
n_equil : int, default=200
|
|
152
|
+
Equilibration sweeps discarded before measuring at each
|
|
153
|
+
temperature.
|
|
154
|
+
n_measure : int, default=500
|
|
155
|
+
Number of measurements collected at each temperature.
|
|
156
|
+
algorithm : {"metropolis", "wolff"}, default="metropolis"
|
|
157
|
+
Update rule, see :meth:`sweep`.
|
|
158
|
+
measure_every : int, default=1
|
|
159
|
+
Number of sweeps between successive measurements.
|
|
160
|
+
|
|
161
|
+
Returns
|
|
162
|
+
-------
|
|
163
|
+
dict of str -> ndarray
|
|
164
|
+
Keys ``"T"``, ``"E"``, ``"M"``, ``"C_v"``, ``"chi"``, each an
|
|
165
|
+
array aligned with ``temperatures``. ``"E"`` and ``"M"`` are
|
|
166
|
+
per-site averages; ``"C_v"`` and ``"chi"`` are per-site.
|
|
167
|
+
|
|
168
|
+
Examples
|
|
169
|
+
--------
|
|
170
|
+
>>> model = Ising2D(L=12, seed=1)
|
|
171
|
+
>>> result = model.run_temperature_sweep(
|
|
172
|
+
... [3.5, 2.269, 1.0], n_equil=20, n_measure=20
|
|
173
|
+
... )
|
|
174
|
+
>>> sorted(result.keys())
|
|
175
|
+
['C_v', 'E', 'M', 'T', 'chi']
|
|
176
|
+
"""
|
|
177
|
+
temperatures = np.asarray(temperatures, dtype=np.float64)
|
|
178
|
+
n_T = len(temperatures)
|
|
179
|
+
E_mean = np.empty(n_T)
|
|
180
|
+
M_mean = np.empty(n_T)
|
|
181
|
+
C_v = np.empty(n_T)
|
|
182
|
+
chi = np.empty(n_T)
|
|
183
|
+
|
|
184
|
+
for k, T in enumerate(temperatures):
|
|
185
|
+
beta = 1.0 / (self.kB * T)
|
|
186
|
+
self.sweep(beta, algorithm=algorithm, n_sweeps=n_equil)
|
|
187
|
+
|
|
188
|
+
energies = np.empty(n_measure)
|
|
189
|
+
magnetizations = np.empty(n_measure)
|
|
190
|
+
for m in range(n_measure):
|
|
191
|
+
self.sweep(beta, algorithm=algorithm, n_sweeps=measure_every)
|
|
192
|
+
energies[m] = self.energy()
|
|
193
|
+
magnetizations[m] = self.magnetization()
|
|
194
|
+
|
|
195
|
+
E_mean[k] = energies.mean() / self.n_sites
|
|
196
|
+
M_mean[k] = np.abs(magnetizations).mean() / self.n_sites
|
|
197
|
+
C_v[k] = specific_heat(energies, T, self.n_sites, kB=self.kB)
|
|
198
|
+
chi[k] = susceptibility(np.abs(magnetizations), T, self.n_sites, kB=self.kB)
|
|
199
|
+
|
|
200
|
+
return {"T": temperatures, "E": E_mean, "M": M_mean, "C_v": C_v, "chi": chi}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class PottsModel2D:
|
|
204
|
+
"""The 2D ferromagnetic q-state Potts model on a periodic :math:`L \\times L` lattice.
|
|
205
|
+
|
|
206
|
+
Each site carries a discrete state :math:`s_i \\in \\{0, \\ldots, q-1\\}`,
|
|
207
|
+
and the Hamiltonian rewards neighboring sites for matching:
|
|
208
|
+
:math:`H = -J \\sum_{\\langle i,j \\rangle} \\delta(s_i, s_j)`. The Ising
|
|
209
|
+
model is the special case :math:`q = 2` (with a rescaled coupling). On the
|
|
210
|
+
square lattice the transition is second order for :math:`q \\le 4` and
|
|
211
|
+
first order for :math:`q > 4`.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
L : int, default=32
|
|
216
|
+
Linear lattice size.
|
|
217
|
+
q : int, default=3
|
|
218
|
+
Number of Potts states.
|
|
219
|
+
J : float, default=1.0
|
|
220
|
+
Coupling constant.
|
|
221
|
+
kB : float, default=1.0
|
|
222
|
+
Boltzmann constant.
|
|
223
|
+
seed : int, optional
|
|
224
|
+
Seed for reproducible dynamics.
|
|
225
|
+
|
|
226
|
+
Attributes
|
|
227
|
+
----------
|
|
228
|
+
spins : ndarray of shape (L, L)
|
|
229
|
+
Current state configuration, values in ``{0, ..., q-1}``.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
def __init__(self, L=32, q=3, J=1.0, kB=1.0, seed=None):
|
|
233
|
+
self.L = L
|
|
234
|
+
self.q = q
|
|
235
|
+
self.J = J
|
|
236
|
+
self.kB = kB
|
|
237
|
+
self.n_sites = L * L
|
|
238
|
+
self._rng = np.random.default_rng(seed)
|
|
239
|
+
if seed is not None:
|
|
240
|
+
seed_numba_random(seed)
|
|
241
|
+
self.spins = self._rng.integers(0, q, size=(L, L)).astype(np.int64)
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def T_C(self):
|
|
245
|
+
"""Exact critical temperature of the square-lattice Potts model, :math:`J / (k_B \\ln(1 + \\sqrt{q}))`."""
|
|
246
|
+
return self.J / (self.kB * np.log(1.0 + np.sqrt(self.q)))
|
|
247
|
+
|
|
248
|
+
def sweep(self, beta, n_sweeps=1):
|
|
249
|
+
"""Advance the lattice by ``n_sweeps`` Metropolis-Hastings sweeps.
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
beta : float
|
|
254
|
+
Inverse temperature.
|
|
255
|
+
n_sweeps : int, default=1
|
|
256
|
+
Number of sweeps to perform.
|
|
257
|
+
"""
|
|
258
|
+
for _ in range(n_sweeps):
|
|
259
|
+
metropolis_sweep_potts(self.spins, beta, self.J, self.q)
|
|
260
|
+
|
|
261
|
+
def energy(self):
|
|
262
|
+
"""Total energy :math:`-J \\sum_{\\langle i,j\\rangle} \\delta(s_i, s_j)` of the current configuration."""
|
|
263
|
+
return potts_total_energy(self.spins, self.J)
|
|
264
|
+
|
|
265
|
+
def order_parameter(self):
|
|
266
|
+
"""Potts order parameter, the rescaled fraction of sites in the majority state.
|
|
267
|
+
|
|
268
|
+
.. math::
|
|
269
|
+
|
|
270
|
+
m = \\frac{q \\cdot n_{\\max} / N - 1}{q - 1}
|
|
271
|
+
|
|
272
|
+
where :math:`n_{\\max}` is the largest population among the ``q``
|
|
273
|
+
states. ``m`` is ``0`` in the fully disordered phase and ``1`` in the
|
|
274
|
+
fully ordered phase.
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
float
|
|
279
|
+
"""
|
|
280
|
+
counts = np.bincount(self.spins.ravel(), minlength=self.q)
|
|
281
|
+
n_max = counts.max()
|
|
282
|
+
return (self.q * n_max / self.n_sites - 1.0) / (self.q - 1.0)
|
|
283
|
+
|
|
284
|
+
def run_temperature_sweep(self, temperatures, n_equil=200, n_measure=500, measure_every=1):
|
|
285
|
+
"""Sweep over temperatures, measuring energy, order parameter, and specific heat.
|
|
286
|
+
|
|
287
|
+
See :meth:`Ising2D.run_temperature_sweep` for the equilibration and
|
|
288
|
+
measurement protocol; this follows the same pattern.
|
|
289
|
+
|
|
290
|
+
Parameters
|
|
291
|
+
----------
|
|
292
|
+
temperatures : array_like
|
|
293
|
+
Temperatures to sample.
|
|
294
|
+
n_equil : int, default=200
|
|
295
|
+
Equilibration sweeps at each temperature.
|
|
296
|
+
n_measure : int, default=500
|
|
297
|
+
Measurements collected at each temperature.
|
|
298
|
+
measure_every : int, default=1
|
|
299
|
+
Sweeps between successive measurements.
|
|
300
|
+
|
|
301
|
+
Returns
|
|
302
|
+
-------
|
|
303
|
+
dict of str -> ndarray
|
|
304
|
+
Keys ``"T"``, ``"E"``, ``"m"``, ``"C_v"``.
|
|
305
|
+
"""
|
|
306
|
+
temperatures = np.asarray(temperatures, dtype=np.float64)
|
|
307
|
+
n_T = len(temperatures)
|
|
308
|
+
E_mean = np.empty(n_T)
|
|
309
|
+
m_mean = np.empty(n_T)
|
|
310
|
+
C_v = np.empty(n_T)
|
|
311
|
+
|
|
312
|
+
for k, T in enumerate(temperatures):
|
|
313
|
+
beta = 1.0 / (self.kB * T)
|
|
314
|
+
self.sweep(beta, n_sweeps=n_equil)
|
|
315
|
+
|
|
316
|
+
energies = np.empty(n_measure)
|
|
317
|
+
orders = np.empty(n_measure)
|
|
318
|
+
for i in range(n_measure):
|
|
319
|
+
self.sweep(beta, n_sweeps=measure_every)
|
|
320
|
+
energies[i] = self.energy()
|
|
321
|
+
orders[i] = self.order_parameter()
|
|
322
|
+
|
|
323
|
+
E_mean[k] = energies.mean() / self.n_sites
|
|
324
|
+
m_mean[k] = orders.mean()
|
|
325
|
+
C_v[k] = specific_heat(energies, T, self.n_sites, kB=self.kB)
|
|
326
|
+
|
|
327
|
+
return {"T": temperatures, "E": E_mean, "m": m_mean, "C_v": C_v}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class XYModel2D:
|
|
331
|
+
"""The 2D classical XY model on a periodic :math:`L \\times L` lattice.
|
|
332
|
+
|
|
333
|
+
Each site carries a planar spin angle :math:`\\theta_i \\in [0, 2\\pi)`,
|
|
334
|
+
with Hamiltonian :math:`H = -J \\sum_{\\langle i,j \\rangle}
|
|
335
|
+
\\cos(\\theta_i - \\theta_j)`. The Mermin-Wagner theorem forbids
|
|
336
|
+
conventional long-range order in 2D, but the model still hosts the
|
|
337
|
+
topological Kosterlitz-Thouless (KT) transition at
|
|
338
|
+
:math:`T_{\\text{KT}} \\approx 0.893\\, J / k_B`: bound vortex-antivortex
|
|
339
|
+
pairs at low temperature unbind into a free vortex plasma above
|
|
340
|
+
:math:`T_{\\text{KT}}`.
|
|
341
|
+
|
|
342
|
+
Parameters
|
|
343
|
+
----------
|
|
344
|
+
L : int, default=32
|
|
345
|
+
Linear lattice size.
|
|
346
|
+
J : float, default=1.0
|
|
347
|
+
Coupling constant.
|
|
348
|
+
kB : float, default=1.0
|
|
349
|
+
Boltzmann constant.
|
|
350
|
+
seed : int, optional
|
|
351
|
+
Seed for reproducible dynamics.
|
|
352
|
+
|
|
353
|
+
Attributes
|
|
354
|
+
----------
|
|
355
|
+
theta : ndarray of shape (L, L)
|
|
356
|
+
Current spin angles, in radians.
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
#: Numerically established Kosterlitz-Thouless temperature, in units of J/kB.
|
|
360
|
+
_T_KT_REDUCED = 0.8929
|
|
361
|
+
|
|
362
|
+
def __init__(self, L=32, J=1.0, kB=1.0, seed=None):
|
|
363
|
+
self.L = L
|
|
364
|
+
self.J = J
|
|
365
|
+
self.kB = kB
|
|
366
|
+
self.n_sites = L * L
|
|
367
|
+
self._rng = np.random.default_rng(seed)
|
|
368
|
+
if seed is not None:
|
|
369
|
+
seed_numba_random(seed)
|
|
370
|
+
self.theta = self._rng.uniform(0.0, 2.0 * np.pi, size=(L, L))
|
|
371
|
+
|
|
372
|
+
@property
|
|
373
|
+
def T_KT(self):
|
|
374
|
+
"""Approximate (numerically established) Kosterlitz-Thouless transition temperature, :math:`\\approx 0.893\\, J / k_B`."""
|
|
375
|
+
return self._T_KT_REDUCED * self.J / self.kB
|
|
376
|
+
|
|
377
|
+
def sweep(self, beta, n_sweeps=1, delta=1.0):
|
|
378
|
+
"""Advance the lattice by ``n_sweeps`` Metropolis-Hastings sweeps.
|
|
379
|
+
|
|
380
|
+
Parameters
|
|
381
|
+
----------
|
|
382
|
+
beta : float
|
|
383
|
+
Inverse temperature.
|
|
384
|
+
n_sweeps : int, default=1
|
|
385
|
+
Number of sweeps to perform.
|
|
386
|
+
delta : float, default=1.0
|
|
387
|
+
Maximum trial angular step (radians); tune towards an acceptance
|
|
388
|
+
rate near 50% for efficient sampling.
|
|
389
|
+
"""
|
|
390
|
+
for _ in range(n_sweeps):
|
|
391
|
+
metropolis_sweep_xy(self.theta, beta, self.J, delta)
|
|
392
|
+
|
|
393
|
+
def energy(self):
|
|
394
|
+
"""Total energy :math:`-J \\sum_{\\langle i,j\\rangle} \\cos(\\theta_i - \\theta_j)` of the current configuration."""
|
|
395
|
+
return xy_total_energy(self.theta, self.J)
|
|
396
|
+
|
|
397
|
+
def magnetization_vector(self):
|
|
398
|
+
"""Net planar magnetization vector :math:`(\\sum_i \\cos\\theta_i, \\sum_i \\sin\\theta_i)`."""
|
|
399
|
+
return np.array([np.cos(self.theta).sum(), np.sin(self.theta).sum()])
|
|
400
|
+
|
|
401
|
+
def vorticity(self):
|
|
402
|
+
"""Topological charge of every plaquette; see :func:`physicskit.statphys.core.monte_carlo.xy_plaquette_vorticity`.
|
|
403
|
+
|
|
404
|
+
Returns
|
|
405
|
+
-------
|
|
406
|
+
ndarray of shape (L, L)
|
|
407
|
+
Plaquette vorticity, close to an integer everywhere and nonzero
|
|
408
|
+
(:math:`\\pm 1`) at vortex/antivortex cores.
|
|
409
|
+
"""
|
|
410
|
+
return xy_plaquette_vorticity(self.theta)
|
|
411
|
+
|
|
412
|
+
def vortex_count(self, threshold=0.5):
|
|
413
|
+
"""Count vortices and antivortices by thresholding the plaquette vorticity.
|
|
414
|
+
|
|
415
|
+
Parameters
|
|
416
|
+
----------
|
|
417
|
+
threshold : float, default=0.5
|
|
418
|
+
Minimum ``|vorticity|`` for a plaquette to be counted as hosting
|
|
419
|
+
a topological charge.
|
|
420
|
+
|
|
421
|
+
Returns
|
|
422
|
+
-------
|
|
423
|
+
n_vortices : int
|
|
424
|
+
Number of plaquettes with vorticity near ``+1``.
|
|
425
|
+
n_antivortices : int
|
|
426
|
+
Number of plaquettes with vorticity near ``-1``.
|
|
427
|
+
"""
|
|
428
|
+
q = self.vorticity()
|
|
429
|
+
n_vortices = int(np.sum(q > threshold))
|
|
430
|
+
n_antivortices = int(np.sum(q < -threshold))
|
|
431
|
+
return n_vortices, n_antivortices
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""The Kardar-Parisi-Zhang equation: universal roughening of growing interfaces.
|
|
2
|
+
|
|
3
|
+
Kardar, Parisi, and Zhang's 1986 stochastic partial differential equation,
|
|
4
|
+
|
|
5
|
+
.. math::
|
|
6
|
+
|
|
7
|
+
\\frac{\\partial h}{\\partial t} = \\nu \\nabla^2 h
|
|
8
|
+
+ \\frac{\\lambda}{2}(\\nabla h)^2 + \\eta(x, t),
|
|
9
|
+
|
|
10
|
+
describes a growing interface driven by uncorrelated noise :math:`\\eta`,
|
|
11
|
+
smoothed by surface tension :math:`\\nu`, and locally accelerated by the
|
|
12
|
+
nonlinear slope term :math:`\\lambda(\\nabla h)^2` -- growth normal to the
|
|
13
|
+
surface, not straight up. That nonlinear term is what separates the KPZ
|
|
14
|
+
universality class from the simpler Edwards-Wilkinson equation
|
|
15
|
+
(:math:`\\lambda = 0`): it couples length scales together and produces a
|
|
16
|
+
new, nontrivial set of scaling exponents shared by an enormous range of
|
|
17
|
+
physical growth processes, from bacterial colonies to burning paper fronts.
|
|
18
|
+
|
|
19
|
+
Rather than discretize the continuum SPDE directly (whose nonlinear term is
|
|
20
|
+
notoriously delicate to finite-difference consistently), this module
|
|
21
|
+
implements the Restricted Solid-On-Solid (RSOS) model, an exact discrete
|
|
22
|
+
growth automaton with no adjustable surface-tension or coupling parameters
|
|
23
|
+
at all, long established (Kim & Kosterlitz, 1989) to lie in the KPZ
|
|
24
|
+
universality class.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import numpy as np
|
|
30
|
+
|
|
31
|
+
from physicskit.statphys.core.kpz_engine import run_rsos
|
|
32
|
+
from physicskit.statphys.core.monte_carlo import seed_numba_random
|
|
33
|
+
|
|
34
|
+
__all__ = ["KPZInterface"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class KPZInterface:
|
|
38
|
+
"""A 1D Restricted Solid-On-Solid growing interface on a periodic lattice of L sites.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
L : int, default=256
|
|
43
|
+
Number of sites (periodic boundary conditions).
|
|
44
|
+
seed : int, optional
|
|
45
|
+
Seed for the random deposition-site sequence.
|
|
46
|
+
|
|
47
|
+
Attributes
|
|
48
|
+
----------
|
|
49
|
+
heights : ndarray of shape (L,)
|
|
50
|
+
Current interface height profile, initialized flat at zero.
|
|
51
|
+
time : float
|
|
52
|
+
Elapsed time, in units of Monte Carlo sweeps (one sweep = L
|
|
53
|
+
attempted deposition events).
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(self, L=256, seed=None):
|
|
57
|
+
self.L = L
|
|
58
|
+
self.heights = np.zeros(L, dtype=np.int64)
|
|
59
|
+
self.time = 0.0
|
|
60
|
+
if seed is not None:
|
|
61
|
+
seed_numba_random(seed)
|
|
62
|
+
|
|
63
|
+
def grow(self, n_sweeps=1):
|
|
64
|
+
"""Advance the interface by ``n_sweeps`` Monte Carlo sweeps of RSOS deposition.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
n_sweeps : float, default=1
|
|
69
|
+
Number of sweeps (``L`` deposition attempts each) to perform.
|
|
70
|
+
"""
|
|
71
|
+
n_attempts = int(round(n_sweeps * self.L))
|
|
72
|
+
run_rsos(self.heights, n_attempts, self.L)
|
|
73
|
+
self.time += n_sweeps
|
|
74
|
+
|
|
75
|
+
def width(self):
|
|
76
|
+
"""Interface width :math:`w = \\sqrt{\\langle (h - \\bar h)^2 \\rangle}`, the key KPZ observable.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
float
|
|
81
|
+
"""
|
|
82
|
+
h = self.heights.astype(np.float64)
|
|
83
|
+
return float(np.sqrt(np.mean((h - h.mean()) ** 2)))
|
|
84
|
+
|
|
85
|
+
def mean_height(self):
|
|
86
|
+
"""Mean interface height :math:`\\bar h`, which grows linearly in time on average."""
|
|
87
|
+
return float(self.heights.mean())
|
|
88
|
+
|
|
89
|
+
def run_growth_curve(self, t_max, n_points=40, log_spaced=True):
|
|
90
|
+
"""Grow the interface while recording the width at a sequence of checkpoint times.
|
|
91
|
+
|
|
92
|
+
The width is expected to grow as :math:`w(t) \\sim t^{\\beta}` with
|
|
93
|
+
:math:`\\beta = 1/3` at early times, crossing over to a
|
|
94
|
+
length-limited saturation :math:`w_{\\text{sat}} \\sim L^{\\alpha}`
|
|
95
|
+
with :math:`\\alpha = 1/2` once :math:`t` exceeds the correlation
|
|
96
|
+
time :math:`\\sim L^{z}` (:math:`z = 3/2`).
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
t_max : float
|
|
101
|
+
Final time (in sweeps) to grow to.
|
|
102
|
+
n_points : int, default=40
|
|
103
|
+
Number of checkpoints to record.
|
|
104
|
+
log_spaced : bool, default=True
|
|
105
|
+
Use logarithmically spaced checkpoints (recommended for
|
|
106
|
+
resolving the early-time power-law growth regime) rather than
|
|
107
|
+
linearly spaced ones.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
times : ndarray of shape (n_points,)
|
|
112
|
+
widths : ndarray of shape (n_points,)
|
|
113
|
+
"""
|
|
114
|
+
if log_spaced:
|
|
115
|
+
checkpoints = np.unique(np.round(np.logspace(0, np.log10(t_max), n_points)).astype(np.int64))
|
|
116
|
+
else:
|
|
117
|
+
checkpoints = np.unique(np.round(np.linspace(1, t_max, n_points)).astype(np.int64))
|
|
118
|
+
|
|
119
|
+
times = np.empty(len(checkpoints))
|
|
120
|
+
widths = np.empty(len(checkpoints))
|
|
121
|
+
t_done = 0
|
|
122
|
+
for k, t in enumerate(checkpoints):
|
|
123
|
+
dt = int(t) - t_done
|
|
124
|
+
if dt > 0:
|
|
125
|
+
self.grow(n_sweeps=dt)
|
|
126
|
+
t_done = int(t)
|
|
127
|
+
times[k] = self.time
|
|
128
|
+
widths[k] = self.width()
|
|
129
|
+
return times, widths
|