universal-physics-tensor 0.47.0 → 1.0.1
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.
- package/LICENSE +21 -21
- package/README.md +396 -383
- package/bin/upt.mjs +28 -22
- package/dist/atlas/benchmark/hybrid-retrieval.d.ts +108 -0
- package/dist/atlas/benchmark/hybrid-retrieval.d.ts.map +1 -0
- package/dist/atlas/benchmark/hybrid-retrieval.js +241 -0
- package/dist/atlas/benchmark/hybrid-retrieval.js.map +1 -0
- package/dist/atlas/catalog-formal-ref.d.ts +24 -0
- package/dist/atlas/catalog-formal-ref.d.ts.map +1 -0
- package/dist/atlas/catalog-formal-ref.js +36 -0
- package/dist/atlas/catalog-formal-ref.js.map +1 -0
- package/dist/atlas/composition-table.d.ts +11 -46
- package/dist/atlas/composition-table.d.ts.map +1 -1
- package/dist/atlas/composition-table.js +7 -124
- package/dist/atlas/composition-table.js.map +1 -1
- package/dist/atlas/conventions.d.ts +4 -58
- package/dist/atlas/conventions.d.ts.map +1 -1
- package/dist/atlas/conventions.js +3 -88
- package/dist/atlas/conventions.js.map +1 -1
- package/dist/atlas/derive-evidence.d.ts +50 -3
- package/dist/atlas/derive-evidence.d.ts.map +1 -1
- package/dist/atlas/derive-evidence.js +73 -4
- package/dist/atlas/derive-evidence.js.map +1 -1
- package/dist/atlas/diffusion/bridges-closure.d.ts.map +1 -1
- package/dist/atlas/diffusion/bridges-closure.js +5 -1
- package/dist/atlas/diffusion/bridges-closure.js.map +1 -1
- package/dist/atlas/index.d.ts +9 -7
- package/dist/atlas/index.d.ts.map +1 -1
- package/dist/atlas/index.js +6 -5
- package/dist/atlas/index.js.map +1 -1
- package/dist/atlas/oscillators/bridges-exact.d.ts.map +1 -1
- package/dist/atlas/oscillators/bridges-exact.js +6 -0
- package/dist/atlas/oscillators/bridges-exact.js.map +1 -1
- package/dist/atlas/oscillators/bridges-limits.d.ts +2 -0
- package/dist/atlas/oscillators/bridges-limits.d.ts.map +1 -1
- package/dist/atlas/oscillators/bridges-limits.js +20 -19
- package/dist/atlas/oscillators/bridges-limits.js.map +1 -1
- package/dist/atlas/oscillators/limit-witnesses.d.ts +93 -0
- package/dist/atlas/oscillators/limit-witnesses.d.ts.map +1 -0
- package/dist/atlas/oscillators/limit-witnesses.js +152 -0
- package/dist/atlas/oscillators/limit-witnesses.js.map +1 -0
- package/dist/atlas/oscillators/models.d.ts +2 -1
- package/dist/atlas/oscillators/models.d.ts.map +1 -1
- package/dist/atlas/oscillators/models.js +4 -3
- package/dist/atlas/oscillators/models.js.map +1 -1
- package/dist/atlas/oscillators/norm-transport-witness.d.ts +37 -0
- package/dist/atlas/oscillators/norm-transport-witness.d.ts.map +1 -0
- package/dist/atlas/oscillators/norm-transport-witness.js +58 -0
- package/dist/atlas/oscillators/norm-transport-witness.js.map +1 -0
- package/dist/atlas/oscillators/norm-transport.d.ts +44 -0
- package/dist/atlas/oscillators/norm-transport.d.ts.map +1 -0
- package/dist/atlas/oscillators/norm-transport.js +66 -0
- package/dist/atlas/oscillators/norm-transport.js.map +1 -0
- package/dist/atlas/oscillators/norms.d.ts +11 -0
- package/dist/atlas/oscillators/norms.d.ts.map +1 -0
- package/dist/atlas/oscillators/norms.js +11 -0
- package/dist/atlas/oscillators/norms.js.map +1 -0
- package/dist/atlas/oscillators/pendulum-motion.d.ts +38 -0
- package/dist/atlas/oscillators/pendulum-motion.d.ts.map +1 -0
- package/dist/atlas/oscillators/pendulum-motion.js +122 -0
- package/dist/atlas/oscillators/pendulum-motion.js.map +1 -0
- package/dist/atlas/oscillators/phase-carriage.d.ts +38 -0
- package/dist/atlas/oscillators/phase-carriage.d.ts.map +1 -0
- package/dist/atlas/oscillators/phase-carriage.js +96 -0
- package/dist/atlas/oscillators/phase-carriage.js.map +1 -0
- package/dist/atlas/oscillators/phase-translation.d.ts +46 -0
- package/dist/atlas/oscillators/phase-translation.d.ts.map +1 -0
- package/dist/atlas/oscillators/phase-translation.js +178 -0
- package/dist/atlas/oscillators/phase-translation.js.map +1 -0
- package/dist/atlas/oscillators/position-translation.d.ts +59 -0
- package/dist/atlas/oscillators/position-translation.d.ts.map +1 -0
- package/dist/atlas/oscillators/position-translation.js +254 -0
- package/dist/atlas/oscillators/position-translation.js.map +1 -0
- package/dist/atlas/path-bound.d.ts +126 -9
- package/dist/atlas/path-bound.d.ts.map +1 -1
- package/dist/atlas/path-bound.js +372 -23
- package/dist/atlas/path-bound.js.map +1 -1
- package/dist/atlas/physjs-ref.d.ts +112 -0
- package/dist/atlas/physjs-ref.d.ts.map +1 -0
- package/dist/atlas/physjs-ref.js +842 -0
- package/dist/atlas/physjs-ref.js.map +1 -0
- package/dist/atlas/regime.d.ts +12 -136
- package/dist/atlas/regime.d.ts.map +1 -1
- package/dist/atlas/regime.js +8 -254
- package/dist/atlas/regime.js.map +1 -1
- package/dist/atlas/serialize.d.ts.map +1 -1
- package/dist/atlas/serialize.js +25 -0
- package/dist/atlas/serialize.js.map +1 -1
- package/dist/atlas/translation-registry.d.ts +22 -0
- package/dist/atlas/translation-registry.d.ts.map +1 -0
- package/dist/atlas/translation-registry.js +31 -0
- package/dist/atlas/translation-registry.js.map +1 -0
- package/dist/atlas/translation.d.ts +116 -0
- package/dist/atlas/translation.d.ts.map +1 -0
- package/dist/atlas/translation.js +34 -0
- package/dist/atlas/translation.js.map +1 -0
- package/dist/atlas/types.d.ts +74 -240
- package/dist/atlas/types.d.ts.map +1 -1
- package/dist/atlas/types.js +5 -37
- package/dist/atlas/types.js.map +1 -1
- package/dist/atlas/waves/bridges-closure.d.ts.map +1 -1
- package/dist/atlas/waves/bridges-closure.js +4 -0
- package/dist/atlas/waves/bridges-closure.js.map +1 -1
- package/dist/atlas/waves/bridges.d.ts.map +1 -1
- package/dist/atlas/waves/bridges.js +3 -0
- package/dist/atlas/waves/bridges.js.map +1 -1
- package/dist/atlas/waves/models.js +1 -1
- package/dist/atlas/waves/models.js.map +1 -1
- package/dist/atlas/witness-dominance.d.ts +50 -0
- package/dist/atlas/witness-dominance.d.ts.map +1 -0
- package/dist/atlas/witness-dominance.js +86 -0
- package/dist/atlas/witness-dominance.js.map +1 -0
- package/dist/atlas/witness-specs.d.ts +30 -0
- package/dist/atlas/witness-specs.d.ts.map +1 -1
- package/dist/atlas/witness-specs.js +107 -0
- package/dist/atlas/witness-specs.js.map +1 -1
- package/dist/bridges/be53-yang-mills-confrontation.d.ts +81 -0
- package/dist/bridges/be53-yang-mills-confrontation.d.ts.map +1 -0
- package/dist/bridges/be53-yang-mills-confrontation.js +110 -0
- package/dist/bridges/be53-yang-mills-confrontation.js.map +1 -0
- package/dist/bridges/confrontations.d.ts +1 -1
- package/dist/bridges/confrontations.d.ts.map +1 -1
- package/dist/bridges/confrontations.js +291 -3
- package/dist/bridges/confrontations.js.map +1 -1
- package/dist/bridges/equations/be-13-einstein-trace.d.ts +2 -3
- package/dist/bridges/equations/be-13-einstein-trace.d.ts.map +1 -1
- package/dist/bridges/equations/be-13-einstein-trace.js +2 -3
- package/dist/bridges/equations/be-13-einstein-trace.js.map +1 -1
- package/dist/bridges/equations/be-38-mond.d.ts +7 -5
- package/dist/bridges/equations/be-38-mond.d.ts.map +1 -1
- package/dist/bridges/equations/be-38-mond.js +7 -5
- package/dist/bridges/equations/be-38-mond.js.map +1 -1
- package/dist/bridges/equations/be-53-yang-mills-beta.d.ts +21 -0
- package/dist/bridges/equations/be-53-yang-mills-beta.d.ts.map +1 -1
- package/dist/bridges/equations/be-53-yang-mills-beta.js +12 -0
- package/dist/bridges/equations/be-53-yang-mills-beta.js.map +1 -1
- package/dist/bridges/evaluator-inputs.d.ts +21 -0
- package/dist/bridges/evaluator-inputs.d.ts.map +1 -0
- package/dist/bridges/evaluator-inputs.js +75 -0
- package/dist/bridges/evaluator-inputs.js.map +1 -0
- package/dist/bridges/evaluators.d.ts +38 -0
- package/dist/bridges/evaluators.d.ts.map +1 -1
- package/dist/bridges/evaluators.js +41 -15
- package/dist/bridges/evaluators.js.map +1 -1
- package/dist/bridges/gravitational-lensing.d.ts +1 -1
- package/dist/bridges/gravitational-lensing.js +1 -1
- package/dist/bridges/index.d.ts +1 -1
- package/dist/bridges/index.d.ts.map +1 -1
- package/dist/bridges/index.js +13 -13
- package/dist/bridges/index.js.map +1 -1
- package/dist/bridges/observations/types.d.ts +110 -2
- package/dist/bridges/observations/types.d.ts.map +1 -1
- package/dist/bridges/observations/types.js +29 -0
- package/dist/bridges/observations/types.js.map +1 -1
- package/dist/bridges/perihelion-precession.d.ts +1 -1
- package/dist/bridges/perihelion-precession.js +1 -1
- package/dist/canonical/canonical-equation.d.ts +1 -1
- package/dist/canonical/canonical-equation.d.ts.map +1 -1
- package/dist/canonical/entries/atomic.d.ts.map +1 -1
- package/dist/canonical/entries/atomic.js +32 -10
- package/dist/canonical/entries/atomic.js.map +1 -1
- package/dist/canonical/entries/dimensional-classics.js +2 -2
- package/dist/canonical/entries/dimensional-classics.js.map +1 -1
- package/dist/canonical/entries/mechanics.d.ts.map +1 -1
- package/dist/canonical/entries/mechanics.js +10 -6
- package/dist/canonical/entries/mechanics.js.map +1 -1
- package/dist/canonical/entries/relativity.d.ts.map +1 -1
- package/dist/canonical/entries/relativity.js +41 -8
- package/dist/canonical/entries/relativity.js.map +1 -1
- package/dist/canonical/entries/thermo-nuclear-cosmo.js +5 -5
- package/dist/canonical/entries/thermo-nuclear-cosmo.js.map +1 -1
- package/dist/canonical/linkage.d.ts.map +1 -1
- package/dist/canonical/linkage.js +14 -8
- package/dist/canonical/linkage.js.map +1 -1
- package/dist/canonical/normal-form.d.ts +17 -0
- package/dist/canonical/normal-form.d.ts.map +1 -1
- package/dist/canonical/normal-form.js +21 -4
- package/dist/canonical/normal-form.js.map +1 -1
- package/dist/cases/brownian-sphere.d.ts +68 -0
- package/dist/cases/brownian-sphere.d.ts.map +1 -0
- package/dist/cases/brownian-sphere.js +353 -0
- package/dist/cases/brownian-sphere.js.map +1 -0
- package/dist/cases/damped-resonator.d.ts +23 -0
- package/dist/cases/damped-resonator.d.ts.map +1 -0
- package/dist/cases/damped-resonator.js +224 -0
- package/dist/cases/damped-resonator.js.map +1 -0
- package/dist/cases/index.d.ts +11 -0
- package/dist/cases/index.d.ts.map +1 -0
- package/dist/cases/index.js +29 -0
- package/dist/cases/index.js.map +1 -0
- package/dist/cases/kepler-rv.d.ts +13 -0
- package/dist/cases/kepler-rv.d.ts.map +1 -0
- package/dist/cases/kepler-rv.js +168 -0
- package/dist/cases/kepler-rv.js.map +1 -0
- package/dist/cases/lumped-cooling.d.ts +46 -0
- package/dist/cases/lumped-cooling.d.ts.map +1 -0
- package/dist/cases/lumped-cooling.js +261 -0
- package/dist/cases/lumped-cooling.js.map +1 -0
- package/dist/cases/quadrature.d.ts +14 -0
- package/dist/cases/quadrature.d.ts.map +1 -0
- package/dist/cases/quadrature.js +41 -0
- package/dist/cases/quadrature.js.map +1 -0
- package/dist/cases/resistor-noise.d.ts +14 -0
- package/dist/cases/resistor-noise.d.ts.map +1 -0
- package/dist/cases/resistor-noise.js +210 -0
- package/dist/cases/resistor-noise.js.map +1 -0
- package/dist/cases/skin-depth.d.ts +21 -0
- package/dist/cases/skin-depth.d.ts.map +1 -0
- package/dist/cases/skin-depth.js +174 -0
- package/dist/cases/skin-depth.js.map +1 -0
- package/dist/cases/types.d.ts +115 -0
- package/dist/cases/types.d.ts.map +1 -0
- package/dist/cases/types.js +20 -0
- package/dist/cases/types.js.map +1 -0
- package/dist/cli/commands/_atlas-map.d.ts +409 -0
- package/dist/cli/commands/_atlas-map.d.ts.map +1 -0
- package/dist/cli/commands/_atlas-map.js +1014 -0
- package/dist/cli/commands/_atlas-map.js.map +1 -0
- package/dist/cli/commands/_atlas-route.d.ts +111 -0
- package/dist/cli/commands/_atlas-route.d.ts.map +1 -0
- package/dist/cli/commands/_atlas-route.js +140 -0
- package/dist/cli/commands/_atlas-route.js.map +1 -0
- package/dist/cli/commands/_discovery-opts.d.ts.map +1 -1
- package/dist/cli/commands/_discovery-opts.js +10 -1
- package/dist/cli/commands/_discovery-opts.js.map +1 -1
- package/dist/cli/commands/atlas.d.ts +20 -0
- package/dist/cli/commands/atlas.d.ts.map +1 -1
- package/dist/cli/commands/atlas.js +333 -19
- package/dist/cli/commands/atlas.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +14 -5
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/axes.js +4 -4
- package/dist/cli/commands/candidates.d.ts.map +1 -1
- package/dist/cli/commands/candidates.js +6 -5
- package/dist/cli/commands/candidates.js.map +1 -1
- package/dist/cli/commands/canonical.d.ts.map +1 -1
- package/dist/cli/commands/canonical.js +41 -12
- package/dist/cli/commands/canonical.js.map +1 -1
- package/dist/cli/commands/confront.d.ts.map +1 -1
- package/dist/cli/commands/confront.js +210 -28
- package/dist/cli/commands/confront.js.map +1 -1
- package/dist/cli/commands/connectors.d.ts.map +1 -1
- package/dist/cli/commands/connectors.js +11 -10
- package/dist/cli/commands/connectors.js.map +1 -1
- package/dist/cli/commands/coverage.js +3 -3
- package/dist/cli/commands/derive.d.ts.map +1 -1
- package/dist/cli/commands/derive.js +22 -10
- package/dist/cli/commands/derive.js.map +1 -1
- package/dist/cli/commands/discover.d.ts.map +1 -1
- package/dist/cli/commands/discover.js +149 -32
- package/dist/cli/commands/discover.js.map +1 -1
- package/dist/cli/commands/eval.d.ts.map +1 -1
- package/dist/cli/commands/eval.js +76 -17
- package/dist/cli/commands/eval.js.map +1 -1
- package/dist/cli/commands/evaluate.d.ts +30 -0
- package/dist/cli/commands/evaluate.d.ts.map +1 -1
- package/dist/cli/commands/evaluate.js +440 -25
- package/dist/cli/commands/evaluate.js.map +1 -1
- package/dist/cli/commands/explain.d.ts.map +1 -1
- package/dist/cli/commands/explain.js +38 -11
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/frontier.d.ts +3 -0
- package/dist/cli/commands/frontier.d.ts.map +1 -0
- package/dist/cli/commands/frontier.js +28 -0
- package/dist/cli/commands/frontier.js.map +1 -0
- package/dist/cli/commands/ground.d.ts.map +1 -1
- package/dist/cli/commands/ground.js +37 -12
- package/dist/cli/commands/ground.js.map +1 -1
- package/dist/cli/commands/index.d.ts +5 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +5 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/map.d.ts +8 -0
- package/dist/cli/commands/map.d.ts.map +1 -1
- package/dist/cli/commands/map.js +401 -64
- package/dist/cli/commands/map.js.map +1 -1
- package/dist/cli/commands/metric.d.ts +3 -0
- package/dist/cli/commands/metric.d.ts.map +1 -0
- package/dist/cli/commands/metric.js +136 -0
- package/dist/cli/commands/metric.js.map +1 -0
- package/dist/cli/commands/path.d.ts +109 -1
- package/dist/cli/commands/path.d.ts.map +1 -1
- package/dist/cli/commands/path.js +1019 -109
- package/dist/cli/commands/path.js.map +1 -1
- package/dist/cli/commands/predict.d.ts.map +1 -1
- package/dist/cli/commands/predict.js +6 -5
- package/dist/cli/commands/predict.js.map +1 -1
- package/dist/cli/commands/priority.d.ts.map +1 -1
- package/dist/cli/commands/priority.js +4 -3
- package/dist/cli/commands/priority.js.map +1 -1
- package/dist/cli/commands/probe.d.ts +7 -0
- package/dist/cli/commands/probe.d.ts.map +1 -1
- package/dist/cli/commands/probe.js +234 -52
- package/dist/cli/commands/probe.js.map +1 -1
- package/dist/cli/commands/recover.d.ts.map +1 -1
- package/dist/cli/commands/recover.js +17 -6
- package/dist/cli/commands/recover.js.map +1 -1
- package/dist/cli/commands/regime.d.ts +1 -1
- package/dist/cli/commands/regime.d.ts.map +1 -1
- package/dist/cli/commands/regime.js +134 -33
- package/dist/cli/commands/regime.js.map +1 -1
- package/dist/cli/commands/retrieve.d.ts +3 -0
- package/dist/cli/commands/retrieve.d.ts.map +1 -0
- package/dist/cli/commands/retrieve.js +65 -0
- package/dist/cli/commands/retrieve.js.map +1 -0
- package/dist/cli/commands/search.d.ts +3 -0
- package/dist/cli/commands/search.d.ts.map +1 -0
- package/dist/cli/commands/search.js +70 -0
- package/dist/cli/commands/search.js.map +1 -0
- package/dist/cli/commands/symbolic.d.ts.map +1 -1
- package/dist/cli/commands/symbolic.js +112 -21
- package/dist/cli/commands/symbolic.js.map +1 -1
- package/dist/cli/commands/testplan.d.ts +3 -0
- package/dist/cli/commands/testplan.d.ts.map +1 -0
- package/dist/cli/commands/testplan.js +131 -0
- package/dist/cli/commands/testplan.js.map +1 -0
- package/dist/cli/conventions.d.ts +22 -0
- package/dist/cli/conventions.d.ts.map +1 -0
- package/dist/cli/conventions.js +48 -0
- package/dist/cli/conventions.js.map +1 -0
- package/dist/cli/euler-guard.d.ts +9 -0
- package/dist/cli/euler-guard.d.ts.map +1 -0
- package/dist/cli/euler-guard.js +11 -0
- package/dist/cli/euler-guard.js.map +1 -0
- package/dist/cli/eval-numbers.d.ts +26 -0
- package/dist/cli/eval-numbers.d.ts.map +1 -0
- package/dist/cli/eval-numbers.js +49 -0
- package/dist/cli/eval-numbers.js.map +1 -0
- package/dist/cli/expr-print.d.ts +25 -0
- package/dist/cli/expr-print.d.ts.map +1 -0
- package/dist/cli/expr-print.js +123 -0
- package/dist/cli/expr-print.js.map +1 -0
- package/dist/cli/graphs.d.ts +26 -0
- package/dist/cli/graphs.d.ts.map +1 -1
- package/dist/cli/graphs.js +19 -0
- package/dist/cli/graphs.js.map +1 -1
- package/dist/cli/main.d.ts +4 -10
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +370 -167
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/map-evidence.d.ts +47 -0
- package/dist/cli/map-evidence.d.ts.map +1 -0
- package/dist/cli/map-evidence.js +53 -0
- package/dist/cli/map-evidence.js.map +1 -0
- package/dist/cli/output.d.ts +21 -1
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +5 -1
- package/dist/cli/output.js.map +1 -1
- package/dist/{composition → cli}/poster-source.d.ts +3 -2
- package/dist/cli/poster-source.d.ts.map +1 -0
- package/dist/{composition → cli}/poster-source.js +2 -1
- package/dist/cli/poster-source.js.map +1 -0
- package/dist/cli/record-reach.d.ts +44 -0
- package/dist/cli/record-reach.d.ts.map +1 -0
- package/dist/cli/record-reach.js +228 -0
- package/dist/cli/record-reach.js.map +1 -0
- package/dist/cli/record-tables.d.ts +38 -0
- package/dist/cli/record-tables.d.ts.map +1 -0
- package/dist/cli/record-tables.js +110 -0
- package/dist/cli/record-tables.js.map +1 -0
- package/dist/cli/record.d.ts +141 -0
- package/dist/cli/record.d.ts.map +1 -0
- package/dist/cli/record.js +612 -0
- package/dist/cli/record.js.map +1 -0
- package/dist/cli/search-index.d.ts +56 -0
- package/dist/cli/search-index.d.ts.map +1 -0
- package/dist/cli/search-index.js +190 -0
- package/dist/cli/search-index.js.map +1 -0
- package/dist/cli/statuses.d.ts +25 -0
- package/dist/cli/statuses.d.ts.map +1 -0
- package/dist/cli/statuses.js +276 -0
- package/dist/cli/statuses.js.map +1 -0
- package/dist/cli/version.d.ts +8 -0
- package/dist/cli/version.d.ts.map +1 -1
- package/dist/cli/version.js +32 -1
- package/dist/cli/version.js.map +1 -1
- package/dist/cli-api.d.ts +33 -15
- package/dist/cli-api.d.ts.map +1 -1
- package/dist/cli-api.js +31 -11
- package/dist/cli-api.js.map +1 -1
- package/dist/composition/bridge-analysis.d.ts.map +1 -1
- package/dist/composition/bridge-analysis.js +2 -1
- package/dist/composition/bridge-analysis.js.map +1 -1
- package/dist/composition/canonical-compare.d.ts +36 -11
- package/dist/composition/canonical-compare.d.ts.map +1 -1
- package/dist/composition/canonical-compare.js +424 -56
- package/dist/composition/canonical-compare.js.map +1 -1
- package/dist/composition/canonical-graph.d.ts +2 -2
- package/dist/composition/canonical-graph.js +3 -3
- package/dist/composition/canonical-graph.js.map +1 -1
- package/dist/composition/canonical-prefactors.d.ts +24 -1
- package/dist/composition/canonical-prefactors.d.ts.map +1 -1
- package/dist/composition/canonical-prefactors.js +97 -1
- package/dist/composition/canonical-prefactors.js.map +1 -1
- package/dist/composition/compose-symbolic.js +1 -1
- package/dist/composition/compose-symbolic.js.map +1 -1
- package/dist/composition/compose.d.ts.map +1 -1
- package/dist/composition/compose.js +17 -9
- package/dist/composition/compose.js.map +1 -1
- package/dist/composition/composition-recovery.d.ts +47 -0
- package/dist/composition/composition-recovery.d.ts.map +1 -0
- package/dist/composition/composition-recovery.js +77 -0
- package/dist/composition/composition-recovery.js.map +1 -0
- package/dist/composition/consequence.d.ts +39 -0
- package/dist/composition/consequence.d.ts.map +1 -1
- package/dist/composition/consequence.js +37 -0
- package/dist/composition/consequence.js.map +1 -1
- package/dist/composition/discovery.d.ts +20 -0
- package/dist/composition/discovery.d.ts.map +1 -1
- package/dist/composition/discovery.js +27 -5
- package/dist/composition/discovery.js.map +1 -1
- package/dist/composition/edge.d.ts +1 -1
- package/dist/composition/edge.d.ts.map +1 -1
- package/dist/composition/edge.js.map +1 -1
- package/dist/composition/edges/_catalog-helpers.d.ts +4 -0
- package/dist/composition/edges/_catalog-helpers.d.ts.map +1 -1
- package/dist/composition/edges/_catalog-helpers.js +15 -0
- package/dist/composition/edges/_catalog-helpers.js.map +1 -1
- package/dist/composition/edges/calibration.d.ts.map +1 -1
- package/dist/composition/edges/calibration.js +57 -0
- package/dist/composition/edges/calibration.js.map +1 -1
- package/dist/composition/edges/catalog-fields.d.ts.map +1 -1
- package/dist/composition/edges/catalog-fields.js +2 -1
- package/dist/composition/edges/catalog-fields.js.map +1 -1
- package/dist/composition/edges/catalog-gravitation-cosmology.d.ts.map +1 -1
- package/dist/composition/edges/catalog-gravitation-cosmology.js +2 -1
- package/dist/composition/edges/catalog-gravitation-cosmology.js.map +1 -1
- package/dist/composition/edges/catalog-quantum.d.ts.map +1 -1
- package/dist/composition/edges/catalog-quantum.js +26 -0
- package/dist/composition/edges/catalog-quantum.js.map +1 -1
- package/dist/composition/edges/catalog-tranche.d.ts.map +1 -1
- package/dist/composition/edges/catalog-tranche.js +2 -1
- package/dist/composition/edges/catalog-tranche.js.map +1 -1
- package/dist/composition/expr-eval.d.ts.map +1 -1
- package/dist/composition/expr-eval.js +4 -1
- package/dist/composition/expr-eval.js.map +1 -1
- package/dist/composition/expr-simplify.js +1 -1
- package/dist/composition/expr-simplify.js.map +1 -1
- package/dist/composition/frontier-account.d.ts +78 -0
- package/dist/composition/frontier-account.d.ts.map +1 -0
- package/dist/composition/frontier-account.js +127 -0
- package/dist/composition/frontier-account.js.map +1 -0
- package/dist/composition/graph-viz.d.ts +7 -22
- package/dist/composition/graph-viz.d.ts.map +1 -1
- package/dist/composition/graph-viz.js +4 -27
- package/dist/composition/graph-viz.js.map +1 -1
- package/dist/composition/grounding.d.ts +49 -0
- package/dist/composition/grounding.d.ts.map +1 -1
- package/dist/composition/grounding.js +38 -0
- package/dist/composition/grounding.js.map +1 -1
- package/dist/composition/index.d.ts +0 -2
- package/dist/composition/index.d.ts.map +1 -1
- package/dist/composition/index.js +1 -1
- package/dist/composition/index.js.map +1 -1
- package/dist/composition/probe/expression-gaps.d.ts +27 -0
- package/dist/composition/probe/expression-gaps.d.ts.map +1 -0
- package/dist/composition/probe/expression-gaps.js +47 -0
- package/dist/composition/probe/expression-gaps.js.map +1 -0
- package/dist/composition/probe/frontier.d.ts +2 -1
- package/dist/composition/probe/frontier.d.ts.map +1 -1
- package/dist/composition/probe/frontier.js +3 -2
- package/dist/composition/probe/frontier.js.map +1 -1
- package/dist/composition/probe/index.d.ts +4 -1
- package/dist/composition/probe/index.d.ts.map +1 -1
- package/dist/composition/probe/index.js +3 -1
- package/dist/composition/probe/index.js.map +1 -1
- package/dist/composition/probe/pipeline.d.ts +2 -0
- package/dist/composition/probe/pipeline.d.ts.map +1 -1
- package/dist/composition/probe/pipeline.js +6 -2
- package/dist/composition/probe/pipeline.js.map +1 -1
- package/dist/composition/probe/problem.d.ts +7 -0
- package/dist/composition/probe/problem.d.ts.map +1 -1
- package/dist/composition/probe/problem.js +15 -5
- package/dist/composition/probe/problem.js.map +1 -1
- package/dist/composition/probe/search-budget.d.ts.map +1 -1
- package/dist/composition/probe/search-budget.js +6 -2
- package/dist/composition/probe/search-budget.js.map +1 -1
- package/dist/composition/probe/study.d.ts +340 -0
- package/dist/composition/probe/study.d.ts.map +1 -0
- package/dist/composition/probe/study.js +1519 -0
- package/dist/composition/probe/study.js.map +1 -0
- package/dist/composition/proposed-bridges.js +1 -1
- package/dist/composition/proposed-bridges.js.map +1 -1
- package/dist/composition/quantities.d.ts +4 -16
- package/dist/composition/quantities.d.ts.map +1 -1
- package/dist/composition/quantities.js +4 -16
- package/dist/composition/quantities.js.map +1 -1
- package/dist/composition/retrodiction.d.ts.map +1 -1
- package/dist/composition/retrodiction.js +6 -2
- package/dist/composition/retrodiction.js.map +1 -1
- package/dist/composition/uncertainty.d.ts +1 -1
- package/dist/composition/uncertainty.d.ts.map +1 -1
- package/dist/composition/user-equation.d.ts +87 -14
- package/dist/composition/user-equation.d.ts.map +1 -1
- package/dist/composition/user-equation.js +266 -59
- package/dist/composition/user-equation.js.map +1 -1
- package/dist/core/constants.d.ts +9 -4
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +9 -4
- package/dist/core/constants.js.map +1 -1
- package/dist/core/types.d.ts +1 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +2 -1
- package/dist/core/types.js.map +1 -1
- package/dist/dimensional/curvature.d.ts +7 -56
- package/dist/dimensional/curvature.d.ts.map +1 -1
- package/dist/dimensional/curvature.js +7 -76
- package/dist/dimensional/curvature.js.map +1 -1
- package/dist/dimensional/dimension-spec.d.ts +7 -1
- package/dist/dimensional/dimension-spec.d.ts.map +1 -1
- package/dist/dimensional/dimension-spec.js +131 -3
- package/dist/dimensional/dimension-spec.js.map +1 -1
- package/dist/dimensional/formula-names.d.ts +30 -0
- package/dist/dimensional/formula-names.d.ts.map +1 -0
- package/dist/dimensional/formula-names.js +37 -0
- package/dist/dimensional/formula-names.js.map +1 -0
- package/dist/dimensional/natural-units.d.ts +33 -0
- package/dist/dimensional/natural-units.d.ts.map +1 -0
- package/dist/dimensional/natural-units.js +58 -0
- package/dist/dimensional/natural-units.js.map +1 -0
- package/dist/{composition → dimensional}/symbolic-constants.d.ts +21 -2
- package/dist/dimensional/symbolic-constants.d.ts.map +1 -0
- package/dist/dimensional/symbolic-constants.js +116 -0
- package/dist/dimensional/symbolic-constants.js.map +1 -0
- package/dist/dimensional/unit-convention.d.ts +30 -0
- package/dist/dimensional/unit-convention.d.ts.map +1 -0
- package/dist/dimensional/unit-convention.js +60 -0
- package/dist/dimensional/unit-convention.js.map +1 -0
- package/dist/dimensional/units.d.ts +43 -0
- package/dist/dimensional/units.d.ts.map +1 -0
- package/dist/dimensional/units.js +197 -0
- package/dist/dimensional/units.js.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/numerical/bianchi-residual.d.ts +55 -0
- package/dist/numerical/bianchi-residual.d.ts.map +1 -0
- package/dist/numerical/bianchi-residual.js +79 -0
- package/dist/numerical/bianchi-residual.js.map +1 -0
- package/dist/numerical/binding-value.d.ts +67 -0
- package/dist/numerical/binding-value.d.ts.map +1 -0
- package/dist/numerical/binding-value.js +347 -0
- package/dist/numerical/binding-value.js.map +1 -0
- package/dist/numerical/connection-lowering-helpers.d.ts.map +1 -1
- package/dist/numerical/connection-lowering-helpers.js +13 -26
- package/dist/numerical/connection-lowering-helpers.js.map +1 -1
- package/dist/numerical/curvature-lowering-helpers.d.ts.map +1 -1
- package/dist/numerical/curvature-lowering-helpers.js +9 -0
- package/dist/numerical/curvature-lowering-helpers.js.map +1 -1
- package/dist/numerical/float64-engine.d.ts.map +1 -1
- package/dist/numerical/float64-engine.js +23 -16
- package/dist/numerical/float64-engine.js.map +1 -1
- package/dist/numerical/formula-dimension.d.ts +7 -0
- package/dist/numerical/formula-dimension.d.ts.map +1 -1
- package/dist/numerical/formula-dimension.js +23 -6
- package/dist/numerical/formula-dimension.js.map +1 -1
- package/dist/numerical/formula-mathts.d.ts.map +1 -1
- package/dist/numerical/formula-mathts.js +68 -6
- package/dist/numerical/formula-mathts.js.map +1 -1
- package/dist/numerical/formula.d.ts +27 -0
- package/dist/numerical/formula.d.ts.map +1 -1
- package/dist/numerical/formula.js +68 -6
- package/dist/numerical/formula.js.map +1 -1
- package/dist/numerical/spacetime-metrics.d.ts +243 -0
- package/dist/numerical/spacetime-metrics.d.ts.map +1 -0
- package/dist/numerical/spacetime-metrics.js +1056 -0
- package/dist/numerical/spacetime-metrics.js.map +1 -0
- package/dist/relations/composition-table.d.ts +61 -0
- package/dist/relations/composition-table.d.ts.map +1 -0
- package/dist/relations/composition-table.js +140 -0
- package/dist/relations/composition-table.js.map +1 -0
- package/dist/relations/conventions.d.ts +63 -0
- package/dist/relations/conventions.d.ts.map +1 -0
- package/dist/relations/conventions.js +93 -0
- package/dist/relations/conventions.js.map +1 -0
- package/dist/relations/regime.d.ts +159 -0
- package/dist/relations/regime.d.ts.map +1 -0
- package/dist/relations/regime.js +304 -0
- package/dist/relations/regime.js.map +1 -0
- package/dist/relations/types.d.ts +259 -0
- package/dist/relations/types.d.ts.map +1 -0
- package/dist/relations/types.js +37 -0
- package/dist/relations/types.js.map +1 -0
- package/package.json +166 -163
- package/dist/composition/poster-source.d.ts.map +0 -1
- package/dist/composition/poster-source.js.map +0 -1
- package/dist/composition/symbolic-constants.d.ts.map +0 -1
- package/dist/composition/symbolic-constants.js +0 -65
- package/dist/composition/symbolic-constants.js.map +0 -1
|
@@ -0,0 +1,1056 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curvature of a few exact metrics for `upt metric`.
|
|
3
|
+
*
|
|
4
|
+
* The line element is mostly-plus, (−,+,+,+), the signature of the
|
|
5
|
+
* Schwarzschild fixture in this repo. The canonical Einstein-equation metric
|
|
6
|
+
* node uses the same mostly-plus signature. The Kretschmann scalar does not
|
|
7
|
+
* depend on that choice.
|
|
8
|
+
*
|
|
9
|
+
* Schwarzschild Christoffel symbols are the closed form. Riemann, Ricci and
|
|
10
|
+
* Kretschmann are a 4th-order finite difference of the metric, checked in
|
|
11
|
+
* tests against the closed forms (Schwarzschild Kretschmann, flat-dust FLRW
|
|
12
|
+
* Ricci scalar, Kerr Kretschmann). Kerr geodesics in Boyer–Lindquist
|
|
13
|
+
* coordinates, including inclined ones, take their initial data from the
|
|
14
|
+
* Carter constant and are integrated with the second-order geodesic equation.
|
|
15
|
+
*
|
|
16
|
+
* @module numerical/spacetime-metrics
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
import { C_SI, G_SI, M_SUN_SI } from '../core/constants.js';
|
|
20
|
+
import { DIMENSIONLESS, LENGTH, MASS, TIME, VELOCITY } from '../dimensional/types.js';
|
|
21
|
+
import { readParameter } from './binding-value.js';
|
|
22
|
+
/** The signature this module differentiates. */
|
|
23
|
+
export const METRIC_SIGNATURE = '(-,+,+,+)';
|
|
24
|
+
/**
|
|
25
|
+
* Printed with every curvature report. The line element and the canonical
|
|
26
|
+
* Einstein-equation metric node share this mostly-plus signature.
|
|
27
|
+
*/
|
|
28
|
+
export const METRIC_SIGNATURE_NOTE = 'Line element signature (−,+,+,+), the same mostly-plus signature as the Schwarzschild fixture ' +
|
|
29
|
+
'and as the canonical Einstein-equation metric node. ' +
|
|
30
|
+
'The Kretschmann scalar does not depend on that choice.';
|
|
31
|
+
const Z = 1e-8;
|
|
32
|
+
function zeros(n) {
|
|
33
|
+
return Array.from({ length: n }, () => 0);
|
|
34
|
+
}
|
|
35
|
+
function mat4() {
|
|
36
|
+
return [zeros(4), zeros(4), zeros(4), zeros(4)];
|
|
37
|
+
}
|
|
38
|
+
function invert4(src) {
|
|
39
|
+
const a = src.map((row, i) => {
|
|
40
|
+
const out = zeros(8);
|
|
41
|
+
for (let j = 0; j < 4; j++)
|
|
42
|
+
out[j] = row[j];
|
|
43
|
+
out[4 + i] = 1;
|
|
44
|
+
return out;
|
|
45
|
+
});
|
|
46
|
+
for (let col = 0; col < 4; col++) {
|
|
47
|
+
let pivot = col;
|
|
48
|
+
for (let r = col + 1; r < 4; r++) {
|
|
49
|
+
if (Math.abs(a[r][col]) > Math.abs(a[pivot][col]))
|
|
50
|
+
pivot = r;
|
|
51
|
+
}
|
|
52
|
+
const tmp = a[col];
|
|
53
|
+
a[col] = a[pivot];
|
|
54
|
+
a[pivot] = tmp;
|
|
55
|
+
const div = a[col][col];
|
|
56
|
+
if (!Number.isFinite(div) || Math.abs(div) < 1e-18)
|
|
57
|
+
throw new Error('metric is singular at this point');
|
|
58
|
+
for (let j = 0; j < 8; j++)
|
|
59
|
+
a[col][j] = a[col][j] / div;
|
|
60
|
+
for (let r = 0; r < 4; r++) {
|
|
61
|
+
if (r === col)
|
|
62
|
+
continue;
|
|
63
|
+
const f = a[r][col];
|
|
64
|
+
for (let j = 0; j < 8; j++)
|
|
65
|
+
a[r][j] = a[r][j] - f * a[col][j];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return a.map((row) => row.slice(4));
|
|
69
|
+
}
|
|
70
|
+
function shift(x, mu, delta) {
|
|
71
|
+
const y = [x[0], x[1], x[2], x[3]];
|
|
72
|
+
y[mu] += delta;
|
|
73
|
+
return y;
|
|
74
|
+
}
|
|
75
|
+
/** 4th-order central difference of a matrix-valued function. */
|
|
76
|
+
function dMetric(g, x, mu, h) {
|
|
77
|
+
const at = (s) => g(shift(x, mu, s * h));
|
|
78
|
+
const a = at(-2);
|
|
79
|
+
const b = at(-1);
|
|
80
|
+
const c = at(1);
|
|
81
|
+
const d = at(2);
|
|
82
|
+
const out = mat4();
|
|
83
|
+
for (let i = 0; i < 4; i++) {
|
|
84
|
+
for (let j = 0; j < 4; j++) {
|
|
85
|
+
const av = a[i][j];
|
|
86
|
+
const bv = b[i][j];
|
|
87
|
+
const cv = c[i][j];
|
|
88
|
+
const dv = d[i][j];
|
|
89
|
+
// A component that does not change must not differentiate a huge constant
|
|
90
|
+
// (g_tt = −c²): the stencil cancels only up to a roundoff, and that
|
|
91
|
+
// roundoff divided by h is a fake Christoffel.
|
|
92
|
+
out[i][j] = av === bv && bv === cv && cv === dv ? 0 : (-dv + 8 * cv - 8 * bv + av) / (12 * h);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
function blankGamma() {
|
|
98
|
+
return [0, 1, 2, 3].map(() => mat4());
|
|
99
|
+
}
|
|
100
|
+
/** A rank-4 array of numbers, indexed [a][b][c][d]. */
|
|
101
|
+
function tensor4() {
|
|
102
|
+
return [0, 1, 2, 3].map(() => [0, 1, 2, 3].map(() => [0, 1, 2, 3].map(() => [0, 0, 0, 0])));
|
|
103
|
+
}
|
|
104
|
+
function christoffelOf(g, x, steps) {
|
|
105
|
+
const gi = invert4(g(x));
|
|
106
|
+
const dg = [0, 1, 2, 3].map((mu) => dMetric(g, x, mu, steps[mu]));
|
|
107
|
+
const G = blankGamma();
|
|
108
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
109
|
+
for (let mu = 0; mu < 4; mu++) {
|
|
110
|
+
for (let nu = mu; nu < 4; nu++) {
|
|
111
|
+
let s = 0;
|
|
112
|
+
for (let sigma = 0; sigma < 4; sigma++) {
|
|
113
|
+
s += gi[rho][sigma] * (dg[mu][nu][sigma] + dg[nu][mu][sigma] - dg[sigma][mu][nu]);
|
|
114
|
+
}
|
|
115
|
+
const v = 0.5 * s;
|
|
116
|
+
G[rho][mu][nu] = v;
|
|
117
|
+
G[rho][nu][mu] = v;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return G;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* R^ρ_{σμν} = ∂_μ Γ^ρ_{νσ} − ∂_ν Γ^ρ_{μσ} + Γ^ρ_{μλ} Γ^λ_{νσ} − Γ^ρ_{νλ} Γ^λ_{μσ}.
|
|
125
|
+
* Christoffel comes from a 4th-order difference of the metric; its coordinate
|
|
126
|
+
* derivative is a central difference of that. Checked against the Schwarzschild
|
|
127
|
+
* Kretschmann closed form.
|
|
128
|
+
*/
|
|
129
|
+
function tensorsOf(g, x, steps) {
|
|
130
|
+
const g0 = g(x);
|
|
131
|
+
const gi = invert4(g0);
|
|
132
|
+
const gamma = christoffelOf(g, x, steps);
|
|
133
|
+
const partial = [];
|
|
134
|
+
for (let mu = 0; mu < 4; mu++) {
|
|
135
|
+
const h = steps[mu];
|
|
136
|
+
const plus = christoffelOf(g, shift(x, mu, h), steps);
|
|
137
|
+
const minus = christoffelOf(g, shift(x, mu, -h), steps);
|
|
138
|
+
const d = blankGamma();
|
|
139
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
140
|
+
for (let a = 0; a < 4; a++) {
|
|
141
|
+
for (let b = 0; b < 4; b++) {
|
|
142
|
+
d[rho][a][b] = (plus[rho][a][b] - minus[rho][a][b]) / (2 * h);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
partial.push(d);
|
|
147
|
+
}
|
|
148
|
+
const up = tensor4();
|
|
149
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
150
|
+
for (let sigma = 0; sigma < 4; sigma++) {
|
|
151
|
+
for (let mu = 0; mu < 4; mu++) {
|
|
152
|
+
for (let nu = 0; nu < 4; nu++) {
|
|
153
|
+
let s = partial[mu][rho][nu][sigma] - partial[nu][rho][mu][sigma];
|
|
154
|
+
for (let lam = 0; lam < 4; lam++) {
|
|
155
|
+
s +=
|
|
156
|
+
gamma[rho][mu][lam] * gamma[lam][nu][sigma] -
|
|
157
|
+
gamma[rho][nu][lam] * gamma[lam][mu][sigma];
|
|
158
|
+
}
|
|
159
|
+
up[rho][sigma][mu][nu] = s;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const lower = tensor4();
|
|
165
|
+
for (let a = 0; a < 4; a++) {
|
|
166
|
+
for (let b = 0; b < 4; b++) {
|
|
167
|
+
for (let c = 0; c < 4; c++) {
|
|
168
|
+
for (let d = 0; d < 4; d++) {
|
|
169
|
+
let s = 0;
|
|
170
|
+
for (let rho = 0; rho < 4; rho++)
|
|
171
|
+
s += g0[a][rho] * up[rho][b][c][d];
|
|
172
|
+
lower[a][b][c][d] = s;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const ricci = mat4();
|
|
178
|
+
for (let sigma = 0; sigma < 4; sigma++) {
|
|
179
|
+
for (let nu = 0; nu < 4; nu++) {
|
|
180
|
+
let s = 0;
|
|
181
|
+
for (let rho = 0; rho < 4; rho++)
|
|
182
|
+
s += up[rho][sigma][rho][nu];
|
|
183
|
+
ricci[sigma][nu] = s;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
let ricciScalar = 0;
|
|
187
|
+
for (let a = 0; a < 4; a++) {
|
|
188
|
+
for (let b = 0; b < 4; b++)
|
|
189
|
+
ricciScalar += gi[a][b] * ricci[a][b];
|
|
190
|
+
}
|
|
191
|
+
let kretschmann = 0;
|
|
192
|
+
for (let a = 0; a < 4; a++) {
|
|
193
|
+
for (let b = 0; b < 4; b++) {
|
|
194
|
+
for (let c = 0; c < 4; c++) {
|
|
195
|
+
for (let d = 0; d < 4; d++) {
|
|
196
|
+
let raised = 0;
|
|
197
|
+
for (let ap = 0; ap < 4; ap++) {
|
|
198
|
+
for (let bp = 0; bp < 4; bp++) {
|
|
199
|
+
for (let cp = 0; cp < 4; cp++) {
|
|
200
|
+
for (let dp = 0; dp < 4; dp++) {
|
|
201
|
+
raised += gi[a][ap] * gi[b][bp] * gi[c][cp] * gi[d][dp] * lower[ap][bp][cp][dp];
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
kretschmann += lower[a][b][c][d] * raised;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return { ricciScalar, kretschmann, ricci, christoffel: gamma };
|
|
212
|
+
}
|
|
213
|
+
function nonzeroMatrix(m, label) {
|
|
214
|
+
const out = [];
|
|
215
|
+
const scale = Math.max(1, ...m.flat().map((v) => Math.abs(v)));
|
|
216
|
+
for (let i = 0; i < 4; i++) {
|
|
217
|
+
for (let j = 0; j < 4; j++) {
|
|
218
|
+
const v = m[i][j];
|
|
219
|
+
if (Math.abs(v) > Z * scale)
|
|
220
|
+
out.push({ index: label(i, j), value: v });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return out;
|
|
224
|
+
}
|
|
225
|
+
function nonzeroGamma(G) {
|
|
226
|
+
const names = ['t', 'r', 'θ', 'φ'];
|
|
227
|
+
const out = [];
|
|
228
|
+
let scale = 1;
|
|
229
|
+
for (const block of G)
|
|
230
|
+
for (const row of block)
|
|
231
|
+
for (const v of row)
|
|
232
|
+
scale = Math.max(scale, Math.abs(v));
|
|
233
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
234
|
+
for (let mu = 0; mu < 4; mu++) {
|
|
235
|
+
for (let nu = mu; nu < 4; nu++) {
|
|
236
|
+
const v = G[rho][mu][nu];
|
|
237
|
+
if (Math.abs(v) > Z * scale) {
|
|
238
|
+
out.push({ index: `Γ^${names[rho]}_${names[mu]}${names[nu]}`, value: v });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
function stepsFor(x) {
|
|
246
|
+
return [Math.max(Math.abs(x[0]), 1) * 1e-4, Math.max(Math.abs(x[1]), 1) * 1e-4, 1e-4, 1e-4];
|
|
247
|
+
}
|
|
248
|
+
function schwarzschildMetric(M, c, G) {
|
|
249
|
+
const rs = (2 * G * M) / (c * c);
|
|
250
|
+
return (x) => {
|
|
251
|
+
const r = x[1];
|
|
252
|
+
const th = x[2];
|
|
253
|
+
const f = 1 - rs / r;
|
|
254
|
+
const g = mat4();
|
|
255
|
+
g[0][0] = -(c * c) * f;
|
|
256
|
+
g[1][1] = 1 / f;
|
|
257
|
+
g[2][2] = r * r;
|
|
258
|
+
g[3][3] = r * r * Math.sin(th) * Math.sin(th);
|
|
259
|
+
return g;
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
/** Schwarzschild Kretschmann 48 G² M² / (c⁴ r⁶). @internal */
|
|
263
|
+
export function schwarzschildKretschmann(M, r, c = C_SI, G = G_SI) {
|
|
264
|
+
return (48 * G * G * M * M) / (c ** 4 * r ** 6);
|
|
265
|
+
}
|
|
266
|
+
function flrwScale(t, a0, t0, n) {
|
|
267
|
+
const a = a0 * Math.pow(t / t0, n);
|
|
268
|
+
const adot = (n * a) / t;
|
|
269
|
+
const addot = (n * (n - 1) * a) / (t * t);
|
|
270
|
+
return { a, adot, addot };
|
|
271
|
+
}
|
|
272
|
+
function flrwMetric(a0, t0, n, k, c) {
|
|
273
|
+
return (x) => {
|
|
274
|
+
const { a } = flrwScale(x[0], a0, t0, n);
|
|
275
|
+
const r = x[1];
|
|
276
|
+
const th = x[2];
|
|
277
|
+
const g = mat4();
|
|
278
|
+
g[0][0] = -(c * c);
|
|
279
|
+
g[1][1] = (a * a) / (1 - k * r * r);
|
|
280
|
+
g[2][2] = a * a * r * r;
|
|
281
|
+
g[3][3] = a * a * r * r * Math.sin(th) * Math.sin(th);
|
|
282
|
+
return g;
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/** FLRW Ricci scalar 6/c² (ä/a + H² + k c²/a²). @internal */
|
|
286
|
+
export function flrwRicciScalar(t, a0, t0, n, k, r, c = C_SI) {
|
|
287
|
+
const { a, adot, addot } = flrwScale(t, a0, t0, n);
|
|
288
|
+
const H = adot / a;
|
|
289
|
+
return (6 / (c * c)) * (addot / a + H * H + (k * c * c) / (a * a));
|
|
290
|
+
}
|
|
291
|
+
/** H² and the Friedmann right-hand side, including curvature and Λ. @internal */
|
|
292
|
+
export function friedmannSides(opts) {
|
|
293
|
+
const c = opts.c ?? C_SI;
|
|
294
|
+
const G = opts.G ?? G_SI;
|
|
295
|
+
const { a, adot } = flrwScale(opts.t, opts.a0, opts.t0, opts.n);
|
|
296
|
+
const H2 = (adot / a) ** 2;
|
|
297
|
+
const rhs = (8 * Math.PI * G * opts.rho) / 3 - (opts.k * c * c) / (a * a) + (opts.lambda * c * c) / 3;
|
|
298
|
+
return { H2, rhs };
|
|
299
|
+
}
|
|
300
|
+
function kerrMetric(Mgeom, a) {
|
|
301
|
+
return (x) => {
|
|
302
|
+
const r = x[1];
|
|
303
|
+
const th = x[2];
|
|
304
|
+
const cth = Math.cos(th);
|
|
305
|
+
const sth = Math.sin(th);
|
|
306
|
+
const Sigma = r * r + a * a * cth * cth;
|
|
307
|
+
const Delta = r * r - 2 * Mgeom * r + a * a;
|
|
308
|
+
const g = mat4();
|
|
309
|
+
g[0][0] = -(1 - (2 * Mgeom * r) / Sigma);
|
|
310
|
+
g[0][3] = g[3][0] = -((2 * Mgeom * r * a * sth * sth) / Sigma);
|
|
311
|
+
g[1][1] = Sigma / Delta;
|
|
312
|
+
g[2][2] = Sigma;
|
|
313
|
+
g[3][3] = sth * sth * (r * r + a * a + (2 * Mgeom * r * a * a * sth * sth) / Sigma);
|
|
314
|
+
return g;
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Kerr Kretschmann in geometrized units (G = c = 1), 1/length⁴.
|
|
319
|
+
* M, r and a are lengths. a = 0 is 48 M²/r⁶.
|
|
320
|
+
* @internal
|
|
321
|
+
*/
|
|
322
|
+
export function kerrKretschmann(M, r, a, theta) {
|
|
323
|
+
const c2 = Math.cos(theta) ** 2;
|
|
324
|
+
const Sigma = r * r + a * a * c2;
|
|
325
|
+
const num = 48 *
|
|
326
|
+
M *
|
|
327
|
+
M *
|
|
328
|
+
(r * r - a * a * c2) *
|
|
329
|
+
((r * r + a * a * c2) ** 2 - 16 * r * r * a * a * c2);
|
|
330
|
+
return num / Sigma ** 6;
|
|
331
|
+
}
|
|
332
|
+
/** SI dimension of each metric parameter. A bare number is already in that unit. */
|
|
333
|
+
const PARAM_DIM = {
|
|
334
|
+
M: MASS,
|
|
335
|
+
c: VELOCITY,
|
|
336
|
+
G: { L: 3, M: -1, T: -2, I: 0, Theta: 0, N: 0, J: 0 },
|
|
337
|
+
r: LENGTH,
|
|
338
|
+
a: LENGTH,
|
|
339
|
+
t: TIME,
|
|
340
|
+
theta: DIMENSIONLESS,
|
|
341
|
+
phi: DIMENSIONLESS,
|
|
342
|
+
a0: DIMENSIONLESS,
|
|
343
|
+
t0: TIME,
|
|
344
|
+
n: DIMENSIONLESS,
|
|
345
|
+
k: { L: -2, M: 0, T: 0, I: 0, Theta: 0, N: 0, J: 0 },
|
|
346
|
+
Lambda: { L: -2, M: 0, T: 0, I: 0, Theta: 0, N: 0, J: 0 },
|
|
347
|
+
rho: { L: -3, M: 1, T: 0, I: 0, Theta: 0, N: 0, J: 0 },
|
|
348
|
+
};
|
|
349
|
+
/** Parse `key=value` pairs. A value is a number, a unit, or a constant expression. @internal */
|
|
350
|
+
export function metricParams(pairs, defaults) {
|
|
351
|
+
const values = { ...defaults };
|
|
352
|
+
const notes = [];
|
|
353
|
+
for (const pair of pairs) {
|
|
354
|
+
const eq = pair.indexOf('=');
|
|
355
|
+
if (eq <= 0)
|
|
356
|
+
throw new Error(`'${pair}' must be key=value`);
|
|
357
|
+
const key = pair.slice(0, eq);
|
|
358
|
+
if (!(key in defaults))
|
|
359
|
+
throw new Error(`unknown parameter '${key}' (expected ${Object.keys(defaults).join(', ')})`);
|
|
360
|
+
const read = readParameter(pair.slice(eq + 1), PARAM_DIM[key] ?? DIMENSIONLESS);
|
|
361
|
+
values[key] = read.value;
|
|
362
|
+
for (const note of read.notes)
|
|
363
|
+
if (!notes.includes(note))
|
|
364
|
+
notes.push(note);
|
|
365
|
+
}
|
|
366
|
+
return { values, notes };
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Curvature at one point. `pairs` overrides the documented defaults.
|
|
370
|
+
* @internal
|
|
371
|
+
*/
|
|
372
|
+
export function curvatureReport(metric, pairs = []) {
|
|
373
|
+
if (metric === 'minkowski') {
|
|
374
|
+
const { values: p, notes } = metricParams(pairs, { c: C_SI, t: 0, r: 1, theta: 1, phi: 0 });
|
|
375
|
+
const g = () => {
|
|
376
|
+
const m = mat4();
|
|
377
|
+
m[0][0] = -(p.c * p.c);
|
|
378
|
+
m[1][1] = 1;
|
|
379
|
+
m[2][2] = 1;
|
|
380
|
+
m[3][3] = 1;
|
|
381
|
+
return m;
|
|
382
|
+
};
|
|
383
|
+
const x = [p.t, p.r, p.theta, p.phi];
|
|
384
|
+
const t = tensorsOf(g, x, stepsFor(x));
|
|
385
|
+
return stateCurvature(pack('minkowski', p, x, t, { ricciScalar: 0, kretschmann: 0 }, [
|
|
386
|
+
'Minkowski in Cartesian-like coordinates (the angular part is not a sphere here; g_θθ = g_φφ = 1).',
|
|
387
|
+
...notes,
|
|
388
|
+
]));
|
|
389
|
+
}
|
|
390
|
+
if (metric === 'schwarzschild') {
|
|
391
|
+
const { values: p, notes } = metricParams(pairs, { M: M_SUN_SI, c: C_SI, G: G_SI, r: 0, theta: Math.PI / 2, phi: 0, t: 0 });
|
|
392
|
+
const rs = (2 * p.G * p.M) / (p.c * p.c);
|
|
393
|
+
if (p.r === 0)
|
|
394
|
+
p.r = 10 * rs;
|
|
395
|
+
if (!(p.r > rs))
|
|
396
|
+
throw new Error(`r must be outside the horizon (r_s = ${rs})`);
|
|
397
|
+
const g = schwarzschildMetric(p.M, p.c, p.G);
|
|
398
|
+
const x = [p.t, p.r, p.theta, p.phi];
|
|
399
|
+
const t = tensorsOf(g, x, stepsFor(x));
|
|
400
|
+
const K = schwarzschildKretschmann(p.M, p.r, p.c, p.G);
|
|
401
|
+
return stateCurvature(pack('schwarzschild', p, x, t, { kretschmann: K, ricciScalar: 0, horizon_m: rs }, [
|
|
402
|
+
'Closed form: Kretschmann = 48 G² M² / (c⁴ r⁶), Ricci = 0.',
|
|
403
|
+
'Christoffel symbols below are the finite-difference values.',
|
|
404
|
+
...notes,
|
|
405
|
+
]));
|
|
406
|
+
}
|
|
407
|
+
if (metric === 'flrw') {
|
|
408
|
+
const { values: p, notes } = metricParams(pairs, {
|
|
409
|
+
a0: 1,
|
|
410
|
+
t0: 1,
|
|
411
|
+
n: 2 / 3,
|
|
412
|
+
k: 0,
|
|
413
|
+
Lambda: 0,
|
|
414
|
+
rho: 0,
|
|
415
|
+
c: C_SI,
|
|
416
|
+
G: G_SI,
|
|
417
|
+
t: 2,
|
|
418
|
+
r: 0.3,
|
|
419
|
+
theta: 1,
|
|
420
|
+
phi: 0.4,
|
|
421
|
+
});
|
|
422
|
+
const { a, adot } = flrwScale(p.t, p.a0, p.t0, p.n);
|
|
423
|
+
const H2 = (adot / a) ** 2;
|
|
424
|
+
if (p.rho === 0 && p.k === 0 && p.Lambda === 0) {
|
|
425
|
+
p.rho = (3 * H2) / (8 * Math.PI * p.G);
|
|
426
|
+
}
|
|
427
|
+
const g = flrwMetric(p.a0, p.t0, p.n, p.k, p.c);
|
|
428
|
+
const x = [p.t, p.r, p.theta, p.phi];
|
|
429
|
+
// Christoffel in the SI metric. Ricci and Kretschmann are computed at c = 1
|
|
430
|
+
// and divided by c² and c⁴: g_tt = −c² makes those scalars smaller than the
|
|
431
|
+
// roundoff of an SI finite difference.
|
|
432
|
+
const tSi = tensorsOf(g, x, stepsFor(x));
|
|
433
|
+
const t1 = p.c === 1 ? tSi : tensorsOf(flrwMetric(p.a0, p.t0, p.n, p.k, 1), x, stepsFor(x));
|
|
434
|
+
const c2 = p.c * p.c;
|
|
435
|
+
const t = {
|
|
436
|
+
christoffel: tSi.christoffel,
|
|
437
|
+
ricci: t1.ricci.map((row) => row.map((v) => v / c2)),
|
|
438
|
+
ricciScalar: t1.ricciScalar / c2,
|
|
439
|
+
kretschmann: t1.kretschmann / (c2 * c2),
|
|
440
|
+
};
|
|
441
|
+
const R = flrwRicciScalar(p.t, p.a0, p.t0, p.n, p.k, p.r, p.c);
|
|
442
|
+
const sides = friedmannSides({
|
|
443
|
+
t: p.t,
|
|
444
|
+
a0: p.a0,
|
|
445
|
+
t0: p.t0,
|
|
446
|
+
n: p.n,
|
|
447
|
+
k: p.k,
|
|
448
|
+
r: p.r,
|
|
449
|
+
rho: p.rho,
|
|
450
|
+
lambda: p.Lambda,
|
|
451
|
+
c: p.c,
|
|
452
|
+
G: p.G,
|
|
453
|
+
});
|
|
454
|
+
return stateCurvature(pack('flrw', p, x, t, { ricciScalar: R, H2: sides.H2, friedmannRhs: sides.rhs }, [
|
|
455
|
+
'ds² = −c² dt² + a(t)² [dr²/(1−k r²) + r² dΩ²], a(t) = a0 (t/t0)^n.',
|
|
456
|
+
'Friedmann: H² = 8πGρ/3 − k c²/a² + Λ c²/3. Flat dust defaults n = 2/3 and ρ = 3 H²/(8πG). CE-friedmann is the flat term; CE-friedmann-curvature carries −k c²/a².',
|
|
457
|
+
'Ricci scalar closed form: R = 6/c² (ä/a + H² + k c²/a²). Flat dust: R = 3 H²/c².',
|
|
458
|
+
'Ricci and Kretschmann are finite-differenced at c = 1 and restored with 1/c² and 1/c⁴. Christoffel symbols are the SI difference.',
|
|
459
|
+
...notes,
|
|
460
|
+
]));
|
|
461
|
+
}
|
|
462
|
+
const { values: p, notes: paramNotes } = metricParams(pairs, {
|
|
463
|
+
M: M_SUN_SI,
|
|
464
|
+
a: 0,
|
|
465
|
+
c: C_SI,
|
|
466
|
+
G: G_SI,
|
|
467
|
+
r: 0,
|
|
468
|
+
theta: Math.PI / 2,
|
|
469
|
+
phi: 0,
|
|
470
|
+
t: 0,
|
|
471
|
+
});
|
|
472
|
+
const Mgeom = (p.G * p.M) / (p.c * p.c);
|
|
473
|
+
if (p.r === 0)
|
|
474
|
+
p.r = 10 * Mgeom;
|
|
475
|
+
if (Math.abs(p.a) >= p.r)
|
|
476
|
+
throw new Error('Kerr finite difference wants |a| < r and r outside the ring');
|
|
477
|
+
const g = kerrMetric(Mgeom, p.a);
|
|
478
|
+
const x = [p.t, p.r, p.theta, p.phi];
|
|
479
|
+
const t = tensorsOf(g, x, stepsFor(x));
|
|
480
|
+
const K = kerrKretschmann(Mgeom, p.r, p.a, p.theta);
|
|
481
|
+
const aOverM = p.a / Mgeom;
|
|
482
|
+
const kerrNotes = [
|
|
483
|
+
'Boyer–Lindquist, geometrized lengths: M stands for GM/c² and a is a length. Kretschmann is 1/length⁴.',
|
|
484
|
+
];
|
|
485
|
+
if (p.a !== 0 && Math.abs(p.a) <= 1 && Mgeom > 10) {
|
|
486
|
+
kerrNotes.push(`a = ${p.a} m is a length, so a/M = ${aOverM}. A dimensionless spin is a/(GM/c²), not the number passed as a.`);
|
|
487
|
+
}
|
|
488
|
+
return stateCurvature(pack('kerr', { ...p, M_geom_m: Mgeom, a_over_M: aOverM }, x, t, { kretschmann: K, ricciScalar: 0 }, [
|
|
489
|
+
...paramNotes,
|
|
490
|
+
...kerrNotes,
|
|
491
|
+
'Closed form: K = 48 M² (r² − a² cos²θ) [(r² + a² cos²θ)² − 16 r² a² cos²θ] / (r² + a² cos²θ)⁶.',
|
|
492
|
+
'a = 0 reduces to the Schwarzschild Kretschmann 48 M²/r⁶.',
|
|
493
|
+
'Geodesics (--geodesic) use the Carter constant. θ = π/2 is an equatorial circular orbit. Any other θ is an inclined spherical orbit with that polar turning point. ISCO and photon radii are closed forms in r/M.',
|
|
494
|
+
]));
|
|
495
|
+
}
|
|
496
|
+
const relDiff = (got, want) => Math.abs(got - want) / Math.max(Math.abs(want), 1e-30);
|
|
497
|
+
/**
|
|
498
|
+
* The headline Ricci scalar is the closed form when the finite difference
|
|
499
|
+
* does not match it. A vacuum metric's finite-difference residual is not
|
|
500
|
+
* listed as Ricci. A scale factor that does not solve Friedmann says so.
|
|
501
|
+
*/
|
|
502
|
+
function stateCurvature(report) {
|
|
503
|
+
const notes = [...report.notes];
|
|
504
|
+
let ricci = report.ricci;
|
|
505
|
+
let ricciScalar = report.ricciScalar;
|
|
506
|
+
const exactR = report.closedForm.ricciScalar;
|
|
507
|
+
if (exactR === 0 && Math.abs(report.ricciScalar) < 1e-6) {
|
|
508
|
+
ricciScalar = 0;
|
|
509
|
+
ricci = [];
|
|
510
|
+
notes.push('Ricci is 0 for this vacuum metric. A finite-difference residual is not listed.');
|
|
511
|
+
}
|
|
512
|
+
else if (exactR !== undefined && relDiff(report.ricciScalar, exactR) > 1e-2) {
|
|
513
|
+
ricciScalar = exactR;
|
|
514
|
+
ricci = [];
|
|
515
|
+
notes.push('Ricci scalar is the closed form. The finite-difference scalar, restored from a c = 1 difference by 1/c², does not match it when spatial curvature is present, so those components are not listed.');
|
|
516
|
+
}
|
|
517
|
+
const H2 = report.closedForm.H2;
|
|
518
|
+
const rhs = report.closedForm.friedmannRhs;
|
|
519
|
+
if (H2 !== undefined && rhs !== undefined && relDiff(H2, rhs) > 1e-6) {
|
|
520
|
+
notes.push('H² and the Friedmann right-hand side differ, so this scale factor is not a solution of the Friedmann equation at the stated ρ, k and Λ. k is a curvature in 1/length²: k = 1 with c in m/s is a curvature radius of about a metre, not the dimensionless k = ±1 of geometrized cosmology.');
|
|
521
|
+
}
|
|
522
|
+
return { ...report, ricci, ricciScalar, notes };
|
|
523
|
+
}
|
|
524
|
+
function pack(metric, parameters, x, t, closedForm, notes) {
|
|
525
|
+
const names = ['t', 'r', 'θ', 'φ'];
|
|
526
|
+
return {
|
|
527
|
+
metric,
|
|
528
|
+
signature: METRIC_SIGNATURE,
|
|
529
|
+
signatureNote: METRIC_SIGNATURE_NOTE,
|
|
530
|
+
coordinates: '(t, r, θ, φ)',
|
|
531
|
+
parameters,
|
|
532
|
+
point: { t: x[0], r: x[1], theta: x[2], phi: x[3] },
|
|
533
|
+
christoffel: nonzeroGamma(t.christoffel),
|
|
534
|
+
ricci: nonzeroMatrix(t.ricci, (i, j) => `R_${names[i]}${names[j]}`),
|
|
535
|
+
ricciScalar: t.ricciScalar,
|
|
536
|
+
kretschmann: t.kretschmann,
|
|
537
|
+
closedForm,
|
|
538
|
+
notes,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* A short Schwarzschild circular-orbit integration (analytic Christoffel, RK4).
|
|
543
|
+
* Returns the radial drift relative to the start and the coordinate φ advance.
|
|
544
|
+
* Kerr is refused.
|
|
545
|
+
* @internal
|
|
546
|
+
*/
|
|
547
|
+
export function schwarzschildCircularOrbit(opts) {
|
|
548
|
+
const Msi = opts?.M ?? M_SUN_SI;
|
|
549
|
+
const c = opts?.c ?? C_SI;
|
|
550
|
+
const G = opts?.G ?? G_SI;
|
|
551
|
+
// Integrate in geometrized units (c = G = 1). An SI Γ^r_tt is ~c² and cancels
|
|
552
|
+
// only after two huge terms; the residual then blows the step up.
|
|
553
|
+
const M = (G * Msi) / (c * c);
|
|
554
|
+
const rs = 2 * M;
|
|
555
|
+
const r0 = opts?.r ?? 10 * rs;
|
|
556
|
+
const f = 1 - rs / r0;
|
|
557
|
+
const Omega = Math.sqrt(M / r0 ** 3);
|
|
558
|
+
const ut = 1 / Math.sqrt(1 - (3 * rs) / (2 * r0));
|
|
559
|
+
const uphi = Omega * ut;
|
|
560
|
+
if (!(f > 0) || !Number.isFinite(ut))
|
|
561
|
+
throw new Error('circular orbit needs r > 1.5 r_s');
|
|
562
|
+
// Analytic Γ for the equatorial circular orbit (θ = π/2, sin = 1, cos = 0).
|
|
563
|
+
// Equatorial reduction. The polar symbols that carry cot θ are omitted:
|
|
564
|
+
// a floating-point step off θ = π/2 makes cot θ explode.
|
|
565
|
+
const gamma = (r) => {
|
|
566
|
+
const ff = 1 - rs / r;
|
|
567
|
+
const Gma = blankGamma();
|
|
568
|
+
const set = (rho, mu, nu, v) => {
|
|
569
|
+
Gma[rho][mu][nu] = v;
|
|
570
|
+
Gma[rho][nu][mu] = v;
|
|
571
|
+
};
|
|
572
|
+
set(0, 0, 1, rs / (2 * r * (r - rs)));
|
|
573
|
+
set(1, 0, 0, (rs * ff) / (2 * r * r));
|
|
574
|
+
set(1, 1, 1, -rs / (2 * r * (r - rs)));
|
|
575
|
+
set(1, 2, 2, -(r - rs));
|
|
576
|
+
set(1, 3, 3, -(r - rs));
|
|
577
|
+
set(2, 1, 2, 1 / r);
|
|
578
|
+
set(3, 1, 3, 1 / r);
|
|
579
|
+
return Gma;
|
|
580
|
+
};
|
|
581
|
+
// state: t, r, th, phi, ut, ur, uth, uphi
|
|
582
|
+
let y = [0, r0, Math.PI / 2, 0, ut, 0, 0, uphi];
|
|
583
|
+
const accel = (s) => {
|
|
584
|
+
const Gma = gamma(s[1]);
|
|
585
|
+
const u = [s[4], s[5], s[6], s[7]];
|
|
586
|
+
const du = [0, 0, 0, 0];
|
|
587
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
588
|
+
let sum = 0;
|
|
589
|
+
for (let mu = 0; mu < 4; mu++) {
|
|
590
|
+
for (let nu = 0; nu < 4; nu++)
|
|
591
|
+
sum += Gma[rho][mu][nu] * u[mu] * u[nu];
|
|
592
|
+
}
|
|
593
|
+
du[rho] = -sum;
|
|
594
|
+
}
|
|
595
|
+
return [u[0], u[1], u[2], u[3], du[0], du[1], du[2], du[3]];
|
|
596
|
+
};
|
|
597
|
+
const add = (a, b, scale) => a.map((v, i) => v + scale * b[i]);
|
|
598
|
+
const period = (2 * Math.PI) / uphi;
|
|
599
|
+
const fraction = opts?.fraction ?? 0.02;
|
|
600
|
+
const steps = 400;
|
|
601
|
+
const h = (period * fraction) / steps;
|
|
602
|
+
for (let n = 0; n < steps; n++) {
|
|
603
|
+
const k1 = accel(y);
|
|
604
|
+
const k2 = accel(add(y, k1, h / 2));
|
|
605
|
+
const k3 = accel(add(y, k2, h / 2));
|
|
606
|
+
const k4 = accel(add(y, k3, h));
|
|
607
|
+
y = y.map((v, i) => v + (h / 6) * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]));
|
|
608
|
+
y[2] = Math.PI / 2;
|
|
609
|
+
y[6] = 0;
|
|
610
|
+
}
|
|
611
|
+
return { r0, rEnd: y[1], phiAdvance: y[3], steps };
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Kerr ISCO radii in units of M. χ = a/M, |χ| ≤ 1.
|
|
615
|
+
* Bardeen, Press & Teukolsky 1972: r/M = 3 + Z2 ∓ √((3−Z1)(3+Z1+2 Z2)),
|
|
616
|
+
* upper sign prograde.
|
|
617
|
+
* @internal
|
|
618
|
+
*/
|
|
619
|
+
export function kerrIscoRadius(aOverM) {
|
|
620
|
+
const chi = aOverM;
|
|
621
|
+
if (!(Math.abs(chi) <= 1))
|
|
622
|
+
throw new Error('|a/M| must be at most 1');
|
|
623
|
+
const z1 = 1 + Math.cbrt(1 - chi * chi) * (Math.cbrt(1 + chi) + Math.cbrt(1 - chi));
|
|
624
|
+
const z2 = Math.sqrt(3 * chi * chi + z1 * z1);
|
|
625
|
+
const inner = Math.sqrt((3 - z1) * (3 + z1 + 2 * z2));
|
|
626
|
+
return { prograde: 3 + z2 - inner, retrograde: 3 + z2 + inner };
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Unstable equatorial photon orbits in units of M.
|
|
630
|
+
* r/M = 2 (1 + cos(⅔ arccos(∓ a/M))), upper sign prograde.
|
|
631
|
+
* @internal
|
|
632
|
+
*/
|
|
633
|
+
export function kerrPhotonRadius(aOverM) {
|
|
634
|
+
const chi = aOverM;
|
|
635
|
+
if (!(Math.abs(chi) <= 1))
|
|
636
|
+
throw new Error('|a/M| must be at most 1');
|
|
637
|
+
return {
|
|
638
|
+
prograde: 2 * (1 + Math.cos((2 / 3) * Math.acos(-chi))),
|
|
639
|
+
retrograde: 2 * (1 + Math.cos((2 / 3) * Math.acos(chi))),
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function radialPotential(M, a, r, E, L, Q, mu2) {
|
|
643
|
+
const Delta = r * r - 2 * M * r + a * a;
|
|
644
|
+
const P = E * (r * r + a * a) - a * L;
|
|
645
|
+
return P * P - Delta * (mu2 * r * r + (L - a * E) ** 2 + Q);
|
|
646
|
+
}
|
|
647
|
+
function radialPotentialPrime(M, a, r, E, L, Q, mu2) {
|
|
648
|
+
const Delta = r * r - 2 * M * r + a * a;
|
|
649
|
+
const dDelta = 2 * (r - M);
|
|
650
|
+
const P = E * (r * r + a * a) - a * L;
|
|
651
|
+
const separated = mu2 * r * r + (L - a * E) ** 2 + Q;
|
|
652
|
+
return 4 * r * E * P - dDelta * separated - 2 * mu2 * r * Delta;
|
|
653
|
+
}
|
|
654
|
+
/** Equatorial circular energy and axial angular momentum. Upper sign is prograde. */
|
|
655
|
+
function equatorialCircular(M, a, r, prograde) {
|
|
656
|
+
const sign = prograde ? 1 : -1;
|
|
657
|
+
const sqrtM = Math.sqrt(M);
|
|
658
|
+
const Omega = (sign * sqrtM) / (r ** 1.5 + sign * a * sqrtM);
|
|
659
|
+
const g0 = kerrMetric(M, a)([0, r, Math.PI / 2, 0]);
|
|
660
|
+
const norm = -(g0[0][0] + 2 * Omega * g0[0][3] + Omega * Omega * g0[3][3]);
|
|
661
|
+
if (!(norm > 0) || !Number.isFinite(Omega))
|
|
662
|
+
throw new Error('circular orbit is not timelike at this radius');
|
|
663
|
+
const ut = 1 / Math.sqrt(norm);
|
|
664
|
+
const uphi = Omega * ut;
|
|
665
|
+
return {
|
|
666
|
+
E: -(g0[0][0] * ut + g0[0][3] * uphi),
|
|
667
|
+
L: g0[3][0] * ut + g0[3][3] * uphi,
|
|
668
|
+
uphi,
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
/** ∂(R, R')/∂(E, L). Lengths are in units of M, so L and Q are L/M and Q/M². */
|
|
672
|
+
function sphericalJacobian(a, r, E, L) {
|
|
673
|
+
const Delta = r * r - 2 * r + a * a;
|
|
674
|
+
const dDelta = 2 * (r - 1);
|
|
675
|
+
const alpha = r * r + a * a;
|
|
676
|
+
const P = E * alpha - a * L;
|
|
677
|
+
const x = L - a * E;
|
|
678
|
+
const dPdE = alpha;
|
|
679
|
+
const dPdL = -a;
|
|
680
|
+
const dSdE = -2 * a * x;
|
|
681
|
+
const dSdL = 2 * x;
|
|
682
|
+
return {
|
|
683
|
+
j11: 2 * P * dPdE - Delta * dSdE,
|
|
684
|
+
j12: 2 * P * dPdL - Delta * dSdL,
|
|
685
|
+
j21: 4 * r * P + 4 * r * E * dPdE - dDelta * dSdE,
|
|
686
|
+
j22: 4 * r * E * dPdL - dDelta * dSdL,
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
function solveSpherical(M, a, r, Q, mu2, prograde) {
|
|
690
|
+
// R is a difference of terms ~ r⁴. Solve in units of M so a solar radius
|
|
691
|
+
// does not wipe the L-column of a finite-difference Jacobian.
|
|
692
|
+
const aHat = a / M;
|
|
693
|
+
const rHat = r / M;
|
|
694
|
+
const QHat = Q / (M * M);
|
|
695
|
+
const seed = equatorialCircular(1, aHat, rHat, prograde);
|
|
696
|
+
let E = seed.E;
|
|
697
|
+
let L = seed.L;
|
|
698
|
+
for (let n = 0; n < 30; n++) {
|
|
699
|
+
const f1 = radialPotential(1, aHat, rHat, E, L, QHat, mu2);
|
|
700
|
+
const f2 = radialPotentialPrime(1, aHat, rHat, E, L, QHat, mu2);
|
|
701
|
+
const { j11, j12, j21, j22 } = sphericalJacobian(aHat, rHat, E, L);
|
|
702
|
+
const det = j11 * j22 - j12 * j21;
|
|
703
|
+
const scale = Math.max(1, Math.abs(j11), Math.abs(j12), Math.abs(j21), Math.abs(j22));
|
|
704
|
+
if (!Number.isFinite(det) || Math.abs(det) < 1e-18 * scale * scale)
|
|
705
|
+
throw new Error('spherical-orbit Jacobian is singular');
|
|
706
|
+
const stepE = (j22 * f1 - j12 * f2) / det;
|
|
707
|
+
const stepL = (-j21 * f1 + j11 * f2) / det;
|
|
708
|
+
E -= stepE;
|
|
709
|
+
L -= stepL;
|
|
710
|
+
// r⁴ cancellation leaves R' uncertain by a fraction of a unit at large r/M.
|
|
711
|
+
const room = Math.max(1, rHat ** 4);
|
|
712
|
+
const settled = Math.abs(stepE) < 1e-10 &&
|
|
713
|
+
Math.abs(stepL) < 1e-8 * Math.max(1, Math.abs(L)) &&
|
|
714
|
+
Math.abs(f1) < 1e-6 * room &&
|
|
715
|
+
Math.abs(f2) < 1e-6 * room;
|
|
716
|
+
if (settled)
|
|
717
|
+
return { E, L: L * M };
|
|
718
|
+
}
|
|
719
|
+
throw new Error('spherical orbit did not converge');
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Timelike spherical orbit at fixed r: R = R' = 0. `Q` is the Carter constant
|
|
723
|
+
* (0 on the equator). E and L come from that pair of conditions.
|
|
724
|
+
* @internal
|
|
725
|
+
*/
|
|
726
|
+
export function kerrSphericalTimelike(opts) {
|
|
727
|
+
const M = opts?.M ?? 1;
|
|
728
|
+
const chi = opts?.aOverM ?? 0;
|
|
729
|
+
if (!(M > 0) || !(Math.abs(chi) <= 1))
|
|
730
|
+
throw new Error('spherical orbit wants M > 0 and |a/M| ≤ 1');
|
|
731
|
+
const a = chi * M;
|
|
732
|
+
const r = (opts?.rOverM ?? 10) * M;
|
|
733
|
+
const Q = opts?.Q ?? 0;
|
|
734
|
+
const solved = solveSpherical(M, a, r, Q, 1, opts?.prograde !== false);
|
|
735
|
+
return {
|
|
736
|
+
E: solved.E,
|
|
737
|
+
L: solved.L,
|
|
738
|
+
Q,
|
|
739
|
+
R: radialPotential(M, a, r, solved.E, solved.L, Q, 1),
|
|
740
|
+
Rp: radialPotentialPrime(M, a, r, solved.E, solved.L, Q, 1),
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Spherical photon orbit between the equatorial photon radii.
|
|
745
|
+
* E is fixed at 1 (null affine scale). L/E and Q/E² are the separated
|
|
746
|
+
* constants with R = R' = 0 and μ² = 0. Q = 0 on either equatorial photon orbit.
|
|
747
|
+
* @internal
|
|
748
|
+
*/
|
|
749
|
+
export function kerrSphericalPhoton(opts) {
|
|
750
|
+
const M = opts?.M ?? 1;
|
|
751
|
+
const chi = opts?.aOverM ?? 0;
|
|
752
|
+
const rHat = opts?.rOverM;
|
|
753
|
+
if (!(M > 0) || !(Math.abs(chi) > 0 && Math.abs(chi) <= 1))
|
|
754
|
+
throw new Error('spherical photon orbit wants M > 0 and 0 < |a/M| ≤ 1');
|
|
755
|
+
if (rHat === undefined)
|
|
756
|
+
throw new Error('spherical photon orbit needs rOverM');
|
|
757
|
+
const ends = kerrPhotonRadius(chi);
|
|
758
|
+
const lo = Math.min(ends.prograde, ends.retrograde);
|
|
759
|
+
const hi = Math.max(ends.prograde, ends.retrograde);
|
|
760
|
+
if (!(rHat >= lo - 1e-9 && rHat <= hi + 1e-9)) {
|
|
761
|
+
throw new Error('spherical photon radius lies between the prograde and retrograde photon orbits');
|
|
762
|
+
}
|
|
763
|
+
const a = chi * M;
|
|
764
|
+
const r = rHat * M;
|
|
765
|
+
if (!(Math.abs(r - M) > 1e-9 * M))
|
|
766
|
+
throw new Error('extremal prograde photon orbit sits on the horizon');
|
|
767
|
+
const Delta = r * r - 2 * M * r + a * a;
|
|
768
|
+
const E = 1;
|
|
769
|
+
const L = E * ((r * r + a * a) / a - (2 * r * Delta) / (a * (r - M)));
|
|
770
|
+
const P = E * (r * r + a * a) - a * L;
|
|
771
|
+
const Q = (P * P) / Delta - (L - a * E) ** 2;
|
|
772
|
+
if (Q < -1e-8 * M * M)
|
|
773
|
+
throw new Error('no spherical photon orbit at this radius');
|
|
774
|
+
return { E, L, Q: Q < 0 ? 0 : Q };
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Spherical timelike orbit whose polar turning point is `theta`.
|
|
778
|
+
* The Carter constant is the value that makes Θ(θ) = 0 there.
|
|
779
|
+
* @internal
|
|
780
|
+
*/
|
|
781
|
+
export function kerrTurningPointOrbit(opts) {
|
|
782
|
+
const M = opts.M ?? 1;
|
|
783
|
+
const chi = opts.aOverM ?? 0;
|
|
784
|
+
if (!(M > 0) || !(Math.abs(chi) <= 1))
|
|
785
|
+
throw new Error('turning-point orbit wants M > 0 and |a/M| ≤ 1');
|
|
786
|
+
const a = chi * M;
|
|
787
|
+
const r = (opts.rOverM ?? 10) * M;
|
|
788
|
+
const theta = opts.theta;
|
|
789
|
+
const s = Math.sin(theta);
|
|
790
|
+
const c = Math.cos(theta);
|
|
791
|
+
if (!(Math.abs(s) > 1e-3) || !(Math.abs(c) > 1e-4)) {
|
|
792
|
+
throw new Error('turning-point θ must sit off the equator and off the pole');
|
|
793
|
+
}
|
|
794
|
+
const seed = equatorialCircular(M, a, r, opts.prograde !== false);
|
|
795
|
+
let Q = seed.L * seed.L * c * c;
|
|
796
|
+
let E = seed.E;
|
|
797
|
+
let L = seed.L;
|
|
798
|
+
for (let n = 0; n < 16; n++) {
|
|
799
|
+
const solved = solveSpherical(M, a, r, Q, 1, opts.prograde !== false);
|
|
800
|
+
E = solved.E;
|
|
801
|
+
L = solved.L;
|
|
802
|
+
const next = c * c * (a * a * (1 - E * E) + (L * L) / (s * s));
|
|
803
|
+
if (!Number.isFinite(next) || next < 0)
|
|
804
|
+
throw new Error('turning-point Carter constant left the physical range');
|
|
805
|
+
if (Math.abs(next - Q) <= 1e-9 * Math.max(1, Math.abs(next)))
|
|
806
|
+
return { E, L, Q: next };
|
|
807
|
+
Q = next;
|
|
808
|
+
}
|
|
809
|
+
throw new Error('turning-point Carter constant did not converge');
|
|
810
|
+
}
|
|
811
|
+
function kerrMetricDerivatives(M, a, r, theta) {
|
|
812
|
+
const c = Math.cos(theta);
|
|
813
|
+
const s = Math.sin(theta);
|
|
814
|
+
const Sigma = r * r + a * a * c * c;
|
|
815
|
+
const dSr = 2 * r;
|
|
816
|
+
const dSt = -2 * a * a * c * s;
|
|
817
|
+
const Delta = r * r - 2 * M * r + a * a;
|
|
818
|
+
const dDr = 2 * (r - M);
|
|
819
|
+
const Sigma2 = Sigma * Sigma;
|
|
820
|
+
const dr = mat4();
|
|
821
|
+
const dth = mat4();
|
|
822
|
+
dr[0][0] = (2 * M * (a * a * c * c - r * r)) / Sigma2;
|
|
823
|
+
dth[0][0] = (4 * M * r * a * a * c * s) / Sigma2;
|
|
824
|
+
const dtpR = (-2 * M * a * s * s * (a * a * c * c - r * r)) / Sigma2;
|
|
825
|
+
const dtpT = (-4 * M * a * r * s * c * (Sigma + a * a * s * s)) / Sigma2;
|
|
826
|
+
dr[0][3] = dr[3][0] = dtpR;
|
|
827
|
+
dth[0][3] = dth[3][0] = dtpT;
|
|
828
|
+
dr[1][1] = (dSr * Delta - Sigma * dDr) / (Delta * Delta);
|
|
829
|
+
dth[1][1] = dSt / Delta;
|
|
830
|
+
dr[2][2] = dSr;
|
|
831
|
+
dth[2][2] = dSt;
|
|
832
|
+
const A = (r * r + a * a) ** 2 - a * a * Delta * s * s;
|
|
833
|
+
const dAr = 4 * r * (r * r + a * a) - a * a * dDr * s * s;
|
|
834
|
+
const dAt = -2 * a * a * Delta * s * c;
|
|
835
|
+
dr[3][3] = (s * s * (dAr * Sigma - A * dSr)) / Sigma2;
|
|
836
|
+
dth[3][3] = ((2 * s * c * A + s * s * dAt) * Sigma - s * s * A * dSt) / Sigma2;
|
|
837
|
+
return { dr, dth };
|
|
838
|
+
}
|
|
839
|
+
function christoffelFrom(g, dg) {
|
|
840
|
+
const gi = invert4(g);
|
|
841
|
+
const G = blankGamma();
|
|
842
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
843
|
+
for (let mu = 0; mu < 4; mu++) {
|
|
844
|
+
for (let nu = mu; nu < 4; nu++) {
|
|
845
|
+
let s = 0;
|
|
846
|
+
for (let sigma = 0; sigma < 4; sigma++) {
|
|
847
|
+
const dmu = dg[mu]?.[nu][sigma] ?? 0;
|
|
848
|
+
const dnu = dg[nu]?.[mu][sigma] ?? 0;
|
|
849
|
+
const dsig = dg[sigma]?.[mu][nu] ?? 0;
|
|
850
|
+
s += gi[rho][sigma] * (dmu + dnu - dsig);
|
|
851
|
+
}
|
|
852
|
+
const v = 0.5 * s;
|
|
853
|
+
G[rho][mu][nu] = v;
|
|
854
|
+
G[rho][nu][mu] = v;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return G;
|
|
859
|
+
}
|
|
860
|
+
function kerrChristoffel(M, a, r, theta) {
|
|
861
|
+
const partial = kerrMetricDerivatives(M, a, r, theta);
|
|
862
|
+
return christoffelFrom(kerrMetric(M, a)([0, r, theta, 0]), [null, partial.dr, partial.dth, null]);
|
|
863
|
+
}
|
|
864
|
+
/** Largest |Γ_analytic − Γ_finite_difference| at one Boyer–Lindquist point. @internal */
|
|
865
|
+
export function kerrChristoffelFdGap(M, a, r, theta) {
|
|
866
|
+
const x = [0, r, theta, 0];
|
|
867
|
+
const analytic = kerrChristoffel(M, a, r, theta);
|
|
868
|
+
const fd = christoffelOf(kerrMetric(M, a), x, stepsFor(x));
|
|
869
|
+
let gap = 0;
|
|
870
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
871
|
+
for (let mu = 0; mu < 4; mu++) {
|
|
872
|
+
for (let nu = 0; nu < 4; nu++)
|
|
873
|
+
gap = Math.max(gap, Math.abs(analytic[rho][mu][nu] - fd[rho][mu][nu]));
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
return gap;
|
|
877
|
+
}
|
|
878
|
+
function schwarzschildChristoffel(M, r, theta) {
|
|
879
|
+
const rs = 2 * M;
|
|
880
|
+
const ff = 1 - rs / r;
|
|
881
|
+
const s = Math.sin(theta);
|
|
882
|
+
const c = Math.cos(theta);
|
|
883
|
+
const Gma = blankGamma();
|
|
884
|
+
const set = (rho, mu, nu, v) => {
|
|
885
|
+
Gma[rho][mu][nu] = v;
|
|
886
|
+
Gma[rho][nu][mu] = v;
|
|
887
|
+
};
|
|
888
|
+
set(0, 0, 1, rs / (2 * r * (r - rs)));
|
|
889
|
+
set(1, 0, 0, (rs * ff) / (2 * r * r));
|
|
890
|
+
set(1, 1, 1, -rs / (2 * r * (r - rs)));
|
|
891
|
+
set(1, 2, 2, -(r - rs));
|
|
892
|
+
set(1, 3, 3, -(r - rs) * s * s);
|
|
893
|
+
set(2, 1, 2, 1 / r);
|
|
894
|
+
set(2, 3, 3, -s * c);
|
|
895
|
+
set(3, 1, 3, 1 / r);
|
|
896
|
+
set(3, 2, 3, c / s);
|
|
897
|
+
return Gma;
|
|
898
|
+
}
|
|
899
|
+
function conservedOf(metric, a, y, mu2) {
|
|
900
|
+
const g = metric([y[0], y[1], y[2], y[3]]);
|
|
901
|
+
const u = [y[4], y[5], y[6], y[7]];
|
|
902
|
+
let norm = 0;
|
|
903
|
+
for (let i = 0; i < 4; i++)
|
|
904
|
+
for (let j = 0; j < 4; j++)
|
|
905
|
+
norm += g[i][j] * u[i] * u[j];
|
|
906
|
+
const E = -(g[0][0] * u[0] + g[0][3] * u[3]);
|
|
907
|
+
const L = g[3][0] * u[0] + g[3][3] * u[3];
|
|
908
|
+
const pTheta = g[2][2] * u[2];
|
|
909
|
+
const c = Math.cos(y[2]);
|
|
910
|
+
const s = Math.sin(y[2]);
|
|
911
|
+
const Q = pTheta * pTheta + c * c * (a * a * (mu2 - E * E) + (L * L) / (s * s));
|
|
912
|
+
return { E, L, Q, norm };
|
|
913
|
+
}
|
|
914
|
+
function carterState(M, a, r, theta, E, L, Q, mu2, signR, signTheta, allowOffShell) {
|
|
915
|
+
const c = Math.cos(theta);
|
|
916
|
+
const s = Math.sin(theta);
|
|
917
|
+
if (!(Math.abs(s) > 1e-6))
|
|
918
|
+
throw new Error('Boyer–Lindquist geodesic wants θ away from the poles');
|
|
919
|
+
const Sigma = r * r + a * a * c * c;
|
|
920
|
+
const Delta = r * r - 2 * M * r + a * a;
|
|
921
|
+
if (!(Delta > 0))
|
|
922
|
+
throw new Error('geodesic start must be outside the horizon');
|
|
923
|
+
const R = radialPotential(M, a, r, E, L, Q, mu2);
|
|
924
|
+
const Theta = Q - c * c * (a * a * (mu2 - E * E) + (L * L) / (s * s));
|
|
925
|
+
const scale = Math.max(1, E * E, L * L, Math.abs(Q));
|
|
926
|
+
if (R < -1e-8 * scale && !allowOffShell)
|
|
927
|
+
throw new Error('radial potential is negative at the start');
|
|
928
|
+
if (Theta < -1e-8 * scale && !allowOffShell)
|
|
929
|
+
throw new Error('polar potential is negative at the start');
|
|
930
|
+
const g = kerrMetric(M, a)([0, r, theta, 0]);
|
|
931
|
+
const det = g[0][0] * g[3][3] - g[0][3] * g[0][3];
|
|
932
|
+
const ut = (g[3][3] * -E - g[0][3] * L) / det;
|
|
933
|
+
const uphi = (g[0][0] * L - g[0][3] * -E) / det;
|
|
934
|
+
const ur = signR * Math.sqrt(Math.max(R, 0)) / Sigma;
|
|
935
|
+
const uth = signTheta * Math.sqrt(Math.max(Theta, 0)) / Sigma;
|
|
936
|
+
return [0, r, theta, 0, ut, ur, uth, uphi];
|
|
937
|
+
}
|
|
938
|
+
function integrateGeodesic(gammaAt, y0, fraction, steps) {
|
|
939
|
+
const accel = (s) => {
|
|
940
|
+
const Gma = gammaAt(s[1], s[2]);
|
|
941
|
+
const u = [s[4], s[5], s[6], s[7]];
|
|
942
|
+
const du = [0, 0, 0, 0];
|
|
943
|
+
for (let rho = 0; rho < 4; rho++) {
|
|
944
|
+
let sum = 0;
|
|
945
|
+
for (let mu = 0; mu < 4; mu++)
|
|
946
|
+
for (let nu = 0; nu < 4; nu++)
|
|
947
|
+
sum += Gma[rho][mu][nu] * u[mu] * u[nu];
|
|
948
|
+
du[rho] = -sum;
|
|
949
|
+
}
|
|
950
|
+
return [u[0], u[1], u[2], u[3], du[0], du[1], du[2], du[3]];
|
|
951
|
+
};
|
|
952
|
+
const add = (left, right, scale) => left.map((v, i) => v + scale * right[i]);
|
|
953
|
+
const angular = Math.max(Math.abs(y0[7]), Math.abs(y0[6]), 1e-12);
|
|
954
|
+
const h = ((2 * Math.PI) / angular) * fraction / steps;
|
|
955
|
+
let y = y0.slice();
|
|
956
|
+
for (let n = 0; n < steps; n++) {
|
|
957
|
+
const k1 = accel(y);
|
|
958
|
+
const k2 = accel(add(y, k1, h / 2));
|
|
959
|
+
const k3 = accel(add(y, k2, h / 2));
|
|
960
|
+
const k4 = accel(add(y, k3, h));
|
|
961
|
+
y = y.map((v, i) => v + (h / 6) * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]));
|
|
962
|
+
}
|
|
963
|
+
return y;
|
|
964
|
+
}
|
|
965
|
+
function sampleOf(metric, a, y0, y1, steps, mu2) {
|
|
966
|
+
const start = conservedOf(metric, a, y0, mu2);
|
|
967
|
+
const end = conservedOf(metric, a, y1, mu2);
|
|
968
|
+
return {
|
|
969
|
+
r0: y0[1],
|
|
970
|
+
rEnd: y1[1],
|
|
971
|
+
theta0: y0[2],
|
|
972
|
+
thetaEnd: y1[2],
|
|
973
|
+
phiAdvance: y1[3],
|
|
974
|
+
steps,
|
|
975
|
+
E0: start.E,
|
|
976
|
+
EEnd: end.E,
|
|
977
|
+
L0: start.L,
|
|
978
|
+
LEnd: end.L,
|
|
979
|
+
Q0: start.Q,
|
|
980
|
+
QEnd: end.Q,
|
|
981
|
+
norm0: start.norm,
|
|
982
|
+
normEnd: end.norm,
|
|
983
|
+
mu2,
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Integrate a Kerr geodesic in Boyer–Lindquist coordinates, geometrized (G = c = 1).
|
|
988
|
+
* Initial u^μ comes from the Carter first-order potentials (E, L, Q, μ²).
|
|
989
|
+
* The step is the second-order geodesic equation with analytic Christoffel symbols,
|
|
990
|
+
* so E, L, Q and g_μν u^μ u^ν are evolved quantities and can drift.
|
|
991
|
+
* `mu2` is 1 for timelike and 0 for null. `allowOffShell` starts the second-order
|
|
992
|
+
* equation even when a potential is negative; that is the control that r can move.
|
|
993
|
+
* @internal
|
|
994
|
+
*/
|
|
995
|
+
export function kerrGeodesic(opts) {
|
|
996
|
+
const M = opts.M ?? 1;
|
|
997
|
+
const chi = opts.aOverM ?? 0;
|
|
998
|
+
if (!(M > 0) || !(Math.abs(chi) <= 1))
|
|
999
|
+
throw new Error('Kerr geodesic wants M > 0 and |a/M| ≤ 1');
|
|
1000
|
+
const a = chi * M;
|
|
1001
|
+
const r = (opts.rOverM ?? 10) * M;
|
|
1002
|
+
const theta = opts.theta ?? Math.PI / 2;
|
|
1003
|
+
const mu2 = opts.mu2 ?? 1;
|
|
1004
|
+
const steps = opts.steps ?? 80;
|
|
1005
|
+
const fraction = opts.fraction ?? 0.01;
|
|
1006
|
+
const metric = kerrMetric(M, a);
|
|
1007
|
+
const y0 = carterState(M, a, r, theta, opts.E, opts.L, opts.Q, mu2, opts.signR ?? 1, opts.signTheta ?? 1, opts.allowOffShell === true);
|
|
1008
|
+
const y1 = integrateGeodesic((rr, th) => kerrChristoffel(M, a, rr, th), y0, fraction, steps);
|
|
1009
|
+
return sampleOf(metric, a, y0, y1, steps, mu2);
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Schwarzschild geodesic in geometrized units, with the closed-form Christoffel
|
|
1013
|
+
* symbols (the polar terms included). The initial 4-velocity is the a = 0 Carter
|
|
1014
|
+
* state, so a Kerr run at a = 0 can be compared coordinate by coordinate.
|
|
1015
|
+
* @internal
|
|
1016
|
+
*/
|
|
1017
|
+
export function schwarzschildGeodesic(opts) {
|
|
1018
|
+
const M = opts.M ?? 1;
|
|
1019
|
+
if (!(M > 0))
|
|
1020
|
+
throw new Error('Schwarzschild geodesic wants M > 0');
|
|
1021
|
+
const r = (opts.rOverM ?? 10) * M;
|
|
1022
|
+
const theta = opts.theta ?? Math.PI / 2;
|
|
1023
|
+
const steps = opts.steps ?? 80;
|
|
1024
|
+
const fraction = opts.fraction ?? 0.01;
|
|
1025
|
+
const metric = schwarzschildMetric(M, 1, 1);
|
|
1026
|
+
const y0 = carterState(M, 0, r, theta, opts.E, opts.L, opts.Q, 1, opts.signR ?? 1, opts.signTheta ?? 1, false);
|
|
1027
|
+
const y1 = integrateGeodesic((rr, th) => schwarzschildChristoffel(M, rr, th), y0, fraction, steps);
|
|
1028
|
+
return sampleOf(metric, 0, y0, y1, steps, 1);
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Integrate a Kerr equatorial circular orbit in geometrized units (G = c = 1).
|
|
1032
|
+
* Q is 0 and θ starts at π/2. E = −u_t and L = u_φ are evolved with the
|
|
1033
|
+
* second-order equation. `rOverM` must sit outside the photon orbit.
|
|
1034
|
+
* @internal
|
|
1035
|
+
*/
|
|
1036
|
+
export function kerrEquatorialCircular(opts) {
|
|
1037
|
+
const M = opts?.M ?? 1;
|
|
1038
|
+
const chi = opts?.aOverM ?? 0;
|
|
1039
|
+
const rOverM = opts?.rOverM ?? 10;
|
|
1040
|
+
if (!(M > 0) || !(Math.abs(chi) <= 1))
|
|
1041
|
+
throw new Error('|a/M| must be at most 1');
|
|
1042
|
+
const eq = equatorialCircular(M, chi * M, rOverM * M, opts?.prograde !== false);
|
|
1043
|
+
return kerrGeodesic({
|
|
1044
|
+
M,
|
|
1045
|
+
aOverM: chi,
|
|
1046
|
+
rOverM,
|
|
1047
|
+
theta: Math.PI / 2,
|
|
1048
|
+
E: eq.E,
|
|
1049
|
+
L: eq.L,
|
|
1050
|
+
Q: 0,
|
|
1051
|
+
mu2: 1,
|
|
1052
|
+
fraction: opts?.fraction ?? 0.01,
|
|
1053
|
+
steps: opts?.steps ?? 80,
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
//# sourceMappingURL=spacetime-metrics.js.map
|