1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.weather;
18
19 import java.util.List;
20 import java.util.SortedSet;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.util.FastMath;
24 import org.hipparchus.util.FieldSinCos;
25 import org.hipparchus.util.MathUtils;
26 import org.hipparchus.util.SinCos;
27 import org.orekit.errors.OrekitException;
28 import org.orekit.errors.OrekitMessages;
29 import org.orekit.utils.Constants;
30
31
32
33
34
35
36 class Grid {
37
38
39 private final SortedSet<Integer> latitudeSample;
40
41
42 private final SortedSet<Integer> longitudeSample;
43
44
45 private final GridEntry[][] entries;
46
47
48
49
50
51
52
53 Grid(final SortedSet<Integer> latitudeSample, final SortedSet<Integer> longitudeSample,
54 final List<GridEntry> loadedEntries, final String name) {
55
56 final int nA = latitudeSample.size();
57 final int nO = longitudeSample.size() + 1;
58 this.entries = new GridEntry[nA][nO];
59 this.latitudeSample = latitudeSample;
60 this.longitudeSample = longitudeSample;
61
62
63 for (final GridEntry entry : loadedEntries) {
64 final int latitudeIndex = latitudeSample.headSet(entry.getLatKey() + 1).size() - 1;
65 final int longitudeIndex = longitudeSample.headSet(entry.getLonKey() + 1).size() - 1;
66 entries[latitudeIndex][longitudeIndex] = entry;
67 }
68
69
70 for (final GridEntry[] row : entries) {
71
72
73 for (int longitudeIndex = 0; longitudeIndex < nO - 1; ++longitudeIndex) {
74 if (row[longitudeIndex] == null) {
75 throw new OrekitException(OrekitMessages.IRREGULAR_OR_INCOMPLETE_GRID, name);
76 }
77 }
78
79
80 row[nO - 1] = row[0].buildWrappedEntry();
81
82 }
83
84 }
85
86
87
88
89
90 private int getSouthIndex(final double latitude) {
91
92 final int latKey = (int) FastMath.rint(FastMath.toDegrees(latitude) * GridEntry.DEG_TO_MAS);
93 final int index = latitudeSample.headSet(latKey + 1).size() - 1;
94
95
96 return FastMath.min(index, latitudeSample.size() - 2);
97
98 }
99
100
101
102
103
104 private int getWestIndex(final double longitude) {
105
106 final int lonKey = (int) FastMath.rint(FastMath.toDegrees(longitude) * GridEntry.DEG_TO_MAS);
107
108
109 return longitudeSample.headSet(lonKey + 1).size() - 1;
110
111 }
112
113
114
115
116
117
118
119
120 CellInterpolator getInterpolator(final double latitude, final double longitude,
121 final double altitude, final double deltaRef) {
122
123
124 final double normalizedLongitude =
125 MathUtils.normalizeAngle(longitude,
126 entries[0][0].getLongitude() + FastMath.PI);
127
128
129 final int southIndex = getSouthIndex(latitude);
130 final int westIndex = getWestIndex(normalizedLongitude);
131
132 final double coef = (deltaRef / Constants.JULIAN_YEAR) * 2 * FastMath.PI;
133 final SinCos sc1 = FastMath.sinCos(coef);
134 final SinCos sc2 = FastMath.sinCos(2.0 * coef);
135
136
137 return new CellInterpolator(latitude, normalizedLongitude,
138 entries[southIndex ][westIndex ].evaluate(sc1, sc2, altitude),
139 entries[southIndex ][westIndex + 1].evaluate(sc1, sc2, altitude),
140 entries[southIndex + 1][westIndex ].evaluate(sc1, sc2, altitude),
141 entries[southIndex + 1][westIndex + 1].evaluate(sc1, sc2, altitude));
142
143 }
144
145
146
147
148
149
150
151
152
153 <T extends CalculusFieldElement<T>> FieldCellInterpolator<T> getInterpolator(final T latitude, final T longitude,
154 final T altitude, final T deltaRef) {
155
156
157 final T normalizedLongitude =
158 MathUtils.normalizeAngle(longitude,
159 longitude.newInstance(entries[0][0].getLongitude() + FastMath.PI));
160
161
162 final int southIndex = getSouthIndex(latitude.getReal());
163 final int westIndex = getWestIndex(normalizedLongitude.getReal());
164
165 final T coef = deltaRef.multiply(2 * FastMath.PI / Constants.JULIAN_YEAR);
166 final FieldSinCos<T> sc1 = FastMath.sinCos(coef);
167 final FieldSinCos<T> sc2 = FastMath.sinCos(coef.multiply(2));
168
169
170 return new FieldCellInterpolator<>(latitude, normalizedLongitude,
171 entries[southIndex ][westIndex ].evaluate(sc1, sc2, altitude),
172 entries[southIndex ][westIndex + 1].evaluate(sc1, sc2, altitude),
173 entries[southIndex + 1][westIndex ].evaluate(sc1, sc2, altitude),
174 entries[southIndex + 1][westIndex + 1].evaluate(sc1, sc2, altitude));
175
176 }
177
178
179
180
181
182 boolean hasModels(final SeasonalModelType... types) {
183 boolean hasAll = true;
184 for (final SeasonalModelType type : types) {
185 hasAll &= entries[0][0].hasModel(type);
186 }
187 return hasAll;
188 }
189
190 }