pray-calc/.wiki/Dynamic-Algorithm.md
Aric Camarata c02f197ece v2.0.0 — TypeScript rewrite, dual ESM/CJS, 14 methods + PCD dynamic algorithm
Complete rewrite from plain JavaScript to TypeScript with dual CJS/ESM output
via tsup. Removes all legacy .js source files and the old CommonJS-only index.

Key changes:
- Full TypeScript source in src/ with strict mode and declaration maps
- tsup build: dist/index.cjs + dist/index.mjs + dual .d.ts / .d.mts types
- 14 traditional fixed-angle methods (UOIF through MUIS) + MSC seasonal method
- PCD dynamic algorithm: MSC seasonal base + Earth-Sun distance correction +
  ecliptic geometry + atmospheric refraction + observer elevation
- getTimesAll() batches all 14x2 zenith angles into a single SPA call
- getMscFajr() / getMscIsha() expose MSC seasonal reference directly
- getAngles() returns the PCD-computed fajrAngle and ishaAngle
- High-latitude bounds: angles clipped to [10, 20] above 55N
- 106 tests across ESM and CJS (test.mjs + test-cjs.cjs)
- CI matrix: Node 20/22/24, typecheck, pack-check
- Wiki: 12 reference pages + 6-page research section with global accuracy study,
  home-territory comparison, observational evidence, and field observation matrix
- Moon functions removed (migrated to moon-sighting package)
- pnpm-only, Node >=20, sideEffects: false
2026-02-25 18:11:20 -05:00

151 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Dynamic Twilight Angle Algorithm
The core differentiator of pray-calc is that it does not use a fixed depression angle
for Fajr and Isha. Instead, it computes the angle that matches the observable
astronomical phenomenon for the specific location and date.
## Why Fixed Angles Fail
A depression angle is the number of degrees the Sun sits below the horizon. Traditional
methods hard-code a value: ISNA uses 15°, MWL uses 18°, MUIS uses 20°.
This works reasonably well near the equator. At 0° latitude, the Sun's path is nearly
vertical at the horizon, so it passes through any given depression quickly. Twilight is
short, and the sky becomes astronomically dark (18°) close to when it visually darkens
for a human observer.
At higher latitudes, the Sun's path is oblique. It skims below the horizon rather than
diving through it. Two consequences follow:
1. **Twilight is extended.** The sky stays illuminated at a given depression longer
than at the equator.
2. **The Sun may never reach the required angle.** Above 48.5°N in summer, the Sun
never reaches 18° depression. Above 51.5°N, it never reaches 15°. A fixed-angle
method produces no Isha in London for weeks in summer.
Even at mid-latitudes, observational campaigns show that true Fajr (the visible
"white thread" of dawn) appears when the Sun is around 1416° below the horizon, not
18°. Using 18° makes Fajr 2030 minutes too early in many regions.
## Three-Layer Model
The `getAngles` function computes a depression angle in three layers.
### Layer 1: MSC Seasonal Base
The Moonsighting Committee Worldwide (Khalid Shaukat) derived a piecewise-linear
empirical model by fitting to field observations across a wide range of latitudes.
The model returns the expected time offset in minutes:
- Fajr: minutes before astronomical sunrise
- Isha: minutes after astronomical sunset
The model uses four seasonal anchor points per latitude (winter solstice, spring
equinox, summer shoulder, summer solstice) and interpolates between them. The
offsets grow with latitude and peak near the summer solstice, reflecting the
astronomical reality of extended twilight.
pray-calc converts those minute offsets to depression angles using spherical
trigonometry:
```
cos(H) = (sin(a) - sin(φ)sin(δ)) / (cos(φ)cos(δ))
depression = -a (where a is the altitude solution)
```
Where `H` is the hour angle derived from the minute offset, `φ` is latitude,
`δ` is solar declination.
### Layer 2: Physics Corrections
Three corrections are added to the MSC base angle:
**Earth-Sun distance correction (Δr)**
The Earth's orbit is elliptical. At perihelion (January 3), r ≈ 0.983 AU; at
aphelion (July 4), r ≈ 1.017 AU. When the Earth is closer to the Sun, sunlight
is more intense, and the scattering that produces twilight glow begins at a slightly
deeper depression. Conversely, at aphelion, the sky stays darker a bit longer.
```
Δr = -0.5 × ln(r) (degrees)
```
This correction is ±0.015° over the year — small, but included for completeness.
**Fourier harmonic correction (Δf)**
A double-harmonic model captures the annual and semi-annual variation in observed
twilight angle that is not fully explained by MSC's piecewise model. It uses the
ecliptic longitude (θ, degrees) and absolute latitude (|φ|):
```
Δf = 0.1 × (|φ|/45) × sin(θ × π/180)
+ 0.05 × (|φ|/45) × sin(2θ × π/180)
```
This adds up to ±0.15° at 45°N and proportionally less near the equator.
**Atmospheric refraction**
Near the horizon, refraction bends light rays by about 34 arcminutes. At twilight
angles (Sun 1418° below horizon), refraction is small — a few arcminutes — but
is still computed via the Bennett/Saemundsson formula for completeness. The current
atmospheric conditions (pressure, temperature) are used.
**Elevation dip**
An observer at elevation `h` meters above sea level sees a horizon that is `d`
degrees below the geometric horizon:
```
d ≈ 1.06 × sqrt(h / 1000) (degrees)
```
At 1000 m, this is 1.06° — the effective depression for a given visual phenomenon
is reduced by this amount. The correction is:
```
Δe = -0.3 × 1.06 × sqrt(h / 1000)
```
The factor 0.3 reflects that twilight depression is only partially affected by
horizon dip (the illumination geometry is dominated by the upper atmosphere, not
the local horizon).
### Layer 3: Physical Bounds
The final angle is clipped to [10°, 22°]. Below 10° the sun is high enough that
no prayer timing convention places a twilight boundary there; above 22° is outside
the range of any empirical observation of dawn or dusk.
## Validation
The dynamic method should stay within the range defined by the full set of
traditional methods for any given location and date. At equatorial latitudes
it converges to approximately 18°, matching MWL and Karachi. At 5055°N in
summer it typically produces 1214°, matching the empirical UK observations
that prompted adjustments from 18° to lower values. At 3040°N it falls in
the 1517° range, consistent with the Egyptian and Saudi observational studies.
The `calcTimesAll` function returns comparison times for all 14 traditional
methods alongside the dynamic method, enabling direct comparison.
## High-Latitude Fallback
When the MSC minutes function would produce an angle outside [10°, 22°] or
when the Sun never reaches the computed angle, the bounds clamp the result.
For extreme latitudes (beyond approximately 57°N/S) in summer, the MSC model
itself uses a "seventh-of-night" rule as a juristic fallback, which is respected
here.
## Code Location
The implementation is in [src/getAngles.ts](../src/getAngles.ts). The MSC
piecewise model is in [src/getMSC.ts](../src/getMSC.ts). The solar ephemeris
(declination, r, ecliptic longitude) is in
[src/getSolarEphemeris.ts](../src/getSolarEphemeris.ts).
---
*[Back to Home](Home) | [Traditional Methods](Traditional-Methods) | [Twilight Physics](Twilight-Physics)*