1 /* Copyright 2022-2025 Thales Alenia Space
2 * Licensed to CS Communication & Systèmes (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.orekit.models.earth.troposphere.iturp834;
18
19 import org.hipparchus.CalculusFieldElement;
20
21 /** Holder for one cell of grid data surrounding one point.
22 * @param <T> type of the field elements
23 * @author Luc Maisonobe
24 * @since 13.0
25 */
26 class FieldGridCell<T extends CalculusFieldElement<T>> {
27
28 /** Latitude difference with respect to South cell edge. */
29 private final T deltaSouth;
30
31 /** Longitude difference with respect to West cell edge. */
32 private final T deltaWest;
33
34 /** Cell size in latitude. */
35 private final double sizeLat;
36
37 /** Cell size in longitude. */
38 private final double sizeLon;
39
40 /** North-West value. */
41 private final T nw;
42
43 /** South-West value. */
44 private final T sw;
45
46 /** South-East value. */
47 private final T se;
48
49 /** North-East value. */
50 private final T ne;
51
52 /**
53 * Build a grid cell from corner data.
54 *
55 * @param deltaSouth point latitude minus South cell edge latitude
56 * @param deltaWest point longitude minus West cell edge longitude
57 * @param sizeLat cell size in latitude
58 * @param sizeLon cell size in longitude
59 * @param nw North-West value
60 * @param sw South-West value
61 * @param se South-East value
62 * @param ne North-East value
63 */
64 FieldGridCell(final T deltaSouth, final T deltaWest, final double sizeLat, final double sizeLon,
65 final T nw, final T sw, final T se, final T ne) {
66 this.deltaSouth = deltaSouth;
67 this.deltaWest = deltaWest;
68 this.sizeLat = sizeLat;
69 this.sizeLon = sizeLon;
70 this.nw = nw;
71 this.sw = sw;
72 this.se = se;
73 this.ne = ne;
74 }
75
76 /** Build a grid cell by applying a function to two existing cells.
77 * <p>
78 * The cells are expected to be consistent (i.e. same locations,
79 * same sizes), but no verification is done here. It works in
80 * the context of ITR-R P.834 because the grids have similar
81 * samplings, it would not work fro general and inconsistent grids.
82 * </p>
83 * @param function function to apply to all cells corners
84 * @param cell1 first cell
85 * @param cell2 second cell
86 */
87 FieldGridCell(final BiFunction<T> function,
88 final FieldGridCell<T> cell1, final FieldGridCell<T> cell2) {
89 this.deltaSouth = cell1.deltaSouth;
90 this.deltaWest = cell1.deltaWest;
91 this.sizeLat = cell1.sizeLat;
92 this.sizeLon = cell1.sizeLon;
93 this.nw = function.apply(cell1.nw, cell2.nw);
94 this.sw = function.apply(cell1.sw, cell2.sw);
95 this.se = function.apply(cell1.se, cell2.se);
96 this.ne = function.apply(cell1.ne, cell2.ne);
97 }
98
99 /** Build a grid cell by applying a function to three existing cells.
100 * <p>
101 * The cells are expected to be consistent (i.e. same locations,
102 * same sizes), but no verification is done here. It works in
103 * the context of ITR-R P.834 because the grids have similar
104 * samplings, it would not work fro general and inconsistent grids.
105 * </p>
106 * @param function function to apply to all cells corners
107 * @param cell1 first cell
108 * @param cell2 second cell
109 * @param cell3 third cell
110 */
111 FieldGridCell(final TriFunction<T> function,
112 final FieldGridCell<T> cell1, final FieldGridCell<T> cell2, final FieldGridCell<T> cell3) {
113 this.deltaSouth = cell1.deltaSouth;
114 this.deltaWest = cell1.deltaWest;
115 this.sizeLat = cell1.sizeLat;
116 this.sizeLon = cell1.sizeLon;
117 this.nw = function.apply(cell1.nw, cell2.nw, cell3.nw);
118 this.sw = function.apply(cell1.sw, cell2.sw, cell3.sw);
119 this.se = function.apply(cell1.se, cell2.se, cell3.se);
120 this.ne = function.apply(cell1.ne, cell2.ne, cell3.ne);
121 }
122
123 /** Build a grid cell by applying a function to four existing cells.
124 * <p>
125 * The cells are expected to be consistent (i.e. same locations,
126 * same sizes), but no verification is done here. It works in
127 * the context of ITR-R P.834 because the grids have similar
128 * samplings, it would not work fro general and inconsistent grids.
129 * </p>
130 * @param function function to apply to all cells corners
131 * @param cell1 first cell
132 * @param cell2 second cell
133 * @param cell3 third cell
134 * @param cell4 fourth cell
135 */
136 FieldGridCell(final QuarticFunction<T> function,
137 final FieldGridCell<T> cell1, final FieldGridCell<T> cell2,
138 final FieldGridCell<T> cell3, final FieldGridCell<T> cell4) {
139 this.deltaSouth = cell1.deltaSouth;
140 this.deltaWest = cell1.deltaWest;
141 this.sizeLat = cell1.sizeLat;
142 this.sizeLon = cell1.sizeLon;
143 this.nw = function.apply(cell1.nw, cell2.nw, cell3.nw, cell4.nw);
144 this.sw = function.apply(cell1.sw, cell2.sw, cell3.sw, cell4.sw);
145 this.se = function.apply(cell1.se, cell2.se, cell3.se, cell4.se);
146 this.ne = function.apply(cell1.ne, cell2.ne, cell3.ne, cell4.ne);
147 }
148
149 /** Build a grid cell by applying a function to five existing cells.
150 * <p>
151 * The cells are expected to be consistent (i.e. same locations,
152 * same sizes), but no verification is done here. It works in
153 * the context of ITR-R P.834 because the grids have similar
154 * samplings, it would not work fro general and inconsistent grids.
155 * </p>
156 * @param function function to apply to all cells corners
157 * @param cell1 first cell
158 * @param cell2 second cell
159 * @param cell3 third cell
160 * @param cell4 fourth cell
161 * @param cell5 fifth cell
162 */
163 FieldGridCell(final QuinticFunction<T> function,
164 final FieldGridCell<T> cell1, final FieldGridCell<T> cell2, final FieldGridCell<T> cell3,
165 final FieldGridCell<T> cell4, final FieldGridCell<T> cell5) {
166 this.deltaSouth = cell1.deltaSouth;
167 this.deltaWest = cell1.deltaWest;
168 this.sizeLat = cell1.sizeLat;
169 this.sizeLon = cell1.sizeLon;
170 this.nw = function.apply(cell1.nw, cell2.nw, cell3.nw, cell4.nw, cell5.nw);
171 this.sw = function.apply(cell1.sw, cell2.sw, cell3.sw, cell4.sw, cell5.sw);
172 this.se = function.apply(cell1.se, cell2.se, cell3.se, cell4.se, cell5.se);
173 this.ne = function.apply(cell1.ne, cell2.ne, cell3.ne, cell4.ne, cell5.ne);
174 }
175
176 /** Evaluate cell value at point location using bi-linear interpolation.
177 * @return cell value at point location
178 */
179 public T evaluate() {
180 final T deltaNorth = deltaSouth.negate().add(sizeLat);
181 final T deltaEast = deltaWest.negate().add(sizeLon);
182 return deltaSouth.multiply(deltaWest.multiply(ne).add(deltaEast.multiply(nw))).
183 add(deltaNorth.multiply(deltaWest.multiply(se).add(deltaEast.multiply(sw)))).
184 divide(sizeLat * sizeLon);
185 }
186
187 /** Interface for function that can be applied to the corners of two cells. */
188 @FunctionalInterface
189 public interface BiFunction<T extends CalculusFieldElement<T>> {
190 /** Apply function to similar corners coming from two cells.
191 * @param corner1 value at corner of first cell
192 * @param corner2 value at corner of second cell
193 * @return function evaluated at similar corners of two cells
194 */
195 T apply(T corner1, T corner2);
196 }
197
198 /** Interface for function that can be applied to the corners of three cells.
199 * @param <T> type of the field elements
200 */
201 @FunctionalInterface
202 public interface TriFunction<T extends CalculusFieldElement<T>> {
203 /** Apply function to similar corners coming from three cells.
204 * @param corner1 value at corner of first cell
205 * @param corner2 value at corner of second cell
206 * @param corner3 value at corner of third cell
207 * @return function evaluated at similar corners of three cells
208 */
209 T apply(T corner1, T corner2, T corner3);
210 }
211
212 /** Interface for function that can be applied to the corners of four cells.
213 * @param <T> type of the field elements
214 */
215 @FunctionalInterface
216 public interface QuarticFunction<T extends CalculusFieldElement<T>> {
217 /** Apply function to similar corners coming from four cells.
218 * @param corner1 value at corner of first cell
219 * @param corner2 value at corner of second cell
220 * @param corner3 value at corner of third cell
221 * @param corner4 value at corner of fourth cell
222 * @return function evaluated at similar corners of four cells
223 */
224 T apply(T corner1, T corner2, T corner3, T corner4);
225 }
226
227 /** Interface for function that can be applied to the corners of five cells.
228 * @param <T> type of the field elements
229 */
230 @FunctionalInterface
231 public interface QuinticFunction<T extends CalculusFieldElement<T>> {
232 /** Apply function to similar corners coming from five cells.
233 * @param corner1 value at corner of first cell
234 * @param corner2 value at corner of second cell
235 * @param corner3 value at corner of third cell
236 * @param corner4 value at corner of fourth cell
237 * @param corner5 value at corner of fifth cell
238 * @return function evaluated at similar corners of five cells
239 */
240 T apply(T corner1, T corner2, T corner3, T corner4, T corner5);
241 }
242
243 }