@neaps/tide-predictor 0.0.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +41 -48
  2. package/dist/index.cjs +931 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +150 -0
  5. package/dist/index.d.ts +150 -0
  6. package/dist/index.js +930 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +20 -36
  9. package/.eslintrc.js +0 -22
  10. package/.github/workflows/test.yml +0 -15
  11. package/.prettierrc +0 -4
  12. package/Gruntfile.js +0 -87
  13. package/LICENSE +0 -21
  14. package/babel.config.js +0 -9
  15. package/dist/tide-predictor.js +0 -1013
  16. package/examples/browser/index.html +0 -51
  17. package/jest.config.js +0 -14
  18. package/lib/astronomy/coefficients.js +0 -31
  19. package/lib/astronomy/constants.js +0 -10
  20. package/lib/astronomy/index.js +0 -199
  21. package/lib/constituents/compound-constituent.js +0 -67
  22. package/lib/constituents/constituent.js +0 -74
  23. package/lib/constituents/index.js +0 -140
  24. package/lib/harmonics/index.js +0 -113
  25. package/lib/harmonics/prediction.js +0 -195
  26. package/lib/index.es6.js +0 -1005
  27. package/lib/index.js +0 -53
  28. package/lib/node-corrections/index.js +0 -147
  29. package/rollup.config.js +0 -21
  30. package/src/__mocks__/constituents.js +0 -335
  31. package/src/__mocks__/secondary-station.js +0 -11
  32. package/src/__tests__/index.js +0 -81
  33. package/src/__tests__/noaa.js +0 -92
  34. package/src/astronomy/__tests__/coefficients.js +0 -12
  35. package/src/astronomy/__tests__/index.js +0 -96
  36. package/src/astronomy/coefficients.js +0 -72
  37. package/src/astronomy/constants.js +0 -4
  38. package/src/astronomy/index.js +0 -201
  39. package/src/constituents/__tests__/compound-constituent.js +0 -44
  40. package/src/constituents/__tests__/constituent.js +0 -65
  41. package/src/constituents/__tests__/index.js +0 -34
  42. package/src/constituents/compound-constituent.js +0 -55
  43. package/src/constituents/constituent.js +0 -74
  44. package/src/constituents/index.js +0 -119
  45. package/src/harmonics/__mocks__/water-levels.js +0 -0
  46. package/src/harmonics/__tests__/index.js +0 -123
  47. package/src/harmonics/__tests__/prediction.js +0 -148
  48. package/src/harmonics/index.js +0 -87
  49. package/src/harmonics/prediction.js +0 -175
  50. package/src/index.js +0 -45
  51. package/src/node-corrections/__tests__/index.js +0 -114
  52. package/src/node-corrections/index.js +0 -208
@@ -1,175 +0,0 @@
1
- import astro from '../astronomy/index'
2
- import { d2r } from '../astronomy/constants'
3
-
4
- const modulus = (a, b) => {
5
- return ((a % b) + b) % b
6
- }
7
-
8
- const addExtremesOffsets = (extreme, offsets) => {
9
- if (typeof offsets === 'undefined' || !offsets) {
10
- return extreme
11
- }
12
- if (extreme.high && offsets.height_offset && offsets.height_offset.high) {
13
- extreme.level *= offsets.height_offset.high
14
- }
15
- if (extreme.low && offsets.height_offset && offsets.height_offset.low) {
16
- extreme.level *= offsets.height_offset.low
17
- }
18
- if (extreme.high && offsets.time_offset && offsets.time_offset.high) {
19
- extreme.time = new Date(
20
- extreme.time.getTime() + offsets.time_offset.high * 60 * 1000
21
- )
22
- }
23
- if (extreme.low && offsets.time_offset && offsets.time_offset.low) {
24
- extreme.time = new Date(
25
- extreme.time.getTime() + offsets.time_offset.low * 60 * 1000
26
- )
27
- }
28
- return extreme
29
- }
30
-
31
- const getExtremeLabel = (label, highLowLabels) => {
32
- if (
33
- typeof highLowLabels !== 'undefined' &&
34
- typeof highLowLabels[label] !== 'undefined'
35
- ) {
36
- return highLowLabels[label]
37
- }
38
- const labels = {
39
- high: 'High',
40
- low: 'Low',
41
- }
42
- return labels[label]
43
- }
44
-
45
- const predictionFactory = ({ timeline, constituents, start }) => {
46
- const getLevel = (hour, modelBaseSpeed, modelU, modelF, modelBaseValue) => {
47
- const amplitudes = []
48
- let result = 0
49
-
50
- constituents.forEach((constituent) => {
51
- const amplitude = constituent.amplitude
52
- const phase = constituent._phase
53
- const f = modelF[constituent.name]
54
- const speed = modelBaseSpeed[constituent.name]
55
- const u = modelU[constituent.name]
56
- const V0 = modelBaseValue[constituent.name]
57
- amplitudes.push(amplitude * f * Math.cos(speed * hour + (V0 + u) - phase))
58
- })
59
- // sum up each row
60
- amplitudes.forEach((item) => {
61
- result += item
62
- })
63
- return result
64
- }
65
-
66
- const prediction = {}
67
-
68
- prediction.getExtremesPrediction = (options) => {
69
- const { labels, offsets } = typeof options !== 'undefined' ? options : {}
70
- const results = []
71
- const { baseSpeed, u, f, baseValue } = prepare()
72
- let goingUp = false
73
- let goingDown = false
74
- let lastLevel = getLevel(0, baseSpeed, u[0], f[0], baseValue)
75
- timeline.items.forEach((time, index) => {
76
- const hour = timeline.hours[index]
77
- const level = getLevel(hour, baseSpeed, u[index], f[index], baseValue)
78
- // Compare this level to the last one, if we
79
- // are changing angle, then the last one was high or low
80
- if (level > lastLevel && goingDown) {
81
- results.push(
82
- addExtremesOffsets(
83
- {
84
- time: timeline.items[index - 1],
85
- level: lastLevel,
86
- high: false,
87
- low: true,
88
- label: getExtremeLabel('low', labels),
89
- },
90
- offsets
91
- )
92
- )
93
- }
94
- if (level < lastLevel && goingUp) {
95
- results.push(
96
- addExtremesOffsets(
97
- {
98
- time: timeline.items[index - 1],
99
- level: lastLevel,
100
- high: true,
101
- low: false,
102
- label: getExtremeLabel('high', labels),
103
- },
104
- offsets
105
- )
106
- )
107
- }
108
- if (level > lastLevel) {
109
- goingUp = true
110
- goingDown = false
111
- }
112
- if (level < lastLevel) {
113
- goingUp = false
114
- goingDown = true
115
- }
116
- lastLevel = level
117
- })
118
- return results
119
- }
120
-
121
- prediction.getTimelinePrediction = () => {
122
- const results = []
123
- const { baseSpeed, u, f, baseValue } = prepare()
124
- timeline.items.forEach((time, index) => {
125
- const hour = timeline.hours[index]
126
- const prediction = {
127
- time: time,
128
- hour: hour,
129
- level: getLevel(hour, baseSpeed, u[index], f[index], baseValue),
130
- }
131
-
132
- results.push(prediction)
133
- })
134
- return results
135
- }
136
-
137
- const prepare = () => {
138
- const baseAstro = astro(start)
139
-
140
- const baseValue = {}
141
- const baseSpeed = {}
142
- const u = []
143
- const f = []
144
- constituents.forEach((constituent) => {
145
- const value = constituent._model.value(baseAstro)
146
- const speed = constituent._model.speed(baseAstro)
147
- baseValue[constituent.name] = d2r * value
148
- baseSpeed[constituent.name] = d2r * speed
149
- })
150
- timeline.items.forEach((time) => {
151
- const uItem = {}
152
- const fItem = {}
153
- const itemAstro = astro(time)
154
- constituents.forEach((constituent) => {
155
- const constituentU = modulus(constituent._model.u(itemAstro), 360)
156
-
157
- uItem[constituent.name] = d2r * constituentU
158
- fItem[constituent.name] = modulus(constituent._model.f(itemAstro), 360)
159
- })
160
- u.push(uItem)
161
- f.push(fItem)
162
- })
163
-
164
- return {
165
- baseValue: baseValue,
166
- baseSpeed: baseSpeed,
167
- u: u,
168
- f: f,
169
- }
170
- }
171
-
172
- return Object.freeze(prediction)
173
- }
174
-
175
- export default predictionFactory
package/src/index.js DELETED
@@ -1,45 +0,0 @@
1
- import harmonics from './harmonics/index'
2
-
3
- const tidePredictionFactory = (constituents, options) => {
4
- const harmonicsOptions = {
5
- harmonicConstituents: constituents,
6
- phaseKey: 'phase_GMT',
7
- offset: false
8
- }
9
-
10
- if (typeof options !== 'undefined') {
11
- Object.keys(harmonicsOptions).forEach(key => {
12
- if (typeof options[key] !== 'undefined') {
13
- harmonicsOptions[key] = options[key]
14
- }
15
- })
16
- }
17
-
18
- const tidePrediction = {
19
- getTimelinePrediction: ({ start, end }) => {
20
- return harmonics(harmonicsOptions)
21
- .setTimeSpan(start, end)
22
- .prediction()
23
- .getTimelinePrediction()
24
- },
25
-
26
- getExtremesPrediction: ({ start, end, labels, offsets, timeFidelity }) => {
27
- return harmonics(harmonicsOptions)
28
- .setTimeSpan(start, end)
29
- .prediction({ timeFidelity: timeFidelity })
30
- .getExtremesPrediction(labels, offsets)
31
- },
32
-
33
- getWaterLevelAtTime: ({ time }) => {
34
- const endDate = new Date(time.getTime() + 10 * 60 * 1000)
35
- return harmonics(harmonicsOptions)
36
- .setTimeSpan(time, endDate)
37
- .prediction()
38
- .getTimelinePrediction()[0]
39
- }
40
- }
41
-
42
- return tidePrediction
43
- }
44
-
45
- export default tidePredictionFactory
@@ -1,114 +0,0 @@
1
- import nodeCorrections from '../index'
2
-
3
- const testItems = {
4
- i: {
5
- value: 5
6
- },
7
- I: { value: 6 },
8
- omega: { value: 3 },
9
- nu: { value: 4 },
10
- nup: { value: 4 },
11
- nupp: { value: 2 },
12
- P: { value: 14 },
13
- xi: {
14
- value: 4
15
- }
16
- }
17
-
18
- describe('Node corrections', () => {
19
- test('have correct unity', () => {
20
- expect(nodeCorrections.fUnity()).toBe(1)
21
- })
22
-
23
- test('calculates Schureman equations 73, 65 (f_Mm)', () => {
24
- expect(nodeCorrections.fMm(testItems)).toBeCloseTo(0.999051998091, 4)
25
- })
26
-
27
- test('calculates Schureman equations 74, 66 (f_Mf)', () => {
28
- expect(nodeCorrections.fMf(testItems)).toBeCloseTo(4.00426673883, 4)
29
- })
30
-
31
- test('calculates Schureman equations 75, 67 (f_O1)', () => {
32
- expect(nodeCorrections.fO1(testItems)).toBeCloseTo(2.00076050158, 4)
33
- })
34
-
35
- test('calculates Schureman equations 76, 68 (f_J1)', () => {
36
- expect(nodeCorrections.fJ1(testItems)).toBeCloseTo(2.0119685329, 4)
37
- })
38
-
39
- test('calculates Schureman equations 77, 69 (f_OO1)', () => {
40
- expect(nodeCorrections.fOO1(testItems)).toBeCloseTo(8.01402871709, 4)
41
- })
42
-
43
- test('calculates Schureman equations 78, 70 (f_M2)', () => {
44
- expect(nodeCorrections.fM2(testItems)).toBeCloseTo(0.999694287563, 4)
45
- })
46
-
47
- test('calculates Schureman equations 227, 226, 68 (f_K1)', () => {
48
- expect(nodeCorrections.fK1(testItems)).toBeCloseTo(1.23843964182, 4)
49
- })
50
-
51
- test('calculates Schureman equations 215, 213, 204 (f_L2)', () => {
52
- expect(nodeCorrections.fL2(testItems)).toBeCloseTo(0.98517860327, 4)
53
- })
54
-
55
- test('calculates Schureman equations 235, 234, 71 (f_K2)', () => {
56
- expect(nodeCorrections.fK2(testItems)).toBeCloseTo(1.09775430048, 4)
57
- })
58
-
59
- test('calculates Schureman equations 206, 207, 195 (f_M1)', () => {
60
- expect(nodeCorrections.fM1(testItems)).toBeCloseTo(3.90313810168, 4)
61
- })
62
-
63
- test('calculates e.g. Schureman equation 149 (f_Modd)', () => {
64
- expect(nodeCorrections.fModd(testItems, 3)).toBeCloseTo(0.999541466395, 4)
65
- })
66
-
67
- test('has a zero for u_zero', () => {
68
- expect(nodeCorrections.uZero()).toBe(0.0)
69
- })
70
-
71
- test('calculates u_Mf', () => {
72
- expect(nodeCorrections.uMf(testItems)).toBe(-8.0)
73
- })
74
-
75
- test('calculates u_O1', () => {
76
- expect(nodeCorrections.uO1(testItems)).toBe(4.0)
77
- })
78
-
79
- test('calculates u_J1', () => {
80
- expect(nodeCorrections.uJ1(testItems)).toBe(-4)
81
- })
82
-
83
- test('calculates u_OO1', () => {
84
- expect(nodeCorrections.uOO1(testItems)).toBe(-12.0)
85
- })
86
-
87
- test('calculates u_M2', () => {
88
- expect(nodeCorrections.uM2(testItems)).toBe(0.0)
89
- })
90
-
91
- test('calculates u_K1', () => {
92
- expect(nodeCorrections.uK1(testItems)).toBe(-4)
93
- })
94
-
95
- test('calculates u_L2', () => {
96
- expect(nodeCorrections.uL2(testItems)).toBeCloseTo(-0.449812364499, 4)
97
- })
98
-
99
- test('calculates u_K2', () => {
100
- expect(nodeCorrections.uK2(testItems)).toBe(-4.0)
101
- })
102
-
103
- test('calculates u_K2', () => {
104
- expect(nodeCorrections.uK2(testItems)).toBe(-4.0)
105
- })
106
-
107
- test('calculates u_M1', () => {
108
- expect(nodeCorrections.uM1(testItems)).toBeCloseTo(7.09154172301, 4)
109
- })
110
-
111
- test('calculates u_Modd', () => {
112
- expect(nodeCorrections.uModd(testItems, 3)).toBe(0)
113
- })
114
- })
@@ -1,208 +0,0 @@
1
- import { d2r, r2d } from '../astronomy/constants'
2
-
3
- const corrections = {
4
- fUnity() {
5
- return 1
6
- },
7
-
8
- // Schureman equations 73, 65
9
- fMm(a) {
10
- const omega = d2r * a.omega.value
11
- const i = d2r * a.i.value
12
- const I = d2r * a.I.value
13
- const mean =
14
- (2 / 3.0 - Math.pow(Math.sin(omega), 2)) *
15
- (1 - (3 / 2.0) * Math.pow(Math.sin(i), 2))
16
- return (2 / 3.0 - Math.pow(Math.sin(I), 2)) / mean
17
- },
18
-
19
- // Schureman equations 74, 66
20
- fMf(a) {
21
- const omega = d2r * a.omega.value
22
- const i = d2r * a.i.value
23
- const I = d2r * a.I.value
24
- const mean = Math.pow(Math.sin(omega), 2) * Math.pow(Math.cos(0.5 * i), 4)
25
- return Math.pow(Math.sin(I), 2) / mean
26
- },
27
-
28
- // Schureman equations 75, 67
29
- fO1(a) {
30
- const omega = d2r * a.omega.value
31
- const i = d2r * a.i.value
32
- const I = d2r * a.I.value
33
- const mean =
34
- Math.sin(omega) *
35
- Math.pow(Math.cos(0.5 * omega), 2) *
36
- Math.pow(Math.cos(0.5 * i), 4)
37
- return (Math.sin(I) * Math.pow(Math.cos(0.5 * I), 2)) / mean
38
- },
39
-
40
- // Schureman equations 76, 68
41
- fJ1(a) {
42
- const omega = d2r * a.omega.value
43
- const i = d2r * a.i.value
44
- const I = d2r * a.I.value
45
- const mean =
46
- Math.sin(2 * omega) * (1 - (3 / 2.0) * Math.pow(Math.sin(i), 2))
47
- return Math.sin(2 * I) / mean
48
- },
49
-
50
- // Schureman equations 77, 69
51
- fOO1(a) {
52
- const omega = d2r * a.omega.value
53
- const i = d2r * a.i.value
54
- const I = d2r * a.I.value
55
- const mean =
56
- Math.sin(omega) *
57
- Math.pow(Math.sin(0.5 * omega), 2) *
58
- Math.pow(Math.cos(0.5 * i), 4)
59
- return (Math.sin(I) * Math.pow(Math.sin(0.5 * I), 2)) / mean
60
- },
61
-
62
- // Schureman equations 78, 70
63
- fM2(a) {
64
- const omega = d2r * a.omega.value
65
- const i = d2r * a.i.value
66
- const I = d2r * a.I.value
67
- const mean =
68
- Math.pow(Math.cos(0.5 * omega), 4) * Math.pow(Math.cos(0.5 * i), 4)
69
- return Math.pow(Math.cos(0.5 * I), 4) / mean
70
- },
71
-
72
- // Schureman equations 227, 226, 68
73
- // Should probably eventually include the derivations of the magic numbers (0.5023 etc).
74
- fK1(a) {
75
- const omega = d2r * a.omega.value
76
- const i = d2r * a.i.value
77
- const I = d2r * a.I.value
78
- const nu = d2r * a.nu.value
79
- const sin2IcosnuMean =
80
- Math.sin(2 * omega) * (1 - (3 / 2.0) * Math.pow(Math.sin(i), 2))
81
- const mean = 0.5023 * sin2IcosnuMean + 0.1681
82
- return (
83
- Math.pow(
84
- 0.2523 * Math.pow(Math.sin(2 * I), 2) +
85
- 0.1689 * Math.sin(2 * I) * Math.cos(nu) +
86
- 0.0283,
87
- 0.5
88
- ) / mean
89
- )
90
- },
91
-
92
- // Schureman equations 215, 213, 204
93
- // It can be (and has been) confirmed that the exponent for R_a reads 1/2 via Schureman Table 7
94
- fL2(a) {
95
- const P = d2r * a.P.value
96
- const I = d2r * a.I.value
97
- const rAInv = Math.pow(
98
- 1 -
99
- 12 * Math.pow(Math.tan(0.5 * I), 2) * Math.cos(2 * P) +
100
- 36 * Math.pow(Math.tan(0.5 * I), 4),
101
- 0.5
102
- )
103
- return corrections.fM2(a) * rAInv
104
- },
105
-
106
- // Schureman equations 235, 234, 71
107
- // Again, magic numbers
108
- fK2(a) {
109
- const omega = d2r * a.omega.value
110
- const i = d2r * a.i.value
111
- const I = d2r * a.I.value
112
- const nu = d2r * a.nu.value
113
- const sinsqIcos2nuMean =
114
- Math.sin(omega) ** 2 * (1 - (3 / 2.0) * Math.sin(i) ** 2)
115
- const mean = 0.5023 * sinsqIcos2nuMean + 0.0365
116
- return (
117
- Math.pow(
118
- 0.2523 * Math.pow(Math.sin(I), 4) +
119
- 0.0367 * Math.pow(Math.sin(I), 2) * Math.cos(2 * nu) +
120
- 0.0013,
121
- 0.5
122
- ) / mean
123
- )
124
- },
125
- // Schureman equations 206, 207, 195
126
- fM1(a) {
127
- const P = d2r * a.P.value
128
- const I = d2r * a.I.value
129
- const qAInv = Math.pow(
130
- 0.25 +
131
- 1.5 *
132
- Math.cos(I) *
133
- Math.cos(2 * P) *
134
- Math.pow(Math.cos(0.5 * I), -0.5) +
135
- 2.25 * Math.pow(Math.cos(I), 2) * Math.pow(Math.cos(0.5 * I), -4),
136
- 0.5
137
- )
138
- return corrections.fO1(a) * qAInv
139
- },
140
-
141
- // See e.g. Schureman equation 149
142
- fModd(a, n) {
143
- return Math.pow(corrections.fM2(a), n / 2.0)
144
- },
145
-
146
- // Node factors u, see Table 2 of Schureman.
147
-
148
- uZero(a) {
149
- return 0.0
150
- },
151
-
152
- uMf(a) {
153
- return -2.0 * a.xi.value
154
- },
155
-
156
- uO1(a) {
157
- return 2.0 * a.xi.value - a.nu.value
158
- },
159
-
160
- uJ1(a) {
161
- return -a.nu.value
162
- },
163
-
164
- uOO1(a) {
165
- return -2.0 * a.xi.value - a.nu.value
166
- },
167
-
168
- uM2(a) {
169
- return 2.0 * a.xi.value - 2.0 * a.nu.value
170
- },
171
-
172
- uK1(a) {
173
- return -a.nup.value
174
- },
175
-
176
- // Schureman 214
177
- uL2(a) {
178
- const I = d2r * a.I.value
179
- const P = d2r * a.P.value
180
- const R =
181
- r2d *
182
- Math.atan(
183
- Math.sin(2 * P) /
184
- ((1 / 6.0) * Math.pow(Math.tan(0.5 * I), -2) - Math.cos(2 * P))
185
- )
186
- return 2.0 * a.xi.value - 2.0 * a.nu.value - R
187
- },
188
-
189
- uK2(a) {
190
- return -2.0 * a.nupp.value
191
- },
192
-
193
- // Schureman 202
194
- uM1(a) {
195
- const I = d2r * a.I.value
196
- const P = d2r * a.P.value
197
- const Q =
198
- r2d *
199
- Math.atan(((5 * Math.cos(I) - 1) / (7 * Math.cos(I) + 1)) * Math.tan(P))
200
- return a.xi.value - a.nu.value + Q
201
- },
202
-
203
- uModd(a, n) {
204
- return (n / 2.0) * corrections.uM2(a)
205
- }
206
- }
207
-
208
- export default corrections