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,149 @@
|
|
|
1
|
+
"""Neutron star structure: the Tolman-Oppenheimer-Volkoff equations.
|
|
2
|
+
|
|
3
|
+
A black hole is not the only fate of a massive star's core: below about
|
|
4
|
+
:math:`3 M_\\odot`, degenerate neutron pressure can halt gravitational
|
|
5
|
+
collapse entirely, leaving behind a neutron star -- matter compressed to
|
|
6
|
+
nuclear density and held up against its own gravity by quantum degeneracy
|
|
7
|
+
pressure. Oppenheimer and Volkoff (1939), building on Tolman's earlier work,
|
|
8
|
+
derived the relativistic generalization of the Newtonian hydrostatic
|
|
9
|
+
equilibrium equation for a self-gravitating fluid sphere. Unlike the
|
|
10
|
+
Newtonian case, the TOV equation predicts a maximum possible neutron star
|
|
11
|
+
mass: add too much matter and pressure alone can no longer resist collapse,
|
|
12
|
+
regardless of the equation of state -- the star must become a black hole.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from scipy.integrate import solve_ivp
|
|
19
|
+
|
|
20
|
+
__all__ = ["NeutronStar"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class NeutronStar:
|
|
24
|
+
"""A neutron star modeled with a polytropic equation of state, solved via the TOV equations.
|
|
25
|
+
|
|
26
|
+
The equation of state is the polytrope :math:`P = K \\rho_0^\\Gamma`
|
|
27
|
+
relating pressure to rest-mass density; the total energy density
|
|
28
|
+
(rest mass plus internal energy) used as the gravitational source is
|
|
29
|
+
:math:`\\varepsilon = \\rho_0 + P/(\\Gamma - 1)`. All quantities are in
|
|
30
|
+
geometrized units; ``K`` and ``Gamma`` are illustrative "toy" parameters
|
|
31
|
+
unless calibrated to a specific realistic equation of state.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
K : float, default=100.0
|
|
36
|
+
Polytropic constant.
|
|
37
|
+
Gamma : float, default=2.0
|
|
38
|
+
Polytropic index (:math:`\\Gamma = 2` is a common toy choice
|
|
39
|
+
loosely representative of nuclear matter).
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(self, K=100.0, Gamma=2.0):
|
|
43
|
+
self.K = K
|
|
44
|
+
self.Gamma = Gamma
|
|
45
|
+
|
|
46
|
+
def energy_density(self, pressure):
|
|
47
|
+
"""Total energy density :math:`\\varepsilon(P) = (P/K)^{1/\\Gamma} + P/(\\Gamma-1)`.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
pressure : float or array_like
|
|
52
|
+
Pressure.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
float or ndarray
|
|
57
|
+
"""
|
|
58
|
+
pressure = np.asarray(pressure, dtype=np.float64)
|
|
59
|
+
rest_mass_density = (pressure / self.K) ** (1.0 / self.Gamma)
|
|
60
|
+
return rest_mass_density + pressure / (self.Gamma - 1.0)
|
|
61
|
+
|
|
62
|
+
def _tov_rhs(self, r, y):
|
|
63
|
+
m, P = y
|
|
64
|
+
if P <= 0.0:
|
|
65
|
+
return [0.0, 0.0]
|
|
66
|
+
eps = self.energy_density(P)
|
|
67
|
+
dm_dr = 4.0 * np.pi * r**2 * eps
|
|
68
|
+
dP_dr = -(eps + P) * (m + 4.0 * np.pi * r**3 * P) / (r * (r - 2.0 * m))
|
|
69
|
+
return [dm_dr, dP_dr]
|
|
70
|
+
|
|
71
|
+
def solve(self, central_density, r_max=50.0, r_start=1.0e-6):
|
|
72
|
+
"""Integrate the TOV equations outward from the center to the stellar surface.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
central_density : float
|
|
77
|
+
Central rest-mass density :math:`\\rho_0(0)`.
|
|
78
|
+
r_max : float, default=50.0
|
|
79
|
+
Outer integration bound (should exceed any physically expected
|
|
80
|
+
stellar radius for the given equation of state).
|
|
81
|
+
r_start : float, default=1e-6
|
|
82
|
+
Small starting radius (avoids the coordinate singularity at
|
|
83
|
+
exactly :math:`r=0`).
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
mass : float
|
|
88
|
+
Total gravitational mass :math:`M`, read off where the pressure
|
|
89
|
+
drops to (numerically) zero -- the stellar surface.
|
|
90
|
+
radius : float
|
|
91
|
+
Stellar radius :math:`R`.
|
|
92
|
+
solution : scipy.integrate.OdeSolution
|
|
93
|
+
The full ``solve_ivp`` result, for inspecting the interior
|
|
94
|
+
profile.
|
|
95
|
+
|
|
96
|
+
Examples
|
|
97
|
+
--------
|
|
98
|
+
>>> star = NeutronStar(K=100.0, Gamma=2.0)
|
|
99
|
+
>>> M, R, sol = star.solve(central_density=1.28e-3)
|
|
100
|
+
>>> bool(M > 0.0 and R > 0.0)
|
|
101
|
+
True
|
|
102
|
+
"""
|
|
103
|
+
pressure_central = self.K * central_density**self.Gamma
|
|
104
|
+
|
|
105
|
+
def surface_event(r, y):
|
|
106
|
+
return y[1] - 1.0e-10 * pressure_central
|
|
107
|
+
|
|
108
|
+
surface_event.terminal = True
|
|
109
|
+
surface_event.direction = -1
|
|
110
|
+
|
|
111
|
+
solution = solve_ivp(
|
|
112
|
+
self._tov_rhs,
|
|
113
|
+
[r_start, r_max],
|
|
114
|
+
[0.0, pressure_central],
|
|
115
|
+
events=surface_event,
|
|
116
|
+
dense_output=True,
|
|
117
|
+
max_step=0.01,
|
|
118
|
+
rtol=1.0e-8,
|
|
119
|
+
atol=1.0e-14,
|
|
120
|
+
)
|
|
121
|
+
radius = solution.t[-1]
|
|
122
|
+
mass = solution.y[0, -1]
|
|
123
|
+
return mass, radius, solution
|
|
124
|
+
|
|
125
|
+
def mass_radius_curve(self, central_densities):
|
|
126
|
+
"""Trace the mass-radius relation over a range of central densities.
|
|
127
|
+
|
|
128
|
+
The existence of a maximum mass (a turning point in :math:`M` as a
|
|
129
|
+
function of central density, beyond which increasing the central
|
|
130
|
+
density *decreases* the stable mass) is the TOV equation's central
|
|
131
|
+
physical prediction.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
central_densities : array_like
|
|
136
|
+
Central densities to sample.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
masses : ndarray
|
|
141
|
+
radii : ndarray
|
|
142
|
+
"""
|
|
143
|
+
masses = np.empty(len(central_densities))
|
|
144
|
+
radii = np.empty(len(central_densities))
|
|
145
|
+
for i, rho_c in enumerate(central_densities):
|
|
146
|
+
M, R, _ = self.solve(rho_c)
|
|
147
|
+
masses[i] = M
|
|
148
|
+
radii[i] = R
|
|
149
|
+
return masses, radii
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"""The Schwarzschild black hole: orbits, precession, light bending, and the photon sphere.
|
|
2
|
+
|
|
3
|
+
The Schwarzschild solution -- the first exact solution to Einstein's field
|
|
4
|
+
equations, found by Karl Schwarzschild in 1916 while serving on the Russian
|
|
5
|
+
front, just weeks after Einstein published General Relativity -- describes
|
|
6
|
+
the spacetime around any non-rotating, uncharged spherical mass. It predicts
|
|
7
|
+
three of GR's classic observational triumphs: the anomalous perihelion
|
|
8
|
+
precession of Mercury, the bending of starlight grazing the Sun (confirmed
|
|
9
|
+
by Eddington's 1919 eclipse expedition), and the Shapiro time delay of radar
|
|
10
|
+
signals passing near the Sun.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from physicskit.relativity.core.geodesics import integrate_schwarzschild_geodesic
|
|
18
|
+
|
|
19
|
+
__all__ = ["SchwarzschildBlackHole"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SchwarzschildBlackHole:
|
|
23
|
+
"""A non-rotating black hole (or any spherical mass) of mass ``M``, in geometrized units.
|
|
24
|
+
|
|
25
|
+
Parameters
|
|
26
|
+
----------
|
|
27
|
+
M : float, default=1.0
|
|
28
|
+
Mass, in geometrized length units (:math:`GM/c^2`). Use
|
|
29
|
+
:func:`physicskit.relativity.utils.constants.solar_masses_to_geometrized`
|
|
30
|
+
to convert from a physical mass in solar masses.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, M=1.0):
|
|
34
|
+
self.M = M
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def horizon_radius(self):
|
|
38
|
+
"""Event horizon radius, :math:`r_s = 2M`."""
|
|
39
|
+
return 2.0 * self.M
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def photon_sphere_radius(self):
|
|
43
|
+
"""Photon sphere radius, :math:`r_{ph} = 3M`."""
|
|
44
|
+
return 3.0 * self.M
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def isco_radius(self):
|
|
48
|
+
"""Innermost stable circular orbit radius, :math:`r_{\\text{ISCO}} = 6M`."""
|
|
49
|
+
return 6.0 * self.M
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def critical_impact_parameter(self):
|
|
53
|
+
"""Critical photon impact parameter, :math:`b_c = 3\\sqrt{3}\\,M`."""
|
|
54
|
+
return 3.0 * np.sqrt(3.0) * self.M
|
|
55
|
+
|
|
56
|
+
def circular_orbit_angular_velocity(self, r):
|
|
57
|
+
"""Coordinate angular velocity :math:`\\Omega = d\\phi/dt` of a circular timelike orbit.
|
|
58
|
+
|
|
59
|
+
Exactly Keplerian in Schwarzschild coordinates:
|
|
60
|
+
:math:`\\Omega = \\sqrt{M/r^3}`.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
r : float
|
|
65
|
+
Orbital radius.
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
float
|
|
70
|
+
"""
|
|
71
|
+
return np.sqrt(self.M / r**3)
|
|
72
|
+
|
|
73
|
+
def circular_orbit_initial_state(self, r0):
|
|
74
|
+
"""Initial 8-component state for a circular, equatorial, timelike orbit at radius ``r0``.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
r0 : float
|
|
79
|
+
Orbital radius. Should exceed :attr:`isco_radius` for the orbit
|
|
80
|
+
to be stable.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
ndarray of shape (8,)
|
|
85
|
+
:math:`(t, r, \\theta, \\phi, u^t, u^r, u^\\theta, u^\\phi)` at
|
|
86
|
+
:math:`\\tau = 0`.
|
|
87
|
+
"""
|
|
88
|
+
M = self.M
|
|
89
|
+
f = 1.0 - 2.0 * M / r0
|
|
90
|
+
Omega = self.circular_orbit_angular_velocity(r0)
|
|
91
|
+
ut = 1.0 / np.sqrt(f - r0**2 * Omega**2)
|
|
92
|
+
uphi = Omega * ut
|
|
93
|
+
return np.array([0.0, r0, np.pi / 2.0, 0.0, ut, 0.0, 0.0, uphi])
|
|
94
|
+
|
|
95
|
+
def eccentric_orbit_initial_state(self, r0, eccentricity_boost=0.0):
|
|
96
|
+
"""Initial state for a bound, generally eccentric equatorial timelike orbit.
|
|
97
|
+
|
|
98
|
+
Starts at radius ``r0`` (taken as the initial apoapsis) with purely
|
|
99
|
+
tangential velocity reduced below the circular value by
|
|
100
|
+
``eccentricity_boost``, producing a radially oscillating (rosette,
|
|
101
|
+
precessing) orbit for ``eccentricity_boost > 0``.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
r0 : float
|
|
106
|
+
Starting radius (apoapsis).
|
|
107
|
+
eccentricity_boost : float, default=0.0
|
|
108
|
+
Fractional reduction of the tangential velocity relative to the
|
|
109
|
+
circular orbit at ``r0``; ``0`` gives a circular orbit, larger
|
|
110
|
+
values give more eccentric orbits.
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
ndarray of shape (8,)
|
|
115
|
+
Initial state, as in :meth:`circular_orbit_initial_state`.
|
|
116
|
+
"""
|
|
117
|
+
M = self.M
|
|
118
|
+
f = 1.0 - 2.0 * M / r0
|
|
119
|
+
Omega = self.circular_orbit_angular_velocity(r0) * (1.0 - eccentricity_boost)
|
|
120
|
+
ut = 1.0 / np.sqrt(f - r0**2 * Omega**2)
|
|
121
|
+
uphi = Omega * ut
|
|
122
|
+
return np.array([0.0, r0, np.pi / 2.0, 0.0, ut, 0.0, 0.0, uphi])
|
|
123
|
+
|
|
124
|
+
def null_geodesic_initial_state(self, r0, impact_parameter, ingoing=True):
|
|
125
|
+
"""Initial state for an equatorial null (photon) geodesic with a given impact parameter.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
r0 : float
|
|
130
|
+
Starting radius.
|
|
131
|
+
impact_parameter : float
|
|
132
|
+
Impact parameter :math:`b = L/E`.
|
|
133
|
+
ingoing : bool, default=True
|
|
134
|
+
Whether the photon starts moving toward decreasing :math:`r`.
|
|
135
|
+
|
|
136
|
+
Returns
|
|
137
|
+
-------
|
|
138
|
+
ndarray of shape (8,)
|
|
139
|
+
Initial state with :math:`E = 1` (an affine-parameter
|
|
140
|
+
normalization choice; only the ratio :math:`b` is physical).
|
|
141
|
+
"""
|
|
142
|
+
M = self.M
|
|
143
|
+
f = 1.0 - 2.0 * M / r0
|
|
144
|
+
E = 1.0
|
|
145
|
+
L = impact_parameter * E
|
|
146
|
+
ut = E / f
|
|
147
|
+
uphi = L / r0**2
|
|
148
|
+
radicand = E**2 - f * L**2 / r0**2
|
|
149
|
+
ur = -np.sqrt(max(radicand, 0.0)) if ingoing else np.sqrt(max(radicand, 0.0))
|
|
150
|
+
return np.array([0.0, r0, np.pi / 2.0, 0.0, ut, ur, 0.0, uphi])
|
|
151
|
+
|
|
152
|
+
def integrate_geodesic(self, y0, dtau, n_steps):
|
|
153
|
+
"""Integrate a geodesic from initial state ``y0`` via fixed-step RK4.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
y0 : ndarray of shape (8,)
|
|
158
|
+
Initial state, e.g. from :meth:`circular_orbit_initial_state`,
|
|
159
|
+
:meth:`eccentric_orbit_initial_state`, or
|
|
160
|
+
:meth:`null_geodesic_initial_state`.
|
|
161
|
+
dtau : float
|
|
162
|
+
Affine-parameter (or proper-time) step size.
|
|
163
|
+
n_steps : int
|
|
164
|
+
Maximum number of steps.
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
dict of str -> ndarray
|
|
169
|
+
Keys ``"t"``, ``"r"``, ``"theta"``, ``"phi"``, ``"ut"``,
|
|
170
|
+
``"ur"``, ``"utheta"``, ``"uphi"``, each a 1D array over the
|
|
171
|
+
(trimmed) trajectory, plus ``"energy"`` and
|
|
172
|
+
``"angular_momentum"``: the conserved
|
|
173
|
+
:math:`E = -u_t = (1-2M/r) u^t` and
|
|
174
|
+
:math:`L = u_\\phi = r^2 \\sin^2\\theta \\, u^\\phi` evaluated
|
|
175
|
+
at every step (constant along an exact geodesic; their spread
|
|
176
|
+
measures integration error).
|
|
177
|
+
|
|
178
|
+
Examples
|
|
179
|
+
--------
|
|
180
|
+
>>> bh = SchwarzschildBlackHole(M=1.0)
|
|
181
|
+
>>> y0 = bh.circular_orbit_initial_state(r0=10.0)
|
|
182
|
+
>>> traj = bh.integrate_geodesic(y0, dtau=0.01, n_steps=500)
|
|
183
|
+
>>> float(np.std(traj["energy"])) < 1e-6
|
|
184
|
+
True
|
|
185
|
+
"""
|
|
186
|
+
trajectory, n_valid = integrate_schwarzschild_geodesic(y0, self.M, dtau, n_steps)
|
|
187
|
+
trajectory = trajectory[: n_valid + 1]
|
|
188
|
+
t, r, theta, phi, ut, ur, uth, uphi = trajectory.T
|
|
189
|
+
f = 1.0 - 2.0 * self.M / r
|
|
190
|
+
energy = f * ut
|
|
191
|
+
ang_mom = r**2 * np.sin(theta) ** 2 * uphi
|
|
192
|
+
return {
|
|
193
|
+
"t": t,
|
|
194
|
+
"r": r,
|
|
195
|
+
"theta": theta,
|
|
196
|
+
"phi": phi,
|
|
197
|
+
"ut": ut,
|
|
198
|
+
"ur": ur,
|
|
199
|
+
"utheta": uth,
|
|
200
|
+
"uphi": uphi,
|
|
201
|
+
"energy": energy,
|
|
202
|
+
"angular_momentum": ang_mom,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
def perihelion_precession(self, trajectory):
|
|
206
|
+
"""Measure the apsidal (perihelion) precession per orbit from an integrated trajectory.
|
|
207
|
+
|
|
208
|
+
Locates successive periapsis passages (local minima of :math:`r(\\lambda)`)
|
|
209
|
+
and returns the excess azimuthal angle swept between them beyond
|
|
210
|
+
:math:`2\\pi`.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
trajectory : dict of str -> ndarray
|
|
215
|
+
Output of :meth:`integrate_geodesic` for an eccentric orbit.
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
ndarray
|
|
220
|
+
Precession (in radians) measured between each pair of
|
|
221
|
+
consecutive periapsis passages found in the trajectory.
|
|
222
|
+
"""
|
|
223
|
+
r = trajectory["r"]
|
|
224
|
+
phi = trajectory["phi"]
|
|
225
|
+
is_min = (r[1:-1] < r[:-2]) & (r[1:-1] < r[2:])
|
|
226
|
+
idx = np.nonzero(is_min)[0] + 1
|
|
227
|
+
if len(idx) < 2:
|
|
228
|
+
return np.array([])
|
|
229
|
+
phi_at_peri = phi[idx]
|
|
230
|
+
delta_phi = np.diff(phi_at_peri)
|
|
231
|
+
return delta_phi - 2.0 * np.pi
|
|
232
|
+
|
|
233
|
+
def weak_field_precession_per_orbit(self, semi_major_axis, eccentricity):
|
|
234
|
+
"""Leading-order post-Newtonian perihelion precession per orbit.
|
|
235
|
+
|
|
236
|
+
.. math::
|
|
237
|
+
|
|
238
|
+
\\Delta\\phi = \\frac{6\\pi M}{a (1 - e^2)}
|
|
239
|
+
|
|
240
|
+
Parameters
|
|
241
|
+
----------
|
|
242
|
+
semi_major_axis : float
|
|
243
|
+
Orbital semi-major axis :math:`a`.
|
|
244
|
+
eccentricity : float
|
|
245
|
+
Orbital eccentricity :math:`e \\in [0, 1)`.
|
|
246
|
+
|
|
247
|
+
Returns
|
|
248
|
+
-------
|
|
249
|
+
float
|
|
250
|
+
Precession per orbit, in radians.
|
|
251
|
+
"""
|
|
252
|
+
return 6.0 * np.pi * self.M / (semi_major_axis * (1.0 - eccentricity**2))
|
|
253
|
+
|
|
254
|
+
def light_deflection_angle(self, impact_parameter):
|
|
255
|
+
"""Leading-order light deflection angle for a photon passing at a given impact parameter.
|
|
256
|
+
|
|
257
|
+
.. math::
|
|
258
|
+
|
|
259
|
+
\\delta\\phi \\approx \\frac{4M}{b}
|
|
260
|
+
|
|
261
|
+
The weak-field (:math:`b \\gg M`) limit of gravitational light
|
|
262
|
+
bending; famously confirmed for starlight grazing the Sun during
|
|
263
|
+
the 1919 solar eclipse.
|
|
264
|
+
|
|
265
|
+
Parameters
|
|
266
|
+
----------
|
|
267
|
+
impact_parameter : float
|
|
268
|
+
Impact parameter :math:`b`.
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
float
|
|
273
|
+
Deflection angle, in radians.
|
|
274
|
+
"""
|
|
275
|
+
return 4.0 * self.M / impact_parameter
|
|
276
|
+
|
|
277
|
+
def shapiro_delay(self, r1, r2, impact_parameter):
|
|
278
|
+
"""Shapiro (gravitational) time delay for light passing between two radii.
|
|
279
|
+
|
|
280
|
+
.. math::
|
|
281
|
+
|
|
282
|
+
\\Delta t = 2M \\ln\\left[
|
|
283
|
+
\\frac{\\left(r_1 + \\sqrt{r_1^2 - b^2}\\right)
|
|
284
|
+
\\left(r_2 + \\sqrt{r_2^2 - b^2}\\right)}{b^2}
|
|
285
|
+
\\right]
|
|
286
|
+
|
|
287
|
+
The excess light-travel time (beyond flat-spacetime expectations)
|
|
288
|
+
caused by spacetime curvature, first measured via radar ranging to
|
|
289
|
+
Venus and the Viking Mars landers.
|
|
290
|
+
|
|
291
|
+
Parameters
|
|
292
|
+
----------
|
|
293
|
+
r1, r2 : float
|
|
294
|
+
Radial coordinates of the two endpoints (e.g. Earth and a
|
|
295
|
+
reflecting planet or spacecraft).
|
|
296
|
+
impact_parameter : float
|
|
297
|
+
Closest approach distance of the light path to the mass.
|
|
298
|
+
|
|
299
|
+
Returns
|
|
300
|
+
-------
|
|
301
|
+
float
|
|
302
|
+
Time delay, in geometrized time units (length; divide by
|
|
303
|
+
:data:`physicskit.relativity.utils.constants.C_SI` for seconds).
|
|
304
|
+
"""
|
|
305
|
+
b = impact_parameter
|
|
306
|
+
term1 = r1 + np.sqrt(r1**2 - b**2)
|
|
307
|
+
term2 = r2 + np.sqrt(r2**2 - b**2)
|
|
308
|
+
return 2.0 * self.M * np.log(term1 * term2 / b**2)
|
|
309
|
+
|
|
310
|
+
def effective_potential(self, r, L):
|
|
311
|
+
"""Effective potential for equatorial timelike orbits, :math:`V_{\\text{eff}}(r) = (1-2M/r)(1+L^2/r^2)`.
|
|
312
|
+
|
|
313
|
+
Radial motion obeys :math:`(dr/d\\tau)^2 = E^2 - V_{\\text{eff}}(r)`.
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
r : float or array_like
|
|
318
|
+
Radial coordinate(s).
|
|
319
|
+
L : float
|
|
320
|
+
Specific angular momentum.
|
|
321
|
+
|
|
322
|
+
Returns
|
|
323
|
+
-------
|
|
324
|
+
float or ndarray
|
|
325
|
+
"""
|
|
326
|
+
r = np.asarray(r, dtype=np.float64)
|
|
327
|
+
return (1.0 - 2.0 * self.M / r) * (1.0 + L**2 / r**2)
|
|
328
|
+
|
|
329
|
+
def disk_redshift_factor(self, r, impact_parameter):
|
|
330
|
+
"""Combined gravitational + Doppler redshift factor for a circularly orbiting disk emitter.
|
|
331
|
+
|
|
332
|
+
For a photon with impact parameter :math:`b = L_{\\text{ph}}/E_{\\text{ph}}`
|
|
333
|
+
received from gas in a circular Keplerian orbit at radius :math:`r`,
|
|
334
|
+
the ratio of observed to emitted photon energy is
|
|
335
|
+
|
|
336
|
+
.. math::
|
|
337
|
+
|
|
338
|
+
g = \\frac{E_{\\text{obs}}}{E_{\\text{emit}}}
|
|
339
|
+
= \\frac{1}{u^t(r)\\left[1 - b\\,\\Omega(r)\\right]}
|
|
340
|
+
|
|
341
|
+
where :math:`u^t(r) = 1/\\sqrt{f(r) - r^2\\Omega(r)^2}` is the
|
|
342
|
+
emitter's time dilation factor and :math:`\\Omega(r) =
|
|
343
|
+
\\sqrt{M/r^3}` its orbital angular velocity (see
|
|
344
|
+
:meth:`circular_orbit_angular_velocity`). :math:`g < 1` is redshifted
|
|
345
|
+
(gravity, or the far/receding side of the disk); :math:`g > 1` is
|
|
346
|
+
blueshifted (the near/approaching side, when Doppler beaming wins).
|
|
347
|
+
|
|
348
|
+
Parameters
|
|
349
|
+
----------
|
|
350
|
+
r : float or array_like
|
|
351
|
+
Disk radius at emission.
|
|
352
|
+
impact_parameter : float or array_like
|
|
353
|
+
The received photon's impact parameter :math:`b`.
|
|
354
|
+
|
|
355
|
+
Returns
|
|
356
|
+
-------
|
|
357
|
+
float or ndarray
|
|
358
|
+
The redshift factor :math:`g`.
|
|
359
|
+
"""
|
|
360
|
+
r = np.asarray(r, dtype=np.float64)
|
|
361
|
+
b = np.asarray(impact_parameter, dtype=np.float64)
|
|
362
|
+
f = 1.0 - 2.0 * self.M / r
|
|
363
|
+
Omega = self.circular_orbit_angular_velocity(r)
|
|
364
|
+
u_t = 1.0 / np.sqrt(f - r**2 * Omega**2)
|
|
365
|
+
return 1.0 / (u_t * (1.0 - b * Omega))
|
|
366
|
+
|
|
367
|
+
def tidal_acceleration(self, r, proper_separation):
|
|
368
|
+
"""Tidal (geodesic deviation) acceleration on a radially infalling object.
|
|
369
|
+
|
|
370
|
+
In the local orthonormal frame of a freely-falling observer, the
|
|
371
|
+
Riemann tensor's nonzero components give a stretching acceleration
|
|
372
|
+
along the radial direction and an equal compression along each
|
|
373
|
+
transverse direction:
|
|
374
|
+
|
|
375
|
+
.. math::
|
|
376
|
+
|
|
377
|
+
a_{\\text{radial}} = \\frac{2M}{r^3}\\,\\ell, \\qquad
|
|
378
|
+
a_{\\text{transverse}} = -\\frac{M}{r^3}\\,\\ell
|
|
379
|
+
|
|
380
|
+
for two points separated by a small proper length :math:`\\ell`.
|
|
381
|
+
This is "spaghettification": an object falling feet-first is
|
|
382
|
+
stretched head-to-toe and squeezed side-to-side, with both effects
|
|
383
|
+
growing as :math:`1/r^3` and formally diverging at the singularity.
|
|
384
|
+
|
|
385
|
+
Parameters
|
|
386
|
+
----------
|
|
387
|
+
r : float or array_like
|
|
388
|
+
Radial coordinate.
|
|
389
|
+
proper_separation : float
|
|
390
|
+
Proper length between the two points being torn apart (e.g. the
|
|
391
|
+
height of an infalling astronaut).
|
|
392
|
+
|
|
393
|
+
Returns
|
|
394
|
+
-------
|
|
395
|
+
radial : float or ndarray
|
|
396
|
+
Stretching acceleration along the radial direction (positive:
|
|
397
|
+
pulls the two points apart).
|
|
398
|
+
transverse : float or ndarray
|
|
399
|
+
Compressing acceleration along each transverse direction
|
|
400
|
+
(negative: pushes together).
|
|
401
|
+
|
|
402
|
+
Examples
|
|
403
|
+
--------
|
|
404
|
+
>>> bh = SchwarzschildBlackHole(M=1.0)
|
|
405
|
+
>>> radial, transverse = bh.tidal_acceleration(r=6.0, proper_separation=1.0)
|
|
406
|
+
>>> bool(radial > 0.0 and transverse < 0.0)
|
|
407
|
+
True
|
|
408
|
+
"""
|
|
409
|
+
r = np.asarray(r, dtype=np.float64)
|
|
410
|
+
radial = 2.0 * self.M / r**3 * proper_separation
|
|
411
|
+
transverse = -self.M / r**3 * proper_separation
|
|
412
|
+
return radial, transverse
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Relativistic clock corrections: why GPS needs General Relativity every day.
|
|
2
|
+
|
|
3
|
+
A GPS satellite clock experiences two competing relativistic effects
|
|
4
|
+
relative to a clock on the ground: it runs *faster* because it sits higher
|
|
5
|
+
in Earth's gravitational potential (gravitational blueshift), and *slower*
|
|
6
|
+
because it moves at orbital speed (special-relativistic time dilation). For
|
|
7
|
+
the GPS constellation's medium-Earth orbit, the gravitational effect wins by
|
|
8
|
+
a wide margin, and the net result -- about 38 microseconds per day -- is
|
|
9
|
+
large enough that, left uncorrected, GPS position errors would accumulate at
|
|
10
|
+
roughly 10 km per day. Every GPS satellite clock is deliberately built to
|
|
11
|
+
tick slightly slow on the ground so that, once in orbit, it keeps pace with
|
|
12
|
+
ground clocks -- General Relativity engineered directly into consumer
|
|
13
|
+
electronics.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
|
|
20
|
+
from physicskit.relativity.utils.constants import C_SI, G_SI
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"EARTH_MASS_KG",
|
|
24
|
+
"EARTH_RADIUS_M",
|
|
25
|
+
"EARTH_SIDEREAL_DAY_S",
|
|
26
|
+
"GPS_ORBITAL_RADIUS_M",
|
|
27
|
+
"clock_rate_factor",
|
|
28
|
+
"earth_mass_geometrized",
|
|
29
|
+
"gps_relativistic_offset_per_day",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
#: Earth's mass, in kg.
|
|
33
|
+
EARTH_MASS_KG = 5.9722e24
|
|
34
|
+
#: Earth's mean equatorial radius, in meters.
|
|
35
|
+
EARTH_RADIUS_M = 6.371e6
|
|
36
|
+
#: Earth's sidereal rotation period, in seconds.
|
|
37
|
+
EARTH_SIDEREAL_DAY_S = 86164.0905
|
|
38
|
+
#: Typical GPS satellite orbital semi-major axis, in meters (~20,200 km altitude).
|
|
39
|
+
GPS_ORBITAL_RADIUS_M = 2.6560e7
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def earth_mass_geometrized():
|
|
43
|
+
"""Earth's mass in geometrized length units, :math:`GM_\\oplus/c^2`.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
float
|
|
48
|
+
"""
|
|
49
|
+
return G_SI * EARTH_MASS_KG / C_SI**2
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def clock_rate_factor(r, angular_velocity_si, M=None):
|
|
53
|
+
"""Proper-to-coordinate time rate :math:`d\\tau/dt` for a clock at radius ``r`` rotating at a given rate.
|
|
54
|
+
|
|
55
|
+
.. math::
|
|
56
|
+
|
|
57
|
+
\\frac{d\\tau}{dt} = \\sqrt{\\left(1 - \\frac{2M}{r}\\right) - r^2 \\Omega^2}
|
|
58
|
+
|
|
59
|
+
combining gravitational time dilation and the special-relativistic time
|
|
60
|
+
dilation of the clock's rotational motion in one formula (this reduces
|
|
61
|
+
to the familiar circular-orbit result :math:`\\sqrt{1-3M/r}` when
|
|
62
|
+
:math:`\\Omega` is the Keplerian orbital angular velocity, and to pure
|
|
63
|
+
gravitational redshift :math:`\\sqrt{1-2M/r}` when :math:`\\Omega = 0`).
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
r : float
|
|
68
|
+
Radial coordinate, in meters.
|
|
69
|
+
angular_velocity_si : float
|
|
70
|
+
The clock's angular velocity, in rad/s (SI).
|
|
71
|
+
M : float, optional
|
|
72
|
+
Central mass, in geometrized length units. Defaults to
|
|
73
|
+
:func:`earth_mass_geometrized`.
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
float
|
|
78
|
+
The dimensionless rate :math:`d\\tau/dt`.
|
|
79
|
+
"""
|
|
80
|
+
if M is None:
|
|
81
|
+
M = earth_mass_geometrized()
|
|
82
|
+
omega_geometrized = angular_velocity_si / C_SI # rad/s -> rad per geometrized length unit
|
|
83
|
+
f = 1.0 - 2.0 * M / r
|
|
84
|
+
return np.sqrt(f - r**2 * omega_geometrized**2)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def gps_relativistic_offset_per_day(r_satellite=None, r_ground=None, M=None):
|
|
88
|
+
"""Net relativistic clock rate offset of a GPS satellite relative to the ground, in microseconds/day.
|
|
89
|
+
|
|
90
|
+
The satellite is treated as free-falling in a circular Keplerian orbit
|
|
91
|
+
(angular velocity :math:`\\Omega = \\sqrt{M/r^3}`); the ground clock is
|
|
92
|
+
treated as co-rotating with Earth at its sidereal rate. A positive
|
|
93
|
+
result means the satellite clock runs fast relative to the ground.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
r_satellite : float, optional
|
|
98
|
+
Satellite orbital radius, in meters. Defaults to
|
|
99
|
+
:data:`GPS_ORBITAL_RADIUS_M`.
|
|
100
|
+
r_ground : float, optional
|
|
101
|
+
Ground station radius, in meters. Defaults to
|
|
102
|
+
:data:`EARTH_RADIUS_M`.
|
|
103
|
+
M : float, optional
|
|
104
|
+
Earth's mass, in geometrized length units. Defaults to
|
|
105
|
+
:func:`earth_mass_geometrized`.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
float
|
|
110
|
+
Accumulated time offset, in microseconds per day (positive: the
|
|
111
|
+
satellite clock runs fast).
|
|
112
|
+
|
|
113
|
+
Examples
|
|
114
|
+
--------
|
|
115
|
+
>>> offset = gps_relativistic_offset_per_day()
|
|
116
|
+
>>> bool(30.0 < offset < 45.0) # the well-known ~38 microseconds/day GPS correction
|
|
117
|
+
True
|
|
118
|
+
"""
|
|
119
|
+
if r_satellite is None:
|
|
120
|
+
r_satellite = GPS_ORBITAL_RADIUS_M
|
|
121
|
+
if r_ground is None:
|
|
122
|
+
r_ground = EARTH_RADIUS_M
|
|
123
|
+
if M is None:
|
|
124
|
+
M = earth_mass_geometrized()
|
|
125
|
+
|
|
126
|
+
omega_satellite_si = np.sqrt(M / r_satellite**3) * C_SI # geometrized Omega -> rad/s
|
|
127
|
+
omega_ground_si = 2.0 * np.pi / EARTH_SIDEREAL_DAY_S
|
|
128
|
+
|
|
129
|
+
rate_satellite = clock_rate_factor(r_satellite, omega_satellite_si, M=M)
|
|
130
|
+
rate_ground = clock_rate_factor(r_ground, omega_ground_si, M=M)
|
|
131
|
+
|
|
132
|
+
fractional_rate_diff = rate_satellite - rate_ground
|
|
133
|
+
return fractional_rate_diff * 86400.0 * 1.0e6
|