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,241 @@
|
|
|
1
|
+
"""A Numba-accelerated backward photon ray-tracer for Schwarzschild gravitational lensing.
|
|
2
|
+
|
|
3
|
+
Rather than integrating the full 4D null geodesic equation per pixel, this
|
|
4
|
+
module exploits two facts about a spherically symmetric spacetime: every
|
|
5
|
+
photon trajectory is confined to a single plane through the black hole
|
|
6
|
+
(by symmetry), and within that plane, the trajectory obeys the classic
|
|
7
|
+
Binet-style orbit equation in :math:`u = 1/r`:
|
|
8
|
+
|
|
9
|
+
.. math::
|
|
10
|
+
|
|
11
|
+
\\frac{d^2 u}{d\\varphi^2} = -u + 3Mu^2
|
|
12
|
+
|
|
13
|
+
This is numerically robust (no turning-point sign ambiguities to handle,
|
|
14
|
+
unlike integrating :math:`dr/d\\lambda` directly) and fast: it reduces each
|
|
15
|
+
pixel's ray to a 2-variable ODE stepped in the orbital-plane angle
|
|
16
|
+
:math:`\\varphi`. To render an accretion disk, each step's in-plane
|
|
17
|
+
position is reconstructed in the observer's fixed 3D frame (using the
|
|
18
|
+
per-pixel orbital-plane basis fixed by its impact parameter geometry) and
|
|
19
|
+
checked against the disk's equatorial plane and radial extent.
|
|
20
|
+
|
|
21
|
+
Every camera ray is treated as parallel to the line of sight (an
|
|
22
|
+
orthographic projection), the standard and excellent approximation for an
|
|
23
|
+
observer at :math:`r_0 \\gg M` with a modest field of view.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import numpy as np
|
|
29
|
+
from numba import njit
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"OUTCOME_CAPTURED",
|
|
33
|
+
"OUTCOME_DISK",
|
|
34
|
+
"OUTCOME_ESCAPED",
|
|
35
|
+
"camera_basis",
|
|
36
|
+
"render_shadow_image",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
#: Pixel outcome code: the photon escaped to infinity without hitting the disk.
|
|
40
|
+
OUTCOME_ESCAPED = 0
|
|
41
|
+
#: Pixel outcome code: the photon crossed the event horizon.
|
|
42
|
+
OUTCOME_CAPTURED = 1
|
|
43
|
+
#: Pixel outcome code: the photon's orbit could not be resolved within the step
|
|
44
|
+
#: budget (deep near-critical winding); treated as captured for imaging purposes.
|
|
45
|
+
OUTCOME_UNRESOLVED = 2
|
|
46
|
+
#: Pixel outcome code: the photon crossed the accretion disk.
|
|
47
|
+
OUTCOME_DISK = 3
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def camera_basis(inclination):
|
|
51
|
+
"""Build an orthonormal camera frame looking at the origin from a given inclination.
|
|
52
|
+
|
|
53
|
+
The black hole sits at the origin with its spin/disk axis along
|
|
54
|
+
:math:`+Z`. The observer is placed in the :math:`X`-:math:`Z` plane at
|
|
55
|
+
polar angle ``inclination`` from the :math:`+Z` axis (``0`` = face-on,
|
|
56
|
+
looking down the pole; ``pi/2`` = edge-on, in the disk plane).
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
inclination : float
|
|
61
|
+
Observer inclination, in radians, measured from the disk's normal axis.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
view_dir : ndarray of shape (3,)
|
|
66
|
+
Unit vector from the observer toward the origin.
|
|
67
|
+
right : ndarray of shape (3,)
|
|
68
|
+
Unit vector spanning the camera's horizontal screen axis.
|
|
69
|
+
up : ndarray of shape (3,)
|
|
70
|
+
Unit vector spanning the camera's vertical screen axis.
|
|
71
|
+
"""
|
|
72
|
+
n_obs = np.array([np.sin(inclination), 0.0, np.cos(inclination)])
|
|
73
|
+
view_dir = -n_obs
|
|
74
|
+
up_hint = np.array([0.0, 0.0, 1.0]) if abs(inclination) > 1e-8 else np.array([1.0, 0.0, 0.0])
|
|
75
|
+
right = np.cross(view_dir, up_hint)
|
|
76
|
+
right = right / np.linalg.norm(right)
|
|
77
|
+
up = np.cross(right, view_dir)
|
|
78
|
+
up = up / np.linalg.norm(up)
|
|
79
|
+
return view_dir, right, up
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@njit(cache=True)
|
|
83
|
+
def _trace_pixel(
|
|
84
|
+
alpha,
|
|
85
|
+
beta,
|
|
86
|
+
obs_pos,
|
|
87
|
+
right,
|
|
88
|
+
up,
|
|
89
|
+
view_dir,
|
|
90
|
+
M,
|
|
91
|
+
r_disk_inner,
|
|
92
|
+
r_disk_outer,
|
|
93
|
+
dphi,
|
|
94
|
+
n_steps,
|
|
95
|
+
r_horizon_factor,
|
|
96
|
+
):
|
|
97
|
+
"""Trace one camera ray; returns (outcome_code, hit_radius)."""
|
|
98
|
+
ray_origin = obs_pos + alpha * right + beta * up
|
|
99
|
+
r0 = np.sqrt(ray_origin[0] ** 2 + ray_origin[1] ** 2 + ray_origin[2] ** 2)
|
|
100
|
+
|
|
101
|
+
cross_ov = np.cross(ray_origin, view_dir)
|
|
102
|
+
b = np.sqrt(cross_ov[0] ** 2 + cross_ov[1] ** 2 + cross_ov[2] ** 2)
|
|
103
|
+
|
|
104
|
+
if b < 1.0e-8:
|
|
105
|
+
return OUTCOME_CAPTURED, -1.0
|
|
106
|
+
|
|
107
|
+
e1 = ray_origin / r0
|
|
108
|
+
proj = view_dir - np.dot(view_dir, e1) * e1
|
|
109
|
+
proj_norm = np.sqrt(proj[0] ** 2 + proj[1] ** 2 + proj[2] ** 2)
|
|
110
|
+
e2 = proj / proj_norm
|
|
111
|
+
|
|
112
|
+
u = 1.0 / r0
|
|
113
|
+
val = 1.0 / (b * b) - u * u + 2.0 * M * u**3
|
|
114
|
+
val = max(val, 0.0)
|
|
115
|
+
dudphi = np.sqrt(val)
|
|
116
|
+
|
|
117
|
+
u_crit = 1.0 / (r_horizon_factor * 2.0 * M)
|
|
118
|
+
phi = 0.0
|
|
119
|
+
pos0 = (1.0 / u) * (np.cos(phi) * e1 + np.sin(phi) * e2)
|
|
120
|
+
prev_z = pos0[2]
|
|
121
|
+
|
|
122
|
+
outcome = OUTCOME_UNRESOLVED
|
|
123
|
+
hit_r = -1.0
|
|
124
|
+
|
|
125
|
+
for i in range(n_steps):
|
|
126
|
+
if u >= u_crit:
|
|
127
|
+
outcome = OUTCOME_CAPTURED
|
|
128
|
+
break
|
|
129
|
+
if u <= 0.0 and i > 0:
|
|
130
|
+
outcome = OUTCOME_ESCAPED
|
|
131
|
+
break
|
|
132
|
+
|
|
133
|
+
k1u = dudphi
|
|
134
|
+
k1v = -u + 3.0 * M * u * u
|
|
135
|
+
u2 = u + 0.5 * dphi * k1u
|
|
136
|
+
v2 = dudphi + 0.5 * dphi * k1v
|
|
137
|
+
k2u = v2
|
|
138
|
+
k2v = -u2 + 3.0 * M * u2 * u2
|
|
139
|
+
u3 = u + 0.5 * dphi * k2u
|
|
140
|
+
v3 = dudphi + 0.5 * dphi * k2v
|
|
141
|
+
k3u = v3
|
|
142
|
+
k3v = -u3 + 3.0 * M * u3 * u3
|
|
143
|
+
u4 = u + dphi * k3u
|
|
144
|
+
v4 = dudphi + dphi * k3v
|
|
145
|
+
k4u = v4
|
|
146
|
+
k4v = -u4 + 3.0 * M * u4 * u4
|
|
147
|
+
|
|
148
|
+
u = u + (dphi / 6.0) * (k1u + 2.0 * k2u + 2.0 * k3u + k4u)
|
|
149
|
+
dudphi = dudphi + (dphi / 6.0) * (k1v + 2.0 * k2v + 2.0 * k3v + k4v)
|
|
150
|
+
phi = phi + dphi
|
|
151
|
+
|
|
152
|
+
if u > 1.0e-10:
|
|
153
|
+
r = 1.0 / u
|
|
154
|
+
pos = r * (np.cos(phi) * e1 + np.sin(phi) * e2)
|
|
155
|
+
z = pos[2]
|
|
156
|
+
if z * prev_z < 0.0 and r_disk_inner <= r <= r_disk_outer:
|
|
157
|
+
hit_r = r
|
|
158
|
+
outcome = OUTCOME_DISK
|
|
159
|
+
break
|
|
160
|
+
prev_z = z
|
|
161
|
+
|
|
162
|
+
return outcome, hit_r
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@njit(cache=True)
|
|
166
|
+
def render_shadow_image(
|
|
167
|
+
ny,
|
|
168
|
+
nx,
|
|
169
|
+
screen_half_width,
|
|
170
|
+
screen_half_height,
|
|
171
|
+
obs_pos,
|
|
172
|
+
right,
|
|
173
|
+
up,
|
|
174
|
+
view_dir,
|
|
175
|
+
M,
|
|
176
|
+
r_disk_inner,
|
|
177
|
+
r_disk_outer,
|
|
178
|
+
dphi=0.01,
|
|
179
|
+
n_steps=3000,
|
|
180
|
+
r_horizon_factor=1.001,
|
|
181
|
+
):
|
|
182
|
+
"""Render a black hole shadow / accretion disk image by backward ray-tracing.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
ny, nx : int
|
|
187
|
+
Image height and width, in pixels.
|
|
188
|
+
screen_half_width, screen_half_height : float
|
|
189
|
+
Half-extent of the camera screen, in geometrized length units
|
|
190
|
+
(impact-parameter space); e.g. ``screen_half_width=15*M`` frames a
|
|
191
|
+
region a few times larger than the shadow.
|
|
192
|
+
obs_pos : ndarray of shape (3,)
|
|
193
|
+
Observer position in the black hole's rest frame.
|
|
194
|
+
right, up, view_dir : ndarray of shape (3,)
|
|
195
|
+
Camera basis vectors, e.g. from :func:`camera_basis`.
|
|
196
|
+
M : float
|
|
197
|
+
Black hole mass, in geometrized units.
|
|
198
|
+
r_disk_inner, r_disk_outer : float
|
|
199
|
+
Inner and outer radius of a thin equatorial accretion disk (set
|
|
200
|
+
``r_disk_inner > r_disk_outer`` or both to 0 to omit the disk).
|
|
201
|
+
dphi : float, default=0.01
|
|
202
|
+
Angular step size for the orbital-plane integration.
|
|
203
|
+
n_steps : int, default=3000
|
|
204
|
+
Maximum steps per ray.
|
|
205
|
+
r_horizon_factor : float, default=1.001
|
|
206
|
+
A ray is marked captured once :math:`r` drops below this factor
|
|
207
|
+
times the horizon radius :math:`2M`.
|
|
208
|
+
|
|
209
|
+
Returns
|
|
210
|
+
-------
|
|
211
|
+
outcomes : ndarray of shape (ny, nx), dtype int64
|
|
212
|
+
Per-pixel outcome code (see :data:`OUTCOME_ESCAPED`,
|
|
213
|
+
:data:`OUTCOME_CAPTURED`, :data:`OUTCOME_UNRESOLVED`,
|
|
214
|
+
:data:`OUTCOME_DISK`).
|
|
215
|
+
hit_radii : ndarray of shape (ny, nx)
|
|
216
|
+
Disk-crossing radius for :data:`OUTCOME_DISK` pixels, ``-1``
|
|
217
|
+
elsewhere.
|
|
218
|
+
"""
|
|
219
|
+
outcomes = np.zeros((ny, nx), dtype=np.int64)
|
|
220
|
+
hit_radii = np.full((ny, nx), -1.0)
|
|
221
|
+
for iy in range(ny):
|
|
222
|
+
beta = screen_half_height * (1.0 - 2.0 * iy / (ny - 1))
|
|
223
|
+
for ix in range(nx):
|
|
224
|
+
alpha = screen_half_width * (2.0 * ix / (nx - 1) - 1.0)
|
|
225
|
+
outcome, hit_r = _trace_pixel(
|
|
226
|
+
alpha,
|
|
227
|
+
beta,
|
|
228
|
+
obs_pos,
|
|
229
|
+
right,
|
|
230
|
+
up,
|
|
231
|
+
view_dir,
|
|
232
|
+
M,
|
|
233
|
+
r_disk_inner,
|
|
234
|
+
r_disk_outer,
|
|
235
|
+
dphi,
|
|
236
|
+
n_steps,
|
|
237
|
+
r_horizon_factor,
|
|
238
|
+
)
|
|
239
|
+
outcomes[iy, ix] = outcome
|
|
240
|
+
hit_radii[iy, ix] = hit_r
|
|
241
|
+
return outcomes, hit_radii
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
"""A numerical differential geometry engine for arbitrary 4D spacetimes.
|
|
2
|
+
|
|
3
|
+
Rather than requiring a symbolic algebra system, this module computes
|
|
4
|
+
Christoffel symbols and curvature tensors **numerically**, by finite
|
|
5
|
+
differencing a metric function :math:`g_{\\mu\\nu}(x)` supplied as a plain
|
|
6
|
+
Python callable. This makes it trivial to plug in any metric -- Schwarzschild,
|
|
7
|
+
Kerr, Reissner-Nordstrom, FLRW, even an exotic metric like the Alcubierre
|
|
8
|
+
warp drive -- and get its curvature out, at the cost of some numerical noise
|
|
9
|
+
relative to an exact symbolic computation (typically negligible at the
|
|
10
|
+
default step size for smooth metrics away from coordinate singularities).
|
|
11
|
+
|
|
12
|
+
A metric function has the signature ``g(coords, **params) -> ndarray`` of
|
|
13
|
+
shape ``(4, 4)``, where ``coords`` is a length-4 array of the four spacetime
|
|
14
|
+
coordinates at which to evaluate the metric.
|
|
15
|
+
|
|
16
|
+
Every function in this module follows the :math:`(-,+,+,+)` signature
|
|
17
|
+
convention.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"alcubierre_metric",
|
|
26
|
+
"christoffel_symbols",
|
|
27
|
+
"einstein_tensor",
|
|
28
|
+
"flrw_metric",
|
|
29
|
+
"inverse_metric",
|
|
30
|
+
"kerr_metric_bl",
|
|
31
|
+
"reissner_nordstrom_metric",
|
|
32
|
+
"ricci_scalar",
|
|
33
|
+
"ricci_tensor",
|
|
34
|
+
"riemann_tensor",
|
|
35
|
+
"schwarzschild_metric",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def inverse_metric(metric_func, coords, params=None):
|
|
40
|
+
"""Inverse metric :math:`g^{\\mu\\nu}` at a point.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
metric_func : callable
|
|
45
|
+
A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
|
|
46
|
+
coords : array_like of shape (4,)
|
|
47
|
+
Coordinates at which to evaluate the metric.
|
|
48
|
+
params : dict, optional
|
|
49
|
+
Keyword parameters forwarded to ``metric_func`` (e.g. ``{"M": 1.0}``).
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
ndarray of shape (4, 4)
|
|
54
|
+
The inverse metric :math:`g^{\\mu\\nu}`.
|
|
55
|
+
"""
|
|
56
|
+
params = params or {}
|
|
57
|
+
g = metric_func(coords, **params)
|
|
58
|
+
return np.linalg.inv(g)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def christoffel_symbols(metric_func, coords, params=None, h=1e-6):
|
|
62
|
+
"""Christoffel symbols of the second kind, :math:`\\Gamma^\\mu_{\\alpha\\beta}`.
|
|
63
|
+
|
|
64
|
+
.. math::
|
|
65
|
+
|
|
66
|
+
\\Gamma^\\mu_{\\alpha\\beta} = \\frac{1}{2} g^{\\mu\\nu}
|
|
67
|
+
\\left(\\partial_\\alpha g_{\\nu\\beta} + \\partial_\\beta g_{\\nu\\alpha}
|
|
68
|
+
- \\partial_\\nu g_{\\alpha\\beta}\\right)
|
|
69
|
+
|
|
70
|
+
Metric derivatives are estimated with a central finite difference.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
metric_func : callable
|
|
75
|
+
A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
|
|
76
|
+
coords : array_like of shape (4,)
|
|
77
|
+
Coordinates at which to evaluate the Christoffel symbols.
|
|
78
|
+
params : dict, optional
|
|
79
|
+
Keyword parameters forwarded to ``metric_func``.
|
|
80
|
+
h : float, default=1e-6
|
|
81
|
+
Finite-difference step size.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
ndarray of shape (4, 4, 4)
|
|
86
|
+
``Gamma[mu, alpha, beta]`` :math:`= \\Gamma^\\mu_{\\alpha\\beta}`.
|
|
87
|
+
|
|
88
|
+
Examples
|
|
89
|
+
--------
|
|
90
|
+
>>> coords = np.array([0.0, 10.0, np.pi / 2, 0.0])
|
|
91
|
+
>>> Gamma = christoffel_symbols(schwarzschild_metric, coords, {"M": 1.0})
|
|
92
|
+
>>> Gamma.shape
|
|
93
|
+
(4, 4, 4)
|
|
94
|
+
"""
|
|
95
|
+
params = params or {}
|
|
96
|
+
coords = np.asarray(coords, dtype=np.float64)
|
|
97
|
+
g_inv = inverse_metric(metric_func, coords, params)
|
|
98
|
+
|
|
99
|
+
dg = np.empty((4, 4, 4)) # dg[alpha, mu, nu] = d_alpha g_{mu nu}
|
|
100
|
+
for alpha in range(4):
|
|
101
|
+
shift = np.zeros(4)
|
|
102
|
+
shift[alpha] = h
|
|
103
|
+
g_plus = metric_func(coords + shift, **params)
|
|
104
|
+
g_minus = metric_func(coords - shift, **params)
|
|
105
|
+
dg[alpha] = (g_plus - g_minus) / (2.0 * h)
|
|
106
|
+
|
|
107
|
+
Gamma = np.zeros((4, 4, 4))
|
|
108
|
+
for mu in range(4):
|
|
109
|
+
for alpha in range(4):
|
|
110
|
+
for beta in range(4):
|
|
111
|
+
s = 0.0
|
|
112
|
+
for nu in range(4):
|
|
113
|
+
s += g_inv[mu, nu] * (dg[alpha, nu, beta] + dg[beta, nu, alpha] - dg[nu, alpha, beta])
|
|
114
|
+
Gamma[mu, alpha, beta] = 0.5 * s
|
|
115
|
+
return Gamma
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def riemann_tensor(metric_func, coords, params=None, h=1e-4):
|
|
119
|
+
"""Riemann curvature tensor :math:`R^\\rho{}_{\\sigma\\mu\\nu}`.
|
|
120
|
+
|
|
121
|
+
.. math::
|
|
122
|
+
|
|
123
|
+
R^\\rho{}_{\\sigma\\mu\\nu} = \\partial_\\mu \\Gamma^\\rho_{\\nu\\sigma}
|
|
124
|
+
- \\partial_\\nu \\Gamma^\\rho_{\\mu\\sigma}
|
|
125
|
+
+ \\Gamma^\\rho_{\\mu\\lambda}\\Gamma^\\lambda_{\\nu\\sigma}
|
|
126
|
+
- \\Gamma^\\rho_{\\nu\\lambda}\\Gamma^\\lambda_{\\mu\\sigma}
|
|
127
|
+
|
|
128
|
+
Christoffel derivatives are estimated with a central finite difference of
|
|
129
|
+
:func:`christoffel_symbols` itself, so this involves an effective
|
|
130
|
+
second derivative of the metric; a coarser default step size than
|
|
131
|
+
:func:`christoffel_symbols` is used to balance truncation and
|
|
132
|
+
round-off error.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
metric_func : callable
|
|
137
|
+
A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
|
|
138
|
+
coords : array_like of shape (4,)
|
|
139
|
+
Coordinates at which to evaluate the Riemann tensor.
|
|
140
|
+
params : dict, optional
|
|
141
|
+
Keyword parameters forwarded to ``metric_func``.
|
|
142
|
+
h : float, default=1e-4
|
|
143
|
+
Finite-difference step size.
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
ndarray of shape (4, 4, 4, 4)
|
|
148
|
+
``R[rho, sigma, mu, nu]``.
|
|
149
|
+
"""
|
|
150
|
+
params = params or {}
|
|
151
|
+
coords = np.asarray(coords, dtype=np.float64)
|
|
152
|
+
|
|
153
|
+
dGamma = np.empty((4, 4, 4, 4)) # dGamma[mu, rho, nu, sigma] = d_mu Gamma^rho_{nu sigma}
|
|
154
|
+
for mu in range(4):
|
|
155
|
+
shift = np.zeros(4)
|
|
156
|
+
shift[mu] = h
|
|
157
|
+
G_plus = christoffel_symbols(metric_func, coords + shift, params, h=h * 1e-2)
|
|
158
|
+
G_minus = christoffel_symbols(metric_func, coords - shift, params, h=h * 1e-2)
|
|
159
|
+
dGamma[mu] = (G_plus - G_minus) / (2.0 * h)
|
|
160
|
+
|
|
161
|
+
Gamma = christoffel_symbols(metric_func, coords, params, h=h * 1e-2)
|
|
162
|
+
|
|
163
|
+
R = np.zeros((4, 4, 4, 4))
|
|
164
|
+
for rho in range(4):
|
|
165
|
+
for sigma in range(4):
|
|
166
|
+
for mu in range(4):
|
|
167
|
+
for nu in range(4):
|
|
168
|
+
term = dGamma[mu, rho, nu, sigma] - dGamma[nu, rho, mu, sigma]
|
|
169
|
+
for lam in range(4):
|
|
170
|
+
term += Gamma[rho, mu, lam] * Gamma[lam, nu, sigma]
|
|
171
|
+
term -= Gamma[rho, nu, lam] * Gamma[lam, mu, sigma]
|
|
172
|
+
R[rho, sigma, mu, nu] = term
|
|
173
|
+
return R
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def ricci_tensor(metric_func, coords, params=None, h=1e-4):
|
|
177
|
+
"""Ricci tensor :math:`R_{\\mu\\nu} = R^\\rho{}_{\\mu\\rho\\nu}`, the trace of the Riemann tensor.
|
|
178
|
+
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
metric_func : callable
|
|
182
|
+
A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
|
|
183
|
+
coords : array_like of shape (4,)
|
|
184
|
+
Coordinates at which to evaluate the Ricci tensor.
|
|
185
|
+
params : dict, optional
|
|
186
|
+
Keyword parameters forwarded to ``metric_func``.
|
|
187
|
+
h : float, default=1e-4
|
|
188
|
+
Finite-difference step size, forwarded to :func:`riemann_tensor`.
|
|
189
|
+
|
|
190
|
+
Returns
|
|
191
|
+
-------
|
|
192
|
+
ndarray of shape (4, 4)
|
|
193
|
+
The Ricci tensor :math:`R_{\\mu\\nu}`.
|
|
194
|
+
"""
|
|
195
|
+
R = riemann_tensor(metric_func, coords, params, h=h)
|
|
196
|
+
return np.einsum("rmrn->mn", R)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def ricci_scalar(metric_func, coords, params=None, h=1e-4):
|
|
200
|
+
"""Ricci scalar :math:`R = g^{\\mu\\nu} R_{\\mu\\nu}`.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
metric_func : callable
|
|
205
|
+
A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
|
|
206
|
+
coords : array_like of shape (4,)
|
|
207
|
+
Coordinates at which to evaluate the Ricci scalar.
|
|
208
|
+
params : dict, optional
|
|
209
|
+
Keyword parameters forwarded to ``metric_func``.
|
|
210
|
+
h : float, default=1e-4
|
|
211
|
+
Finite-difference step size, forwarded to :func:`riemann_tensor`.
|
|
212
|
+
|
|
213
|
+
Returns
|
|
214
|
+
-------
|
|
215
|
+
float
|
|
216
|
+
The Ricci scalar :math:`R`.
|
|
217
|
+
"""
|
|
218
|
+
params = params or {}
|
|
219
|
+
g_inv = inverse_metric(metric_func, coords, params)
|
|
220
|
+
Ric = ricci_tensor(metric_func, coords, params, h=h)
|
|
221
|
+
return float(np.einsum("mn,mn->", g_inv, Ric))
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def einstein_tensor(metric_func, coords, params=None, h=1e-4):
|
|
225
|
+
"""Einstein tensor :math:`G_{\\mu\\nu} = R_{\\mu\\nu} - \\frac{1}{2} R g_{\\mu\\nu}`.
|
|
226
|
+
|
|
227
|
+
In vacuum, Einstein's field equations require :math:`G_{\\mu\\nu} = 0`;
|
|
228
|
+
evaluating this on the Schwarzschild metric and finding it numerically
|
|
229
|
+
close to zero is a good sanity check of both the metric and this
|
|
230
|
+
finite-difference curvature engine (see the Examples).
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
metric_func : callable
|
|
235
|
+
A metric function ``g(coords, **params) -> ndarray`` of shape (4, 4).
|
|
236
|
+
coords : array_like of shape (4,)
|
|
237
|
+
Coordinates at which to evaluate the Einstein tensor.
|
|
238
|
+
params : dict, optional
|
|
239
|
+
Keyword parameters forwarded to ``metric_func``.
|
|
240
|
+
h : float, default=1e-4
|
|
241
|
+
Finite-difference step size, forwarded to :func:`riemann_tensor`.
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
ndarray of shape (4, 4)
|
|
246
|
+
The Einstein tensor :math:`G_{\\mu\\nu}`.
|
|
247
|
+
|
|
248
|
+
Examples
|
|
249
|
+
--------
|
|
250
|
+
>>> coords = np.array([0.0, 10.0, np.pi / 2, 0.0])
|
|
251
|
+
>>> G = einstein_tensor(schwarzschild_metric, coords, {"M": 1.0})
|
|
252
|
+
>>> bool(np.max(np.abs(G)) < 1e-2)
|
|
253
|
+
True
|
|
254
|
+
"""
|
|
255
|
+
params = params or {}
|
|
256
|
+
g = metric_func(coords, **params)
|
|
257
|
+
Ric = ricci_tensor(metric_func, coords, params, h=h)
|
|
258
|
+
R = ricci_scalar(metric_func, coords, params, h=h)
|
|
259
|
+
return Ric - 0.5 * R * g
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# ---------------------------------------------------------------------------
|
|
263
|
+
# Standard metrics
|
|
264
|
+
# ---------------------------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def schwarzschild_metric(coords, M=1.0):
|
|
268
|
+
"""The Schwarzschild metric in Schwarzschild coordinates :math:`(t, r, \\theta, \\phi)`.
|
|
269
|
+
|
|
270
|
+
.. math::
|
|
271
|
+
|
|
272
|
+
ds^2 = -\\left(1 - \\frac{2M}{r}\\right) dt^2
|
|
273
|
+
+ \\left(1 - \\frac{2M}{r}\\right)^{-1} dr^2
|
|
274
|
+
+ r^2 d\\theta^2 + r^2 \\sin^2\\theta \\, d\\phi^2
|
|
275
|
+
|
|
276
|
+
Parameters
|
|
277
|
+
----------
|
|
278
|
+
coords : array_like of shape (4,)
|
|
279
|
+
Coordinates :math:`(t, r, \\theta, \\phi)`.
|
|
280
|
+
M : float, default=1.0
|
|
281
|
+
Black hole mass, in geometrized units.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
ndarray of shape (4, 4)
|
|
286
|
+
The metric tensor :math:`g_{\\mu\\nu}`.
|
|
287
|
+
"""
|
|
288
|
+
_t, r, theta, _phi = coords
|
|
289
|
+
f = 1.0 - 2.0 * M / r
|
|
290
|
+
g = np.zeros((4, 4))
|
|
291
|
+
g[0, 0] = -f
|
|
292
|
+
g[1, 1] = 1.0 / f
|
|
293
|
+
g[2, 2] = r**2
|
|
294
|
+
g[3, 3] = r**2 * np.sin(theta) ** 2
|
|
295
|
+
return g
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def kerr_metric_bl(coords, M=1.0, a=0.0):
|
|
299
|
+
"""The Kerr metric in Boyer-Lindquist coordinates :math:`(t, r, \\theta, \\phi)`.
|
|
300
|
+
|
|
301
|
+
.. math::
|
|
302
|
+
|
|
303
|
+
ds^2 = -\\left(1 - \\frac{2Mr}{\\Sigma}\\right) dt^2
|
|
304
|
+
- \\frac{4Mar\\sin^2\\theta}{\\Sigma} dt\\, d\\phi
|
|
305
|
+
+ \\frac{\\Sigma}{\\Delta} dr^2 + \\Sigma\\, d\\theta^2
|
|
306
|
+
+ \\left(r^2 + a^2 + \\frac{2Ma^2 r \\sin^2\\theta}{\\Sigma}\\right)
|
|
307
|
+
\\sin^2\\theta \\, d\\phi^2
|
|
308
|
+
|
|
309
|
+
with :math:`\\Sigma = r^2 + a^2\\cos^2\\theta` and
|
|
310
|
+
:math:`\\Delta = r^2 - 2Mr + a^2`.
|
|
311
|
+
|
|
312
|
+
Parameters
|
|
313
|
+
----------
|
|
314
|
+
coords : array_like of shape (4,)
|
|
315
|
+
Coordinates :math:`(t, r, \\theta, \\phi)`.
|
|
316
|
+
M : float, default=1.0
|
|
317
|
+
Black hole mass, in geometrized units.
|
|
318
|
+
a : float, default=0.0
|
|
319
|
+
Spin parameter :math:`a = J/M`, with :math:`0 \\le a < M`.
|
|
320
|
+
``a=0`` recovers the Schwarzschild metric.
|
|
321
|
+
|
|
322
|
+
Returns
|
|
323
|
+
-------
|
|
324
|
+
ndarray of shape (4, 4)
|
|
325
|
+
The metric tensor :math:`g_{\\mu\\nu}`.
|
|
326
|
+
"""
|
|
327
|
+
_t, r, theta, _phi = coords
|
|
328
|
+
sin2 = np.sin(theta) ** 2
|
|
329
|
+
Sigma = r**2 + a**2 * np.cos(theta) ** 2
|
|
330
|
+
Delta = r**2 - 2.0 * M * r + a**2
|
|
331
|
+
|
|
332
|
+
g = np.zeros((4, 4))
|
|
333
|
+
g[0, 0] = -(1.0 - 2.0 * M * r / Sigma)
|
|
334
|
+
g[0, 3] = g[3, 0] = -2.0 * M * a * r * sin2 / Sigma
|
|
335
|
+
g[1, 1] = Sigma / Delta
|
|
336
|
+
g[2, 2] = Sigma
|
|
337
|
+
g[3, 3] = (r**2 + a**2 + 2.0 * M * a**2 * r * sin2 / Sigma) * sin2
|
|
338
|
+
return g
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def reissner_nordstrom_metric(coords, M=1.0, Q=0.0):
|
|
342
|
+
"""The Reissner-Nordstrom metric of a charged, non-rotating black hole.
|
|
343
|
+
|
|
344
|
+
.. math::
|
|
345
|
+
|
|
346
|
+
ds^2 = -\\left(1 - \\frac{2M}{r} + \\frac{Q^2}{r^2}\\right) dt^2
|
|
347
|
+
+ \\left(1 - \\frac{2M}{r} + \\frac{Q^2}{r^2}\\right)^{-1} dr^2
|
|
348
|
+
+ r^2 d\\theta^2 + r^2 \\sin^2\\theta \\, d\\phi^2
|
|
349
|
+
|
|
350
|
+
Parameters
|
|
351
|
+
----------
|
|
352
|
+
coords : array_like of shape (4,)
|
|
353
|
+
Coordinates :math:`(t, r, \\theta, \\phi)`.
|
|
354
|
+
M : float, default=1.0
|
|
355
|
+
Mass, in geometrized units.
|
|
356
|
+
Q : float, default=0.0
|
|
357
|
+
Electric charge, in geometrized units (``Q=0`` recovers Schwarzschild).
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
ndarray of shape (4, 4)
|
|
362
|
+
The metric tensor :math:`g_{\\mu\\nu}`.
|
|
363
|
+
"""
|
|
364
|
+
_t, r, theta, _phi = coords
|
|
365
|
+
f = 1.0 - 2.0 * M / r + Q**2 / r**2
|
|
366
|
+
g = np.zeros((4, 4))
|
|
367
|
+
g[0, 0] = -f
|
|
368
|
+
g[1, 1] = 1.0 / f
|
|
369
|
+
g[2, 2] = r**2
|
|
370
|
+
g[3, 3] = r**2 * np.sin(theta) ** 2
|
|
371
|
+
return g
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def flrw_metric(coords, a_func, k=0.0):
|
|
375
|
+
"""The FLRW metric in comoving spherical coordinates :math:`(t, \\chi, \\theta, \\phi)`.
|
|
376
|
+
|
|
377
|
+
.. math::
|
|
378
|
+
|
|
379
|
+
ds^2 = -dt^2 + a(t)^2 \\left[d\\chi^2 + S_k(\\chi)^2 d\\Omega^2\\right]
|
|
380
|
+
|
|
381
|
+
where :math:`S_k(\\chi) = \\chi` for a flat universe (:math:`k=0`),
|
|
382
|
+
:math:`\\sin\\chi` for a closed universe (:math:`k=+1`), and
|
|
383
|
+
:math:`\\sinh\\chi` for an open universe (:math:`k=-1`).
|
|
384
|
+
|
|
385
|
+
Parameters
|
|
386
|
+
----------
|
|
387
|
+
coords : array_like of shape (4,)
|
|
388
|
+
Coordinates :math:`(t, \\chi, \\theta, \\phi)`.
|
|
389
|
+
a_func : callable
|
|
390
|
+
The scale factor as a function of cosmic time, ``a_func(t) -> float``.
|
|
391
|
+
k : {-1, 0, 1}, default=0.0
|
|
392
|
+
Spatial curvature sign.
|
|
393
|
+
|
|
394
|
+
Returns
|
|
395
|
+
-------
|
|
396
|
+
ndarray of shape (4, 4)
|
|
397
|
+
The metric tensor :math:`g_{\\mu\\nu}`.
|
|
398
|
+
"""
|
|
399
|
+
t, chi, theta, _phi = coords
|
|
400
|
+
a = a_func(t)
|
|
401
|
+
if k == 0:
|
|
402
|
+
Sk = chi
|
|
403
|
+
elif k > 0:
|
|
404
|
+
Sk = np.sin(chi)
|
|
405
|
+
else:
|
|
406
|
+
Sk = np.sinh(chi)
|
|
407
|
+
|
|
408
|
+
g = np.zeros((4, 4))
|
|
409
|
+
g[0, 0] = -1.0
|
|
410
|
+
g[1, 1] = a**2
|
|
411
|
+
g[2, 2] = a**2 * Sk**2
|
|
412
|
+
g[3, 3] = a**2 * Sk**2 * np.sin(theta) ** 2
|
|
413
|
+
return g
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def alcubierre_metric(coords, v_s=2.0, sigma=8.0, R=1.0):
|
|
417
|
+
"""The Alcubierre "warp drive" metric in Cartesian coordinates :math:`(t, x, y, z)`.
|
|
418
|
+
|
|
419
|
+
.. math::
|
|
420
|
+
|
|
421
|
+
ds^2 = -dt^2 + \\left[dx - v_s(t) f(r_s) \\, dt\\right]^2 + dy^2 + dz^2
|
|
422
|
+
|
|
423
|
+
where :math:`r_s = \\sqrt{(x - x_s(t))^2 + y^2 + z^2}` is the distance
|
|
424
|
+
from the center of the "warp bubble" (moving along :math:`x` at
|
|
425
|
+
coordinate speed :math:`v_s`, with :math:`x_s(t) = v_s t`), and
|
|
426
|
+
|
|
427
|
+
.. math::
|
|
428
|
+
|
|
429
|
+
f(r_s) = \\frac{\\tanh(\\sigma(r_s + R)) - \\tanh(\\sigma(r_s - R))}
|
|
430
|
+
{2 \\tanh(\\sigma R)}
|
|
431
|
+
|
|
432
|
+
is a smooth top-hat function equal to 1 well inside the bubble
|
|
433
|
+
(:math:`r_s \\ll R`) and 0 far outside it. Spacetime is flat both inside
|
|
434
|
+
and outside the thin bubble wall, but a ship riding inside can traverse
|
|
435
|
+
coordinate distance faster than light as measured by a distant observer
|
|
436
|
+
-- entirely by locally contracting spacetime ahead of it and expanding
|
|
437
|
+
spacetime behind, without ever locally exceeding the speed of light.
|
|
438
|
+
Known solutions like this one require exotic (negative-energy-density)
|
|
439
|
+
matter to source them via Einstein's equations.
|
|
440
|
+
|
|
441
|
+
Parameters
|
|
442
|
+
----------
|
|
443
|
+
coords : array_like of shape (4,)
|
|
444
|
+
Coordinates :math:`(t, x, y, z)`.
|
|
445
|
+
v_s : float, default=2.0
|
|
446
|
+
Coordinate warp speed, in units of :math:`c`.
|
|
447
|
+
sigma : float, default=8.0
|
|
448
|
+
Bubble wall steepness.
|
|
449
|
+
R : float, default=1.0
|
|
450
|
+
Bubble radius, in geometrized length units.
|
|
451
|
+
|
|
452
|
+
Returns
|
|
453
|
+
-------
|
|
454
|
+
ndarray of shape (4, 4)
|
|
455
|
+
The metric tensor :math:`g_{\\mu\\nu}`.
|
|
456
|
+
"""
|
|
457
|
+
t, x, y, z = coords
|
|
458
|
+
x_s = v_s * t
|
|
459
|
+
r_s = np.sqrt((x - x_s) ** 2 + y**2 + z**2)
|
|
460
|
+
f = (np.tanh(sigma * (r_s + R)) - np.tanh(sigma * (r_s - R))) / (2.0 * np.tanh(sigma * R))
|
|
461
|
+
|
|
462
|
+
g = np.zeros((4, 4))
|
|
463
|
+
g[0, 0] = v_s**2 * f**2 - 1.0
|
|
464
|
+
g[0, 1] = g[1, 0] = -v_s * f
|
|
465
|
+
g[1, 1] = 1.0
|
|
466
|
+
g[2, 2] = 1.0
|
|
467
|
+
g[3, 3] = 1.0
|
|
468
|
+
return g
|
|
File without changes
|