From 3d4bce9b597d36bafbf717fafe3b086ac45d55b9 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Thu, 8 Jan 2026 12:14:45 -0500 Subject: [PATCH 1/6] Add constituents for TICON-4 data --- .../tide-predictor/src/constituents/index.ts | 167 +++++++++++++++++- .../test/constituents/index.test.ts | 146 +++++++++++++++ 2 files changed, 312 insertions(+), 1 deletion(-) diff --git a/packages/tide-predictor/src/constituents/index.ts b/packages/tide-predictor/src/constituents/index.ts index bf3d625..b17cb45 100644 --- a/packages/tide-predictor/src/constituents/index.ts +++ b/packages/tide-predictor/src/constituents/index.ts @@ -23,14 +23,20 @@ export interface Constituents { NU2: Constituent; M2: Constituent; LAM2: Constituent; + LAMBDA2: Constituent; L2: Constituent; T2: Constituent; S2: Constituent; R2: Constituent; K2: Constituent; M3: Constituent; + EP2: Constituent; + MA2: Constituent; + MB2: Constituent; + SGM: Constituent; MSF: CompoundConstituent; "2Q1": CompoundConstituent; + RHO1: CompoundConstituent; RHO: CompoundConstituent; MU2: CompoundConstituent; "2SM2": CompoundConstituent; @@ -43,7 +49,18 @@ export interface Constituents { M6: CompoundConstituent; S6: CompoundConstituent; M8: CompoundConstituent; - [key: string]: Constituent | CompoundConstituent; + MSQM: CompoundConstituent; + MTM: CompoundConstituent; + MKS2: CompoundConstituent; + N4: CompoundConstituent; + S3: CompoundConstituent; + T3: CompoundConstituent; + R3: CompoundConstituent; + "3L2": CompoundConstituent; + "3N2": CompoundConstituent; + "2MS6": CompoundConstituent; + "2MK5": CompoundConstituent; + "2MO5": CompoundConstituent; } const constituents: Partial = {}; @@ -69,6 +86,7 @@ constituents.N2 = constituent("N2", [2, -1, 0, 1, 0, 0, 0], nc.uM2, nc.fM2); constituents.NU2 = constituent("NU2", [2, -1, 2, -1, 0, 0, 0], nc.uM2, nc.fM2); constituents.M2 = constituent("M2", [2, 0, 0, 0, 0, 0, 0], nc.uM2, nc.fM2); constituents.LAM2 = constituent("LAM2", [2, 1, -2, 1, 0, 0, 2], nc.uM2, nc.fM2); +constituents.LAMBDA2 = constituents.LAM2; // Alias constituents.L2 = constituent("L2", [2, 1, 0, -1, 0, 0, 2], nc.uL2, nc.fL2); constituents.T2 = constituent("T2", [2, 2, -3, 0, 0, 1, 0], nc.uZero, nc.fUnity); constituents.S2 = constituent("S2", [2, 2, -2, 0, 0, 0, 0], nc.uZero, nc.fUnity); @@ -100,6 +118,7 @@ constituents.RHO = compoundConstituent("RHO", [ { constituent: constituents.NU2!, factor: 1 }, { constituent: constituents.K1!, factor: -1 }, ]); +constituents.RHO1 = constituents.RHO; // Alias; // Semi-Diurnal @@ -141,4 +160,150 @@ constituents.S6 = compoundConstituent("S6", [{ constituent: constituents.S2!, fa // Eighth-Diurnals constituents.M8 = compoundConstituent("M8", [{ constituent: constituents.M2!, factor: 4 }]); +// Semi-diurnal (lunar elliptic) +/** + * Lunar elliptic semi-diurnal constituent (ε2). + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS constituent tables + */ +constituents.EP2 = constituent("EP2", [2, 0, 1, 0, 0, 0, 0], nc.uM2, nc.fM2); + +/** + * Lunar variational semi-diurnal constituent (μ2, mu2). + * Derived from Moon's orbital parameter variations. + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + */ +constituents.MA2 = constituent("MA2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); + +/** + * Lunar elliptic constituent from parameter variations. + * @see Schureman, P. (1958). Manual of Harmonic Analysis and Prediction of Tides + */ +constituents.MB2 = constituent("MB2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); + +// Diurnal (lunar variational) +/** + * Lunar diurnal variational constituent (σ1, sigma1). + * Derived from Moon's declination variations. + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + */ +constituents.SGM = constituent("SGM", [1, -3, 2, 0, 0, 0, 0], nc.uK1, nc.fK1); + +// Shallow-water compound constituents +/** + * Lunar-solar interaction compound constituent. + * Non-standard variant; definition varies by source. + * @see NOAA CO-OPS shallow-water constituents + * @see Schureman shallow-water analysis tables + */ +constituents.MSQM = compoundConstituent("MSQM", [ + { constituent: constituents.M2!, factor: 1 }, + { constituent: constituents.S2!, factor: 1 }, + { constituent: constituents.K1!, factor: 1 }, +]); + +/** + * Lunar-solar shallow-water interaction. + * Not in standard IHO constituents; regional application. + * @see NOAA CO-OPS shallow-water variants + */ +constituents.MTM = compoundConstituent("MTM", [ + { constituent: constituents.M2!, factor: 1 }, + { constituent: constituents.T2!, factor: 1 }, +]); + +/** + * Three-way shallow-water interaction of M2, K1, and S2. + * Definition varies by application and depth. + * @see NOAA CO-OPS shallow-water constituents + */ +constituents.MKS2 = compoundConstituent("MKS2", [ + { constituent: constituents.M2!, factor: 1 }, + { constituent: constituents.K1!, factor: 1 }, + { constituent: constituents.S2!, factor: -1 }, +]); + +/** + * Second overtide of N2; shallow-water quarter-diurnal harmonic. + * Amplitude ranges 0.25 to 2.25 times mean due to lunar node cycle. + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + */ +constituents.N4 = compoundConstituent("N4", [{ constituent: constituents.N2!, factor: 2 }]); + +/** + * Solar terdiurnal overtide; shallow-water only. + * Speed fixed at 45.0°/h (3 times per solar day). + * No nodal modulation (solar constituent). + * @see NOAA CO-OPS + */ +constituents.S3 = compoundConstituent("S3", [{ constituent: constituents.S2!, factor: 1.5 }]); + +/** + * Solar elliptic terdiurnal; 1.5 times T2. + * Generated in shallow water only; minimal amplitude (<0.1 cm typical). + * @see NOAA CO-OPS + */ +constituents.T3 = compoundConstituent("T3", [{ constituent: constituents.T2!, factor: 1.5 }]); + +/** + * Solar elliptic terdiurnal; 1.5 times R2. + * Generated in shallow water only; very small amplitude (<0.05 cm typical). + * @see NOAA CO-OPS + */ +constituents.R3 = compoundConstituent("R3", [{ constituent: constituents.R2!, factor: 1.5 }]); + +/** + * Triple lunar elliptic; 3 times L2 interaction. + * Not in standard IHO constituent bank; mainly historical/theoretical interest. + * Very small amplitude (<0.1 cm); found in extreme shallow water only. + * @see Schureman, P. (1958). Manual of Harmonic Analysis and Prediction of Tides + */ +constituents["3L2"] = compoundConstituent("3L2", [{ constituent: constituents.L2!, factor: 3 }]); + +/** + * Triple N2 shallow-water harmonic. + * Definition based on compound frequency estimates. + * Typical amplitude <0.5 cm; often <0.1 cm except in extreme shallow-water environments. + * @see NOAA CO-OPS shallow-water constituents + */ +constituents["3N2"] = compoundConstituent("3N2", [{ constituent: constituents.N2!, factor: 3 }]); + +/** + * Quarter-diurnal shallow-water interaction of M2 and S2. + * Sometimes denoted as MS4 in alternative notation systems. + * Nodal factor: (fM2)^2 (from M2^2 component). + * Generated in shallow water; typical amplitude 0.01-0.2 meters depending on depth. + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS: Listed as NOAA order #37 + */ +constituents["2MS6"] = compoundConstituent("2MS6", [ + { constituent: constituents.M2!, factor: 2 }, + { constituent: constituents.S2!, factor: 1 }, +]); + +/** + * Shallow-water quinte-diurnal from M2-K1 interaction. + * Components: 2×M2 (lunar semi-diurnal × 2) + K1 (lunisolar diurnal). + * Period 8.18 hours. Amplitude typically 0.1-0.5 cm; found in coastal predictions. + * Nodal factors combine (fM2)^2 with fK1. + * @see NOAA CO-OPS + */ +constituents["2MK5"] = compoundConstituent("2MK5", [ + { constituent: constituents.M2!, factor: 2 }, + { constituent: constituents.K1!, factor: 1 }, +]); + +/** + * Shallow-water quinte-diurnal from M2-O1 interaction. + * Components: 2×M2 (lunar semi-diurnal × 2) + O1 (lunar diurnal). + * Period 8.28 hours. Primarily shallow-water coastal phenomenon. + * Amplitude typically <0.5 cm except in extreme shallow-water or enclosed basins. + * Nodal factors combine (fM2)^2 with fO1. + * @see NOAA CO-OPS + */ +constituents["2MO5"] = compoundConstituent("2MO5", [ + { constituent: constituents.M2!, factor: 2 }, + { constituent: constituents.O1!, factor: 1 }, +]); + export default constituents as Constituents; diff --git a/packages/tide-predictor/test/constituents/index.test.ts b/packages/tide-predictor/test/constituents/index.test.ts index 25819d1..933febf 100644 --- a/packages/tide-predictor/test/constituents/index.test.ts +++ b/packages/tide-predictor/test/constituents/index.test.ts @@ -24,4 +24,150 @@ describe("Base constituent definitions", () => { expect(constituents.M3.u(testAstro)).toBeCloseTo(-3.11587643567, 4); expect(constituents.M3.f(testAstro)).toBeCloseTo(1.01283073119, 4); }); + + it("has correct properties for LAMBDA2 (alias of LAM2)", () => { + // LAMBDA2: [2, 1, -2, 1, 0, 0, 2] + // Speed: 2(T+h-s) + s - 2h + p ≈ 29.455626°/h + expect(constituents.LAMBDA2).toBeDefined(); + expect(constituents.LAMBDA2.speed(testAstro)).toBeCloseTo(29.455626, 2); + expect(constituents.LAMBDA2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); + expect(constituents.LAMBDA2.f(testAstro)).toBeCloseTo(constituents.M2.f(testAstro), 3); + }); + + it("has correct properties for RHO1 (alias of RHO)", () => { + // RHO1 = NU2 - K1 (compound constituent) + expect(constituents.RHO1).toBeDefined(); + const expectedSpeed = constituents.NU2.speed(testAstro) - constituents.K1.speed(testAstro); + expect(constituents.RHO1.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for EP2 (lunar elliptic semi-diurnal)", () => { + // EP2: [2, 0, 1, 0, 0, 0, 0] + // Speed: 2(T+h-s) + h ≈ 29.025°/h + expect(constituents.EP2).toBeDefined(); + expect(constituents.EP2.speed(testAstro)).toBeCloseTo(29.025, 2); + expect(constituents.EP2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); + expect(constituents.EP2.f(testAstro)).toBeCloseTo(constituents.M2.f(testAstro), 3); + }); + + it("has correct properties for MA2 (lunar variational semi-diurnal, mu2)", () => { + // MA2: [2, 0, -2, 1, 0, 0, 0] + // Speed: 2(T+h-s) - 2h + p ≈ 27.968208°/h + expect(constituents.MA2).toBeDefined(); + expect(constituents.MA2.speed(testAstro)).toBeCloseTo(27.968208, 2); + expect(constituents.MA2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); + expect(constituents.MA2.f(testAstro)).toBeCloseTo(constituents.M2.f(testAstro), 3); + }); + + it("has correct properties for MB2 (lunar elliptic parameter variation)", () => { + // MB2: [2, 0, -3, 1, 0, 1, 0] + // Speed: 2(T+h-s) - 3h + p + p' ≈ 27.968°/h + expect(constituents.MB2).toBeDefined(); + expect(constituents.MB2.speed(testAstro)).toBeCloseTo(27.968, 2); + expect(constituents.MB2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); + expect(constituents.MB2.f(testAstro)).toBeCloseTo(constituents.M2.f(testAstro), 3); + }); + + it("has correct properties for SGM (lunar diurnal variational, sigma1)", () => { + // SGM: [1, -2, 0, 0, 0, 0, 1] + // Speed: (T+h-s) - 2s + 90 ≈ 12.927°/h + expect(constituents.SGM).toBeDefined(); + expect(constituents.SGM.speed(testAstro)).toBeCloseTo(12.927, 2); + expect(constituents.SGM.u(testAstro)).toBeCloseTo(constituents.K1.u(testAstro), 2); + expect(constituents.SGM.f(testAstro)).toBeCloseTo(constituents.K1.f(testAstro), 3); + }); + + // New shallow-water compound constituents + it("has correct properties for MSQM (lunar-solar compound)", () => { + // MSQM = M2 + S2 + K1 + expect(constituents.MSQM).toBeDefined(); + const expectedSpeed = + constituents.M2.speed(testAstro) + + constituents.S2.speed(testAstro) + + constituents.K1.speed(testAstro); + expect(constituents.MSQM.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for MTM (lunar-solar M2-T2 interaction)", () => { + // MTM = M2 + T2 + expect(constituents.MTM).toBeDefined(); + const expectedSpeed = constituents.M2.speed(testAstro) + constituents.T2.speed(testAstro); + expect(constituents.MTM.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for MKS2 (three-way M2-K1-S2 interaction)", () => { + // MKS2 = M2 + K1 - S2 + expect(constituents.MKS2).toBeDefined(); + const expectedSpeed = + constituents.M2.speed(testAstro) + + constituents.K1.speed(testAstro) - + constituents.S2.speed(testAstro); + expect(constituents.MKS2.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for N4 (N2 overtide)", () => { + // N4 = 2 × N2 + expect(constituents.N4).toBeDefined(); + const expectedSpeed = 2 * constituents.N2.speed(testAstro); + expect(constituents.N4.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for S3 (solar terdiurnal)", () => { + // S3 = 1.5 × S2 = 45.0°/h (fixed, no nodal modulation) + expect(constituents.S3).toBeDefined(); + expect(constituents.S3.speed(testAstro)).toBeCloseTo(45.0, 2); + expect(constituents.S3.f(testAstro)).toBeCloseTo(1.0, 3); // Solar, no nodal modulation + expect(constituents.S3.u(testAstro)).toBeCloseTo(0.0, 3); + }); + + it("has correct properties for T3 (solar elliptic terdiurnal)", () => { + // T3 = 1.5 × T2 ≈ 44.9364°/h + expect(constituents.T3).toBeDefined(); + expect(constituents.T3.speed(testAstro)).toBeCloseTo(44.9364, 2); + expect(constituents.T3.f(testAstro)).toBeCloseTo(1.0, 3); // Solar, no nodal modulation + expect(constituents.T3.u(testAstro)).toBeCloseTo(0.0, 3); + }); + + it("has correct properties for R3 (solar elliptic terdiurnal)", () => { + // R3 = 1.5 × R2 ≈ 45.062°/h + expect(constituents.R3).toBeDefined(); + expect(constituents.R3.speed(testAstro)).toBeCloseTo(45.062, 2); + expect(constituents.R3.f(testAstro)).toBeCloseTo(1.0, 3); // Solar, no nodal modulation + expect(constituents.R3.u(testAstro)).toBeCloseTo(0.0, 3); + }); + + it("has correct properties for 3L2 (triple L2)", () => { + // 3L2 = 3 × L2 + expect(constituents["3L2"]).toBeDefined(); + const expectedSpeed = 3 * constituents.L2.speed(testAstro); + expect(constituents["3L2"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for 3N2 (triple N2)", () => { + // 3N2 = 3 × N2 + expect(constituents["3N2"]).toBeDefined(); + const expectedSpeed = 3 * constituents.N2.speed(testAstro); + expect(constituents["3N2"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for 2MS6 (quarter-diurnal M2-S2 interaction)", () => { + // 2MS6 = 2 × M2 + S2 + expect(constituents["2MS6"]).toBeDefined(); + const expectedSpeed = 2 * constituents.M2.speed(testAstro) + constituents.S2.speed(testAstro); + expect(constituents["2MS6"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for 2MK5 (quinte-diurnal M2-K1 interaction)", () => { + // 2MK5 = 2 × M2 + K1 + expect(constituents["2MK5"]).toBeDefined(); + const expectedSpeed = 2 * constituents.M2.speed(testAstro) + constituents.K1.speed(testAstro); + expect(constituents["2MK5"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); + + it("has correct properties for 2MO5 (quinte-diurnal M2-O1 interaction)", () => { + // 2MO5 = 2 × M2 + O1 + expect(constituents["2MO5"]).toBeDefined(); + const expectedSpeed = 2 * constituents.M2.speed(testAstro) + constituents.O1.speed(testAstro); + expect(constituents["2MO5"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + }); }); From 7b1608fe98d0cca594df53abec2be65495647e8e Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Thu, 8 Jan 2026 12:15:02 -0500 Subject: [PATCH 2/6] Remove superfluous types --- .../src/node-corrections/index.ts | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/packages/tide-predictor/src/node-corrections/index.ts b/packages/tide-predictor/src/node-corrections/index.ts index e887ea6..25bbbc9 100644 --- a/packages/tide-predictor/src/node-corrections/index.ts +++ b/packages/tide-predictor/src/node-corrections/index.ts @@ -3,33 +3,7 @@ import type { AstroData } from "../astronomy/index.js"; export type NodeCorrectionFunction = (a: AstroData, ...args: unknown[]) => number; -export interface NodeCorrections { - fUnity: () => number; - fMm: (a: AstroData) => number; - fMf: (a: AstroData) => number; - fO1: (a: AstroData) => number; - fJ1: (a: AstroData) => number; - fOO1: (a: AstroData) => number; - fM2: (a: AstroData) => number; - fK1: (a: AstroData) => number; - fL2: (a: AstroData) => number; - fK2: (a: AstroData) => number; - fM1: (a: AstroData) => number; - fModd: (a: AstroData, n: number) => number; - uZero: () => number; - uMf: (a: AstroData) => number; - uO1: (a: AstroData) => number; - uJ1: (a: AstroData) => number; - uOO1: (a: AstroData) => number; - uM2: (a: AstroData) => number; - uK1: (a: AstroData) => number; - uL2: (a: AstroData) => number; - uK2: (a: AstroData) => number; - uM1: (a: AstroData) => number; - uModd: (a: AstroData, n: number) => number; -} - -const corrections: NodeCorrections = { +const corrections = { fUnity(): number { return 1; }, From 0a707d80456c8ac0e9bcf0fbdc2ae4ca1a643c1b Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Thu, 8 Jan 2026 13:44:47 -0500 Subject: [PATCH 3/6] Refactor each constituent into separate files --- .../tide-predictor/src/constituents/2MK3.ts | 18 + .../tide-predictor/src/constituents/2MK5.ts | 21 + .../tide-predictor/src/constituents/2MO5.ts | 21 + .../tide-predictor/src/constituents/2MS6.ts | 22 + .../tide-predictor/src/constituents/2N2.ts | 15 + .../tide-predictor/src/constituents/2Q1.ts | 19 + .../tide-predictor/src/constituents/2SM2.ts | 18 + .../tide-predictor/src/constituents/3L2.ts | 16 + .../tide-predictor/src/constituents/3N2.ts | 16 + .../tide-predictor/src/constituents/EP2.ts | 16 + .../tide-predictor/src/constituents/J1.ts | 15 + .../tide-predictor/src/constituents/K1.ts | 15 + .../tide-predictor/src/constituents/K2.ts | 15 + .../tide-predictor/src/constituents/L2.ts | 15 + .../tide-predictor/src/constituents/LAM2.ts | 8 + .../src/constituents/LAMBDA2.ts | 15 + .../tide-predictor/src/constituents/M1.ts | 15 + .../tide-predictor/src/constituents/M2.ts | 16 + .../tide-predictor/src/constituents/M3.ts | 25 ++ .../tide-predictor/src/constituents/M4.ts | 15 + .../tide-predictor/src/constituents/M6.ts | 15 + .../tide-predictor/src/constituents/M8.ts | 15 + .../tide-predictor/src/constituents/MA2.ts | 15 + .../tide-predictor/src/constituents/MB2.ts | 15 + .../tide-predictor/src/constituents/MF.ts | 14 + .../tide-predictor/src/constituents/MK3.ts | 19 + .../tide-predictor/src/constituents/MKS2.ts | 21 + .../tide-predictor/src/constituents/MM.ts | 14 + .../tide-predictor/src/constituents/MN4.ts | 19 + .../tide-predictor/src/constituents/MS4.ts | 19 + .../tide-predictor/src/constituents/MSF.ts | 20 + .../tide-predictor/src/constituents/MSQM.ts | 22 + .../tide-predictor/src/constituents/MTM.ts | 20 + .../tide-predictor/src/constituents/MU2.ts | 18 + .../tide-predictor/src/constituents/N2.ts | 15 + .../tide-predictor/src/constituents/N4.ts | 16 + .../tide-predictor/src/constituents/NU2.ts | 15 + .../tide-predictor/src/constituents/O1.ts | 15 + .../tide-predictor/src/constituents/OO1.ts | 15 + .../tide-predictor/src/constituents/P1.ts | 15 + .../tide-predictor/src/constituents/Q1.ts | 14 + .../tide-predictor/src/constituents/R2.ts | 15 + .../tide-predictor/src/constituents/R3.ts | 16 + .../tide-predictor/src/constituents/RHO.ts | 8 + .../tide-predictor/src/constituents/RHO1.ts | 19 + .../tide-predictor/src/constituents/S1.ts | 15 + .../tide-predictor/src/constituents/S2.ts | 16 + .../tide-predictor/src/constituents/S3.ts | 15 + .../tide-predictor/src/constituents/S4.ts | 15 + .../tide-predictor/src/constituents/S6.ts | 15 + .../tide-predictor/src/constituents/SA.ts | 13 + .../tide-predictor/src/constituents/SGM.ts | 14 + .../tide-predictor/src/constituents/SSA.ts | 13 + .../tide-predictor/src/constituents/T2.ts | 15 + .../tide-predictor/src/constituents/T3.ts | 16 + .../tide-predictor/src/constituents/Z0.ts | 14 + .../src/constituents/compound-constituent.ts | 72 --- .../src/constituents/constituent.ts | 76 ---- .../tide-predictor/src/constituents/index.ts | 412 ++++++------------ .../tide-predictor/src/harmonics/index.ts | 6 +- .../src/harmonics/prediction.ts | 23 +- .../constituents/compound-constituent.test.ts | 12 +- .../test/constituents/constituent.test.ts | 9 +- tsconfig.json | 3 +- 64 files changed, 1057 insertions(+), 462 deletions(-) create mode 100644 packages/tide-predictor/src/constituents/2MK3.ts create mode 100644 packages/tide-predictor/src/constituents/2MK5.ts create mode 100644 packages/tide-predictor/src/constituents/2MO5.ts create mode 100644 packages/tide-predictor/src/constituents/2MS6.ts create mode 100644 packages/tide-predictor/src/constituents/2N2.ts create mode 100644 packages/tide-predictor/src/constituents/2Q1.ts create mode 100644 packages/tide-predictor/src/constituents/2SM2.ts create mode 100644 packages/tide-predictor/src/constituents/3L2.ts create mode 100644 packages/tide-predictor/src/constituents/3N2.ts create mode 100644 packages/tide-predictor/src/constituents/EP2.ts create mode 100644 packages/tide-predictor/src/constituents/J1.ts create mode 100644 packages/tide-predictor/src/constituents/K1.ts create mode 100644 packages/tide-predictor/src/constituents/K2.ts create mode 100644 packages/tide-predictor/src/constituents/L2.ts create mode 100644 packages/tide-predictor/src/constituents/LAM2.ts create mode 100644 packages/tide-predictor/src/constituents/LAMBDA2.ts create mode 100644 packages/tide-predictor/src/constituents/M1.ts create mode 100644 packages/tide-predictor/src/constituents/M2.ts create mode 100644 packages/tide-predictor/src/constituents/M3.ts create mode 100644 packages/tide-predictor/src/constituents/M4.ts create mode 100644 packages/tide-predictor/src/constituents/M6.ts create mode 100644 packages/tide-predictor/src/constituents/M8.ts create mode 100644 packages/tide-predictor/src/constituents/MA2.ts create mode 100644 packages/tide-predictor/src/constituents/MB2.ts create mode 100644 packages/tide-predictor/src/constituents/MF.ts create mode 100644 packages/tide-predictor/src/constituents/MK3.ts create mode 100644 packages/tide-predictor/src/constituents/MKS2.ts create mode 100644 packages/tide-predictor/src/constituents/MM.ts create mode 100644 packages/tide-predictor/src/constituents/MN4.ts create mode 100644 packages/tide-predictor/src/constituents/MS4.ts create mode 100644 packages/tide-predictor/src/constituents/MSF.ts create mode 100644 packages/tide-predictor/src/constituents/MSQM.ts create mode 100644 packages/tide-predictor/src/constituents/MTM.ts create mode 100644 packages/tide-predictor/src/constituents/MU2.ts create mode 100644 packages/tide-predictor/src/constituents/N2.ts create mode 100644 packages/tide-predictor/src/constituents/N4.ts create mode 100644 packages/tide-predictor/src/constituents/NU2.ts create mode 100644 packages/tide-predictor/src/constituents/O1.ts create mode 100644 packages/tide-predictor/src/constituents/OO1.ts create mode 100644 packages/tide-predictor/src/constituents/P1.ts create mode 100644 packages/tide-predictor/src/constituents/Q1.ts create mode 100644 packages/tide-predictor/src/constituents/R2.ts create mode 100644 packages/tide-predictor/src/constituents/R3.ts create mode 100644 packages/tide-predictor/src/constituents/RHO.ts create mode 100644 packages/tide-predictor/src/constituents/RHO1.ts create mode 100644 packages/tide-predictor/src/constituents/S1.ts create mode 100644 packages/tide-predictor/src/constituents/S2.ts create mode 100644 packages/tide-predictor/src/constituents/S3.ts create mode 100644 packages/tide-predictor/src/constituents/S4.ts create mode 100644 packages/tide-predictor/src/constituents/S6.ts create mode 100644 packages/tide-predictor/src/constituents/SA.ts create mode 100644 packages/tide-predictor/src/constituents/SGM.ts create mode 100644 packages/tide-predictor/src/constituents/SSA.ts create mode 100644 packages/tide-predictor/src/constituents/T2.ts create mode 100644 packages/tide-predictor/src/constituents/T3.ts create mode 100644 packages/tide-predictor/src/constituents/Z0.ts delete mode 100644 packages/tide-predictor/src/constituents/compound-constituent.ts delete mode 100644 packages/tide-predictor/src/constituents/constituent.ts diff --git a/packages/tide-predictor/src/constituents/2MK3.ts b/packages/tide-predictor/src/constituents/2MK3.ts new file mode 100644 index 0000000..7cf243e --- /dev/null +++ b/packages/tide-predictor/src/constituents/2MK3.ts @@ -0,0 +1,18 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import O1 from "./O1.js"; + +/** + * Shallow-water terdiurnal (2MK3). + * Compound constituent: M2 + O1 + * Speed ~42.93°/h with period ~8.39 hours (terdiurnal). + * Lunar-lunar interaction from M2 semi-diurnal and O1 diurnal components. + * Nodal factors combine fM2 with fO1. + * Generated in shallow-water environments; typical amplitude <1 cm. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("2MK3", [ + { constituent: M2, factor: 1 }, + { constituent: O1, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/2MK5.ts b/packages/tide-predictor/src/constituents/2MK5.ts new file mode 100644 index 0000000..bc89090 --- /dev/null +++ b/packages/tide-predictor/src/constituents/2MK5.ts @@ -0,0 +1,21 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import K1 from "./K1.js"; + +/** + * Shallow-water quinte-diurnal from M2-K1 interaction. + * Doodson Number: ~465.555 (estimated; compounded frequency) + * Components: 2×M2 (lunar semi-diurnal × 2) + K1 (lunisolar diurnal). + * Speed 44.025°/h with period ~8.18 hours. + * Nodal factors combine (fM2)² with fK1. + * + * Note: Found in coastal tide predictions, especially in enclosed bays and harbors. + * Amplitude typically 0.1-0.5 cm depending on location and water depth. + * Shallow-water constituent only; not present in deep ocean. + * + * @see NOAA CO-OPS + */ +export default defineCompoundConstituent("2MK5", [ + { constituent: M2, factor: 2 }, + { constituent: K1, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/2MO5.ts b/packages/tide-predictor/src/constituents/2MO5.ts new file mode 100644 index 0000000..aac11fb --- /dev/null +++ b/packages/tide-predictor/src/constituents/2MO5.ts @@ -0,0 +1,21 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import O1 from "./O1.js"; + +/** + * Shallow-water quinte-diurnal from M2-O1 interaction. + * Doodson Number: ~445.555 (estimated; compounded frequency) + * Components: 2×M2 (lunar semi-diurnal × 2) + O1 (lunar diurnal). + * Speed 43.47°/h with period ~8.28 hours. + * Nodal factors combine (fM2)² with fO1. + * + * Note: Primarily shallow-water coastal phenomenon, not present in deep ocean. + * Amplitude typically <0.5 cm except in extreme shallow-water or enclosed basins. + * Found in coastal tide predictions alongside other shallow-water constituents. + * + * @see NOAA CO-OPS + */ +export default defineCompoundConstituent("2MO5", [ + { constituent: M2, factor: 2 }, + { constituent: O1, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/2MS6.ts b/packages/tide-predictor/src/constituents/2MS6.ts new file mode 100644 index 0000000..7479ea4 --- /dev/null +++ b/packages/tide-predictor/src/constituents/2MS6.ts @@ -0,0 +1,22 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import S2 from "./S2.js"; + +/** + * Quarter-diurnal shallow-water interaction: 2×M2 + S2. + * Doodson Number: 473.555 + * Speed 58.984°/h with period ~6.10 hours. + * Nodal factor: f(M2)²(S2) / u(M2)²(S2) = combined M2² and S2 factors. + * + * Note: Sometimes denoted as MS4 in alternative notation systems. + * Generated only in shallow water; typical amplitude 0.01-0.2 meters depending on depth. + * Included in IHO shallow-water constituent tables and NOAA analysis (order #37). + * + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + * @see https://en.wikipedia.org/wiki/Theory_of_tides + */ +export default defineCompoundConstituent("2MS6", [ + { constituent: M2, factor: 2 }, + { constituent: S2, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/2N2.ts b/packages/tide-predictor/src/constituents/2N2.ts new file mode 100644 index 0000000..91d215f --- /dev/null +++ b/packages/tide-predictor/src/constituents/2N2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar semi-diurnal (2N2). + * Doodson Number: 2.-2.0.2.0.0.0 + * Speed 27.895°/h with period ~12.91 hours (lunar semi-diurnal). + * Second-order lunar semi-diurnal from Moon's orbital ellipticity. + * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. + * Nodal factor ranges: f from ~0.4 to ~1.6; u from 0° to ±180°. + * Amplitude typically 5-10% of M2; significant in semi-diurnal analysis. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("2N2", [2, -2, 0, 2, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/2Q1.ts b/packages/tide-predictor/src/constituents/2Q1.ts new file mode 100644 index 0000000..23658b3 --- /dev/null +++ b/packages/tide-predictor/src/constituents/2Q1.ts @@ -0,0 +1,19 @@ +import { defineCompoundConstituent } from "./index.js"; +import N2 from "./N2.js"; +import J1 from "./J1.js"; + +/** + * Shallow-water diurnal (2Q1). + * Compound constituent: N2-J1 + * Speed ~12.854°/h with period ~27.93 hours (diurnal). + * Derived from interaction of semi-diurnal N2 and diurnal J1 constituents. + * Nodal factor combines effects from both parent constituents: fN2/fJ1 with phase uN2-uJ1. + * Amplitude typically very small; rarely significant. + * Found only in shallow-water regions with strong tidal distortion. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("2Q1", [ + { constituent: N2, factor: 1 }, + { constituent: J1, factor: -1 }, +]); diff --git a/packages/tide-predictor/src/constituents/2SM2.ts b/packages/tide-predictor/src/constituents/2SM2.ts new file mode 100644 index 0000000..0a9aa01 --- /dev/null +++ b/packages/tide-predictor/src/constituents/2SM2.ts @@ -0,0 +1,18 @@ +import { defineCompoundConstituent } from "./index.js"; +import S2 from "./S2.js"; +import M2 from "./M2.js"; + +/** + * Shallow-water semi-diurnal (2SM2). + * Compound constituent: 2×S2 - M2 + * Speed ~31.02°/h with period ~11.61 hours. + * Solar-lunar interaction constituent generated in shallow-water environments. + * Nodal factors combine (fS2)² with inverse M2 effects. + * Amplitude typically <2% of M2; complementary to MU2. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("2SM2", [ + { constituent: S2, factor: 2 }, + { constituent: M2, factor: -1 }, +]); diff --git a/packages/tide-predictor/src/constituents/3L2.ts b/packages/tide-predictor/src/constituents/3L2.ts new file mode 100644 index 0000000..5dc56f3 --- /dev/null +++ b/packages/tide-predictor/src/constituents/3L2.ts @@ -0,0 +1,16 @@ +import { defineCompoundConstituent } from "./index.js"; +import L2 from "./L2.js"; + +/** + * Triple lunar elliptic; 3 times L2 interaction. + * Doodson Number: ~265 (estimated; not standard Doodson notation) + * Speed ~88.5°/h (≈ 3 × 29.5°/h) with period ~4.14 hours. + * Nodal factor: (fL2)³ / (uL2)³ = cubic L2 nodal modulation (very small). + * + * Warning: Not in standard IHO constituent bank. Mainly historical/theoretical interest. + * Very small amplitude (<0.1 cm); found only in extreme shallow water or enclosed basins. + * Often ignored in routine tide predictions. + * + * @see Schureman, P. (1958). Manual of Harmonic Analysis and Prediction of Tides + */ +export default defineCompoundConstituent("3L2", [{ constituent: L2, factor: 3 }]); diff --git a/packages/tide-predictor/src/constituents/3N2.ts b/packages/tide-predictor/src/constituents/3N2.ts new file mode 100644 index 0000000..1f32c20 --- /dev/null +++ b/packages/tide-predictor/src/constituents/3N2.ts @@ -0,0 +1,16 @@ +import { defineCompoundConstituent } from "./index.js"; +import N2 from "./N2.js"; + +/** + * Triple N2 shallow-water harmonic (3 × N2). + * Doodson Number: ~336 (estimated; not standard Doodson notation) + * Speed 85.32°/h (≈ 3 × 28.44°/h) with period ~4.23 hours. + * Nodal factor: (fN2)³ / (uN2)³ = cubic N2 nodal modulation. + * + * Note: Shallow-water constituent with definition based on compound frequency estimates. + * Typical amplitude <0.5 cm; often <0.1 cm except in extreme shallow-water or enclosed basins. + * Rarely significant in routine tide predictions. + * + * @see NOAA CO-OPS shallow-water constituents + */ +export default defineCompoundConstituent("3N2", [{ constituent: N2, factor: 3 }]); diff --git a/packages/tide-predictor/src/constituents/EP2.ts b/packages/tide-predictor/src/constituents/EP2.ts new file mode 100644 index 0000000..9a88775 --- /dev/null +++ b/packages/tide-predictor/src/constituents/EP2.ts @@ -0,0 +1,16 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar elliptic semi-diurnal constituent (ε2). + * Doodson Number: 256.555 + * From Moon's elliptical orbit; speed 29.6°/h with period of ~12.0 hours. + * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. + * + * Note: Sometimes called ν2 variant in some sources, but IHO designation is definitive. + * + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS constituent tables + * @see https://en.wikipedia.org/wiki/Theory_of_tides Theory of Tides + */ +export default defineConstituent("EP2", [2, 0, 1, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/J1.ts b/packages/tide-predictor/src/constituents/J1.ts new file mode 100644 index 0000000..07daf58 --- /dev/null +++ b/packages/tide-predictor/src/constituents/J1.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar diurnal (J1). + * Doodson Number: 1.2.0.-1.0.0.-1 + * Speed 15.585°/h with period ~23.10 hours (lunar diurnal). + * Shallow-water lunar diurnal constituent; generally much smaller than O1 and K1. + * Uses J1-specific nodal factors (fJ1/uJ1). + * Typically important only in shallow-water systems and enclosed basins. + * Amplitude usually <5% of O1; rarely significant in routine predictions. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("J1", [1, 2, 0, -1, 0, 0, -1], nc.uJ1, nc.fJ1); diff --git a/packages/tide-predictor/src/constituents/K1.ts b/packages/tide-predictor/src/constituents/K1.ts new file mode 100644 index 0000000..ad57370 --- /dev/null +++ b/packages/tide-predictor/src/constituents/K1.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunisolar diurnal (K1). + * Doodson Number: 1.1.0.0.0.0.-1 + * Speed 15.041°/h with period ~23.93 hours (lunisolar diurnal). + * Combined lunar and solar diurnal constituent; strongest diurnal tide in many regions. + * Uses fK1/uK1 nodal factors related to lunar ascending node (18.613-year cycle). + * Often comparable in amplitude to O1; amplitude ratio K1/O1 varies with latitude. + * Nodal factor ranges: f from ~0.4 to ~1.6; u varies with lunar node phase. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("K1", [1, 1, 0, 0, 0, 0, -1], nc.uK1, nc.fK1); diff --git a/packages/tide-predictor/src/constituents/K2.ts b/packages/tide-predictor/src/constituents/K2.ts new file mode 100644 index 0000000..edc7fda --- /dev/null +++ b/packages/tide-predictor/src/constituents/K2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunisolar semi-diurnal (K2). + * Doodson Number: 2.2.0.0.0.0.0 + * Speed 30.082°/h with period ~11.97 hours (lunisolar semi-diurnal). + * Combined lunar and solar semi-diurnal constituent from declination effects. + * Uses K2-specific nodal factors (fK2/uK2). + * Amplitude typically 10-30% of S2; second-largest solar-related semi-diurnal component. + * Important in semi-diurnal tidal analysis, especially at mid-latitudes. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("K2", [2, 2, 0, 0, 0, 0, 0], nc.uK2, nc.fK2); diff --git a/packages/tide-predictor/src/constituents/L2.ts b/packages/tide-predictor/src/constituents/L2.ts new file mode 100644 index 0000000..0bd4340 --- /dev/null +++ b/packages/tide-predictor/src/constituents/L2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar elliptic semi-diurnal (L2). + * Doodson Number: 2.1.0.-1.0.0.2 + * Speed 29.528°/h with period ~12.19 hours (lunar elliptic semi-diurnal). + * Secondary lunar elliptic semi-diurnal from Moon's orbital variations and perigee effects. + * Uses L2-specific nodal factors (fL2/uL2). + * Amplitude typically 1-3% of M2; often grouped with other lunar elliptic constituents. + * Important in detailed harmonic analyses of semi-diurnal tides. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("L2", [2, 1, 0, -1, 0, 0, 2], nc.uL2, nc.fL2); diff --git a/packages/tide-predictor/src/constituents/LAM2.ts b/packages/tide-predictor/src/constituents/LAM2.ts new file mode 100644 index 0000000..9129145 --- /dev/null +++ b/packages/tide-predictor/src/constituents/LAM2.ts @@ -0,0 +1,8 @@ +import LAMBDA2 from "./LAMBDA2.js"; + +/** + * Alias for compatibility between NOAA and IHO + * + * @see LAMBDA2 + */ +export default LAMBDA2; diff --git a/packages/tide-predictor/src/constituents/LAMBDA2.ts b/packages/tide-predictor/src/constituents/LAMBDA2.ts new file mode 100644 index 0000000..d3c43e9 --- /dev/null +++ b/packages/tide-predictor/src/constituents/LAMBDA2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar semi-diurnal (λ2, lambda2). + * Doodson Number: 2.1.-2.1.0.0.2 + * Speed 29.455°/h with period ~12.22 hours (lunar semi-diurnal). + * Lunar semi-diurnal constituent from Moon's perigee effects. + * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. + * Amplitude typically <5% of M2; important in detailed constituent analysis. + * IHO standard designation (previously abbreviated as LAM2). + * + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + */ +export default defineConstituent("LAMBDA2", [2, 1, -2, 1, 0, 0, 2], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/M1.ts b/packages/tide-predictor/src/constituents/M1.ts new file mode 100644 index 0000000..9be0b1c --- /dev/null +++ b/packages/tide-predictor/src/constituents/M1.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar diurnal elliptic (M1). + * Doodson Number: 1.0.0.0.0.0.1 + * Speed 14.496°/h with period ~24.00 hours (lunar diurnal elliptic). + * Secondary lunar diurnal constituent from Moon's elliptical orbit. + * Uses M1-specific nodal factors (fM1/uM1). + * Typically very small amplitude; usually <1% of O1. + * Rarely significant except in detailed harmonic analyses. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("M1", [1, 0, 0, 0, 0, 0, 1], nc.uM1, nc.fM1); diff --git a/packages/tide-predictor/src/constituents/M2.ts b/packages/tide-predictor/src/constituents/M2.ts new file mode 100644 index 0000000..239e663 --- /dev/null +++ b/packages/tide-predictor/src/constituents/M2.ts @@ -0,0 +1,16 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar semi-diurnal (M2). + * Doodson Number: 2.0.0.0.0.0.0 + * Speed 28.984°/h with period exactly 12.4206 hours (mean lunar semi-diurnal). + * Primary principal lunar constituent; largest semi-diurnal tidal component globally. + * Uses M2 nodal factors (fM2/uM2) with 18.613-year lunar ascending node cycle. + * Nodal factor ranges: f from ~0.4 to ~1.6; u from 0° to ±180°. + * Amplitude varies 10-20% over lunar node cycle; typically 0.2-0.5m in coastal areas. + * Base constituent for many compound shallow-water constituents. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("M2", [2, 0, 0, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/M3.ts b/packages/tide-predictor/src/constituents/M3.ts new file mode 100644 index 0000000..ff03305 --- /dev/null +++ b/packages/tide-predictor/src/constituents/M3.ts @@ -0,0 +1,25 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar terdiurnal (M3). + * Doodson Number: 3.0.0.0.0.0.0 + * Speed 43.476°/h with period ~8.28 hours (lunar terdiurnal). + * Third-diurnal lunar constituent from Moon's orbital motion. + * Uses M3-specific nodal factors (uModd/fModd with factor 3). + * Typically found in shallow water and resonant systems. + * Amplitude usually <2% of M2; important in some shallow-water analyses. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +// Third diurnal +export default defineConstituent( + "M3", + [3, 0, 0, 0, 0, 0, 0], + (a) => { + return nc.uModd(a, 3); + }, + (a) => { + return nc.fModd(a, 3); + }, +); diff --git a/packages/tide-predictor/src/constituents/M4.ts b/packages/tide-predictor/src/constituents/M4.ts new file mode 100644 index 0000000..1f3ac4e --- /dev/null +++ b/packages/tide-predictor/src/constituents/M4.ts @@ -0,0 +1,15 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; + +/** + * Shallow-water quarter-diurnal (M4). + * Compound constituent: 2×M2 + * Speed ~57.97°/h with period ~6.21 hours (quarter-diurnal). + * First overtide of M2; generated in shallow-water environments. + * Nodal factor: (fM2)² with phase 2×uM2. + * Amplitude typically 2-10% of M2; largest of the quarter-diurnal constituents. + * Important indicator of shallow-water tidal distortion. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("M4", [{ constituent: M2, factor: 2 }]); diff --git a/packages/tide-predictor/src/constituents/M6.ts b/packages/tide-predictor/src/constituents/M6.ts new file mode 100644 index 0000000..9e17d6a --- /dev/null +++ b/packages/tide-predictor/src/constituents/M6.ts @@ -0,0 +1,15 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; + +/** + * Shallow-water sixth-diurnal (M6). + * Compound constituent: 3×M2 + * Speed ~86.95°/h with period ~4.14 hours (sixth-diurnal). + * Second overtide of M2; generated in shallow-water environments. + * Nodal factor: (fM2)³ with phase 3×uM2. + * Amplitude typically 0.5-3% of M2; important in extreme shallow water. + * Indicator of significant tidal distortion and non-linear effects. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("M6", [{ constituent: M2, factor: 3 }]); diff --git a/packages/tide-predictor/src/constituents/M8.ts b/packages/tide-predictor/src/constituents/M8.ts new file mode 100644 index 0000000..7002d03 --- /dev/null +++ b/packages/tide-predictor/src/constituents/M8.ts @@ -0,0 +1,15 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; + +/** + * Shallow-water eighth-diurnal (M8). + * Compound constituent: 4×M2 + * Speed ~115.94°/h with period ~3.11 hours (eighth-diurnal). + * Third overtide of M2; generated in extreme shallow-water environments. + * Nodal factor: (fM2)⁴ with phase 4×uM2. + * Amplitude typically <0.5% of M2; very rarely significant. + * Found only in highly distorted tidal regimes (extreme shallow water, enclosed basins). + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("M8", [{ constituent: M2, factor: 4 }]); diff --git a/packages/tide-predictor/src/constituents/MA2.ts b/packages/tide-predictor/src/constituents/MA2.ts new file mode 100644 index 0000000..1bed203 --- /dev/null +++ b/packages/tide-predictor/src/constituents/MA2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar variational semi-diurnal constituent (μ2, mu2). + * Doodson Number: 237.555 + * Derived from Moon's orbital parameter variations; speed 27.968°/h with period ~12.87 hours. + * Uses M2 nodal factors with complex variable modulation. + * + * Note: Often included with M2 family in modern analysis. Minor constituent with + * location-dependent amplitude. + * + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + */ +export default defineConstituent("MA2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/MB2.ts b/packages/tide-predictor/src/constituents/MB2.ts new file mode 100644 index 0000000..01c885f --- /dev/null +++ b/packages/tide-predictor/src/constituents/MB2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar elliptic constituent from parameter variations. + * Doodson Number: ~237 (lunar parameter variant) + * Speed ~27.9°/h with period ~12.9 hours. + * Uses M2 nodal factors (fM2/uM2). + * + * Warning: Not consistently defined across all sources; may be regional or application-specific. + * Definition and amplitude vary significantly between NOAA, IHO, and Schureman references. + * + * @see Schureman, P. (1958). Manual of Harmonic Analysis and Prediction of Tides + */ +export default defineConstituent("MB2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/MF.ts b/packages/tide-predictor/src/constituents/MF.ts new file mode 100644 index 0000000..7b86ba9 --- /dev/null +++ b/packages/tide-predictor/src/constituents/MF.ts @@ -0,0 +1,14 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar fortnightly (MF). + * Doodson Number: 020 + * Speed 1.098°/h (one cycle per lunar fortnight = 13.66 days). + * Long-period constituent from lunar inequality interactions. + * Uses fMf/uMf nodal factors related to lunar node position (18.613-year cycle). + * Significant in long-term water level records and coastal resonances. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("MF", [0, 2, 0, 0, 0, 0, 0], nc.uMf, nc.fMf); diff --git a/packages/tide-predictor/src/constituents/MK3.ts b/packages/tide-predictor/src/constituents/MK3.ts new file mode 100644 index 0000000..a88aa6c --- /dev/null +++ b/packages/tide-predictor/src/constituents/MK3.ts @@ -0,0 +1,19 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import K1 from "./K1.js"; + +/** + * Shallow-water terdiurnal (MK3). + * Compound constituent: M2 + K1 + * Speed ~44.03°/h with period ~8.18 hours (terdiurnal). + * Lunisolar interaction from M2 semi-diurnal and K1 diurnal components. + * Nodal factors combine fM2 with fK1. + * Generated in shallow-water environments; typical amplitude 0.5-2 cm. + * Often paired with 2MK3 in terdiurnal tide analysis. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("MK3", [ + { constituent: M2, factor: 1 }, + { constituent: K1, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/MKS2.ts b/packages/tide-predictor/src/constituents/MKS2.ts new file mode 100644 index 0000000..8b8107b --- /dev/null +++ b/packages/tide-predictor/src/constituents/MKS2.ts @@ -0,0 +1,21 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import K1 from "./K1.js"; +import S2 from "./S2.js"; + +/** + * Three-way shallow-water interaction of M2, K1, and S2. + * Speed ~29.5°/h with period ~12.0-12.1 hours. + * Uses combined M2 and K1 nodal factors (fM2/uM2 and fK1/uK1). + * + * Warning: Not in standard IHO constituent bank. Shallow-water specific constituent + * with definition varying by application and water depth. Use with caution and document + * the specific convention used in your analysis. + * + * @see NOAA CO-OPS shallow-water constituents + */ +export default defineCompoundConstituent("MKS2", [ + { constituent: M2, factor: 1 }, + { constituent: K1, factor: 1 }, + { constituent: S2, factor: -1 }, +]); diff --git a/packages/tide-predictor/src/constituents/MM.ts b/packages/tide-predictor/src/constituents/MM.ts new file mode 100644 index 0000000..19b52f0 --- /dev/null +++ b/packages/tide-predictor/src/constituents/MM.ts @@ -0,0 +1,14 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar monthly (MM). + * Doodson Number: 010.-10 + * Speed 0.544°/h (one cycle per lunar month = 27.55 days). + * Long-period constituent from lunar declination variations. + * Uses fMm/uMm nodal factors related to lunar orbital variations. + * Important for long-term water level studies. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("MM", [0, 1, 0, -1, 0, 0, 0], nc.uZero, nc.fMm); diff --git a/packages/tide-predictor/src/constituents/MN4.ts b/packages/tide-predictor/src/constituents/MN4.ts new file mode 100644 index 0000000..ae1321d --- /dev/null +++ b/packages/tide-predictor/src/constituents/MN4.ts @@ -0,0 +1,19 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import N2 from "./N2.js"; + +/** + * Shallow-water quarter-diurnal (MN4). + * Compound constituent: M2 + N2 + * Speed ~57.42°/h with period ~6.27 hours (quarter-diurnal). + * Lunar-lunar elliptic interaction from M2 and N2 semi-diurnal components. + * Nodal factors combine fM2 with fN2 (both use M2 nodal corrections). + * Generated in shallow-water environments; typical amplitude 1-5 cm. + * Often significant in shallow seas and estuaries. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("MN4", [ + { constituent: M2, factor: 1 }, + { constituent: N2, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/MS4.ts b/packages/tide-predictor/src/constituents/MS4.ts new file mode 100644 index 0000000..ff5f983 --- /dev/null +++ b/packages/tide-predictor/src/constituents/MS4.ts @@ -0,0 +1,19 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import S2 from "./S2.js"; + +/** + * Shallow-water quarter-diurnal (MS4). + * Compound constituent: M2 + S2 + * Speed ~58.98°/h with period ~6.10 hours (quarter-diurnal). + * Lunar-solar interaction from M2 and S2 semi-diurnal components. + * Nodal factors combine fM2 with fS2 (S2 has no nodal correction). + * Generated in shallow-water environments; typical amplitude 1-5 cm. + * Often second-largest quarter-diurnal component after M4. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("MS4", [ + { constituent: M2, factor: 1 }, + { constituent: S2, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/MSF.ts b/packages/tide-predictor/src/constituents/MSF.ts new file mode 100644 index 0000000..29bc5ba --- /dev/null +++ b/packages/tide-predictor/src/constituents/MSF.ts @@ -0,0 +1,20 @@ +import { defineCompoundConstituent } from "./index.js"; +import S2 from "./S2.js"; +import M2 from "./M2.js"; + +/** + * Lunisolar synodic fortnightly (MSF). + * Compound constituent: S2-M2 + * Speed ~1.016°/h with period ~354.37 hours (~14.76 days, fortnightly). + * Long-period constituent representing beat frequency between solar S2 and lunar M2. + * Manifests as fortnightly modulation of tidal range (spring-neap cycle). + * Nodal factor: fM2/fS2 with phase uS2-uM2. + * Amplitude typically 5-15% of M2; represents the primary spring-neap variation. + * Important for tidal range predictions and coastal flooding assessments. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("MSF", [ + { constituent: S2, factor: 1 }, + { constituent: M2, factor: -1 }, +]); diff --git a/packages/tide-predictor/src/constituents/MSQM.ts b/packages/tide-predictor/src/constituents/MSQM.ts new file mode 100644 index 0000000..b490784 --- /dev/null +++ b/packages/tide-predictor/src/constituents/MSQM.ts @@ -0,0 +1,22 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import S2 from "./S2.js"; +import K1 from "./K1.js"; + +/** + * Lunar-solar interaction compound constituent. + * Doodson Number: 254.658 (or ~255 variant) + * Speed ~28.5°/h; Uses fK1/uK1 nodal corrections. + * + * Warning: Non-standard constituent not in IHO or modern NOAA standard tables. + * Definition varies significantly across sources. Rarely used in modern tide prediction. + * Appears in Schureman's tables as variant shallow-water interaction. + * + * @see NOAA CO-OPS shallow-water constituents + * @see Schureman shallow-water analysis tables + */ +export default defineCompoundConstituent("MSQM", [ + { constituent: M2, factor: 1 }, + { constituent: S2, factor: 1 }, + { constituent: K1, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/MTM.ts b/packages/tide-predictor/src/constituents/MTM.ts new file mode 100644 index 0000000..5063129 --- /dev/null +++ b/packages/tide-predictor/src/constituents/MTM.ts @@ -0,0 +1,20 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import T2 from "./T2.js"; + +/** + * Lunar-solar shallow-water interaction (M2 modulated by lunar orbit). + * Speed ~29.0°/h with period ~12.0-12.2 hours. + * Uses M2 nodal factors (fM2/uM2). + * + * Warning: Not in modern IHO standard constituents; mostly historical interest. + * Often replaced by specific ν2, λ2, or other lunar elliptic terms in modern analysis. + * Amplitude is location and depth-dependent. + * + * @see NOAA CO-OPS shallow-water variants + * @see Schureman Manual + */ +export default defineCompoundConstituent("MTM", [ + { constituent: M2, factor: 1 }, + { constituent: T2, factor: 1 }, +]); diff --git a/packages/tide-predictor/src/constituents/MU2.ts b/packages/tide-predictor/src/constituents/MU2.ts new file mode 100644 index 0000000..c988147 --- /dev/null +++ b/packages/tide-predictor/src/constituents/MU2.ts @@ -0,0 +1,18 @@ +import { defineCompoundConstituent } from "./index.js"; +import M2 from "./M2.js"; +import S2 from "./S2.js"; + +/** + * Shallow-water semi-diurnal (MU2 or μ2). + * Compound constituent: 2×M2 - S2 + * Speed ~27.97°/h with period ~12.87 hours. + * Lunar variational constituent generated in shallow-water environments. + * Nodal factors combine (fM2)² with inverse S2 effects. + * Amplitude typically <2% of M2; found in coastal shallow-water predictions. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("MU2", [ + { constituent: M2, factor: 2 }, + { constituent: S2, factor: -1 }, +]); diff --git a/packages/tide-predictor/src/constituents/N2.ts b/packages/tide-predictor/src/constituents/N2.ts new file mode 100644 index 0000000..1137ad8 --- /dev/null +++ b/packages/tide-predictor/src/constituents/N2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar elliptic semi-diurnal (N2). + * Doodson Number: 2.-1.0.1.0.0.0 + * Speed 28.439°/h with period ~12.66 hours (lunar elliptic semi-diurnal). + * Primary lunar elliptic semi-diurnal constituent from Moon's orbital variations. + * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. + * Nodal factor ranges: f from ~0.4 to ~1.6; u varies over 18.613-year cycle. + * Amplitude typically 5-15% of M2; third-largest semi-diurnal constituent. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("N2", [2, -1, 0, 1, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/N4.ts b/packages/tide-predictor/src/constituents/N4.ts new file mode 100644 index 0000000..b4a28bb --- /dev/null +++ b/packages/tide-predictor/src/constituents/N4.ts @@ -0,0 +1,16 @@ +import { defineCompoundConstituent } from "./index.js"; +import N2 from "./N2.js"; + +/** + * Second overtide of N2; shallow-water quarter-diurnal harmonic. + * Doodson Number: 445.655 + * Speed 56.88°/h (= 2 × N2 speed) with period ~6.27 hours. + * Nodal factor: (fN2)² / (uN2)² = squared N2 nodal modulation. + * Amplitude ranges 0.25 to 2.25 times mean due to 18.613-year lunar node cycle. + * + * Note: Shallow-water constituent, typically found in tide predictions for coastal areas. + * + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + * @see https://en.wikipedia.org/wiki/Theory_of_tides + */ +export default defineCompoundConstituent("N4", [{ constituent: N2, factor: 2 }]); diff --git a/packages/tide-predictor/src/constituents/NU2.ts b/packages/tide-predictor/src/constituents/NU2.ts new file mode 100644 index 0000000..bb4ce79 --- /dev/null +++ b/packages/tide-predictor/src/constituents/NU2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar elliptic semi-diurnal (NU2). + * Doodson Number: 2.-1.2.-1.0.0.0 + * Speed 28.512°/h with period ~12.63 hours (lunar elliptic semi-diurnal). + * Secondary lunar elliptic semi-diurnal from Moon's orbital variations. + * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. + * Amplitude typically 2-5% of M2; smaller than N2. + * Important in detailed semi-diurnal constituent analysis. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("NU2", [2, -1, 2, -1, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/O1.ts b/packages/tide-predictor/src/constituents/O1.ts new file mode 100644 index 0000000..5f4aef7 --- /dev/null +++ b/packages/tide-predictor/src/constituents/O1.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar diurnal (O1). + * Doodson Number: 1.-1.0.0.0.0.1 + * Speed 13.943°/h with period ~24.84 hours (lunar diurnal). + * Primary lunar diurnal constituent; one-per-lunar-day oscillation. + * Uses fO1/uO1 nodal factors related to lunar ascending node (18.613-year cycle). + * Nodal factor ranges: f from ~0.4 to ~1.6; u from 0° to ±180°. + * Amplitude varies 10-20% due to lunar node effects. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("O1", [1, -1, 0, 0, 0, 0, 1], nc.uO1, nc.fO1); diff --git a/packages/tide-predictor/src/constituents/OO1.ts b/packages/tide-predictor/src/constituents/OO1.ts new file mode 100644 index 0000000..b680f5e --- /dev/null +++ b/packages/tide-predictor/src/constituents/OO1.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar diurnal (OO1). + * Doodson Number: 1.3.0.0.0.0.-1 + * Speed 16.139°/h with period ~22.31 hours (lunar diurnal). + * Second-order lunar diurnal constituent from Moon's orbital eccentricity. + * Uses OO1-specific nodal factors (fOO1/uOO1). + * Typically very small amplitude; <2% of O1 in most locations. + * Important for detailed harmonic analysis in some regions. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("OO1", [1, 3, 0, 0, 0, 0, -1], nc.uOO1, nc.fOO1); diff --git a/packages/tide-predictor/src/constituents/P1.ts b/packages/tide-predictor/src/constituents/P1.ts new file mode 100644 index 0000000..7f316e7 --- /dev/null +++ b/packages/tide-predictor/src/constituents/P1.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Solar diurnal (P1). + * Doodson Number: 1.1.-2.0.0.0.1 + * Speed 14.959°/h with period ~24.07 hours (solar diurnal). + * Principal solar diurnal constituent; one-per-solar-day oscillation. + * No nodal corrections (solar constituent; invariant in time). + * Amplitude typically 1/3 of K1; varies with latitude. + * Forms key component of diurnal tidal analysis alongside K1 and O1. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("P1", [1, 1, -2, 0, 0, 0, 1], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/Q1.ts b/packages/tide-predictor/src/constituents/Q1.ts new file mode 100644 index 0000000..b7862fa --- /dev/null +++ b/packages/tide-predictor/src/constituents/Q1.ts @@ -0,0 +1,14 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Elliptic lunar diurnal (Q1). + * Doodson Number: 1.-2.0.1.0.0.1 + * Speed 13.398°/h with period ~26.87 hours (lunar elliptic diurnal). + * One solar day and one lunar day modulation interaction. + * Uses O1 nodal factors (fO1/uO1) related to lunar node position. + * Amplitude typically 2-5% of O1; important in diurnal constituent analysis. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("Q1", [1, -2, 0, 1, 0, 0, 1], nc.uO1, nc.fO1); diff --git a/packages/tide-predictor/src/constituents/R2.ts b/packages/tide-predictor/src/constituents/R2.ts new file mode 100644 index 0000000..530b979 --- /dev/null +++ b/packages/tide-predictor/src/constituents/R2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Solar elliptic semi-diurnal (R2). + * Doodson Number: 2.2.-1.0.0.-1.2 + * Speed 30.041°/h with period ~11.98 hours (solar elliptic semi-diurnal). + * Smaller solar elliptic semi-diurnal constituent from solar declination effects. + * No nodal corrections (solar constituent). + * Amplitude typically <2% of S2; smallest of the solar semi-diurnal group. + * Rarely significant except in very detailed analyses. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("R2", [2, 2, -1, 0, 0, -1, 2], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/R3.ts b/packages/tide-predictor/src/constituents/R3.ts new file mode 100644 index 0000000..fcc8571 --- /dev/null +++ b/packages/tide-predictor/src/constituents/R3.ts @@ -0,0 +1,16 @@ +import { defineCompoundConstituent } from "./index.js"; +import R2 from "./R2.js"; + +/** + * Solar elliptic terdiurnal; 1.5 times R2 (smaller solar elliptic semi-diurnal). + * Doodson Number: ~437.555 (estimated from solar elliptic family) + * Speed ~45.04°/h with period ~8.0 hours. + * No nodal modulation (solar constituent). + * R2 reference: Doodson 274.555 (smaller solar elliptic with speed ~30.0°/h). + * + * Note: Generated only in shallow water; very small amplitude (<0.05 cm typical). + * Usually negligible except in extreme shallow-water environments. + * + * @see NOAA CO-OPS + */ +export default defineCompoundConstituent("R3", [{ constituent: R2, factor: 1.5 }]); diff --git a/packages/tide-predictor/src/constituents/RHO.ts b/packages/tide-predictor/src/constituents/RHO.ts new file mode 100644 index 0000000..336041c --- /dev/null +++ b/packages/tide-predictor/src/constituents/RHO.ts @@ -0,0 +1,8 @@ +import RHO1 from "./RHO1.js"; + +/** + * Alias for compatibility between NOAA and IHO + * + * @see RHO1 + */ +export default RHO1; diff --git a/packages/tide-predictor/src/constituents/RHO1.ts b/packages/tide-predictor/src/constituents/RHO1.ts new file mode 100644 index 0000000..89e112f --- /dev/null +++ b/packages/tide-predictor/src/constituents/RHO1.ts @@ -0,0 +1,19 @@ +import { defineCompoundConstituent } from "./index.js"; +import NU2 from "./NU2.js"; +import K1 from "./K1.js"; + +/** + * Shallow-water diurnal (RHO1, ρ1). + * Compound constituent: NU2-K1 (ν2-K1) + * Speed ~13.471°/h with period ~26.72 hours (diurnal). + * Derived from interaction of semi-diurnal NU2 and diurnal K1 constituents. + * Nodal factor combines effects from both parent constituents: fNU2/fK1 with phase uNU2-uK1. + * Amplitude typically very small; rarely significant. + * Found only in shallow-water regions with strong tidal distortion. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("RHO1", [ + { constituent: NU2, factor: 1 }, + { constituent: K1, factor: -1 }, +]); diff --git a/packages/tide-predictor/src/constituents/S1.ts b/packages/tide-predictor/src/constituents/S1.ts new file mode 100644 index 0000000..dbe3b7f --- /dev/null +++ b/packages/tide-predictor/src/constituents/S1.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Solar diurnal (S1). + * Doodson Number: 1.1.-1.0.0.0.0 + * Speed 15.000°/h with period 24.00 hours exactly (solar diurnal). + * Secondary solar diurnal constituent related to solar declination inequality. + * No nodal corrections (solar constituent). + * Usually very small amplitude; typically dominated by K1 and P1 in diurnal analysis. + * Rarely included in routine harmonic analyses. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("S1", [1, 1, -1, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/S2.ts b/packages/tide-predictor/src/constituents/S2.ts new file mode 100644 index 0000000..9437b53 --- /dev/null +++ b/packages/tide-predictor/src/constituents/S2.ts @@ -0,0 +1,16 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Solar semi-diurnal (S2). + * Doodson Number: 2.2.-2.0.0.0.0 + * Speed 30.000°/h with period exactly 12.00 hours (principal solar semi-diurnal). + * Principal solar semi-diurnal constituent; largest solar tide component. + * No nodal corrections (solar constituent; invariant in time). + * Amplitude typically 20-50% of M2; varies with geographic location and latitude. + * Ratio M2/S2 determines tidal form factor (diurnal vs semi-diurnal regimes). + * Base constituent for many compound shallow-water constituents. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("S2", [2, 2, -2, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/S3.ts b/packages/tide-predictor/src/constituents/S3.ts new file mode 100644 index 0000000..976226d --- /dev/null +++ b/packages/tide-predictor/src/constituents/S3.ts @@ -0,0 +1,15 @@ +import { defineCompoundConstituent } from "./index.js"; +import S2 from "./S2.js"; + +/** + * Solar terdiurnal overtide; shallow-water only. + * Doodson Number: 333.555 + * Speed fixed at 45.0°/h (= 1.5 × S2) with period ~8.0 hours. + * No nodal modulation (solar constituent - invariant). + * + * Note: Generated only in shallow water; not found in deep ocean. + * Typical amplitude <1 cm except in extreme shallow-water environments. + * + * @see NOAA CO-OPS + */ +export default defineCompoundConstituent("S3", [{ constituent: S2, factor: 1.5 }]); diff --git a/packages/tide-predictor/src/constituents/S4.ts b/packages/tide-predictor/src/constituents/S4.ts new file mode 100644 index 0000000..9c32c2f --- /dev/null +++ b/packages/tide-predictor/src/constituents/S4.ts @@ -0,0 +1,15 @@ +import { defineCompoundConstituent } from "./index.js"; +import S2 from "./S2.js"; + +/** + * Shallow-water quarter-diurnal (S4). + * Compound constituent: 2×S2 + * Speed 60.00°/h with period exactly 6.00 hours (quarter-diurnal). + * First overtide of S2; generated in shallow-water environments. + * No nodal corrections (solar constituent). + * Amplitude typically 1-3% of S2; smallest of the common quarter-diurnal constituents. + * Purely solar, so has fixed amplitude and phase at any location. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("S4", [{ constituent: S2, factor: 2 }]); diff --git a/packages/tide-predictor/src/constituents/S6.ts b/packages/tide-predictor/src/constituents/S6.ts new file mode 100644 index 0000000..ec7be6b --- /dev/null +++ b/packages/tide-predictor/src/constituents/S6.ts @@ -0,0 +1,15 @@ +import { defineCompoundConstituent } from "./index.js"; +import S2 from "./S2.js"; + +/** + * Shallow-water sixth-diurnal (S6). + * Compound constituent: 3×S2 + * Speed 90.00°/h with period exactly 4.00 hours (sixth-diurnal). + * Second overtide of S2; generated in shallow-water environments. + * No nodal corrections (solar constituent). + * Amplitude typically 0.5-1% of S2; smallest of the common overtides. + * Rarely significant except in extreme shallow water or resonant systems. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineCompoundConstituent("S6", [{ constituent: S2, factor: 3 }]); diff --git a/packages/tide-predictor/src/constituents/SA.ts b/packages/tide-predictor/src/constituents/SA.ts new file mode 100644 index 0000000..de8b2d3 --- /dev/null +++ b/packages/tide-predictor/src/constituents/SA.ts @@ -0,0 +1,13 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Solar annual (Sa). + * Doodson Number: 001.000 + * Speed 0.041°/h (one cycle per solar year = 365.24 days). + * Long-term constituent driven by solar declination variations over the year. + * No nodal corrections (solar constituent). + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("Sa", [0, 0, 1, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/SGM.ts b/packages/tide-predictor/src/constituents/SGM.ts new file mode 100644 index 0000000..28a69d5 --- /dev/null +++ b/packages/tide-predictor/src/constituents/SGM.ts @@ -0,0 +1,14 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Lunar diurnal variational constituent (σ1, sigma1). + * Doodson Number: 127.555 + * Derived from Moon's declination variations; speed 12.73°/h with period ~28.3 hours. + * Uses K1 nodal factors (fK1/uK1) for amplitude and phase modulation. + * + * Note: Often has small amplitude; closely related to K1 and O1 variations. + * + * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + */ +export default defineConstituent("SGM", [1, -3, 2, 0, 0, 0, 0], nc.uK1, nc.fK1); diff --git a/packages/tide-predictor/src/constituents/SSA.ts b/packages/tide-predictor/src/constituents/SSA.ts new file mode 100644 index 0000000..70f126f --- /dev/null +++ b/packages/tide-predictor/src/constituents/SSA.ts @@ -0,0 +1,13 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Solar semi-annual (Ssa). + * Doodson Number: 002.000 + * Speed 0.0823°/h (one cycle per solar half-year = 182.6 days). + * Semi-annual constituent from solar declination with twice-yearly periodicity. + * No nodal corrections (solar constituent). + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("Ssa", [0, 0, 2, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/T2.ts b/packages/tide-predictor/src/constituents/T2.ts new file mode 100644 index 0000000..209fcf2 --- /dev/null +++ b/packages/tide-predictor/src/constituents/T2.ts @@ -0,0 +1,15 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Solar elliptic semi-diurnal (T2). + * Doodson Number: 2.2.-3.0.0.1.0 + * Speed 29.959°/h with period ~12.01 hours (solar elliptic semi-diurnal). + * Larger solar elliptic semi-diurnal constituent from solar declination effects. + * No nodal corrections (solar constituent). + * Amplitude typically <5% of S2; increases at higher latitudes. + * Forms part of solar semi-diurnal analysis alongside S2 and R2. + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("T2", [2, 2, -3, 0, 0, 1, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/T3.ts b/packages/tide-predictor/src/constituents/T3.ts new file mode 100644 index 0000000..83e198a --- /dev/null +++ b/packages/tide-predictor/src/constituents/T3.ts @@ -0,0 +1,16 @@ +import { defineCompoundConstituent } from "./index.js"; +import T2 from "./T2.js"; + +/** + * Solar elliptic terdiurnal; 1.5 times T2 (larger solar elliptic semi-diurnal). + * Doodson Number: ~438.555 (estimated from solar elliptic family) + * Speed ~44.94°/h with period ~8.0 hours. + * Minimal nodal modulation (solar constituent). + * T2 reference: Doodson 272.555 (larger solar elliptic with speed ~60.0°/h). + * + * Note: Generated only in shallow water; minimal amplitude (<0.1 cm typical). + * Rarely significant except in extreme shallow-water or enclosed basins. + * + * @see NOAA CO-OPS + */ +export default defineCompoundConstituent("T3", [{ constituent: T2, factor: 1.5 }]); diff --git a/packages/tide-predictor/src/constituents/Z0.ts b/packages/tide-predictor/src/constituents/Z0.ts new file mode 100644 index 0000000..64d5229 --- /dev/null +++ b/packages/tide-predictor/src/constituents/Z0.ts @@ -0,0 +1,14 @@ +import { defineConstituent } from "./index.js"; +import nc from "../node-corrections/index.js"; + +/** + * Mean sea level (Z0). + * Doodson Number: 000.000 + * Not a tidal constituent in the strict sense, but represents the mean sea level offset + * or the "zero" reference level used in tidal predictions. + * No astronomical forcing; typically determined from harmonic analysis of observed data. + * No nodal corrections applied (constant offset). + * + * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS + */ +export default defineConstituent("Z0", [0, 0, 0, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/compound-constituent.ts b/packages/tide-predictor/src/constituents/compound-constituent.ts deleted file mode 100644 index 0771cfe..0000000 --- a/packages/tide-predictor/src/constituents/compound-constituent.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { Constituent } from "./constituent.js"; -import type { AstroData } from "../astronomy/index.js"; - -export interface ConstituentMember { - constituent: Constituent; - factor: number; -} - -export interface CompoundConstituent { - name: string; - coefficients: number[]; - speed: (astro: AstroData) => number; - value: (astro: AstroData) => number; - u: (astro: AstroData) => number; - f: (astro: AstroData) => number; -} - -const compoundConstituentFactory = ( - name: string, - members: ConstituentMember[], -): CompoundConstituent => { - const coefficients: number[] = []; - members.forEach(({ constituent, factor }) => { - constituent.coefficients.forEach((coefficient, index) => { - if (typeof coefficients[index] === "undefined") { - coefficients[index] = 0; - } - coefficients[index] += coefficient * factor; - }); - }); - - const compoundConstituent: CompoundConstituent = { - name, - coefficients, - - speed: (astro: AstroData): number => { - let speed = 0; - members.forEach(({ constituent, factor }) => { - speed += constituent.speed(astro) * factor; - }); - return speed; - }, - - value: (astro: AstroData): number => { - let value = 0; - members.forEach(({ constituent, factor }) => { - value += constituent.value(astro) * factor; - }); - return value; - }, - - u: (astro: AstroData): number => { - let u = 0; - members.forEach(({ constituent, factor }) => { - u += constituent.u(astro) * factor; - }); - return u; - }, - - f: (astro: AstroData): number => { - const f: number[] = []; - members.forEach(({ constituent, factor }) => { - f.push(Math.pow(constituent.f(astro), Math.abs(factor))); - }); - return f.reduce((previous, value) => previous * value); - }, - }; - - return Object.freeze(compoundConstituent); -}; - -export default compoundConstituentFactory; diff --git a/packages/tide-predictor/src/constituents/constituent.ts b/packages/tide-predictor/src/constituents/constituent.ts deleted file mode 100644 index a5d50e8..0000000 --- a/packages/tide-predictor/src/constituents/constituent.ts +++ /dev/null @@ -1,76 +0,0 @@ -import nodeCorrections from "../node-corrections/index.js"; -import type { AstroData } from "../astronomy/index.js"; -import type { NodeCorrectionFunction } from "../node-corrections/index.js"; - -/** - * Computes the dot notation of two arrays - */ -const dotArray = (a: number[], b: number[]): number => { - const results: number[] = []; - a.forEach((value, index) => { - results.push(value * b[index]); - }); - return results.reduce((total, value) => total + value); -}; - -const astronimicDoodsonNumber = (astro: AstroData): AstroData[keyof AstroData][] => { - return [astro["T+h-s"], astro.s, astro.h, astro.p, astro.N, astro.pp, astro["90"]]; -}; - -const astronomicSpeed = (astro: AstroData): number[] => { - const results: number[] = []; - astronimicDoodsonNumber(astro).forEach((number) => { - results.push(number.speed); - }); - return results; -}; - -const astronomicValues = (astro: AstroData): number[] => { - const results: number[] = []; - astronimicDoodsonNumber(astro).forEach((number) => { - results.push(number.value); - }); - return results; -}; - -export interface Constituent { - name: string; - coefficients: number[]; - value: (astro: AstroData) => number; - speed: (astro: AstroData) => number; - u: NodeCorrectionFunction; - f: NodeCorrectionFunction; -} - -const constituentFactory = ( - name: string, - coefficients: number[], - u?: NodeCorrectionFunction, - f?: NodeCorrectionFunction, -): Constituent => { - if (!coefficients) { - throw new Error("Coefficient must be defined for a constituent"); - } - - const constituent: Constituent = { - name, - coefficients, - - value: (astro: AstroData): number => { - return dotArray(coefficients, astronomicValues(astro)); - }, - - speed(astro: AstroData): number { - return dotArray(coefficients, astronomicSpeed(astro)); - }, - - u: typeof u !== "undefined" ? u : nodeCorrections.uZero, - - f: typeof f !== "undefined" ? f : nodeCorrections.fUnity, - }; - - return Object.freeze(constituent); -}; - -export default constituentFactory; -export { astronimicDoodsonNumber, astronomicSpeed, astronomicValues }; diff --git a/packages/tide-predictor/src/constituents/index.ts b/packages/tide-predictor/src/constituents/index.ts index b17cb45..7d1ab5a 100644 --- a/packages/tide-predictor/src/constituents/index.ts +++ b/packages/tide-predictor/src/constituents/index.ts @@ -1,309 +1,145 @@ -import constituent from "./constituent.js"; -import compoundConstituent from "./compound-constituent.js"; -import nc from "../node-corrections/index.js"; -import type { Constituent } from "./constituent.js"; -import type { CompoundConstituent } from "./compound-constituent.js"; - -export interface Constituents { - Z0: Constituent; - SA: Constituent; - SSA: Constituent; - MM: Constituent; - MF: Constituent; - Q1: Constituent; - O1: Constituent; - K1: Constituent; - J1: Constituent; - M1: Constituent; - P1: Constituent; - S1: Constituent; - OO1: Constituent; - "2N2": Constituent; - N2: Constituent; - NU2: Constituent; - M2: Constituent; - LAM2: Constituent; - LAMBDA2: Constituent; - L2: Constituent; - T2: Constituent; - S2: Constituent; - R2: Constituent; - K2: Constituent; - M3: Constituent; - EP2: Constituent; - MA2: Constituent; - MB2: Constituent; - SGM: Constituent; - MSF: CompoundConstituent; - "2Q1": CompoundConstituent; - RHO1: CompoundConstituent; - RHO: CompoundConstituent; - MU2: CompoundConstituent; - "2SM2": CompoundConstituent; - "2MK3": CompoundConstituent; - MK3: CompoundConstituent; - MN4: CompoundConstituent; - M4: CompoundConstituent; - MS4: CompoundConstituent; - S4: CompoundConstituent; - M6: CompoundConstituent; - S6: CompoundConstituent; - M8: CompoundConstituent; - MSQM: CompoundConstituent; - MTM: CompoundConstituent; - MKS2: CompoundConstituent; - N4: CompoundConstituent; - S3: CompoundConstituent; - T3: CompoundConstituent; - R3: CompoundConstituent; - "3L2": CompoundConstituent; - "3N2": CompoundConstituent; - "2MS6": CompoundConstituent; - "2MK5": CompoundConstituent; - "2MO5": CompoundConstituent; +import type { AstroData } from "../astronomy/index.js"; +import nodeCorrections, { type NodeCorrectionFunction } from "../node-corrections/index.js"; + +export interface Constituent { + name: string; + coefficients: number[]; + value: (astro: AstroData) => number; + speed: (astro: AstroData) => number; + u: NodeCorrectionFunction; + f: NodeCorrectionFunction; } -const constituents: Partial = {}; - -// Long Term -constituents.Z0 = constituent("Z0", [0, 0, 0, 0, 0, 0, 0], nc.uZero, nc.fUnity); -constituents.SA = constituent("Sa", [0, 0, 1, 0, 0, 0, 0], nc.uZero, nc.fUnity); -constituents.SSA = constituent("Ssa", [0, 0, 2, 0, 0, 0, 0], nc.uZero, nc.fUnity); -constituents.MM = constituent("MM", [0, 1, 0, -1, 0, 0, 0], nc.uZero, nc.fMm); -constituents.MF = constituent("MF", [0, 2, 0, 0, 0, 0, 0], nc.uMf, nc.fMf); -// Diurnals -constituents.Q1 = constituent("Q1", [1, -2, 0, 1, 0, 0, 1], nc.uO1, nc.fO1); -constituents.O1 = constituent("O1", [1, -1, 0, 0, 0, 0, 1], nc.uO1, nc.fO1); -constituents.K1 = constituent("K1", [1, 1, 0, 0, 0, 0, -1], nc.uK1, nc.fK1); -constituents.J1 = constituent("J1", [1, 2, 0, -1, 0, 0, -1], nc.uJ1, nc.fJ1); -constituents.M1 = constituent("M1", [1, 0, 0, 0, 0, 0, 1], nc.uM1, nc.fM1); -constituents.P1 = constituent("P1", [1, 1, -2, 0, 0, 0, 1], nc.uZero, nc.fUnity); -constituents.S1 = constituent("S1", [1, 1, -1, 0, 0, 0, 0], nc.uZero, nc.fUnity); -constituents.OO1 = constituent("OO1", [1, 3, 0, 0, 0, 0, -1], nc.uOO1, nc.fOO1); -// Semi diurnals -constituents["2N2"] = constituent("2N2", [2, -2, 0, 2, 0, 0, 0], nc.uM2, nc.fM2); -constituents.N2 = constituent("N2", [2, -1, 0, 1, 0, 0, 0], nc.uM2, nc.fM2); -constituents.NU2 = constituent("NU2", [2, -1, 2, -1, 0, 0, 0], nc.uM2, nc.fM2); -constituents.M2 = constituent("M2", [2, 0, 0, 0, 0, 0, 0], nc.uM2, nc.fM2); -constituents.LAM2 = constituent("LAM2", [2, 1, -2, 1, 0, 0, 2], nc.uM2, nc.fM2); -constituents.LAMBDA2 = constituents.LAM2; // Alias -constituents.L2 = constituent("L2", [2, 1, 0, -1, 0, 0, 2], nc.uL2, nc.fL2); -constituents.T2 = constituent("T2", [2, 2, -3, 0, 0, 1, 0], nc.uZero, nc.fUnity); -constituents.S2 = constituent("S2", [2, 2, -2, 0, 0, 0, 0], nc.uZero, nc.fUnity); -constituents.R2 = constituent("R2", [2, 2, -1, 0, 0, -1, 2], nc.uZero, nc.fUnity); -constituents.K2 = constituent("K2", [2, 2, 0, 0, 0, 0, 0], nc.uK2, nc.fK2); -// Third diurnal -constituents.M3 = constituent( - "M3", - [3, 0, 0, 0, 0, 0, 0], - (a) => { - return nc.uModd(a, 3); - }, - (a) => { - return nc.fModd(a, 3); - }, -); -// Compound -constituents.MSF = compoundConstituent("MSF", [ - { constituent: constituents.S2!, factor: 1 }, - { constituent: constituents.M2!, factor: -1 }, -]); - -// Diurnal -constituents["2Q1"] = compoundConstituent("2Q1", [ - { constituent: constituents.N2!, factor: 1 }, - { constituent: constituents.J1!, factor: -1 }, -]); -constituents.RHO = compoundConstituent("RHO", [ - { constituent: constituents.NU2!, factor: 1 }, - { constituent: constituents.K1!, factor: -1 }, -]); -constituents.RHO1 = constituents.RHO; // Alias; - -// Semi-Diurnal - -constituents.MU2 = compoundConstituent("MU2", [ - { constituent: constituents.M2!, factor: 2 }, - { constituent: constituents.S2!, factor: -1 }, -]); -constituents["2SM2"] = compoundConstituent("2SM2", [ - { constituent: constituents.S2!, factor: 2 }, - { constituent: constituents.M2!, factor: -1 }, -]); - -// Third-Diurnal -constituents["2MK3"] = compoundConstituent("2MK3", [ - { constituent: constituents.M2!, factor: 1 }, - { constituent: constituents.O1!, factor: 1 }, -]); -constituents.MK3 = compoundConstituent("MK3", [ - { constituent: constituents.M2!, factor: 1 }, - { constituent: constituents.K1!, factor: 1 }, -]); +export function defineConstituent( + name: string, + coefficients: number[], + u?: NodeCorrectionFunction, + f?: NodeCorrectionFunction, +): Constituent { + if (!coefficients) { + throw new Error("Coefficient must be defined for a constituent"); + } -// Quarter-Diurnal -constituents.MN4 = compoundConstituent("MN4", [ - { constituent: constituents.M2!, factor: 1 }, - { constituent: constituents.N2!, factor: 1 }, -]); -constituents.M4 = compoundConstituent("M4", [{ constituent: constituents.M2!, factor: 2 }]); -constituents.MS4 = compoundConstituent("MS4", [ - { constituent: constituents.M2!, factor: 1 }, - { constituent: constituents.S2!, factor: 1 }, -]); -constituents.S4 = compoundConstituent("S4", [{ constituent: constituents.S2!, factor: 2 }]); + return Object.freeze({ + name, + coefficients, -// Sixth-Diurnal -constituents.M6 = compoundConstituent("M6", [{ constituent: constituents.M2!, factor: 3 }]); -constituents.S6 = compoundConstituent("S6", [{ constituent: constituents.S2!, factor: 3 }]); - -// Eighth-Diurnals -constituents.M8 = compoundConstituent("M8", [{ constituent: constituents.M2!, factor: 4 }]); - -// Semi-diurnal (lunar elliptic) -/** - * Lunar elliptic semi-diurnal constituent (ε2). - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS constituent tables - */ -constituents.EP2 = constituent("EP2", [2, 0, 1, 0, 0, 0, 0], nc.uM2, nc.fM2); - -/** - * Lunar variational semi-diurnal constituent (μ2, mu2). - * Derived from Moon's orbital parameter variations. - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank - */ -constituents.MA2 = constituent("MA2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); + value: (astro: AstroData): number => { + return dotArray(coefficients, astronomicValues(astro)); + }, -/** - * Lunar elliptic constituent from parameter variations. - * @see Schureman, P. (1958). Manual of Harmonic Analysis and Prediction of Tides - */ -constituents.MB2 = constituent("MB2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); + speed(astro: AstroData): number { + return dotArray(coefficients, astronomicSpeed(astro)); + }, -// Diurnal (lunar variational) -/** - * Lunar diurnal variational constituent (σ1, sigma1). - * Derived from Moon's declination variations. - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank - */ -constituents.SGM = constituent("SGM", [1, -3, 2, 0, 0, 0, 0], nc.uK1, nc.fK1); + u: typeof u !== "undefined" ? u : nodeCorrections.uZero, -// Shallow-water compound constituents -/** - * Lunar-solar interaction compound constituent. - * Non-standard variant; definition varies by source. - * @see NOAA CO-OPS shallow-water constituents - * @see Schureman shallow-water analysis tables - */ -constituents.MSQM = compoundConstituent("MSQM", [ - { constituent: constituents.M2!, factor: 1 }, - { constituent: constituents.S2!, factor: 1 }, - { constituent: constituents.K1!, factor: 1 }, -]); + f: typeof f !== "undefined" ? f : nodeCorrections.fUnity, + }); +} -/** - * Lunar-solar shallow-water interaction. - * Not in standard IHO constituents; regional application. - * @see NOAA CO-OPS shallow-water variants - */ -constituents.MTM = compoundConstituent("MTM", [ - { constituent: constituents.M2!, factor: 1 }, - { constituent: constituents.T2!, factor: 1 }, -]); +export interface ConstituentMember { + constituent: Constituent; + factor: number; +} -/** - * Three-way shallow-water interaction of M2, K1, and S2. - * Definition varies by application and depth. - * @see NOAA CO-OPS shallow-water constituents - */ -constituents.MKS2 = compoundConstituent("MKS2", [ - { constituent: constituents.M2!, factor: 1 }, - { constituent: constituents.K1!, factor: 1 }, - { constituent: constituents.S2!, factor: -1 }, -]); +export function defineCompoundConstituent(name: string, members: ConstituentMember[]): Constituent { + const coefficients: number[] = []; + members.forEach(({ constituent, factor }) => { + constituent.coefficients.forEach((coefficient, index) => { + if (typeof coefficients[index] === "undefined") { + coefficients[index] = 0; + } + coefficients[index] += coefficient * factor; + }); + }); + + return Object.freeze({ + name, + coefficients, + + speed: (astro: AstroData): number => { + let speed = 0; + members.forEach(({ constituent, factor }) => { + speed += constituent.speed(astro) * factor; + }); + return speed; + }, + + value: (astro: AstroData): number => { + let value = 0; + members.forEach(({ constituent, factor }) => { + value += constituent.value(astro) * factor; + }); + return value; + }, + + u: (astro: AstroData): number => { + let u = 0; + members.forEach(({ constituent, factor }) => { + u += constituent.u(astro) * factor; + }); + return u; + }, + + f: (astro: AstroData): number => { + const f: number[] = []; + members.forEach(({ constituent, factor }) => { + f.push(Math.pow(constituent.f(astro), Math.abs(factor))); + }); + return f.reduce((previous, value) => previous * value); + }, + }); +} /** - * Second overtide of N2; shallow-water quarter-diurnal harmonic. - * Amplitude ranges 0.25 to 2.25 times mean due to lunar node cycle. - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank + * Computes the dot notation of two arrays */ -constituents.N4 = compoundConstituent("N4", [{ constituent: constituents.N2!, factor: 2 }]); +function dotArray(a: number[], b: number[]): number { + const results: number[] = []; + a.forEach((value, index) => { + results.push(value * b[index]); + }); + return results.reduce((total, value) => total + value); +} -/** - * Solar terdiurnal overtide; shallow-water only. - * Speed fixed at 45.0°/h (3 times per solar day). - * No nodal modulation (solar constituent). - * @see NOAA CO-OPS - */ -constituents.S3 = compoundConstituent("S3", [{ constituent: constituents.S2!, factor: 1.5 }]); +export function astronimicDoodsonNumber(astro: AstroData): AstroData[keyof AstroData][] { + return [astro["T+h-s"], astro.s, astro.h, astro.p, astro.N, astro.pp, astro["90"]]; +} -/** - * Solar elliptic terdiurnal; 1.5 times T2. - * Generated in shallow water only; minimal amplitude (<0.1 cm typical). - * @see NOAA CO-OPS - */ -constituents.T3 = compoundConstituent("T3", [{ constituent: constituents.T2!, factor: 1.5 }]); +export function astronomicSpeed(astro: AstroData): number[] { + const results: number[] = []; + astronimicDoodsonNumber(astro).forEach((number) => { + results.push(number.speed); + }); + return results; +} -/** - * Solar elliptic terdiurnal; 1.5 times R2. - * Generated in shallow water only; very small amplitude (<0.05 cm typical). - * @see NOAA CO-OPS - */ -constituents.R3 = compoundConstituent("R3", [{ constituent: constituents.R2!, factor: 1.5 }]); +export function astronomicValues(astro: AstroData): number[] { + const results: number[] = []; + astronimicDoodsonNumber(astro).forEach((number) => { + results.push(number.value); + }); + return results; +} -/** - * Triple lunar elliptic; 3 times L2 interaction. - * Not in standard IHO constituent bank; mainly historical/theoretical interest. - * Very small amplitude (<0.1 cm); found in extreme shallow water only. - * @see Schureman, P. (1958). Manual of Harmonic Analysis and Prediction of Tides - */ -constituents["3L2"] = compoundConstituent("3L2", [{ constituent: constituents.L2!, factor: 3 }]); +// Dynamically import all constituent files +const constituentModules = import.meta.glob("./*.ts", { + eager: true, + import: "default", +}); -/** - * Triple N2 shallow-water harmonic. - * Definition based on compound frequency estimates. - * Typical amplitude <0.5 cm; often <0.1 cm except in extreme shallow-water environments. - * @see NOAA CO-OPS shallow-water constituents - */ -constituents["3N2"] = compoundConstituent("3N2", [{ constituent: constituents.N2!, factor: 3 }]); +const constituents: Record = {}; -/** - * Quarter-diurnal shallow-water interaction of M2 and S2. - * Sometimes denoted as MS4 in alternative notation systems. - * Nodal factor: (fM2)^2 (from M2^2 component). - * Generated in shallow water; typical amplitude 0.01-0.2 meters depending on depth. - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS: Listed as NOAA order #37 - */ -constituents["2MS6"] = compoundConstituent("2MS6", [ - { constituent: constituents.M2!, factor: 2 }, - { constituent: constituents.S2!, factor: 1 }, -]); +// Extract constituent name from file path and populate the constituents object +for (const [path, module] of Object.entries(constituentModules)) { + // Skip the index file itself + if (path.includes("index.ts")) continue; -/** - * Shallow-water quinte-diurnal from M2-K1 interaction. - * Components: 2×M2 (lunar semi-diurnal × 2) + K1 (lunisolar diurnal). - * Period 8.18 hours. Amplitude typically 0.1-0.5 cm; found in coastal predictions. - * Nodal factors combine (fM2)^2 with fK1. - * @see NOAA CO-OPS - */ -constituents["2MK5"] = compoundConstituent("2MK5", [ - { constituent: constituents.M2!, factor: 2 }, - { constituent: constituents.K1!, factor: 1 }, -]); + // Extract filename without extension and .js suffix + const name = path.split("/").pop()?.replace(/\.ts$/, "") ?? ""; -/** - * Shallow-water quinte-diurnal from M2-O1 interaction. - * Components: 2×M2 (lunar semi-diurnal × 2) + O1 (lunar diurnal). - * Period 8.28 hours. Primarily shallow-water coastal phenomenon. - * Amplitude typically <0.5 cm except in extreme shallow-water or enclosed basins. - * Nodal factors combine (fM2)^2 with fO1. - * @see NOAA CO-OPS - */ -constituents["2MO5"] = compoundConstituent("2MO5", [ - { constituent: constituents.M2!, factor: 2 }, - { constituent: constituents.O1!, factor: 1 }, -]); + constituents[name] = module; +} -export default constituents as Constituents; +export default constituents; diff --git a/packages/tide-predictor/src/harmonics/index.ts b/packages/tide-predictor/src/harmonics/index.ts index 50c9e65..6e75509 100644 --- a/packages/tide-predictor/src/harmonics/index.ts +++ b/packages/tide-predictor/src/harmonics/index.ts @@ -1,7 +1,7 @@ import prediction from "./prediction.js"; import constituentModels from "../constituents/index.js"; import { d2r } from "../astronomy/constants.js"; -import type { HarmonicConstituent, InternalHarmonicConstituent, Prediction } from "./prediction.js"; +import type { HarmonicConstituent, Prediction } from "./prediction.js"; export type * from "./prediction.js"; @@ -51,7 +51,7 @@ const harmonicsFactory = ({ harmonicConstituents, offset }: HarmonicsOptions): H if (!Array.isArray(harmonicConstituents)) { throw new Error("Harmonic constituents are not an array"); } - const constituents: InternalHarmonicConstituent[] = []; + const constituents: HarmonicConstituent[] = []; harmonicConstituents.forEach((constituent) => { if (typeof constituent.name === "undefined") { throw new Error("Harmonic constituents must have a name property"); @@ -59,7 +59,6 @@ const harmonicsFactory = ({ harmonicConstituents, offset }: HarmonicsOptions): H if (constituentModels[constituent.name] !== undefined) { constituents.push({ ...constituent, - _model: constituentModels[constituent.name], phase: d2r * constituent.phase, }); } @@ -68,7 +67,6 @@ const harmonicsFactory = ({ harmonicConstituents, offset }: HarmonicsOptions): H if (offset !== false) { constituents.push({ name: "Z0", - _model: constituentModels.Z0, phase: 0, amplitude: offset, }); diff --git a/packages/tide-predictor/src/harmonics/prediction.ts b/packages/tide-predictor/src/harmonics/prediction.ts index 7443a4e..e3bf407 100644 --- a/packages/tide-predictor/src/harmonics/prediction.ts +++ b/packages/tide-predictor/src/harmonics/prediction.ts @@ -1,7 +1,6 @@ import astro from "../astronomy/index.js"; import { d2r } from "../astronomy/constants.js"; -import type { Constituent } from "../constituents/constituent.js"; -import type { CompoundConstituent } from "../constituents/compound-constituent.js"; +import constituentModels from "../constituents/index.js"; export interface Timeline { items: Date[]; @@ -16,10 +15,6 @@ export interface HarmonicConstituent { description?: string; } -export interface InternalHarmonicConstituent extends HarmonicConstituent { - _model: Constituent | CompoundConstituent; -} - export interface TimelinePoint { time: Date; hour: number; @@ -106,7 +101,7 @@ const getExtremeLabel = (label: "high" | "low", highLowLabels?: ExtremeLabels): interface PredictionFactoryParams { timeline: Timeline; - constituents: InternalHarmonicConstituent[]; + constituents: HarmonicConstituent[]; start: Date; } @@ -220,8 +215,11 @@ const predictionFactory = ({ const u: Record[] = []; const f: Record[] = []; constituents.forEach((constituent) => { - const value = constituent._model.value(baseAstro); - const speed = constituent._model.speed(baseAstro); + const model = constituentModels[constituent.name]; + if (!model) return; + + const value = model.value(baseAstro); + const speed = model.speed(baseAstro); baseValue[constituent.name] = d2r * value; baseSpeed[constituent.name] = d2r * speed; }); @@ -230,11 +228,14 @@ const predictionFactory = ({ const fItem: Record = {}; const itemAstro = astro(time); constituents.forEach((constituent) => { - const constituentU = modulus(constituent._model.u(itemAstro), 360); + const model = constituentModels[constituent.name]; + if (!model) return; + const constituentU = modulus(model.u(itemAstro), 360); uItem[constituent.name] = d2r * constituentU; - fItem[constituent.name] = modulus(constituent._model.f(itemAstro), 360); + fItem[constituent.name] = modulus(model.f(itemAstro), 360); }); + u.push(uItem); f.push(fItem); }); diff --git a/packages/tide-predictor/test/constituents/compound-constituent.test.ts b/packages/tide-predictor/test/constituents/compound-constituent.test.ts index d553ceb..6c6c4f6 100644 --- a/packages/tide-predictor/test/constituents/compound-constituent.test.ts +++ b/packages/tide-predictor/test/constituents/compound-constituent.test.ts @@ -1,20 +1,20 @@ import { describe, it, expect } from "vitest"; -import compoundConstituent from "../../src/constituents/compound-constituent.js"; -import Constituent from "../../src/constituents/constituent.js"; +import { defineCompoundConstituent } from "../../src/constituents/index.js"; +import { defineConstituent } from "../../src/constituents/index.js"; import astro from "../../src/astronomy/index.js"; const sampleTime = new Date("2019-10-04T10:15:40.010Z"); const testAstro = astro(sampleTime); // This is a made-up doodson number for a test coefficient -const testConstituentA = Constituent("testa", [1, 1, -1, 0, 0, 0, 1]); -const testConstituentB = Constituent("testb", [0, 1, -1, 0, 0, 0, 1]); +const testConstituentA = defineConstituent("testa", [1, 1, -1, 0, 0, 0, 1]); +const testConstituentB = defineConstituent("testb", [0, 1, -1, 0, 0, 0, 1]); -const compoundTest = compoundConstituent("test compound", [ +const compoundTest = defineCompoundConstituent("test compound", [ { constituent: testConstituentA, factor: 1 }, { constituent: testConstituentB, factor: -1 }, ]); -describe("compund constituent", () => { +describe("compound constituent", () => { it("it calculates compound coefficients", () => { expect(compoundTest.coefficients).toEqual([1, 0, 0, 0, 0, 0, 0]); }); diff --git a/packages/tide-predictor/test/constituents/constituent.test.ts b/packages/tide-predictor/test/constituents/constituent.test.ts index 25f4c7f..f4ee7d5 100644 --- a/packages/tide-predictor/test/constituents/constituent.test.ts +++ b/packages/tide-predictor/test/constituents/constituent.test.ts @@ -1,22 +1,23 @@ import { describe, it, expect } from "vitest"; -import constituent, { +import { astronimicDoodsonNumber, astronomicSpeed, astronomicValues, -} from "../../src/constituents/constituent.js"; + defineConstituent, +} from "../../src/constituents/index.js"; import astro from "../../src/astronomy/index.js"; const sampleTime = new Date("2019-10-04T10:15:40.010Z"); const testAstro = astro(sampleTime); // This is a made-up doodson number for a test coefficient -const testConstituent = constituent("test", [1, 1, -1, 0, 0, 0, 1]); +const testConstituent = defineConstituent("test", [1, 1, -1, 0, 0, 0, 1]); describe("constituent", () => { it("it throws error if missing coefficients", () => { expect(() => { // @ts-expect-error: Testing invalid input - constituent("fail"); + defineConstituent("fail"); }).toThrow("Coefficient must be defined for a constituent"); }); diff --git a/tsconfig.json b/tsconfig.json index cac6e0e..d5566bd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "allowImportingTsExtensions": false, - "noEmit": true + "noEmit": true, + "types": ["vite/client"] } } From 735557c70b2400df30b1f2b93e6e6c508e56d52b Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Fri, 9 Jan 2026 08:28:55 -0500 Subject: [PATCH 4/6] Correct MA2, MB2,SGM, EP2. Use speeds from IHO doc --- .../tide-predictor/src/constituents/EP2.ts | 6 +-- .../tide-predictor/src/constituents/MA2.ts | 4 +- .../tide-predictor/src/constituents/MB2.ts | 13 ++++-- .../tide-predictor/src/constituents/SGM.ts | 6 +-- .../test/constituents/index.test.ts | 41 ++++--------------- 5 files changed, 23 insertions(+), 47 deletions(-) diff --git a/packages/tide-predictor/src/constituents/EP2.ts b/packages/tide-predictor/src/constituents/EP2.ts index 9a88775..a1363b4 100644 --- a/packages/tide-predictor/src/constituents/EP2.ts +++ b/packages/tide-predictor/src/constituents/EP2.ts @@ -3,14 +3,10 @@ import nc from "../node-corrections/index.js"; /** * Lunar elliptic semi-diurnal constituent (ε2). - * Doodson Number: 256.555 - * From Moon's elliptical orbit; speed 29.6°/h with period of ~12.0 hours. * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. * - * Note: Sometimes called ν2 variant in some sources, but IHO designation is definitive. - * * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS constituent tables * @see https://en.wikipedia.org/wiki/Theory_of_tides Theory of Tides */ -export default defineConstituent("EP2", [2, 0, 1, 0, 0, 0, 0], nc.uM2, nc.fM2); +export default defineConstituent("EP2", [2, -3, 2, 1, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/MA2.ts b/packages/tide-predictor/src/constituents/MA2.ts index 1bed203..27e964c 100644 --- a/packages/tide-predictor/src/constituents/MA2.ts +++ b/packages/tide-predictor/src/constituents/MA2.ts @@ -3,7 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Lunar variational semi-diurnal constituent (μ2, mu2). - * Doodson Number: 237.555 + * Doodson Number: 545.555 * Derived from Moon's orbital parameter variations; speed 27.968°/h with period ~12.87 hours. * Uses M2 nodal factors with complex variable modulation. * @@ -12,4 +12,4 @@ import nc from "../node-corrections/index.js"; * * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank */ -export default defineConstituent("MA2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); +export default defineConstituent("MA2", [2, 0, -1, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/MB2.ts b/packages/tide-predictor/src/constituents/MB2.ts index 01c885f..8b4bd11 100644 --- a/packages/tide-predictor/src/constituents/MB2.ts +++ b/packages/tide-predictor/src/constituents/MB2.ts @@ -3,13 +3,18 @@ import nc from "../node-corrections/index.js"; /** * Lunar elliptic constituent from parameter variations. - * Doodson Number: ~237 (lunar parameter variant) + * Doodson Number: ~565.555 * Speed ~27.9°/h with period ~12.9 hours. * Uses M2 nodal factors (fM2/uM2). * - * Warning: Not consistently defined across all sources; may be regional or application-specific. - * Definition and amplitude vary significantly between NOAA, IHO, and Schureman references. + * From https://iho.int/mtg_docs/com_wg/IHOTC/IHOTC_Misc/TWCWG_Constituent_list.pdf: + * + * > MB2 was originally called Ma2 but this became ambiguous when spoken, or typed on + * > computers without lower case, and so it was initially changed to MA2*. However, this + * > in turn was thought to be clumsy and hence MB2 was finally adopted. Although + * > theoretically they should have the same values of u and f as M2, they are so small + * > that they are commonly treated as having values of u = 0 and f = 1. * * @see Schureman, P. (1958). Manual of Harmonic Analysis and Prediction of Tides */ -export default defineConstituent("MB2", [2, -2, 2, 0, 0, 0, 0], nc.uM2, nc.fM2); +export default defineConstituent("MB2", [2, 0, 1, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/SGM.ts b/packages/tide-predictor/src/constituents/SGM.ts index 28a69d5..3c0c3b3 100644 --- a/packages/tide-predictor/src/constituents/SGM.ts +++ b/packages/tide-predictor/src/constituents/SGM.ts @@ -3,12 +3,12 @@ import nc from "../node-corrections/index.js"; /** * Lunar diurnal variational constituent (σ1, sigma1). - * Doodson Number: 127.555 + * Doodson Number: 275.554 * Derived from Moon's declination variations; speed 12.73°/h with period ~28.3 hours. - * Uses K1 nodal factors (fK1/uK1) for amplitude and phase modulation. + * Uses O1 nodal factors (fO1/uO1) for amplitude and phase modulation. * * Note: Often has small amplitude; closely related to K1 and O1 variations. * * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank */ -export default defineConstituent("SGM", [1, -3, 2, 0, 0, 0, 0], nc.uK1, nc.fK1); +export default defineConstituent("SGM", [1, -3, 2, 0, 0, 0, -1], nc.uO1, nc.fO1); diff --git a/packages/tide-predictor/test/constituents/index.test.ts b/packages/tide-predictor/test/constituents/index.test.ts index 933febf..ec6265d 100644 --- a/packages/tide-predictor/test/constituents/index.test.ts +++ b/packages/tide-predictor/test/constituents/index.test.ts @@ -26,8 +26,6 @@ describe("Base constituent definitions", () => { }); it("has correct properties for LAMBDA2 (alias of LAM2)", () => { - // LAMBDA2: [2, 1, -2, 1, 0, 0, 2] - // Speed: 2(T+h-s) + s - 2h + p ≈ 29.455626°/h expect(constituents.LAMBDA2).toBeDefined(); expect(constituents.LAMBDA2.speed(testAstro)).toBeCloseTo(29.455626, 2); expect(constituents.LAMBDA2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); @@ -35,51 +33,41 @@ describe("Base constituent definitions", () => { }); it("has correct properties for RHO1 (alias of RHO)", () => { - // RHO1 = NU2 - K1 (compound constituent) expect(constituents.RHO1).toBeDefined(); const expectedSpeed = constituents.NU2.speed(testAstro) - constituents.K1.speed(testAstro); expect(constituents.RHO1.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); }); it("has correct properties for EP2 (lunar elliptic semi-diurnal)", () => { - // EP2: [2, 0, 1, 0, 0, 0, 0] - // Speed: 2(T+h-s) + h ≈ 29.025°/h expect(constituents.EP2).toBeDefined(); - expect(constituents.EP2.speed(testAstro)).toBeCloseTo(29.025, 2); + expect(constituents.EP2.speed(testAstro)).toBeCloseTo(27.4238338, 7); expect(constituents.EP2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); expect(constituents.EP2.f(testAstro)).toBeCloseTo(constituents.M2.f(testAstro), 3); }); it("has correct properties for MA2 (lunar variational semi-diurnal, mu2)", () => { - // MA2: [2, 0, -2, 1, 0, 0, 0] - // Speed: 2(T+h-s) - 2h + p ≈ 27.968208°/h expect(constituents.MA2).toBeDefined(); - expect(constituents.MA2.speed(testAstro)).toBeCloseTo(27.968208, 2); + expect(constituents.MA2.speed(testAstro)).toBeCloseTo(28.943036, 6); expect(constituents.MA2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); expect(constituents.MA2.f(testAstro)).toBeCloseTo(constituents.M2.f(testAstro), 3); }); it("has correct properties for MB2 (lunar elliptic parameter variation)", () => { - // MB2: [2, 0, -3, 1, 0, 1, 0] - // Speed: 2(T+h-s) - 3h + p + p' ≈ 27.968°/h expect(constituents.MB2).toBeDefined(); - expect(constituents.MB2.speed(testAstro)).toBeCloseTo(27.968, 2); + expect(constituents.MB2.speed(testAstro)).toBeCloseTo(29.025173, 6); expect(constituents.MB2.u(testAstro)).toBeCloseTo(constituents.M2.u(testAstro), 2); expect(constituents.MB2.f(testAstro)).toBeCloseTo(constituents.M2.f(testAstro), 3); }); it("has correct properties for SGM (lunar diurnal variational, sigma1)", () => { - // SGM: [1, -2, 0, 0, 0, 0, 1] - // Speed: (T+h-s) - 2s + 90 ≈ 12.927°/h expect(constituents.SGM).toBeDefined(); - expect(constituents.SGM.speed(testAstro)).toBeCloseTo(12.927, 2); - expect(constituents.SGM.u(testAstro)).toBeCloseTo(constituents.K1.u(testAstro), 2); - expect(constituents.SGM.f(testAstro)).toBeCloseTo(constituents.K1.f(testAstro), 3); + expect(constituents.SGM.speed(testAstro)).toBeCloseTo(12.9271398); + expect(constituents.SGM.u(testAstro)).toBeCloseTo(constituents.O1.u(testAstro), 2); + expect(constituents.SGM.f(testAstro)).toBeCloseTo(constituents.O1.f(testAstro), 3); }); // New shallow-water compound constituents it("has correct properties for MSQM (lunar-solar compound)", () => { - // MSQM = M2 + S2 + K1 expect(constituents.MSQM).toBeDefined(); const expectedSpeed = constituents.M2.speed(testAstro) + @@ -89,14 +77,12 @@ describe("Base constituent definitions", () => { }); it("has correct properties for MTM (lunar-solar M2-T2 interaction)", () => { - // MTM = M2 + T2 expect(constituents.MTM).toBeDefined(); const expectedSpeed = constituents.M2.speed(testAstro) + constituents.T2.speed(testAstro); expect(constituents.MTM.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); }); it("has correct properties for MKS2 (three-way M2-K1-S2 interaction)", () => { - // MKS2 = M2 + K1 - S2 expect(constituents.MKS2).toBeDefined(); const expectedSpeed = constituents.M2.speed(testAstro) + @@ -106,14 +92,12 @@ describe("Base constituent definitions", () => { }); it("has correct properties for N4 (N2 overtide)", () => { - // N4 = 2 × N2 expect(constituents.N4).toBeDefined(); const expectedSpeed = 2 * constituents.N2.speed(testAstro); expect(constituents.N4.speed(testAstro)).toBeCloseTo(expectedSpeed, 2); }); it("has correct properties for S3 (solar terdiurnal)", () => { - // S3 = 1.5 × S2 = 45.0°/h (fixed, no nodal modulation) expect(constituents.S3).toBeDefined(); expect(constituents.S3.speed(testAstro)).toBeCloseTo(45.0, 2); expect(constituents.S3.f(testAstro)).toBeCloseTo(1.0, 3); // Solar, no nodal modulation @@ -121,7 +105,6 @@ describe("Base constituent definitions", () => { }); it("has correct properties for T3 (solar elliptic terdiurnal)", () => { - // T3 = 1.5 × T2 ≈ 44.9364°/h expect(constituents.T3).toBeDefined(); expect(constituents.T3.speed(testAstro)).toBeCloseTo(44.9364, 2); expect(constituents.T3.f(testAstro)).toBeCloseTo(1.0, 3); // Solar, no nodal modulation @@ -129,7 +112,6 @@ describe("Base constituent definitions", () => { }); it("has correct properties for R3 (solar elliptic terdiurnal)", () => { - // R3 = 1.5 × R2 ≈ 45.062°/h expect(constituents.R3).toBeDefined(); expect(constituents.R3.speed(testAstro)).toBeCloseTo(45.062, 2); expect(constituents.R3.f(testAstro)).toBeCloseTo(1.0, 3); // Solar, no nodal modulation @@ -137,37 +119,30 @@ describe("Base constituent definitions", () => { }); it("has correct properties for 3L2 (triple L2)", () => { - // 3L2 = 3 × L2 expect(constituents["3L2"]).toBeDefined(); const expectedSpeed = 3 * constituents.L2.speed(testAstro); expect(constituents["3L2"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); }); it("has correct properties for 3N2 (triple N2)", () => { - // 3N2 = 3 × N2 expect(constituents["3N2"]).toBeDefined(); const expectedSpeed = 3 * constituents.N2.speed(testAstro); expect(constituents["3N2"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); }); it("has correct properties for 2MS6 (quarter-diurnal M2-S2 interaction)", () => { - // 2MS6 = 2 × M2 + S2 expect(constituents["2MS6"]).toBeDefined(); - const expectedSpeed = 2 * constituents.M2.speed(testAstro) + constituents.S2.speed(testAstro); - expect(constituents["2MS6"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + expect(constituents["2MS6"].speed(testAstro)).toBeCloseTo(87.9682085, 7); }); it("has correct properties for 2MK5 (quinte-diurnal M2-K1 interaction)", () => { - // 2MK5 = 2 × M2 + K1 expect(constituents["2MK5"]).toBeDefined(); const expectedSpeed = 2 * constituents.M2.speed(testAstro) + constituents.K1.speed(testAstro); expect(constituents["2MK5"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); }); it("has correct properties for 2MO5 (quinte-diurnal M2-O1 interaction)", () => { - // 2MO5 = 2 × M2 + O1 expect(constituents["2MO5"]).toBeDefined(); - const expectedSpeed = 2 * constituents.M2.speed(testAstro) + constituents.O1.speed(testAstro); - expect(constituents["2MO5"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); + expect(constituents["2MO5"].speed(testAstro)).toBeCloseTo(71.911244, 6); }); }); From e78410c6a122ef4d30d56978dab3d90be82cab09 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Fri, 9 Jan 2026 09:07:45 -0500 Subject: [PATCH 5/6] Remove comments that will be outdated as implementation improves --- packages/tide-predictor/src/constituents/2MK3.ts | 7 +------ packages/tide-predictor/src/constituents/2MK5.ts | 6 +----- packages/tide-predictor/src/constituents/2MO5.ts | 6 +----- packages/tide-predictor/src/constituents/2MS6.ts | 10 +--------- packages/tide-predictor/src/constituents/2N2.ts | 6 ------ packages/tide-predictor/src/constituents/2Q1.ts | 7 +------ packages/tide-predictor/src/constituents/2SM2.ts | 4 ---- packages/tide-predictor/src/constituents/3L2.ts | 3 --- packages/tide-predictor/src/constituents/3N2.ts | 3 --- packages/tide-predictor/src/constituents/EP2.ts | 5 ----- packages/tide-predictor/src/constituents/J1.ts | 5 ----- packages/tide-predictor/src/constituents/K1.ts | 6 ------ packages/tide-predictor/src/constituents/K2.ts | 5 ----- packages/tide-predictor/src/constituents/L2.ts | 5 ----- packages/tide-predictor/src/constituents/LAMBDA2.ts | 5 ----- packages/tide-predictor/src/constituents/M1.ts | 5 ----- packages/tide-predictor/src/constituents/M2.ts | 6 ------ packages/tide-predictor/src/constituents/M3.ts | 5 ----- packages/tide-predictor/src/constituents/M4.ts | 7 +------ packages/tide-predictor/src/constituents/M6.ts | 7 +------ packages/tide-predictor/src/constituents/M8.ts | 7 +------ packages/tide-predictor/src/constituents/MA2.ts | 6 +----- packages/tide-predictor/src/constituents/MB2.ts | 3 --- packages/tide-predictor/src/constituents/MF.ts | 5 ----- packages/tide-predictor/src/constituents/MK3.ts | 4 ---- packages/tide-predictor/src/constituents/MKS2.ts | 2 -- packages/tide-predictor/src/constituents/MM.ts | 5 ----- packages/tide-predictor/src/constituents/MN4.ts | 4 ---- packages/tide-predictor/src/constituents/MS4.ts | 4 ---- packages/tide-predictor/src/constituents/MSF.ts | 7 +------ packages/tide-predictor/src/constituents/MSQM.ts | 2 -- packages/tide-predictor/src/constituents/MTM.ts | 2 -- packages/tide-predictor/src/constituents/MU2.ts | 4 ---- packages/tide-predictor/src/constituents/N2.ts | 6 ------ packages/tide-predictor/src/constituents/N4.ts | 6 ------ packages/tide-predictor/src/constituents/NU2.ts | 5 ----- packages/tide-predictor/src/constituents/O1.ts | 6 ------ packages/tide-predictor/src/constituents/OO1.ts | 5 ----- packages/tide-predictor/src/constituents/P1.ts | 5 ----- packages/tide-predictor/src/constituents/Q1.ts | 5 ----- packages/tide-predictor/src/constituents/R2.ts | 5 ----- packages/tide-predictor/src/constituents/R3.ts | 4 ---- packages/tide-predictor/src/constituents/RHO1.ts | 4 ---- packages/tide-predictor/src/constituents/S1.ts | 5 ----- packages/tide-predictor/src/constituents/S2.ts | 5 ----- packages/tide-predictor/src/constituents/S3.ts | 3 --- packages/tide-predictor/src/constituents/S4.ts | 4 ---- packages/tide-predictor/src/constituents/S6.ts | 4 ---- packages/tide-predictor/src/constituents/SA.ts | 5 ----- packages/tide-predictor/src/constituents/SGM.ts | 6 +----- packages/tide-predictor/src/constituents/SSA.ts | 5 ----- packages/tide-predictor/src/constituents/T2.ts | 5 ----- packages/tide-predictor/src/constituents/T3.ts | 4 ---- packages/tide-predictor/src/constituents/Z0.ts | 4 ---- .../tide-predictor/test/constituents/index.test.ts | 4 ++-- 55 files changed, 13 insertions(+), 260 deletions(-) diff --git a/packages/tide-predictor/src/constituents/2MK3.ts b/packages/tide-predictor/src/constituents/2MK3.ts index 7cf243e..4574eb4 100644 --- a/packages/tide-predictor/src/constituents/2MK3.ts +++ b/packages/tide-predictor/src/constituents/2MK3.ts @@ -3,14 +3,9 @@ import M2 from "./M2.js"; import O1 from "./O1.js"; /** - * Shallow-water terdiurnal (2MK3). - * Compound constituent: M2 + O1 - * Speed ~42.93°/h with period ~8.39 hours (terdiurnal). + * Shallow-water terdiurnal (2MK3 = M2 + O1). * Lunar-lunar interaction from M2 semi-diurnal and O1 diurnal components. - * Nodal factors combine fM2 with fO1. * Generated in shallow-water environments; typical amplitude <1 cm. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("2MK3", [ { constituent: M2, factor: 1 }, diff --git a/packages/tide-predictor/src/constituents/2MK5.ts b/packages/tide-predictor/src/constituents/2MK5.ts index bc89090..de91e9a 100644 --- a/packages/tide-predictor/src/constituents/2MK5.ts +++ b/packages/tide-predictor/src/constituents/2MK5.ts @@ -3,11 +3,7 @@ import M2 from "./M2.js"; import K1 from "./K1.js"; /** - * Shallow-water quinte-diurnal from M2-K1 interaction. - * Doodson Number: ~465.555 (estimated; compounded frequency) - * Components: 2×M2 (lunar semi-diurnal × 2) + K1 (lunisolar diurnal). - * Speed 44.025°/h with period ~8.18 hours. - * Nodal factors combine (fM2)² with fK1. + * Shallow-water fifth-diurnal from M2-K1 interaction. * * Note: Found in coastal tide predictions, especially in enclosed bays and harbors. * Amplitude typically 0.1-0.5 cm depending on location and water depth. diff --git a/packages/tide-predictor/src/constituents/2MO5.ts b/packages/tide-predictor/src/constituents/2MO5.ts index aac11fb..dfcfa07 100644 --- a/packages/tide-predictor/src/constituents/2MO5.ts +++ b/packages/tide-predictor/src/constituents/2MO5.ts @@ -3,11 +3,7 @@ import M2 from "./M2.js"; import O1 from "./O1.js"; /** - * Shallow-water quinte-diurnal from M2-O1 interaction. - * Doodson Number: ~445.555 (estimated; compounded frequency) - * Components: 2×M2 (lunar semi-diurnal × 2) + O1 (lunar diurnal). - * Speed 43.47°/h with period ~8.28 hours. - * Nodal factors combine (fM2)² with fO1. + * Shallow-water fifth-diurnal from M2-O1 interaction. * * Note: Primarily shallow-water coastal phenomenon, not present in deep ocean. * Amplitude typically <0.5 cm except in extreme shallow-water or enclosed basins. diff --git a/packages/tide-predictor/src/constituents/2MS6.ts b/packages/tide-predictor/src/constituents/2MS6.ts index 7479ea4..f9f2c8f 100644 --- a/packages/tide-predictor/src/constituents/2MS6.ts +++ b/packages/tide-predictor/src/constituents/2MS6.ts @@ -3,18 +3,10 @@ import M2 from "./M2.js"; import S2 from "./S2.js"; /** - * Quarter-diurnal shallow-water interaction: 2×M2 + S2. - * Doodson Number: 473.555 - * Speed 58.984°/h with period ~6.10 hours. - * Nodal factor: f(M2)²(S2) / u(M2)²(S2) = combined M2² and S2 factors. + * Sixth-diurnal shallow-water interaction: 2×M2 + S2. * - * Note: Sometimes denoted as MS4 in alternative notation systems. * Generated only in shallow water; typical amplitude 0.01-0.2 meters depending on depth. * Included in IHO shallow-water constituent tables and NOAA analysis (order #37). - * - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS - * @see https://en.wikipedia.org/wiki/Theory_of_tides */ export default defineCompoundConstituent("2MS6", [ { constituent: M2, factor: 2 }, diff --git a/packages/tide-predictor/src/constituents/2N2.ts b/packages/tide-predictor/src/constituents/2N2.ts index 91d215f..6ef0bae 100644 --- a/packages/tide-predictor/src/constituents/2N2.ts +++ b/packages/tide-predictor/src/constituents/2N2.ts @@ -3,13 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Lunar semi-diurnal (2N2). - * Doodson Number: 2.-2.0.2.0.0.0 - * Speed 27.895°/h with period ~12.91 hours (lunar semi-diurnal). * Second-order lunar semi-diurnal from Moon's orbital ellipticity. - * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. - * Nodal factor ranges: f from ~0.4 to ~1.6; u from 0° to ±180°. * Amplitude typically 5-10% of M2; significant in semi-diurnal analysis. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("2N2", [2, -2, 0, 2, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/2Q1.ts b/packages/tide-predictor/src/constituents/2Q1.ts index 23658b3..8cb9585 100644 --- a/packages/tide-predictor/src/constituents/2Q1.ts +++ b/packages/tide-predictor/src/constituents/2Q1.ts @@ -3,15 +3,10 @@ import N2 from "./N2.js"; import J1 from "./J1.js"; /** - * Shallow-water diurnal (2Q1). - * Compound constituent: N2-J1 - * Speed ~12.854°/h with period ~27.93 hours (diurnal). + * Shallow-water diurnal (2Q1 = N2-J1). * Derived from interaction of semi-diurnal N2 and diurnal J1 constituents. - * Nodal factor combines effects from both parent constituents: fN2/fJ1 with phase uN2-uJ1. * Amplitude typically very small; rarely significant. * Found only in shallow-water regions with strong tidal distortion. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("2Q1", [ { constituent: N2, factor: 1 }, diff --git a/packages/tide-predictor/src/constituents/2SM2.ts b/packages/tide-predictor/src/constituents/2SM2.ts index 0a9aa01..093d660 100644 --- a/packages/tide-predictor/src/constituents/2SM2.ts +++ b/packages/tide-predictor/src/constituents/2SM2.ts @@ -5,12 +5,8 @@ import M2 from "./M2.js"; /** * Shallow-water semi-diurnal (2SM2). * Compound constituent: 2×S2 - M2 - * Speed ~31.02°/h with period ~11.61 hours. * Solar-lunar interaction constituent generated in shallow-water environments. - * Nodal factors combine (fS2)² with inverse M2 effects. * Amplitude typically <2% of M2; complementary to MU2. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("2SM2", [ { constituent: S2, factor: 2 }, diff --git a/packages/tide-predictor/src/constituents/3L2.ts b/packages/tide-predictor/src/constituents/3L2.ts index 5dc56f3..63fc67a 100644 --- a/packages/tide-predictor/src/constituents/3L2.ts +++ b/packages/tide-predictor/src/constituents/3L2.ts @@ -3,9 +3,6 @@ import L2 from "./L2.js"; /** * Triple lunar elliptic; 3 times L2 interaction. - * Doodson Number: ~265 (estimated; not standard Doodson notation) - * Speed ~88.5°/h (≈ 3 × 29.5°/h) with period ~4.14 hours. - * Nodal factor: (fL2)³ / (uL2)³ = cubic L2 nodal modulation (very small). * * Warning: Not in standard IHO constituent bank. Mainly historical/theoretical interest. * Very small amplitude (<0.1 cm); found only in extreme shallow water or enclosed basins. diff --git a/packages/tide-predictor/src/constituents/3N2.ts b/packages/tide-predictor/src/constituents/3N2.ts index 1f32c20..be14788 100644 --- a/packages/tide-predictor/src/constituents/3N2.ts +++ b/packages/tide-predictor/src/constituents/3N2.ts @@ -3,9 +3,6 @@ import N2 from "./N2.js"; /** * Triple N2 shallow-water harmonic (3 × N2). - * Doodson Number: ~336 (estimated; not standard Doodson notation) - * Speed 85.32°/h (≈ 3 × 28.44°/h) with period ~4.23 hours. - * Nodal factor: (fN2)³ / (uN2)³ = cubic N2 nodal modulation. * * Note: Shallow-water constituent with definition based on compound frequency estimates. * Typical amplitude <0.5 cm; often <0.1 cm except in extreme shallow-water or enclosed basins. diff --git a/packages/tide-predictor/src/constituents/EP2.ts b/packages/tide-predictor/src/constituents/EP2.ts index a1363b4..882722d 100644 --- a/packages/tide-predictor/src/constituents/EP2.ts +++ b/packages/tide-predictor/src/constituents/EP2.ts @@ -3,10 +3,5 @@ import nc from "../node-corrections/index.js"; /** * Lunar elliptic semi-diurnal constituent (ε2). - * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. - * - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS constituent tables - * @see https://en.wikipedia.org/wiki/Theory_of_tides Theory of Tides */ export default defineConstituent("EP2", [2, -3, 2, 1, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/J1.ts b/packages/tide-predictor/src/constituents/J1.ts index 07daf58..5b869c8 100644 --- a/packages/tide-predictor/src/constituents/J1.ts +++ b/packages/tide-predictor/src/constituents/J1.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar diurnal (J1). - * Doodson Number: 1.2.0.-1.0.0.-1 - * Speed 15.585°/h with period ~23.10 hours (lunar diurnal). * Shallow-water lunar diurnal constituent; generally much smaller than O1 and K1. - * Uses J1-specific nodal factors (fJ1/uJ1). * Typically important only in shallow-water systems and enclosed basins. * Amplitude usually <5% of O1; rarely significant in routine predictions. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("J1", [1, 2, 0, -1, 0, 0, -1], nc.uJ1, nc.fJ1); diff --git a/packages/tide-predictor/src/constituents/K1.ts b/packages/tide-predictor/src/constituents/K1.ts index ad57370..b0eadbe 100644 --- a/packages/tide-predictor/src/constituents/K1.ts +++ b/packages/tide-predictor/src/constituents/K1.ts @@ -3,13 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Lunisolar diurnal (K1). - * Doodson Number: 1.1.0.0.0.0.-1 - * Speed 15.041°/h with period ~23.93 hours (lunisolar diurnal). * Combined lunar and solar diurnal constituent; strongest diurnal tide in many regions. - * Uses fK1/uK1 nodal factors related to lunar ascending node (18.613-year cycle). * Often comparable in amplitude to O1; amplitude ratio K1/O1 varies with latitude. - * Nodal factor ranges: f from ~0.4 to ~1.6; u varies with lunar node phase. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("K1", [1, 1, 0, 0, 0, 0, -1], nc.uK1, nc.fK1); diff --git a/packages/tide-predictor/src/constituents/K2.ts b/packages/tide-predictor/src/constituents/K2.ts index edc7fda..42f9b02 100644 --- a/packages/tide-predictor/src/constituents/K2.ts +++ b/packages/tide-predictor/src/constituents/K2.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunisolar semi-diurnal (K2). - * Doodson Number: 2.2.0.0.0.0.0 - * Speed 30.082°/h with period ~11.97 hours (lunisolar semi-diurnal). * Combined lunar and solar semi-diurnal constituent from declination effects. - * Uses K2-specific nodal factors (fK2/uK2). * Amplitude typically 10-30% of S2; second-largest solar-related semi-diurnal component. * Important in semi-diurnal tidal analysis, especially at mid-latitudes. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("K2", [2, 2, 0, 0, 0, 0, 0], nc.uK2, nc.fK2); diff --git a/packages/tide-predictor/src/constituents/L2.ts b/packages/tide-predictor/src/constituents/L2.ts index 0bd4340..aee2887 100644 --- a/packages/tide-predictor/src/constituents/L2.ts +++ b/packages/tide-predictor/src/constituents/L2.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar elliptic semi-diurnal (L2). - * Doodson Number: 2.1.0.-1.0.0.2 - * Speed 29.528°/h with period ~12.19 hours (lunar elliptic semi-diurnal). * Secondary lunar elliptic semi-diurnal from Moon's orbital variations and perigee effects. - * Uses L2-specific nodal factors (fL2/uL2). * Amplitude typically 1-3% of M2; often grouped with other lunar elliptic constituents. * Important in detailed harmonic analyses of semi-diurnal tides. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("L2", [2, 1, 0, -1, 0, 0, 2], nc.uL2, nc.fL2); diff --git a/packages/tide-predictor/src/constituents/LAMBDA2.ts b/packages/tide-predictor/src/constituents/LAMBDA2.ts index d3c43e9..a5e578d 100644 --- a/packages/tide-predictor/src/constituents/LAMBDA2.ts +++ b/packages/tide-predictor/src/constituents/LAMBDA2.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar semi-diurnal (λ2, lambda2). - * Doodson Number: 2.1.-2.1.0.0.2 - * Speed 29.455°/h with period ~12.22 hours (lunar semi-diurnal). * Lunar semi-diurnal constituent from Moon's perigee effects. - * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. * Amplitude typically <5% of M2; important in detailed constituent analysis. * IHO standard designation (previously abbreviated as LAM2). - * - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank */ export default defineConstituent("LAMBDA2", [2, 1, -2, 1, 0, 0, 2], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/M1.ts b/packages/tide-predictor/src/constituents/M1.ts index 9be0b1c..63a4eb3 100644 --- a/packages/tide-predictor/src/constituents/M1.ts +++ b/packages/tide-predictor/src/constituents/M1.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar diurnal elliptic (M1). - * Doodson Number: 1.0.0.0.0.0.1 - * Speed 14.496°/h with period ~24.00 hours (lunar diurnal elliptic). * Secondary lunar diurnal constituent from Moon's elliptical orbit. - * Uses M1-specific nodal factors (fM1/uM1). * Typically very small amplitude; usually <1% of O1. * Rarely significant except in detailed harmonic analyses. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("M1", [1, 0, 0, 0, 0, 0, 1], nc.uM1, nc.fM1); diff --git a/packages/tide-predictor/src/constituents/M2.ts b/packages/tide-predictor/src/constituents/M2.ts index 239e663..1a58344 100644 --- a/packages/tide-predictor/src/constituents/M2.ts +++ b/packages/tide-predictor/src/constituents/M2.ts @@ -3,14 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar semi-diurnal (M2). - * Doodson Number: 2.0.0.0.0.0.0 - * Speed 28.984°/h with period exactly 12.4206 hours (mean lunar semi-diurnal). * Primary principal lunar constituent; largest semi-diurnal tidal component globally. - * Uses M2 nodal factors (fM2/uM2) with 18.613-year lunar ascending node cycle. - * Nodal factor ranges: f from ~0.4 to ~1.6; u from 0° to ±180°. * Amplitude varies 10-20% over lunar node cycle; typically 0.2-0.5m in coastal areas. * Base constituent for many compound shallow-water constituents. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("M2", [2, 0, 0, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/M3.ts b/packages/tide-predictor/src/constituents/M3.ts index ff03305..cfbb410 100644 --- a/packages/tide-predictor/src/constituents/M3.ts +++ b/packages/tide-predictor/src/constituents/M3.ts @@ -3,14 +3,9 @@ import nc from "../node-corrections/index.js"; /** * Lunar terdiurnal (M3). - * Doodson Number: 3.0.0.0.0.0.0 - * Speed 43.476°/h with period ~8.28 hours (lunar terdiurnal). * Third-diurnal lunar constituent from Moon's orbital motion. - * Uses M3-specific nodal factors (uModd/fModd with factor 3). * Typically found in shallow water and resonant systems. * Amplitude usually <2% of M2; important in some shallow-water analyses. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ // Third diurnal export default defineConstituent( diff --git a/packages/tide-predictor/src/constituents/M4.ts b/packages/tide-predictor/src/constituents/M4.ts index 1f3ac4e..ec3be41 100644 --- a/packages/tide-predictor/src/constituents/M4.ts +++ b/packages/tide-predictor/src/constituents/M4.ts @@ -2,14 +2,9 @@ import { defineCompoundConstituent } from "./index.js"; import M2 from "./M2.js"; /** - * Shallow-water quarter-diurnal (M4). - * Compound constituent: 2×M2 - * Speed ~57.97°/h with period ~6.21 hours (quarter-diurnal). + * Shallow-water quarter-diurnal (M4 = 2×M2). * First overtide of M2; generated in shallow-water environments. - * Nodal factor: (fM2)² with phase 2×uM2. * Amplitude typically 2-10% of M2; largest of the quarter-diurnal constituents. * Important indicator of shallow-water tidal distortion. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("M4", [{ constituent: M2, factor: 2 }]); diff --git a/packages/tide-predictor/src/constituents/M6.ts b/packages/tide-predictor/src/constituents/M6.ts index 9e17d6a..0d65921 100644 --- a/packages/tide-predictor/src/constituents/M6.ts +++ b/packages/tide-predictor/src/constituents/M6.ts @@ -2,14 +2,9 @@ import { defineCompoundConstituent } from "./index.js"; import M2 from "./M2.js"; /** - * Shallow-water sixth-diurnal (M6). - * Compound constituent: 3×M2 - * Speed ~86.95°/h with period ~4.14 hours (sixth-diurnal). + * Shallow-water sixth-diurnal (M6 = 3×M2). * Second overtide of M2; generated in shallow-water environments. - * Nodal factor: (fM2)³ with phase 3×uM2. * Amplitude typically 0.5-3% of M2; important in extreme shallow water. * Indicator of significant tidal distortion and non-linear effects. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("M6", [{ constituent: M2, factor: 3 }]); diff --git a/packages/tide-predictor/src/constituents/M8.ts b/packages/tide-predictor/src/constituents/M8.ts index 7002d03..4bc92df 100644 --- a/packages/tide-predictor/src/constituents/M8.ts +++ b/packages/tide-predictor/src/constituents/M8.ts @@ -2,14 +2,9 @@ import { defineCompoundConstituent } from "./index.js"; import M2 from "./M2.js"; /** - * Shallow-water eighth-diurnal (M8). - * Compound constituent: 4×M2 - * Speed ~115.94°/h with period ~3.11 hours (eighth-diurnal). + * Shallow-water eighth-diurnal (M8 = 4×M2). * Third overtide of M2; generated in extreme shallow-water environments. - * Nodal factor: (fM2)⁴ with phase 4×uM2. * Amplitude typically <0.5% of M2; very rarely significant. * Found only in highly distorted tidal regimes (extreme shallow water, enclosed basins). - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("M8", [{ constituent: M2, factor: 4 }]); diff --git a/packages/tide-predictor/src/constituents/MA2.ts b/packages/tide-predictor/src/constituents/MA2.ts index 27e964c..25d3934 100644 --- a/packages/tide-predictor/src/constituents/MA2.ts +++ b/packages/tide-predictor/src/constituents/MA2.ts @@ -3,13 +3,9 @@ import nc from "../node-corrections/index.js"; /** * Lunar variational semi-diurnal constituent (μ2, mu2). - * Doodson Number: 545.555 - * Derived from Moon's orbital parameter variations; speed 27.968°/h with period ~12.87 hours. - * Uses M2 nodal factors with complex variable modulation. + * Derived from Moon's orbital parameter variations. * * Note: Often included with M2 family in modern analysis. Minor constituent with * location-dependent amplitude. - * - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank */ export default defineConstituent("MA2", [2, 0, -1, 0, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/MB2.ts b/packages/tide-predictor/src/constituents/MB2.ts index 8b4bd11..9dd35be 100644 --- a/packages/tide-predictor/src/constituents/MB2.ts +++ b/packages/tide-predictor/src/constituents/MB2.ts @@ -3,9 +3,6 @@ import nc from "../node-corrections/index.js"; /** * Lunar elliptic constituent from parameter variations. - * Doodson Number: ~565.555 - * Speed ~27.9°/h with period ~12.9 hours. - * Uses M2 nodal factors (fM2/uM2). * * From https://iho.int/mtg_docs/com_wg/IHOTC/IHOTC_Misc/TWCWG_Constituent_list.pdf: * diff --git a/packages/tide-predictor/src/constituents/MF.ts b/packages/tide-predictor/src/constituents/MF.ts index 7b86ba9..f23c44a 100644 --- a/packages/tide-predictor/src/constituents/MF.ts +++ b/packages/tide-predictor/src/constituents/MF.ts @@ -3,12 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Lunar fortnightly (MF). - * Doodson Number: 020 - * Speed 1.098°/h (one cycle per lunar fortnight = 13.66 days). * Long-period constituent from lunar inequality interactions. - * Uses fMf/uMf nodal factors related to lunar node position (18.613-year cycle). * Significant in long-term water level records and coastal resonances. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("MF", [0, 2, 0, 0, 0, 0, 0], nc.uMf, nc.fMf); diff --git a/packages/tide-predictor/src/constituents/MK3.ts b/packages/tide-predictor/src/constituents/MK3.ts index a88aa6c..061e3ce 100644 --- a/packages/tide-predictor/src/constituents/MK3.ts +++ b/packages/tide-predictor/src/constituents/MK3.ts @@ -5,13 +5,9 @@ import K1 from "./K1.js"; /** * Shallow-water terdiurnal (MK3). * Compound constituent: M2 + K1 - * Speed ~44.03°/h with period ~8.18 hours (terdiurnal). * Lunisolar interaction from M2 semi-diurnal and K1 diurnal components. - * Nodal factors combine fM2 with fK1. * Generated in shallow-water environments; typical amplitude 0.5-2 cm. * Often paired with 2MK3 in terdiurnal tide analysis. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("MK3", [ { constituent: M2, factor: 1 }, diff --git a/packages/tide-predictor/src/constituents/MKS2.ts b/packages/tide-predictor/src/constituents/MKS2.ts index 8b8107b..31ff02a 100644 --- a/packages/tide-predictor/src/constituents/MKS2.ts +++ b/packages/tide-predictor/src/constituents/MKS2.ts @@ -5,8 +5,6 @@ import S2 from "./S2.js"; /** * Three-way shallow-water interaction of M2, K1, and S2. - * Speed ~29.5°/h with period ~12.0-12.1 hours. - * Uses combined M2 and K1 nodal factors (fM2/uM2 and fK1/uK1). * * Warning: Not in standard IHO constituent bank. Shallow-water specific constituent * with definition varying by application and water depth. Use with caution and document diff --git a/packages/tide-predictor/src/constituents/MM.ts b/packages/tide-predictor/src/constituents/MM.ts index 19b52f0..b74a980 100644 --- a/packages/tide-predictor/src/constituents/MM.ts +++ b/packages/tide-predictor/src/constituents/MM.ts @@ -3,12 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Lunar monthly (MM). - * Doodson Number: 010.-10 - * Speed 0.544°/h (one cycle per lunar month = 27.55 days). * Long-period constituent from lunar declination variations. - * Uses fMm/uMm nodal factors related to lunar orbital variations. * Important for long-term water level studies. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("MM", [0, 1, 0, -1, 0, 0, 0], nc.uZero, nc.fMm); diff --git a/packages/tide-predictor/src/constituents/MN4.ts b/packages/tide-predictor/src/constituents/MN4.ts index ae1321d..5798ca0 100644 --- a/packages/tide-predictor/src/constituents/MN4.ts +++ b/packages/tide-predictor/src/constituents/MN4.ts @@ -5,13 +5,9 @@ import N2 from "./N2.js"; /** * Shallow-water quarter-diurnal (MN4). * Compound constituent: M2 + N2 - * Speed ~57.42°/h with period ~6.27 hours (quarter-diurnal). * Lunar-lunar elliptic interaction from M2 and N2 semi-diurnal components. - * Nodal factors combine fM2 with fN2 (both use M2 nodal corrections). * Generated in shallow-water environments; typical amplitude 1-5 cm. * Often significant in shallow seas and estuaries. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("MN4", [ { constituent: M2, factor: 1 }, diff --git a/packages/tide-predictor/src/constituents/MS4.ts b/packages/tide-predictor/src/constituents/MS4.ts index ff5f983..c432a2e 100644 --- a/packages/tide-predictor/src/constituents/MS4.ts +++ b/packages/tide-predictor/src/constituents/MS4.ts @@ -5,13 +5,9 @@ import S2 from "./S2.js"; /** * Shallow-water quarter-diurnal (MS4). * Compound constituent: M2 + S2 - * Speed ~58.98°/h with period ~6.10 hours (quarter-diurnal). * Lunar-solar interaction from M2 and S2 semi-diurnal components. - * Nodal factors combine fM2 with fS2 (S2 has no nodal correction). * Generated in shallow-water environments; typical amplitude 1-5 cm. * Often second-largest quarter-diurnal component after M4. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("MS4", [ { constituent: M2, factor: 1 }, diff --git a/packages/tide-predictor/src/constituents/MSF.ts b/packages/tide-predictor/src/constituents/MSF.ts index 29bc5ba..391265a 100644 --- a/packages/tide-predictor/src/constituents/MSF.ts +++ b/packages/tide-predictor/src/constituents/MSF.ts @@ -3,16 +3,11 @@ import S2 from "./S2.js"; import M2 from "./M2.js"; /** - * Lunisolar synodic fortnightly (MSF). - * Compound constituent: S2-M2 - * Speed ~1.016°/h with period ~354.37 hours (~14.76 days, fortnightly). + * Lunisolar synodic fortnightly (MSF = S2-M2). * Long-period constituent representing beat frequency between solar S2 and lunar M2. * Manifests as fortnightly modulation of tidal range (spring-neap cycle). - * Nodal factor: fM2/fS2 with phase uS2-uM2. * Amplitude typically 5-15% of M2; represents the primary spring-neap variation. * Important for tidal range predictions and coastal flooding assessments. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("MSF", [ { constituent: S2, factor: 1 }, diff --git a/packages/tide-predictor/src/constituents/MSQM.ts b/packages/tide-predictor/src/constituents/MSQM.ts index b490784..ba069cc 100644 --- a/packages/tide-predictor/src/constituents/MSQM.ts +++ b/packages/tide-predictor/src/constituents/MSQM.ts @@ -5,8 +5,6 @@ import K1 from "./K1.js"; /** * Lunar-solar interaction compound constituent. - * Doodson Number: 254.658 (or ~255 variant) - * Speed ~28.5°/h; Uses fK1/uK1 nodal corrections. * * Warning: Non-standard constituent not in IHO or modern NOAA standard tables. * Definition varies significantly across sources. Rarely used in modern tide prediction. diff --git a/packages/tide-predictor/src/constituents/MTM.ts b/packages/tide-predictor/src/constituents/MTM.ts index 5063129..e15fe04 100644 --- a/packages/tide-predictor/src/constituents/MTM.ts +++ b/packages/tide-predictor/src/constituents/MTM.ts @@ -4,8 +4,6 @@ import T2 from "./T2.js"; /** * Lunar-solar shallow-water interaction (M2 modulated by lunar orbit). - * Speed ~29.0°/h with period ~12.0-12.2 hours. - * Uses M2 nodal factors (fM2/uM2). * * Warning: Not in modern IHO standard constituents; mostly historical interest. * Often replaced by specific ν2, λ2, or other lunar elliptic terms in modern analysis. diff --git a/packages/tide-predictor/src/constituents/MU2.ts b/packages/tide-predictor/src/constituents/MU2.ts index c988147..bae3653 100644 --- a/packages/tide-predictor/src/constituents/MU2.ts +++ b/packages/tide-predictor/src/constituents/MU2.ts @@ -5,12 +5,8 @@ import S2 from "./S2.js"; /** * Shallow-water semi-diurnal (MU2 or μ2). * Compound constituent: 2×M2 - S2 - * Speed ~27.97°/h with period ~12.87 hours. * Lunar variational constituent generated in shallow-water environments. - * Nodal factors combine (fM2)² with inverse S2 effects. * Amplitude typically <2% of M2; found in coastal shallow-water predictions. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("MU2", [ { constituent: M2, factor: 2 }, diff --git a/packages/tide-predictor/src/constituents/N2.ts b/packages/tide-predictor/src/constituents/N2.ts index 1137ad8..55ecd03 100644 --- a/packages/tide-predictor/src/constituents/N2.ts +++ b/packages/tide-predictor/src/constituents/N2.ts @@ -3,13 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Lunar elliptic semi-diurnal (N2). - * Doodson Number: 2.-1.0.1.0.0.0 - * Speed 28.439°/h with period ~12.66 hours (lunar elliptic semi-diurnal). * Primary lunar elliptic semi-diurnal constituent from Moon's orbital variations. - * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. - * Nodal factor ranges: f from ~0.4 to ~1.6; u varies over 18.613-year cycle. * Amplitude typically 5-15% of M2; third-largest semi-diurnal constituent. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("N2", [2, -1, 0, 1, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/N4.ts b/packages/tide-predictor/src/constituents/N4.ts index b4a28bb..254e66f 100644 --- a/packages/tide-predictor/src/constituents/N4.ts +++ b/packages/tide-predictor/src/constituents/N4.ts @@ -3,14 +3,8 @@ import N2 from "./N2.js"; /** * Second overtide of N2; shallow-water quarter-diurnal harmonic. - * Doodson Number: 445.655 - * Speed 56.88°/h (= 2 × N2 speed) with period ~6.27 hours. - * Nodal factor: (fN2)² / (uN2)² = squared N2 nodal modulation. * Amplitude ranges 0.25 to 2.25 times mean due to 18.613-year lunar node cycle. * * Note: Shallow-water constituent, typically found in tide predictions for coastal areas. - * - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank - * @see https://en.wikipedia.org/wiki/Theory_of_tides */ export default defineCompoundConstituent("N4", [{ constituent: N2, factor: 2 }]); diff --git a/packages/tide-predictor/src/constituents/NU2.ts b/packages/tide-predictor/src/constituents/NU2.ts index bb4ce79..736bf38 100644 --- a/packages/tide-predictor/src/constituents/NU2.ts +++ b/packages/tide-predictor/src/constituents/NU2.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar elliptic semi-diurnal (NU2). - * Doodson Number: 2.-1.2.-1.0.0.0 - * Speed 28.512°/h with period ~12.63 hours (lunar elliptic semi-diurnal). * Secondary lunar elliptic semi-diurnal from Moon's orbital variations. - * Uses M2 nodal factors (fM2/uM2) for amplitude and phase modulation. * Amplitude typically 2-5% of M2; smaller than N2. * Important in detailed semi-diurnal constituent analysis. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("NU2", [2, -1, 2, -1, 0, 0, 0], nc.uM2, nc.fM2); diff --git a/packages/tide-predictor/src/constituents/O1.ts b/packages/tide-predictor/src/constituents/O1.ts index 5f4aef7..99ce8a8 100644 --- a/packages/tide-predictor/src/constituents/O1.ts +++ b/packages/tide-predictor/src/constituents/O1.ts @@ -3,13 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Lunar diurnal (O1). - * Doodson Number: 1.-1.0.0.0.0.1 - * Speed 13.943°/h with period ~24.84 hours (lunar diurnal). * Primary lunar diurnal constituent; one-per-lunar-day oscillation. - * Uses fO1/uO1 nodal factors related to lunar ascending node (18.613-year cycle). - * Nodal factor ranges: f from ~0.4 to ~1.6; u from 0° to ±180°. * Amplitude varies 10-20% due to lunar node effects. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("O1", [1, -1, 0, 0, 0, 0, 1], nc.uO1, nc.fO1); diff --git a/packages/tide-predictor/src/constituents/OO1.ts b/packages/tide-predictor/src/constituents/OO1.ts index b680f5e..934a750 100644 --- a/packages/tide-predictor/src/constituents/OO1.ts +++ b/packages/tide-predictor/src/constituents/OO1.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar diurnal (OO1). - * Doodson Number: 1.3.0.0.0.0.-1 - * Speed 16.139°/h with period ~22.31 hours (lunar diurnal). * Second-order lunar diurnal constituent from Moon's orbital eccentricity. - * Uses OO1-specific nodal factors (fOO1/uOO1). * Typically very small amplitude; <2% of O1 in most locations. * Important for detailed harmonic analysis in some regions. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("OO1", [1, 3, 0, 0, 0, 0, -1], nc.uOO1, nc.fOO1); diff --git a/packages/tide-predictor/src/constituents/P1.ts b/packages/tide-predictor/src/constituents/P1.ts index 7f316e7..2827d93 100644 --- a/packages/tide-predictor/src/constituents/P1.ts +++ b/packages/tide-predictor/src/constituents/P1.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Solar diurnal (P1). - * Doodson Number: 1.1.-2.0.0.0.1 - * Speed 14.959°/h with period ~24.07 hours (solar diurnal). * Principal solar diurnal constituent; one-per-solar-day oscillation. - * No nodal corrections (solar constituent; invariant in time). * Amplitude typically 1/3 of K1; varies with latitude. * Forms key component of diurnal tidal analysis alongside K1 and O1. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("P1", [1, 1, -2, 0, 0, 0, 1], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/Q1.ts b/packages/tide-predictor/src/constituents/Q1.ts index b7862fa..db1f601 100644 --- a/packages/tide-predictor/src/constituents/Q1.ts +++ b/packages/tide-predictor/src/constituents/Q1.ts @@ -3,12 +3,7 @@ import nc from "../node-corrections/index.js"; /** * Elliptic lunar diurnal (Q1). - * Doodson Number: 1.-2.0.1.0.0.1 - * Speed 13.398°/h with period ~26.87 hours (lunar elliptic diurnal). * One solar day and one lunar day modulation interaction. - * Uses O1 nodal factors (fO1/uO1) related to lunar node position. * Amplitude typically 2-5% of O1; important in diurnal constituent analysis. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("Q1", [1, -2, 0, 1, 0, 0, 1], nc.uO1, nc.fO1); diff --git a/packages/tide-predictor/src/constituents/R2.ts b/packages/tide-predictor/src/constituents/R2.ts index 530b979..387818f 100644 --- a/packages/tide-predictor/src/constituents/R2.ts +++ b/packages/tide-predictor/src/constituents/R2.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Solar elliptic semi-diurnal (R2). - * Doodson Number: 2.2.-1.0.0.-1.2 - * Speed 30.041°/h with period ~11.98 hours (solar elliptic semi-diurnal). * Smaller solar elliptic semi-diurnal constituent from solar declination effects. - * No nodal corrections (solar constituent). * Amplitude typically <2% of S2; smallest of the solar semi-diurnal group. * Rarely significant except in very detailed analyses. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("R2", [2, 2, -1, 0, 0, -1, 2], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/R3.ts b/packages/tide-predictor/src/constituents/R3.ts index fcc8571..9b15e62 100644 --- a/packages/tide-predictor/src/constituents/R3.ts +++ b/packages/tide-predictor/src/constituents/R3.ts @@ -3,10 +3,6 @@ import R2 from "./R2.js"; /** * Solar elliptic terdiurnal; 1.5 times R2 (smaller solar elliptic semi-diurnal). - * Doodson Number: ~437.555 (estimated from solar elliptic family) - * Speed ~45.04°/h with period ~8.0 hours. - * No nodal modulation (solar constituent). - * R2 reference: Doodson 274.555 (smaller solar elliptic with speed ~30.0°/h). * * Note: Generated only in shallow water; very small amplitude (<0.05 cm typical). * Usually negligible except in extreme shallow-water environments. diff --git a/packages/tide-predictor/src/constituents/RHO1.ts b/packages/tide-predictor/src/constituents/RHO1.ts index 89e112f..1c4d5e2 100644 --- a/packages/tide-predictor/src/constituents/RHO1.ts +++ b/packages/tide-predictor/src/constituents/RHO1.ts @@ -5,13 +5,9 @@ import K1 from "./K1.js"; /** * Shallow-water diurnal (RHO1, ρ1). * Compound constituent: NU2-K1 (ν2-K1) - * Speed ~13.471°/h with period ~26.72 hours (diurnal). * Derived from interaction of semi-diurnal NU2 and diurnal K1 constituents. - * Nodal factor combines effects from both parent constituents: fNU2/fK1 with phase uNU2-uK1. * Amplitude typically very small; rarely significant. * Found only in shallow-water regions with strong tidal distortion. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("RHO1", [ { constituent: NU2, factor: 1 }, diff --git a/packages/tide-predictor/src/constituents/S1.ts b/packages/tide-predictor/src/constituents/S1.ts index dbe3b7f..f1f2533 100644 --- a/packages/tide-predictor/src/constituents/S1.ts +++ b/packages/tide-predictor/src/constituents/S1.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Solar diurnal (S1). - * Doodson Number: 1.1.-1.0.0.0.0 - * Speed 15.000°/h with period 24.00 hours exactly (solar diurnal). * Secondary solar diurnal constituent related to solar declination inequality. - * No nodal corrections (solar constituent). * Usually very small amplitude; typically dominated by K1 and P1 in diurnal analysis. * Rarely included in routine harmonic analyses. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("S1", [1, 1, -1, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/S2.ts b/packages/tide-predictor/src/constituents/S2.ts index 9437b53..1054180 100644 --- a/packages/tide-predictor/src/constituents/S2.ts +++ b/packages/tide-predictor/src/constituents/S2.ts @@ -3,14 +3,9 @@ import nc from "../node-corrections/index.js"; /** * Solar semi-diurnal (S2). - * Doodson Number: 2.2.-2.0.0.0.0 - * Speed 30.000°/h with period exactly 12.00 hours (principal solar semi-diurnal). * Principal solar semi-diurnal constituent; largest solar tide component. - * No nodal corrections (solar constituent; invariant in time). * Amplitude typically 20-50% of M2; varies with geographic location and latitude. * Ratio M2/S2 determines tidal form factor (diurnal vs semi-diurnal regimes). * Base constituent for many compound shallow-water constituents. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("S2", [2, 2, -2, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/S3.ts b/packages/tide-predictor/src/constituents/S3.ts index 976226d..9a590b4 100644 --- a/packages/tide-predictor/src/constituents/S3.ts +++ b/packages/tide-predictor/src/constituents/S3.ts @@ -3,9 +3,6 @@ import S2 from "./S2.js"; /** * Solar terdiurnal overtide; shallow-water only. - * Doodson Number: 333.555 - * Speed fixed at 45.0°/h (= 1.5 × S2) with period ~8.0 hours. - * No nodal modulation (solar constituent - invariant). * * Note: Generated only in shallow water; not found in deep ocean. * Typical amplitude <1 cm except in extreme shallow-water environments. diff --git a/packages/tide-predictor/src/constituents/S4.ts b/packages/tide-predictor/src/constituents/S4.ts index 9c32c2f..88c2afd 100644 --- a/packages/tide-predictor/src/constituents/S4.ts +++ b/packages/tide-predictor/src/constituents/S4.ts @@ -4,12 +4,8 @@ import S2 from "./S2.js"; /** * Shallow-water quarter-diurnal (S4). * Compound constituent: 2×S2 - * Speed 60.00°/h with period exactly 6.00 hours (quarter-diurnal). * First overtide of S2; generated in shallow-water environments. - * No nodal corrections (solar constituent). * Amplitude typically 1-3% of S2; smallest of the common quarter-diurnal constituents. * Purely solar, so has fixed amplitude and phase at any location. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("S4", [{ constituent: S2, factor: 2 }]); diff --git a/packages/tide-predictor/src/constituents/S6.ts b/packages/tide-predictor/src/constituents/S6.ts index ec7be6b..2f70dff 100644 --- a/packages/tide-predictor/src/constituents/S6.ts +++ b/packages/tide-predictor/src/constituents/S6.ts @@ -4,12 +4,8 @@ import S2 from "./S2.js"; /** * Shallow-water sixth-diurnal (S6). * Compound constituent: 3×S2 - * Speed 90.00°/h with period exactly 4.00 hours (sixth-diurnal). * Second overtide of S2; generated in shallow-water environments. - * No nodal corrections (solar constituent). * Amplitude typically 0.5-1% of S2; smallest of the common overtides. * Rarely significant except in extreme shallow water or resonant systems. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineCompoundConstituent("S6", [{ constituent: S2, factor: 3 }]); diff --git a/packages/tide-predictor/src/constituents/SA.ts b/packages/tide-predictor/src/constituents/SA.ts index de8b2d3..e0cb5cc 100644 --- a/packages/tide-predictor/src/constituents/SA.ts +++ b/packages/tide-predictor/src/constituents/SA.ts @@ -3,11 +3,6 @@ import nc from "../node-corrections/index.js"; /** * Solar annual (Sa). - * Doodson Number: 001.000 - * Speed 0.041°/h (one cycle per solar year = 365.24 days). * Long-term constituent driven by solar declination variations over the year. - * No nodal corrections (solar constituent). - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("Sa", [0, 0, 1, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/SGM.ts b/packages/tide-predictor/src/constituents/SGM.ts index 3c0c3b3..2dbec73 100644 --- a/packages/tide-predictor/src/constituents/SGM.ts +++ b/packages/tide-predictor/src/constituents/SGM.ts @@ -3,12 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Lunar diurnal variational constituent (σ1, sigma1). - * Doodson Number: 275.554 - * Derived from Moon's declination variations; speed 12.73°/h with period ~28.3 hours. - * Uses O1 nodal factors (fO1/uO1) for amplitude and phase modulation. + * Derived from Moon's declination variations. * * Note: Often has small amplitude; closely related to K1 and O1 variations. - * - * @see https://iho.int/en/standards-and-specifications/standards/s-14 IHO Tidal Constituent Bank */ export default defineConstituent("SGM", [1, -3, 2, 0, 0, 0, -1], nc.uO1, nc.fO1); diff --git a/packages/tide-predictor/src/constituents/SSA.ts b/packages/tide-predictor/src/constituents/SSA.ts index 70f126f..5b5b60b 100644 --- a/packages/tide-predictor/src/constituents/SSA.ts +++ b/packages/tide-predictor/src/constituents/SSA.ts @@ -3,11 +3,6 @@ import nc from "../node-corrections/index.js"; /** * Solar semi-annual (Ssa). - * Doodson Number: 002.000 - * Speed 0.0823°/h (one cycle per solar half-year = 182.6 days). * Semi-annual constituent from solar declination with twice-yearly periodicity. - * No nodal corrections (solar constituent). - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("Ssa", [0, 0, 2, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/T2.ts b/packages/tide-predictor/src/constituents/T2.ts index 209fcf2..07c9416 100644 --- a/packages/tide-predictor/src/constituents/T2.ts +++ b/packages/tide-predictor/src/constituents/T2.ts @@ -3,13 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Solar elliptic semi-diurnal (T2). - * Doodson Number: 2.2.-3.0.0.1.0 - * Speed 29.959°/h with period ~12.01 hours (solar elliptic semi-diurnal). * Larger solar elliptic semi-diurnal constituent from solar declination effects. - * No nodal corrections (solar constituent). * Amplitude typically <5% of S2; increases at higher latitudes. * Forms part of solar semi-diurnal analysis alongside S2 and R2. - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("T2", [2, 2, -3, 0, 0, 1, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/src/constituents/T3.ts b/packages/tide-predictor/src/constituents/T3.ts index 83e198a..7063174 100644 --- a/packages/tide-predictor/src/constituents/T3.ts +++ b/packages/tide-predictor/src/constituents/T3.ts @@ -3,10 +3,6 @@ import T2 from "./T2.js"; /** * Solar elliptic terdiurnal; 1.5 times T2 (larger solar elliptic semi-diurnal). - * Doodson Number: ~438.555 (estimated from solar elliptic family) - * Speed ~44.94°/h with period ~8.0 hours. - * Minimal nodal modulation (solar constituent). - * T2 reference: Doodson 272.555 (larger solar elliptic with speed ~60.0°/h). * * Note: Generated only in shallow water; minimal amplitude (<0.1 cm typical). * Rarely significant except in extreme shallow-water or enclosed basins. diff --git a/packages/tide-predictor/src/constituents/Z0.ts b/packages/tide-predictor/src/constituents/Z0.ts index 64d5229..24e7f78 100644 --- a/packages/tide-predictor/src/constituents/Z0.ts +++ b/packages/tide-predictor/src/constituents/Z0.ts @@ -3,12 +3,8 @@ import nc from "../node-corrections/index.js"; /** * Mean sea level (Z0). - * Doodson Number: 000.000 * Not a tidal constituent in the strict sense, but represents the mean sea level offset * or the "zero" reference level used in tidal predictions. * No astronomical forcing; typically determined from harmonic analysis of observed data. - * No nodal corrections applied (constant offset). - * - * @see https://tidesandcurrents.noaa.gov/ NOAA CO-OPS */ export default defineConstituent("Z0", [0, 0, 0, 0, 0, 0, 0], nc.uZero, nc.fUnity); diff --git a/packages/tide-predictor/test/constituents/index.test.ts b/packages/tide-predictor/test/constituents/index.test.ts index ec6265d..47e4780 100644 --- a/packages/tide-predictor/test/constituents/index.test.ts +++ b/packages/tide-predictor/test/constituents/index.test.ts @@ -135,13 +135,13 @@ describe("Base constituent definitions", () => { expect(constituents["2MS6"].speed(testAstro)).toBeCloseTo(87.9682085, 7); }); - it("has correct properties for 2MK5 (quinte-diurnal M2-K1 interaction)", () => { + it("has correct properties for 2MK5 (fifth-diurnal M2-K1 interaction)", () => { expect(constituents["2MK5"]).toBeDefined(); const expectedSpeed = 2 * constituents.M2.speed(testAstro) + constituents.K1.speed(testAstro); expect(constituents["2MK5"].speed(testAstro)).toBeCloseTo(expectedSpeed, 2); }); - it("has correct properties for 2MO5 (quinte-diurnal M2-O1 interaction)", () => { + it("has correct properties for 2MO5 (fifth-diurnal M2-O1 interaction)", () => { expect(constituents["2MO5"]).toBeDefined(); expect(constituents["2MO5"].speed(testAstro)).toBeCloseTo(71.911244, 6); }); From 26d2c5cbea64b18e9f29090341e62d80ab165a7c Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Fri, 9 Jan 2026 09:34:37 -0500 Subject: [PATCH 6/6] Fix circular references --- .../tide-predictor/src/constituents/2MK3.ts | 2 +- .../tide-predictor/src/constituents/2MK5.ts | 2 +- .../tide-predictor/src/constituents/2MO5.ts | 2 +- .../tide-predictor/src/constituents/2MS6.ts | 2 +- .../tide-predictor/src/constituents/2N2.ts | 2 +- .../tide-predictor/src/constituents/2Q1.ts | 2 +- .../tide-predictor/src/constituents/2SM2.ts | 2 +- .../tide-predictor/src/constituents/3L2.ts | 2 +- .../tide-predictor/src/constituents/3N2.ts | 2 +- .../tide-predictor/src/constituents/EP2.ts | 2 +- .../tide-predictor/src/constituents/J1.ts | 2 +- .../tide-predictor/src/constituents/K1.ts | 2 +- .../tide-predictor/src/constituents/K2.ts | 2 +- .../tide-predictor/src/constituents/L2.ts | 2 +- .../src/constituents/LAMBDA2.ts | 2 +- .../tide-predictor/src/constituents/M1.ts | 2 +- .../tide-predictor/src/constituents/M2.ts | 2 +- .../tide-predictor/src/constituents/M3.ts | 2 +- .../tide-predictor/src/constituents/M4.ts | 2 +- .../tide-predictor/src/constituents/M6.ts | 2 +- .../tide-predictor/src/constituents/M8.ts | 2 +- .../tide-predictor/src/constituents/MA2.ts | 2 +- .../tide-predictor/src/constituents/MB2.ts | 2 +- .../tide-predictor/src/constituents/MF.ts | 2 +- .../tide-predictor/src/constituents/MK3.ts | 2 +- .../tide-predictor/src/constituents/MKS2.ts | 2 +- .../tide-predictor/src/constituents/MM.ts | 2 +- .../tide-predictor/src/constituents/MN4.ts | 2 +- .../tide-predictor/src/constituents/MS4.ts | 2 +- .../tide-predictor/src/constituents/MSF.ts | 2 +- .../tide-predictor/src/constituents/MSQM.ts | 2 +- .../tide-predictor/src/constituents/MTM.ts | 2 +- .../tide-predictor/src/constituents/MU2.ts | 2 +- .../tide-predictor/src/constituents/N2.ts | 2 +- .../tide-predictor/src/constituents/N4.ts | 2 +- .../tide-predictor/src/constituents/NU2.ts | 2 +- .../tide-predictor/src/constituents/O1.ts | 2 +- .../tide-predictor/src/constituents/OO1.ts | 2 +- .../tide-predictor/src/constituents/P1.ts | 2 +- .../tide-predictor/src/constituents/Q1.ts | 2 +- .../tide-predictor/src/constituents/R2.ts | 2 +- .../tide-predictor/src/constituents/R3.ts | 2 +- .../tide-predictor/src/constituents/RHO1.ts | 2 +- .../tide-predictor/src/constituents/S1.ts | 2 +- .../tide-predictor/src/constituents/S2.ts | 2 +- .../tide-predictor/src/constituents/S3.ts | 2 +- .../tide-predictor/src/constituents/S4.ts | 2 +- .../tide-predictor/src/constituents/S6.ts | 2 +- .../tide-predictor/src/constituents/SA.ts | 2 +- .../tide-predictor/src/constituents/SGM.ts | 2 +- .../tide-predictor/src/constituents/SSA.ts | 2 +- .../tide-predictor/src/constituents/T2.ts | 2 +- .../tide-predictor/src/constituents/T3.ts | 2 +- .../tide-predictor/src/constituents/Z0.ts | 2 +- .../src/constituents/definition.ts | 127 +++++++++++++++++ .../tide-predictor/src/constituents/index.ts | 130 +----------------- .../constituents/compound-constituent.test.ts | 3 +- .../test/constituents/constituent.test.ts | 2 +- 58 files changed, 188 insertions(+), 182 deletions(-) create mode 100644 packages/tide-predictor/src/constituents/definition.ts diff --git a/packages/tide-predictor/src/constituents/2MK3.ts b/packages/tide-predictor/src/constituents/2MK3.ts index 4574eb4..198d5ad 100644 --- a/packages/tide-predictor/src/constituents/2MK3.ts +++ b/packages/tide-predictor/src/constituents/2MK3.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import O1 from "./O1.js"; diff --git a/packages/tide-predictor/src/constituents/2MK5.ts b/packages/tide-predictor/src/constituents/2MK5.ts index de91e9a..73da81d 100644 --- a/packages/tide-predictor/src/constituents/2MK5.ts +++ b/packages/tide-predictor/src/constituents/2MK5.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import K1 from "./K1.js"; diff --git a/packages/tide-predictor/src/constituents/2MO5.ts b/packages/tide-predictor/src/constituents/2MO5.ts index dfcfa07..ff02516 100644 --- a/packages/tide-predictor/src/constituents/2MO5.ts +++ b/packages/tide-predictor/src/constituents/2MO5.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import O1 from "./O1.js"; diff --git a/packages/tide-predictor/src/constituents/2MS6.ts b/packages/tide-predictor/src/constituents/2MS6.ts index f9f2c8f..0e2fd94 100644 --- a/packages/tide-predictor/src/constituents/2MS6.ts +++ b/packages/tide-predictor/src/constituents/2MS6.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import S2 from "./S2.js"; diff --git a/packages/tide-predictor/src/constituents/2N2.ts b/packages/tide-predictor/src/constituents/2N2.ts index 6ef0bae..904e41c 100644 --- a/packages/tide-predictor/src/constituents/2N2.ts +++ b/packages/tide-predictor/src/constituents/2N2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/2Q1.ts b/packages/tide-predictor/src/constituents/2Q1.ts index 8cb9585..1771c74 100644 --- a/packages/tide-predictor/src/constituents/2Q1.ts +++ b/packages/tide-predictor/src/constituents/2Q1.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import N2 from "./N2.js"; import J1 from "./J1.js"; diff --git a/packages/tide-predictor/src/constituents/2SM2.ts b/packages/tide-predictor/src/constituents/2SM2.ts index 093d660..1d71762 100644 --- a/packages/tide-predictor/src/constituents/2SM2.ts +++ b/packages/tide-predictor/src/constituents/2SM2.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import S2 from "./S2.js"; import M2 from "./M2.js"; diff --git a/packages/tide-predictor/src/constituents/3L2.ts b/packages/tide-predictor/src/constituents/3L2.ts index 63fc67a..e8fc821 100644 --- a/packages/tide-predictor/src/constituents/3L2.ts +++ b/packages/tide-predictor/src/constituents/3L2.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import L2 from "./L2.js"; /** diff --git a/packages/tide-predictor/src/constituents/3N2.ts b/packages/tide-predictor/src/constituents/3N2.ts index be14788..8bc1d8c 100644 --- a/packages/tide-predictor/src/constituents/3N2.ts +++ b/packages/tide-predictor/src/constituents/3N2.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import N2 from "./N2.js"; /** diff --git a/packages/tide-predictor/src/constituents/EP2.ts b/packages/tide-predictor/src/constituents/EP2.ts index 882722d..66247ee 100644 --- a/packages/tide-predictor/src/constituents/EP2.ts +++ b/packages/tide-predictor/src/constituents/EP2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/J1.ts b/packages/tide-predictor/src/constituents/J1.ts index 5b869c8..aa2914a 100644 --- a/packages/tide-predictor/src/constituents/J1.ts +++ b/packages/tide-predictor/src/constituents/J1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/K1.ts b/packages/tide-predictor/src/constituents/K1.ts index b0eadbe..739a5e7 100644 --- a/packages/tide-predictor/src/constituents/K1.ts +++ b/packages/tide-predictor/src/constituents/K1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/K2.ts b/packages/tide-predictor/src/constituents/K2.ts index 42f9b02..2538318 100644 --- a/packages/tide-predictor/src/constituents/K2.ts +++ b/packages/tide-predictor/src/constituents/K2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/L2.ts b/packages/tide-predictor/src/constituents/L2.ts index aee2887..19085d2 100644 --- a/packages/tide-predictor/src/constituents/L2.ts +++ b/packages/tide-predictor/src/constituents/L2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/LAMBDA2.ts b/packages/tide-predictor/src/constituents/LAMBDA2.ts index a5e578d..c93e98d 100644 --- a/packages/tide-predictor/src/constituents/LAMBDA2.ts +++ b/packages/tide-predictor/src/constituents/LAMBDA2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/M1.ts b/packages/tide-predictor/src/constituents/M1.ts index 63a4eb3..d99d0b0 100644 --- a/packages/tide-predictor/src/constituents/M1.ts +++ b/packages/tide-predictor/src/constituents/M1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/M2.ts b/packages/tide-predictor/src/constituents/M2.ts index 1a58344..e94c5c2 100644 --- a/packages/tide-predictor/src/constituents/M2.ts +++ b/packages/tide-predictor/src/constituents/M2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/M3.ts b/packages/tide-predictor/src/constituents/M3.ts index cfbb410..2387c01 100644 --- a/packages/tide-predictor/src/constituents/M3.ts +++ b/packages/tide-predictor/src/constituents/M3.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/M4.ts b/packages/tide-predictor/src/constituents/M4.ts index ec3be41..7a31785 100644 --- a/packages/tide-predictor/src/constituents/M4.ts +++ b/packages/tide-predictor/src/constituents/M4.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; /** diff --git a/packages/tide-predictor/src/constituents/M6.ts b/packages/tide-predictor/src/constituents/M6.ts index 0d65921..7a59e75 100644 --- a/packages/tide-predictor/src/constituents/M6.ts +++ b/packages/tide-predictor/src/constituents/M6.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; /** diff --git a/packages/tide-predictor/src/constituents/M8.ts b/packages/tide-predictor/src/constituents/M8.ts index 4bc92df..ee95e88 100644 --- a/packages/tide-predictor/src/constituents/M8.ts +++ b/packages/tide-predictor/src/constituents/M8.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; /** diff --git a/packages/tide-predictor/src/constituents/MA2.ts b/packages/tide-predictor/src/constituents/MA2.ts index 25d3934..ee0fb2d 100644 --- a/packages/tide-predictor/src/constituents/MA2.ts +++ b/packages/tide-predictor/src/constituents/MA2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/MB2.ts b/packages/tide-predictor/src/constituents/MB2.ts index 9dd35be..cf51164 100644 --- a/packages/tide-predictor/src/constituents/MB2.ts +++ b/packages/tide-predictor/src/constituents/MB2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/MF.ts b/packages/tide-predictor/src/constituents/MF.ts index f23c44a..57dcc0c 100644 --- a/packages/tide-predictor/src/constituents/MF.ts +++ b/packages/tide-predictor/src/constituents/MF.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/MK3.ts b/packages/tide-predictor/src/constituents/MK3.ts index 061e3ce..e00f705 100644 --- a/packages/tide-predictor/src/constituents/MK3.ts +++ b/packages/tide-predictor/src/constituents/MK3.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import K1 from "./K1.js"; diff --git a/packages/tide-predictor/src/constituents/MKS2.ts b/packages/tide-predictor/src/constituents/MKS2.ts index 31ff02a..95a599e 100644 --- a/packages/tide-predictor/src/constituents/MKS2.ts +++ b/packages/tide-predictor/src/constituents/MKS2.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import K1 from "./K1.js"; import S2 from "./S2.js"; diff --git a/packages/tide-predictor/src/constituents/MM.ts b/packages/tide-predictor/src/constituents/MM.ts index b74a980..cca61b7 100644 --- a/packages/tide-predictor/src/constituents/MM.ts +++ b/packages/tide-predictor/src/constituents/MM.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/MN4.ts b/packages/tide-predictor/src/constituents/MN4.ts index 5798ca0..7b3f3cd 100644 --- a/packages/tide-predictor/src/constituents/MN4.ts +++ b/packages/tide-predictor/src/constituents/MN4.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import N2 from "./N2.js"; diff --git a/packages/tide-predictor/src/constituents/MS4.ts b/packages/tide-predictor/src/constituents/MS4.ts index c432a2e..4e929bb 100644 --- a/packages/tide-predictor/src/constituents/MS4.ts +++ b/packages/tide-predictor/src/constituents/MS4.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import S2 from "./S2.js"; diff --git a/packages/tide-predictor/src/constituents/MSF.ts b/packages/tide-predictor/src/constituents/MSF.ts index 391265a..7acae0b 100644 --- a/packages/tide-predictor/src/constituents/MSF.ts +++ b/packages/tide-predictor/src/constituents/MSF.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import S2 from "./S2.js"; import M2 from "./M2.js"; diff --git a/packages/tide-predictor/src/constituents/MSQM.ts b/packages/tide-predictor/src/constituents/MSQM.ts index ba069cc..4b0ca2c 100644 --- a/packages/tide-predictor/src/constituents/MSQM.ts +++ b/packages/tide-predictor/src/constituents/MSQM.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import S2 from "./S2.js"; import K1 from "./K1.js"; diff --git a/packages/tide-predictor/src/constituents/MTM.ts b/packages/tide-predictor/src/constituents/MTM.ts index e15fe04..8bff616 100644 --- a/packages/tide-predictor/src/constituents/MTM.ts +++ b/packages/tide-predictor/src/constituents/MTM.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import T2 from "./T2.js"; diff --git a/packages/tide-predictor/src/constituents/MU2.ts b/packages/tide-predictor/src/constituents/MU2.ts index bae3653..d1ea392 100644 --- a/packages/tide-predictor/src/constituents/MU2.ts +++ b/packages/tide-predictor/src/constituents/MU2.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import M2 from "./M2.js"; import S2 from "./S2.js"; diff --git a/packages/tide-predictor/src/constituents/N2.ts b/packages/tide-predictor/src/constituents/N2.ts index 55ecd03..f075ac8 100644 --- a/packages/tide-predictor/src/constituents/N2.ts +++ b/packages/tide-predictor/src/constituents/N2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/N4.ts b/packages/tide-predictor/src/constituents/N4.ts index 254e66f..b225fff 100644 --- a/packages/tide-predictor/src/constituents/N4.ts +++ b/packages/tide-predictor/src/constituents/N4.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import N2 from "./N2.js"; /** diff --git a/packages/tide-predictor/src/constituents/NU2.ts b/packages/tide-predictor/src/constituents/NU2.ts index 736bf38..23d9257 100644 --- a/packages/tide-predictor/src/constituents/NU2.ts +++ b/packages/tide-predictor/src/constituents/NU2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/O1.ts b/packages/tide-predictor/src/constituents/O1.ts index 99ce8a8..34c30b0 100644 --- a/packages/tide-predictor/src/constituents/O1.ts +++ b/packages/tide-predictor/src/constituents/O1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/OO1.ts b/packages/tide-predictor/src/constituents/OO1.ts index 934a750..e202678 100644 --- a/packages/tide-predictor/src/constituents/OO1.ts +++ b/packages/tide-predictor/src/constituents/OO1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/P1.ts b/packages/tide-predictor/src/constituents/P1.ts index 2827d93..8ea7cd3 100644 --- a/packages/tide-predictor/src/constituents/P1.ts +++ b/packages/tide-predictor/src/constituents/P1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/Q1.ts b/packages/tide-predictor/src/constituents/Q1.ts index db1f601..47bce7e 100644 --- a/packages/tide-predictor/src/constituents/Q1.ts +++ b/packages/tide-predictor/src/constituents/Q1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/R2.ts b/packages/tide-predictor/src/constituents/R2.ts index 387818f..a0115d7 100644 --- a/packages/tide-predictor/src/constituents/R2.ts +++ b/packages/tide-predictor/src/constituents/R2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/R3.ts b/packages/tide-predictor/src/constituents/R3.ts index 9b15e62..f52db88 100644 --- a/packages/tide-predictor/src/constituents/R3.ts +++ b/packages/tide-predictor/src/constituents/R3.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import R2 from "./R2.js"; /** diff --git a/packages/tide-predictor/src/constituents/RHO1.ts b/packages/tide-predictor/src/constituents/RHO1.ts index 1c4d5e2..aff5ffc 100644 --- a/packages/tide-predictor/src/constituents/RHO1.ts +++ b/packages/tide-predictor/src/constituents/RHO1.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import NU2 from "./NU2.js"; import K1 from "./K1.js"; diff --git a/packages/tide-predictor/src/constituents/S1.ts b/packages/tide-predictor/src/constituents/S1.ts index f1f2533..7ab07fa 100644 --- a/packages/tide-predictor/src/constituents/S1.ts +++ b/packages/tide-predictor/src/constituents/S1.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/S2.ts b/packages/tide-predictor/src/constituents/S2.ts index 1054180..5e71d5f 100644 --- a/packages/tide-predictor/src/constituents/S2.ts +++ b/packages/tide-predictor/src/constituents/S2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/S3.ts b/packages/tide-predictor/src/constituents/S3.ts index 9a590b4..be45c68 100644 --- a/packages/tide-predictor/src/constituents/S3.ts +++ b/packages/tide-predictor/src/constituents/S3.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import S2 from "./S2.js"; /** diff --git a/packages/tide-predictor/src/constituents/S4.ts b/packages/tide-predictor/src/constituents/S4.ts index 88c2afd..586e05b 100644 --- a/packages/tide-predictor/src/constituents/S4.ts +++ b/packages/tide-predictor/src/constituents/S4.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import S2 from "./S2.js"; /** diff --git a/packages/tide-predictor/src/constituents/S6.ts b/packages/tide-predictor/src/constituents/S6.ts index 2f70dff..e0df0d7 100644 --- a/packages/tide-predictor/src/constituents/S6.ts +++ b/packages/tide-predictor/src/constituents/S6.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import S2 from "./S2.js"; /** diff --git a/packages/tide-predictor/src/constituents/SA.ts b/packages/tide-predictor/src/constituents/SA.ts index e0cb5cc..c1a47b9 100644 --- a/packages/tide-predictor/src/constituents/SA.ts +++ b/packages/tide-predictor/src/constituents/SA.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/SGM.ts b/packages/tide-predictor/src/constituents/SGM.ts index 2dbec73..a8f9a69 100644 --- a/packages/tide-predictor/src/constituents/SGM.ts +++ b/packages/tide-predictor/src/constituents/SGM.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/SSA.ts b/packages/tide-predictor/src/constituents/SSA.ts index 5b5b60b..d02262d 100644 --- a/packages/tide-predictor/src/constituents/SSA.ts +++ b/packages/tide-predictor/src/constituents/SSA.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/T2.ts b/packages/tide-predictor/src/constituents/T2.ts index 07c9416..222a611 100644 --- a/packages/tide-predictor/src/constituents/T2.ts +++ b/packages/tide-predictor/src/constituents/T2.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/T3.ts b/packages/tide-predictor/src/constituents/T3.ts index 7063174..0a81399 100644 --- a/packages/tide-predictor/src/constituents/T3.ts +++ b/packages/tide-predictor/src/constituents/T3.ts @@ -1,4 +1,4 @@ -import { defineCompoundConstituent } from "./index.js"; +import { defineCompoundConstituent } from "./definition.js"; import T2 from "./T2.js"; /** diff --git a/packages/tide-predictor/src/constituents/Z0.ts b/packages/tide-predictor/src/constituents/Z0.ts index 24e7f78..a097ba8 100644 --- a/packages/tide-predictor/src/constituents/Z0.ts +++ b/packages/tide-predictor/src/constituents/Z0.ts @@ -1,4 +1,4 @@ -import { defineConstituent } from "./index.js"; +import { defineConstituent } from "./definition.js"; import nc from "../node-corrections/index.js"; /** diff --git a/packages/tide-predictor/src/constituents/definition.ts b/packages/tide-predictor/src/constituents/definition.ts new file mode 100644 index 0000000..4f56397 --- /dev/null +++ b/packages/tide-predictor/src/constituents/definition.ts @@ -0,0 +1,127 @@ +import type { AstroData } from "../astronomy/index.js"; +import nodeCorrections, { type NodeCorrectionFunction } from "../node-corrections/index.js"; + +export interface Constituent { + name: string; + coefficients: number[]; + value: (astro: AstroData) => number; + speed: (astro: AstroData) => number; + u: NodeCorrectionFunction; + f: NodeCorrectionFunction; +} + +export function defineConstituent( + name: string, + coefficients: number[], + u?: NodeCorrectionFunction, + f?: NodeCorrectionFunction, +): Constituent { + if (!coefficients) { + throw new Error("Coefficient must be defined for a constituent"); + } + + return Object.freeze({ + name, + coefficients, + + value: (astro: AstroData): number => { + return dotArray(coefficients, astronomicValues(astro)); + }, + + speed(astro: AstroData): number { + return dotArray(coefficients, astronomicSpeed(astro)); + }, + + u: typeof u !== "undefined" ? u : nodeCorrections.uZero, + + f: typeof f !== "undefined" ? f : nodeCorrections.fUnity, + }); +} + +export interface ConstituentMember { + constituent: Constituent; + factor: number; +} + +export function defineCompoundConstituent(name: string, members: ConstituentMember[]): Constituent { + const coefficients: number[] = []; + members.forEach(({ constituent, factor }) => { + constituent.coefficients.forEach((coefficient, index) => { + if (typeof coefficients[index] === "undefined") { + coefficients[index] = 0; + } + coefficients[index] += coefficient * factor; + }); + }); + + return Object.freeze({ + name, + coefficients, + + speed: (astro: AstroData): number => { + let speed = 0; + members.forEach(({ constituent, factor }) => { + speed += constituent.speed(astro) * factor; + }); + return speed; + }, + + value: (astro: AstroData): number => { + let value = 0; + members.forEach(({ constituent, factor }) => { + value += constituent.value(astro) * factor; + }); + return value; + }, + + u: (astro: AstroData): number => { + let u = 0; + members.forEach(({ constituent, factor }) => { + u += constituent.u(astro) * factor; + }); + return u; + }, + + f: (astro: AstroData): number => { + const f: number[] = []; + members.forEach(({ constituent, factor }) => { + f.push(Math.pow(constituent.f(astro), Math.abs(factor))); + }); + return f.reduce((previous, value) => previous * value); + }, + }); +} + +/** + * Computes the dot notation of two arrays + */ +function dotArray(a: number[], b: number[]): number { + const results: number[] = []; + a.forEach((value, index) => { + results.push(value * b[index]); + }); + return results.reduce((total, value) => total + value); +} + +export function astronimicDoodsonNumber(astro: AstroData): AstroData[keyof AstroData][] { + return [astro["T+h-s"], astro.s, astro.h, astro.p, astro.N, astro.pp, astro["90"]]; +} + +export function astronomicSpeed(astro: AstroData): number[] { + const results: number[] = []; + astronimicDoodsonNumber(astro).forEach((number) => { + results.push(number.speed); + }); + return results; +} + +export function astronomicValues(astro: AstroData): number[] { + const results: number[] = []; + astronimicDoodsonNumber(astro).forEach((number) => { + results.push(number.value); + }); + return results; +} + +// Silence TS warning for empty module +export default {}; diff --git a/packages/tide-predictor/src/constituents/index.ts b/packages/tide-predictor/src/constituents/index.ts index 7d1ab5a..7055c60 100644 --- a/packages/tide-predictor/src/constituents/index.ts +++ b/packages/tide-predictor/src/constituents/index.ts @@ -1,127 +1,4 @@ -import type { AstroData } from "../astronomy/index.js"; -import nodeCorrections, { type NodeCorrectionFunction } from "../node-corrections/index.js"; - -export interface Constituent { - name: string; - coefficients: number[]; - value: (astro: AstroData) => number; - speed: (astro: AstroData) => number; - u: NodeCorrectionFunction; - f: NodeCorrectionFunction; -} - -export function defineConstituent( - name: string, - coefficients: number[], - u?: NodeCorrectionFunction, - f?: NodeCorrectionFunction, -): Constituent { - if (!coefficients) { - throw new Error("Coefficient must be defined for a constituent"); - } - - return Object.freeze({ - name, - coefficients, - - value: (astro: AstroData): number => { - return dotArray(coefficients, astronomicValues(astro)); - }, - - speed(astro: AstroData): number { - return dotArray(coefficients, astronomicSpeed(astro)); - }, - - u: typeof u !== "undefined" ? u : nodeCorrections.uZero, - - f: typeof f !== "undefined" ? f : nodeCorrections.fUnity, - }); -} - -export interface ConstituentMember { - constituent: Constituent; - factor: number; -} - -export function defineCompoundConstituent(name: string, members: ConstituentMember[]): Constituent { - const coefficients: number[] = []; - members.forEach(({ constituent, factor }) => { - constituent.coefficients.forEach((coefficient, index) => { - if (typeof coefficients[index] === "undefined") { - coefficients[index] = 0; - } - coefficients[index] += coefficient * factor; - }); - }); - - return Object.freeze({ - name, - coefficients, - - speed: (astro: AstroData): number => { - let speed = 0; - members.forEach(({ constituent, factor }) => { - speed += constituent.speed(astro) * factor; - }); - return speed; - }, - - value: (astro: AstroData): number => { - let value = 0; - members.forEach(({ constituent, factor }) => { - value += constituent.value(astro) * factor; - }); - return value; - }, - - u: (astro: AstroData): number => { - let u = 0; - members.forEach(({ constituent, factor }) => { - u += constituent.u(astro) * factor; - }); - return u; - }, - - f: (astro: AstroData): number => { - const f: number[] = []; - members.forEach(({ constituent, factor }) => { - f.push(Math.pow(constituent.f(astro), Math.abs(factor))); - }); - return f.reduce((previous, value) => previous * value); - }, - }); -} - -/** - * Computes the dot notation of two arrays - */ -function dotArray(a: number[], b: number[]): number { - const results: number[] = []; - a.forEach((value, index) => { - results.push(value * b[index]); - }); - return results.reduce((total, value) => total + value); -} - -export function astronimicDoodsonNumber(astro: AstroData): AstroData[keyof AstroData][] { - return [astro["T+h-s"], astro.s, astro.h, astro.p, astro.N, astro.pp, astro["90"]]; -} - -export function astronomicSpeed(astro: AstroData): number[] { - const results: number[] = []; - astronimicDoodsonNumber(astro).forEach((number) => { - results.push(number.speed); - }); - return results; -} - -export function astronomicValues(astro: AstroData): number[] { - const results: number[] = []; - astronimicDoodsonNumber(astro).forEach((number) => { - results.push(number.value); - }); - return results; -} +import { type Constituent } from "./definition"; // Dynamically import all constituent files const constituentModules = import.meta.glob("./*.ts", { @@ -137,7 +14,10 @@ for (const [path, module] of Object.entries(constituentModules)) { if (path.includes("index.ts")) continue; // Extract filename without extension and .js suffix - const name = path.split("/").pop()?.replace(/\.ts$/, "") ?? ""; + const name = path.split("/").pop()?.replace(/\..*$/, "") ?? ""; + + // Skip module for definition.ts + if (name === "definition") continue; constituents[name] = module; } diff --git a/packages/tide-predictor/test/constituents/compound-constituent.test.ts b/packages/tide-predictor/test/constituents/compound-constituent.test.ts index 6c6c4f6..00fd4d4 100644 --- a/packages/tide-predictor/test/constituents/compound-constituent.test.ts +++ b/packages/tide-predictor/test/constituents/compound-constituent.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect } from "vitest"; -import { defineCompoundConstituent } from "../../src/constituents/index.js"; -import { defineConstituent } from "../../src/constituents/index.js"; +import { defineCompoundConstituent, defineConstituent } from "../../src/constituents/definition.js"; import astro from "../../src/astronomy/index.js"; const sampleTime = new Date("2019-10-04T10:15:40.010Z"); diff --git a/packages/tide-predictor/test/constituents/constituent.test.ts b/packages/tide-predictor/test/constituents/constituent.test.ts index f4ee7d5..4ac864a 100644 --- a/packages/tide-predictor/test/constituents/constituent.test.ts +++ b/packages/tide-predictor/test/constituents/constituent.test.ts @@ -4,7 +4,7 @@ import { astronomicSpeed, astronomicValues, defineConstituent, -} from "../../src/constituents/index.js"; +} from "../../src/constituents/definition.js"; import astro from "../../src/astronomy/index.js"; const sampleTime = new Date("2019-10-04T10:15:40.010Z");