@neaps/tide-predictor 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +22 -0
- package/.github/workflows/test.yml +15 -0
- package/.prettierrc +4 -0
- package/Gruntfile.js +87 -0
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/babel.config.js +9 -0
- package/dist/tide-predictor.js +1013 -0
- package/examples/browser/index.html +51 -0
- package/jest.config.js +14 -0
- package/lib/astronomy/coefficients.js +31 -0
- package/lib/astronomy/constants.js +10 -0
- package/lib/astronomy/index.js +199 -0
- package/lib/constituents/compound-constituent.js +67 -0
- package/lib/constituents/constituent.js +74 -0
- package/lib/constituents/index.js +140 -0
- package/lib/harmonics/index.js +113 -0
- package/lib/harmonics/prediction.js +195 -0
- package/lib/index.es6.js +1005 -0
- package/lib/index.js +53 -0
- package/lib/node-corrections/index.js +147 -0
- package/package.json +45 -0
- package/rollup.config.js +21 -0
- package/src/__mocks__/constituents.js +335 -0
- package/src/__mocks__/secondary-station.js +11 -0
- package/src/__tests__/index.js +81 -0
- package/src/__tests__/noaa.js +92 -0
- package/src/astronomy/__tests__/coefficients.js +12 -0
- package/src/astronomy/__tests__/index.js +96 -0
- package/src/astronomy/coefficients.js +72 -0
- package/src/astronomy/constants.js +4 -0
- package/src/astronomy/index.js +201 -0
- package/src/constituents/__tests__/compound-constituent.js +44 -0
- package/src/constituents/__tests__/constituent.js +65 -0
- package/src/constituents/__tests__/index.js +34 -0
- package/src/constituents/compound-constituent.js +55 -0
- package/src/constituents/constituent.js +74 -0
- package/src/constituents/index.js +119 -0
- package/src/harmonics/__mocks__/water-levels.js +0 -0
- package/src/harmonics/__tests__/index.js +123 -0
- package/src/harmonics/__tests__/prediction.js +148 -0
- package/src/harmonics/index.js +87 -0
- package/src/harmonics/prediction.js +175 -0
- package/src/index.js +45 -0
- package/src/node-corrections/__tests__/index.js +114 -0
- package/src/node-corrections/index.js +208 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import compoundConstituent from '../compound-constituent'
|
|
2
|
+
import Constituent from '../constituent'
|
|
3
|
+
import astro from '../../astronomy'
|
|
4
|
+
|
|
5
|
+
const sampleTime = new Date()
|
|
6
|
+
sampleTime.setFullYear(2019)
|
|
7
|
+
sampleTime.setMonth(9)
|
|
8
|
+
sampleTime.setDate(4)
|
|
9
|
+
sampleTime.setHours(10)
|
|
10
|
+
sampleTime.setMinutes(15)
|
|
11
|
+
sampleTime.setSeconds(40)
|
|
12
|
+
sampleTime.setMilliseconds(10)
|
|
13
|
+
|
|
14
|
+
const testAstro = astro(sampleTime)
|
|
15
|
+
|
|
16
|
+
// This is a made-up doodson number for a test coefficient
|
|
17
|
+
const testConstituentA = new Constituent('testa', [1, 1, -1, 0, 0, 0, 1])
|
|
18
|
+
const testConstituentB = new Constituent('testb', [0, 1, -1, 0, 0, 0, 1])
|
|
19
|
+
|
|
20
|
+
const compoundTest = compoundConstituent('test compound', [
|
|
21
|
+
{ constituent: testConstituentA, factor: 1 },
|
|
22
|
+
{ constituent: testConstituentB, factor: -1 }
|
|
23
|
+
])
|
|
24
|
+
describe('compund constituent', () => {
|
|
25
|
+
test('it calculates compound coefficients', () => {
|
|
26
|
+
expect(compoundTest.coefficients).toEqual([1, 0, 0, 0, 0, 0, 0])
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('it calculates speed', () => {
|
|
30
|
+
expect(compoundTest.speed(testAstro)).toBeCloseTo(14.4920521208, 4)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('it calculates value', () => {
|
|
34
|
+
expect(compoundTest.value(testAstro)).toBeCloseTo(268.504355062, 4)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('it returns u correctly', () => {
|
|
38
|
+
expect(compoundTest.u(testAstro)).toBe(0)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
test('it returns f correctly', () => {
|
|
42
|
+
expect(compoundTest.f(testAstro)).toBe(1)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import constituent, {
|
|
2
|
+
astronimicDoodsonNumber,
|
|
3
|
+
astronomicSpeed,
|
|
4
|
+
astronomicValues
|
|
5
|
+
} from '../constituent'
|
|
6
|
+
import astro from '../../astronomy'
|
|
7
|
+
|
|
8
|
+
const sampleTime = new Date()
|
|
9
|
+
sampleTime.setFullYear(2019)
|
|
10
|
+
sampleTime.setMonth(9)
|
|
11
|
+
sampleTime.setDate(4)
|
|
12
|
+
sampleTime.setHours(10)
|
|
13
|
+
sampleTime.setMinutes(15)
|
|
14
|
+
sampleTime.setSeconds(40)
|
|
15
|
+
sampleTime.setMilliseconds(10)
|
|
16
|
+
|
|
17
|
+
const testAstro = astro(sampleTime)
|
|
18
|
+
|
|
19
|
+
// This is a made-up doodson number for a test coefficient
|
|
20
|
+
const testConstituent = constituent('test', [1, 1, -1, 0, 0, 0, 1])
|
|
21
|
+
|
|
22
|
+
describe('constituent', () => {
|
|
23
|
+
test('it throws error if missing coefficients', () => {
|
|
24
|
+
let errorMessage = false
|
|
25
|
+
try {
|
|
26
|
+
const a = constituent('fail') // eslint-disable-line
|
|
27
|
+
} catch (error) {
|
|
28
|
+
errorMessage = error
|
|
29
|
+
}
|
|
30
|
+
expect(errorMessage.message).toBe(
|
|
31
|
+
'Coefficient must be defined for a constituent'
|
|
32
|
+
)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
test('it fetches astronimic Doodson Number values', () => {
|
|
36
|
+
const values = astronimicDoodsonNumber(testAstro)
|
|
37
|
+
expect(values[0].value).toBe(testAstro['T+h-s'].value)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('it fetches astronimic speed', () => {
|
|
41
|
+
const values = astronomicSpeed(testAstro)
|
|
42
|
+
expect(values[0]).toBe(testAstro['T+h-s'].speed)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('it fetches astronimic values', () => {
|
|
46
|
+
const values = astronomicValues(testAstro)
|
|
47
|
+
expect(values[0]).toBe(testAstro['T+h-s'].value)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('it computes constituent value', () => {
|
|
51
|
+
expect(testConstituent.value(testAstro)).toBeCloseTo(423.916666657, 4)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test('it computes constituent speed', () => {
|
|
55
|
+
expect(testConstituent.speed(testAstro)).toBe(15)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('it returns u correctly', () => {
|
|
59
|
+
expect(testConstituent.u(testAstro)).toBe(0)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('it returns f correctly', () => {
|
|
63
|
+
expect(testConstituent.f(testAstro)).toBe(1)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import constituents from '../index'
|
|
2
|
+
import astro from '../../astronomy'
|
|
3
|
+
|
|
4
|
+
const sampleTime = new Date()
|
|
5
|
+
sampleTime.setFullYear(2019)
|
|
6
|
+
sampleTime.setMonth(9)
|
|
7
|
+
sampleTime.setDate(4)
|
|
8
|
+
sampleTime.setHours(10)
|
|
9
|
+
sampleTime.setMinutes(15)
|
|
10
|
+
sampleTime.setSeconds(40)
|
|
11
|
+
sampleTime.setMilliseconds(10)
|
|
12
|
+
|
|
13
|
+
const testAstro = astro(sampleTime)
|
|
14
|
+
|
|
15
|
+
describe('Base constituent definitions', () => {
|
|
16
|
+
test('it prepared constituent SA', () => {
|
|
17
|
+
expect(constituents.SA.value(testAstro)).toBeCloseTo(192.826398978, 4)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('it prepared constituent SSA', () => {
|
|
21
|
+
expect(constituents.SSA.value(testAstro)).toBeCloseTo(385.652797955, 4)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('it prepared constituent M2', () => {
|
|
25
|
+
expect(constituents.M2.value(testAstro)).toBeCloseTo(537.008710124, 4)
|
|
26
|
+
expect(constituents.M2.u(testAstro)).toBeCloseTo(-2.07725095711, 4)
|
|
27
|
+
expect(constituents.M2.f(testAstro)).toBeCloseTo(1.00853563237, 4)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('has a correct lambda for M3', () => {
|
|
31
|
+
expect(constituents.M3.u(testAstro)).toBeCloseTo(-3.11587643567, 4)
|
|
32
|
+
expect(constituents.M3.f(testAstro)).toBeCloseTo(1.01283073119, 4)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const compoundConstituentFactory = (name, members) => {
|
|
2
|
+
const coefficients = []
|
|
3
|
+
members.forEach(({ constituent, factor }) => {
|
|
4
|
+
constituent.coefficients.forEach((coefficient, index) => {
|
|
5
|
+
if (typeof coefficients[index] === 'undefined') {
|
|
6
|
+
coefficients[index] = 0
|
|
7
|
+
}
|
|
8
|
+
coefficients[index] += coefficient * factor
|
|
9
|
+
})
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const compoundConstituent = {
|
|
13
|
+
name: name,
|
|
14
|
+
|
|
15
|
+
coefficients: coefficients,
|
|
16
|
+
|
|
17
|
+
speed: (astro) => {
|
|
18
|
+
let speed = 0
|
|
19
|
+
members.forEach(({ constituent, factor }) => {
|
|
20
|
+
speed += constituent.speed(astro) * factor
|
|
21
|
+
})
|
|
22
|
+
return speed
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
value: (astro) => {
|
|
26
|
+
let value = 0
|
|
27
|
+
members.forEach(({ constituent, factor }) => {
|
|
28
|
+
value += constituent.value(astro) * factor
|
|
29
|
+
})
|
|
30
|
+
return value
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
u: (astro) => {
|
|
34
|
+
let u = 0
|
|
35
|
+
members.forEach(({ constituent, factor }) => {
|
|
36
|
+
u += constituent.u(astro) * factor
|
|
37
|
+
})
|
|
38
|
+
return u
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
f: (astro) => {
|
|
42
|
+
const f = []
|
|
43
|
+
members.forEach(({ constituent, factor }) => {
|
|
44
|
+
f.push(Math.pow(constituent.f(astro), Math.abs(factor)))
|
|
45
|
+
})
|
|
46
|
+
return f.reduce((previous, value) => {
|
|
47
|
+
return previous * value
|
|
48
|
+
})
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return Object.freeze(compoundConstituent)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default compoundConstituentFactory
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import nodeCorrections from '../node-corrections/index'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Computes the dot notation of two arrays
|
|
5
|
+
* @param {*} a
|
|
6
|
+
* @param {*} b
|
|
7
|
+
*/
|
|
8
|
+
const dotArray = (a, b) => {
|
|
9
|
+
const results = []
|
|
10
|
+
a.forEach((value, index) => {
|
|
11
|
+
results.push(value * b[index])
|
|
12
|
+
})
|
|
13
|
+
return results.reduce((total, value) => {
|
|
14
|
+
return total + value
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const astronimicDoodsonNumber = (astro) => {
|
|
19
|
+
return [
|
|
20
|
+
astro['T+h-s'],
|
|
21
|
+
astro.s,
|
|
22
|
+
astro.h,
|
|
23
|
+
astro.p,
|
|
24
|
+
astro.N,
|
|
25
|
+
astro.pp,
|
|
26
|
+
astro['90'],
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const astronomicSpeed = (astro) => {
|
|
31
|
+
const results = []
|
|
32
|
+
astronimicDoodsonNumber(astro).forEach((number) => {
|
|
33
|
+
results.push(number.speed)
|
|
34
|
+
})
|
|
35
|
+
return results
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const astronomicValues = (astro) => {
|
|
39
|
+
const results = []
|
|
40
|
+
astronimicDoodsonNumber(astro).forEach((number) => {
|
|
41
|
+
results.push(number.value)
|
|
42
|
+
})
|
|
43
|
+
return results
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const constituentFactory = (name, coefficients, u, f) => {
|
|
47
|
+
if (!coefficients) {
|
|
48
|
+
throw new Error('Coefficient must be defined for a constituent')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const constituent = {
|
|
52
|
+
name: name,
|
|
53
|
+
|
|
54
|
+
coefficients: coefficients,
|
|
55
|
+
|
|
56
|
+
value: (astro) => {
|
|
57
|
+
return dotArray(coefficients, astronomicValues(astro))
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
speed(astro) {
|
|
61
|
+
return dotArray(coefficients, astronomicSpeed(astro))
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
u: typeof u !== 'undefined' ? u : nodeCorrections.uZero,
|
|
65
|
+
|
|
66
|
+
f: typeof f !== 'undefined' ? f : nodeCorrections.fUnity,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return Object.freeze(constituent)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default constituentFactory
|
|
73
|
+
|
|
74
|
+
export { astronimicDoodsonNumber, astronomicSpeed, astronomicValues }
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import constituent from './constituent'
|
|
2
|
+
import compoundConstituent from './compound-constituent'
|
|
3
|
+
import nc from '../node-corrections/index'
|
|
4
|
+
|
|
5
|
+
const constituents = {}
|
|
6
|
+
// Long Term
|
|
7
|
+
constituents.Z0 = constituent('Z0', [0, 0, 0, 0, 0, 0, 0], nc.uZero, nc.fUnity)
|
|
8
|
+
constituents.SA = constituent('Sa', [0, 0, 1, 0, 0, 0, 0], nc.uZero, nc.fUnity)
|
|
9
|
+
constituents.SSA = constituent(
|
|
10
|
+
'Ssa',
|
|
11
|
+
[0, 0, 2, 0, 0, 0, 0],
|
|
12
|
+
nc.uZero,
|
|
13
|
+
nc.fUnity
|
|
14
|
+
)
|
|
15
|
+
constituents.MM = constituent('MM', [0, 1, 0, -1, 0, 0, 0], nc.uZero, nc.fMm)
|
|
16
|
+
constituents.MF = constituent('MF', [0, 2, 0, 0, 0, 0, 0], nc.uMf, nc.fMf)
|
|
17
|
+
// Diurnals
|
|
18
|
+
constituents.Q1 = constituent('Q1', [1, -2, 0, 1, 0, 0, 1], nc.uO1, nc.fO1)
|
|
19
|
+
constituents.O1 = constituent('O1', [1, -1, 0, 0, 0, 0, 1], nc.uO1, nc.fO1)
|
|
20
|
+
constituents.K1 = constituent('K1', [1, 1, 0, 0, 0, 0, -1], nc.uK1, nc.fK1)
|
|
21
|
+
constituents.J1 = constituent('J1', [1, 2, 0, -1, 0, 0, -1], nc.uJ1, nc.fJ1)
|
|
22
|
+
constituents.M1 = constituent('M1', [1, 0, 0, 0, 0, 0, 1], nc.uM1, nc.fM1)
|
|
23
|
+
constituents.P1 = constituent('P1', [1, 1, -2, 0, 0, 0, 1], nc.uZero, nc.fUnity)
|
|
24
|
+
constituents.S1 = constituent('S1', [1, 1, -1, 0, 0, 0, 0], nc.uZero, nc.fUnity)
|
|
25
|
+
constituents.OO1 = constituent('OO1', [1, 3, 0, 0, 0, 0, -1], nc.uOO1, nc.fOO1)
|
|
26
|
+
// Semi diurnals
|
|
27
|
+
constituents['2N2'] = constituent('2N2', [2, -2, 0, 2, 0, 0, 0], nc.uM2, nc.fM2)
|
|
28
|
+
constituents.N2 = constituent('N2', [2, -1, 0, 1, 0, 0, 0], nc.uM2, nc.fM2)
|
|
29
|
+
constituents.NU2 = constituent('NU2', [2, -1, 2, -1, 0, 0, 0], nc.uM2, nc.fM2)
|
|
30
|
+
constituents.M2 = constituent('M2', [2, 0, 0, 0, 0, 0, 0], nc.uM2, nc.fM2)
|
|
31
|
+
constituents.LAM2 = constituent('LAM2', [2, 1, -2, 1, 0, 0, 2], nc.uM2, nc.fM2)
|
|
32
|
+
constituents.L2 = constituent('L2', [2, 1, 0, -1, 0, 0, 2], nc.uL2, nc.fL2)
|
|
33
|
+
constituents.T2 = constituent('T2', [2, 2, -3, 0, 0, 1, 0], nc.uZero, nc.fUnity)
|
|
34
|
+
constituents.S2 = constituent('S2', [2, 2, -2, 0, 0, 0, 0], nc.uZero, nc.fUnity)
|
|
35
|
+
constituents.R2 = constituent(
|
|
36
|
+
'R2',
|
|
37
|
+
[2, 2, -1, 0, 0, -1, 2],
|
|
38
|
+
nc.uZero,
|
|
39
|
+
nc.fUnity
|
|
40
|
+
)
|
|
41
|
+
constituents.K2 = constituent('K2', [2, 2, 0, 0, 0, 0, 0], nc.uK2, nc.fK2)
|
|
42
|
+
// Third diurnal
|
|
43
|
+
constituents.M3 = constituent(
|
|
44
|
+
'M3',
|
|
45
|
+
[3, 0, 0, 0, 0, 0, 0],
|
|
46
|
+
(a) => {
|
|
47
|
+
return nc.uModd(a, 3)
|
|
48
|
+
},
|
|
49
|
+
(a) => {
|
|
50
|
+
return nc.fModd(a, 3)
|
|
51
|
+
}
|
|
52
|
+
)
|
|
53
|
+
// Compound
|
|
54
|
+
constituents.MSF = compoundConstituent('MSF', [
|
|
55
|
+
{ constituent: constituents.S2, factor: 1 },
|
|
56
|
+
{ constituent: constituents.M2, factor: -1 },
|
|
57
|
+
])
|
|
58
|
+
|
|
59
|
+
// Diurnal
|
|
60
|
+
constituents['2Q1'] = compoundConstituent('2Q1', [
|
|
61
|
+
{ constituent: constituents.N2, factor: 1 },
|
|
62
|
+
{ constituent: constituents.J1, factor: -1 },
|
|
63
|
+
])
|
|
64
|
+
constituents.RHO = compoundConstituent('RHO', [
|
|
65
|
+
{ constituent: constituents.NU2, factor: 1 },
|
|
66
|
+
{ constituent: constituents.K1, factor: -1 },
|
|
67
|
+
])
|
|
68
|
+
|
|
69
|
+
// Semi-Diurnal
|
|
70
|
+
|
|
71
|
+
constituents.MU2 = compoundConstituent('MU2', [
|
|
72
|
+
{ constituent: constituents.M2, factor: 2 },
|
|
73
|
+
{ constituent: constituents.S2, factor: -1 },
|
|
74
|
+
])
|
|
75
|
+
constituents['2SM2'] = compoundConstituent('2SM2', [
|
|
76
|
+
{ constituent: constituents.S2, factor: 2 },
|
|
77
|
+
{ constituent: constituents.M2, factor: -1 },
|
|
78
|
+
])
|
|
79
|
+
|
|
80
|
+
// Third-Diurnal
|
|
81
|
+
constituents['2MK3'] = compoundConstituent('2MK3', [
|
|
82
|
+
{ constituent: constituents.M2, factor: 1 },
|
|
83
|
+
{ constituent: constituents.O1, factor: 1 },
|
|
84
|
+
])
|
|
85
|
+
constituents.MK3 = compoundConstituent('MK3', [
|
|
86
|
+
{ constituent: constituents.M2, factor: 1 },
|
|
87
|
+
{ constituent: constituents.K1, factor: 1 },
|
|
88
|
+
])
|
|
89
|
+
|
|
90
|
+
// Quarter-Diurnal
|
|
91
|
+
constituents.MN4 = compoundConstituent('MN4', [
|
|
92
|
+
{ constituent: constituents.M2, factor: 1 },
|
|
93
|
+
{ constituent: constituents.N2, factor: 1 },
|
|
94
|
+
])
|
|
95
|
+
constituents.M4 = compoundConstituent('M4', [
|
|
96
|
+
{ constituent: constituents.M2, factor: 2 },
|
|
97
|
+
])
|
|
98
|
+
constituents.MS4 = compoundConstituent('MS4', [
|
|
99
|
+
{ constituent: constituents.M2, factor: 1 },
|
|
100
|
+
{ constituent: constituents.S2, factor: 1 },
|
|
101
|
+
])
|
|
102
|
+
constituents.S4 = compoundConstituent('S4', [
|
|
103
|
+
{ constituent: constituents.S2, factor: 2 },
|
|
104
|
+
])
|
|
105
|
+
|
|
106
|
+
// Sixth-Diurnal
|
|
107
|
+
constituents.M6 = compoundConstituent('M6', [
|
|
108
|
+
{ constituent: constituents.M2, factor: 3 },
|
|
109
|
+
])
|
|
110
|
+
constituents.S6 = compoundConstituent('S6', [
|
|
111
|
+
{ constituent: constituents.S2, factor: 3 },
|
|
112
|
+
])
|
|
113
|
+
|
|
114
|
+
// Eighth-Diurnals
|
|
115
|
+
constituents.M8 = compoundConstituent('M8', [
|
|
116
|
+
{ constituent: constituents.M2, factor: 4 },
|
|
117
|
+
])
|
|
118
|
+
|
|
119
|
+
export default constituents
|
|
File without changes
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import harmonics, { getDate, getTimeline } from '../index'
|
|
2
|
+
import mockHarmonicConstituents from '../../__mocks__/constituents'
|
|
3
|
+
|
|
4
|
+
const startDate = new Date(1567346400 * 1000) // 2019-09-01
|
|
5
|
+
const endDate = new Date(1569966078 * 1000) // 2019-10-01
|
|
6
|
+
|
|
7
|
+
describe('harmonics', () => {
|
|
8
|
+
test('it checks constituents', () => {
|
|
9
|
+
let errorMessage = false
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
harmonics({ harmonicConstituents: 'not array' })
|
|
13
|
+
} catch (error) {
|
|
14
|
+
errorMessage = error
|
|
15
|
+
}
|
|
16
|
+
expect(errorMessage.message).toBe('Harmonic constituents are not an array')
|
|
17
|
+
|
|
18
|
+
errorMessage = false
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
harmonics({
|
|
22
|
+
harmonicConstituents: [
|
|
23
|
+
{
|
|
24
|
+
name: 'M2',
|
|
25
|
+
description: 'Principal lunar semidiurnal constituent',
|
|
26
|
+
amplitude: 1.61,
|
|
27
|
+
phase_GMT: 181.3,
|
|
28
|
+
phase_local: 309.4,
|
|
29
|
+
speed: 28.984104,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
description: 'Principal solar semidiurnal constituent',
|
|
33
|
+
amplitude: 0.43,
|
|
34
|
+
phase_GMT: 180.1,
|
|
35
|
+
phase_local: 309.4,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
})
|
|
39
|
+
} catch (error) {
|
|
40
|
+
errorMessage = error
|
|
41
|
+
}
|
|
42
|
+
expect(errorMessage.message).toBe(
|
|
43
|
+
'Harmonic constituents must have a name property'
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
errorMessage = false
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
harmonics({
|
|
50
|
+
harmonicConstituents: [
|
|
51
|
+
{
|
|
52
|
+
name: 'not a name',
|
|
53
|
+
description: 'Principal lunar semidiurnal constituent',
|
|
54
|
+
amplitude: 1.61,
|
|
55
|
+
phase_GMT: 181.3,
|
|
56
|
+
phase_local: 309.4,
|
|
57
|
+
speed: 28.984104,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'M2',
|
|
61
|
+
description: 'Principal solar semidiurnal constituent',
|
|
62
|
+
amplitude: 0.43,
|
|
63
|
+
phase_GMT: 180.1,
|
|
64
|
+
phase_local: 309.4,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
})
|
|
68
|
+
} catch (error) {
|
|
69
|
+
errorMessage = error
|
|
70
|
+
}
|
|
71
|
+
expect(errorMessage.message).toBeFalsy()
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('it checks start and end times', () => {
|
|
75
|
+
const testHarmonics = harmonics({
|
|
76
|
+
harmonicConstituents: mockHarmonicConstituents,
|
|
77
|
+
})
|
|
78
|
+
let timeErrorMessage = false
|
|
79
|
+
try {
|
|
80
|
+
testHarmonics.setTimeSpan('lkjsdlf', 'sdfklj')
|
|
81
|
+
} catch (error) {
|
|
82
|
+
timeErrorMessage = error
|
|
83
|
+
}
|
|
84
|
+
expect(timeErrorMessage.message).toBe(
|
|
85
|
+
'Invalid date format, should be a Date object, or timestamp'
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
timeErrorMessage = false
|
|
89
|
+
try {
|
|
90
|
+
testHarmonics.setTimeSpan(startDate, startDate)
|
|
91
|
+
} catch (error) {
|
|
92
|
+
timeErrorMessage = error
|
|
93
|
+
}
|
|
94
|
+
expect(timeErrorMessage.message).toBe('Start time must be before end time')
|
|
95
|
+
|
|
96
|
+
timeErrorMessage = false
|
|
97
|
+
try {
|
|
98
|
+
testHarmonics.setTimeSpan(startDate, endDate)
|
|
99
|
+
} catch (error) {
|
|
100
|
+
timeErrorMessage = error
|
|
101
|
+
}
|
|
102
|
+
expect(timeErrorMessage.message).toBeFalsy()
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('it parses dates correctly', () => {
|
|
106
|
+
const parsedDate = getDate(startDate)
|
|
107
|
+
expect(parsedDate.getTime()).toBe(startDate.getTime())
|
|
108
|
+
|
|
109
|
+
const parsedUnixDate = getDate(startDate.getTime() / 1000)
|
|
110
|
+
expect(parsedUnixDate.getTime()).toBe(startDate.getTime())
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('it creates timeline correctly', () => {
|
|
114
|
+
const seconds = 20 * 60
|
|
115
|
+
const difference =
|
|
116
|
+
Math.round(
|
|
117
|
+
(endDate.getTime() / 1000 - startDate.getTime() / 1000) / seconds
|
|
118
|
+
) + 1
|
|
119
|
+
const { items, hours } = getTimeline(startDate, endDate, seconds)
|
|
120
|
+
expect(items.length).toBe(difference)
|
|
121
|
+
expect(hours.length).toBe(difference)
|
|
122
|
+
})
|
|
123
|
+
})
|