arepytools 1.7.6__py3-none-any.whl

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 (53) hide show
  1. arepytools/__init__.py +8 -0
  2. arepytools/constants.py +109 -0
  3. arepytools/geometry/__init__.py +6 -0
  4. arepytools/geometry/_geodetic.py +107 -0
  5. arepytools/geometry/_interpolator.py +210 -0
  6. arepytools/geometry/anx_time.py +134 -0
  7. arepytools/geometry/attitude_utils.py +88 -0
  8. arepytools/geometry/conversions.py +120 -0
  9. arepytools/geometry/curve.py +344 -0
  10. arepytools/geometry/curve_protocols.py +113 -0
  11. arepytools/geometry/direct_geocoding.py +1062 -0
  12. arepytools/geometry/ellipsoid.py +233 -0
  13. arepytools/geometry/generalsarattitude.py +528 -0
  14. arepytools/geometry/generalsarorbit.py +831 -0
  15. arepytools/geometry/geometric_functions.py +493 -0
  16. arepytools/geometry/inverse_geocoding.py +315 -0
  17. arepytools/geometry/inverse_geocoding_core.py +806 -0
  18. arepytools/geometry/orbit.py +160 -0
  19. arepytools/geometry/reference_frames.py +289 -0
  20. arepytools/geometry/rotation.py +144 -0
  21. arepytools/geometry/wgs84.py +22 -0
  22. arepytools/io/__init__.py +59 -0
  23. arepytools/io/channel.py +513 -0
  24. arepytools/io/channel_iteration.py +147 -0
  25. arepytools/io/create_orbit.py +35 -0
  26. arepytools/io/debugio.py +65 -0
  27. arepytools/io/io_support.py +683 -0
  28. arepytools/io/manifest.py +100 -0
  29. arepytools/io/metadata.py +2679 -0
  30. arepytools/io/parsing/__init__.py +6 -0
  31. arepytools/io/parsing/metadata_models/__init__.py +93 -0
  32. arepytools/io/parsing/metadata_models/aresys_generic_metadata.py +222 -0
  33. arepytools/io/parsing/metadata_models/aresys_types.py +3391 -0
  34. arepytools/io/parsing/metadata_parsing.py +49 -0
  35. arepytools/io/parsing/parsing.py +70 -0
  36. arepytools/io/parsing/translate.py +1701 -0
  37. arepytools/io/point_target_binary.py +406 -0
  38. arepytools/io/point_target_file.py +299 -0
  39. arepytools/io/point_target_models/__init__.py +25 -0
  40. arepytools/io/point_target_models/aresys_point_target_models.py +181 -0
  41. arepytools/io/productfolder.py +467 -0
  42. arepytools/io/productfolder2.py +538 -0
  43. arepytools/io/productfolder_layout.py +184 -0
  44. arepytools/math/__init__.py +6 -0
  45. arepytools/math/axis.py +434 -0
  46. arepytools/math/genericpoly.py +155 -0
  47. arepytools/timing/__init__.py +6 -0
  48. arepytools/timing/conversions.py +54 -0
  49. arepytools/timing/precisedatetime.py +863 -0
  50. arepytools-1.7.6.dist-info/METADATA +64 -0
  51. arepytools-1.7.6.dist-info/RECORD +53 -0
  52. arepytools-1.7.6.dist-info/WHEEL +4 -0
  53. arepytools-1.7.6.dist-info/licenses/LICENSE.txt +21 -0
@@ -0,0 +1,120 @@
1
+ # SPDX-FileCopyrightText: Aresys S.r.l. <info@aresys.it>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ Coordinate conversions module
6
+ -----------------------------
7
+ """
8
+
9
+ from typing import Union
10
+
11
+ import numpy as np
12
+
13
+ from arepytools.geometry.ellipsoid import WGS84
14
+
15
+ _NUMBER_OF_ITERATIONS = 5
16
+
17
+ _A_MAX_SQUARE_MINUS_A_MIN_SQUARE_DIVIDED_BY_A_MAX = (
18
+ WGS84.semi_major_axis**2 - WGS84.semi_minor_axis**2
19
+ ) / WGS84.semi_major_axis
20
+ _A_MIN_TIMES_EP2 = WGS84.semi_minor_axis * WGS84.ep2
21
+
22
+
23
+ def llh2xyz(coordinates: Union[list, np.ndarray]) -> np.ndarray:
24
+ """Conversion from llh geodetic coordinates to xyz
25
+
26
+ Parameters
27
+ ----------
28
+ coordinates : Union[list, np.ndarray]
29
+ a numpy ndarray of shape (3,), (3, 1) or (3, N) or a list
30
+
31
+ Returns
32
+ -------
33
+ np.ndarray
34
+ a two dimensional numpy array of shape (3, N) with xyz coordinates
35
+ """
36
+ coordinates = np.asarray(coordinates)
37
+ if coordinates.shape[0] != 3:
38
+ raise RuntimeError(f"Coordinates has wrong shape: {coordinates.shape} not in (3,), (3, 1) or (3, N)")
39
+
40
+ if coordinates.ndim == 1:
41
+ coordinates = coordinates.copy()
42
+ coordinates.shape = (3, 1)
43
+
44
+ lat = coordinates[0, :]
45
+ lon = coordinates[1, :]
46
+ h = coordinates[2, :]
47
+
48
+ big_n = WGS84.semi_major_axis / np.sqrt(1 - WGS84.eccentricity_square * np.sin(lat) ** 2)
49
+ r = (big_n + h) * np.cos(lat)
50
+
51
+ x = r * np.cos(lon)
52
+ y = r * np.sin(lon)
53
+ z = (big_n * WGS84.semi_axes_ratio_min_max**2 + h) * np.sin(lat)
54
+
55
+ return np.vstack((x, y, z)).astype(float)
56
+
57
+
58
+ def xyz2llh(coordinates: Union[list, np.ndarray]) -> np.ndarray:
59
+ """Conversion from xyz coordinates to llh geodetic coordinates
60
+
61
+ Parameters
62
+ ----------
63
+ coordinates : Union[list, np.ndarray]
64
+ a numpy ndarray of shape (3,), (3, 1) or (3, N) or a list
65
+
66
+ Returns
67
+ -------
68
+ np.ndarray
69
+ a two dimensional numpy array of shape (3, N) with llh coordinates
70
+ """
71
+ coordinates = np.asarray(coordinates)
72
+ if coordinates.shape[0] != 3:
73
+ raise RuntimeError(f"Coordinates has wrong shape: {coordinates.shape} not in (3,), (3, 1) or (3, N)")
74
+
75
+ if coordinates.ndim == 1:
76
+ coordinates = coordinates.copy()
77
+ coordinates.shape = (3, 1)
78
+
79
+ x = coordinates[0, :]
80
+ y = coordinates[1, :]
81
+ z = coordinates[2, :]
82
+
83
+ lon = np.arctan2(y, x)
84
+
85
+ k = np.maximum(np.absolute(x), np.absolute(y))
86
+ k[np.where(k == 0)] = 1.0
87
+
88
+ c1 = x / k
89
+ c2 = y / k
90
+
91
+ r = k * np.sqrt(c1**2 + c2**2)
92
+
93
+ beta = np.arctan2(z, r * WGS84.semi_axes_ratio_min_max)
94
+ sin_beta, cos_beta = np.sin(beta), np.cos(beta)
95
+
96
+ lat = np.arctan2(
97
+ z + _A_MIN_TIMES_EP2 * sin_beta**3,
98
+ r - _A_MAX_SQUARE_MINUS_A_MIN_SQUARE_DIVIDED_BY_A_MAX * cos_beta**3,
99
+ )
100
+ beta_new = np.arctan2(WGS84.semi_axes_ratio_min_max * np.sin(lat), np.cos(lat))
101
+
102
+ for _ in range(_NUMBER_OF_ITERATIONS):
103
+ if np.array_equal(beta, beta_new):
104
+ break
105
+
106
+ beta = beta_new
107
+ sin_beta, cos_beta = np.sin(beta), np.cos(beta)
108
+
109
+ lat = np.arctan2(
110
+ z + _A_MIN_TIMES_EP2 * sin_beta**3,
111
+ r - _A_MAX_SQUARE_MINUS_A_MIN_SQUARE_DIVIDED_BY_A_MAX * cos_beta**3,
112
+ )
113
+ beta_new = np.arctan2(WGS84.semi_axes_ratio_min_max * np.sin(lat), np.cos(lat))
114
+
115
+ # Compute height
116
+ sin_phi = np.sin(lat)
117
+ big_n = WGS84.semi_major_axis / np.sqrt(1 - sin_phi**2 * WGS84.eccentricity_square)
118
+ h = r * np.cos(lat) + (z + WGS84.eccentricity_square * big_n * sin_phi) * sin_phi - big_n
119
+
120
+ return np.vstack((lat, lon, h)).astype(float)
@@ -0,0 +1,344 @@
1
+ # SPDX-FileCopyrightText: Aresys S.r.l. <info@aresys.it>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ Curve classes implementation of curve protocols
6
+ -----------------------------------------------
7
+ """
8
+
9
+ from typing import Tuple, Union
10
+
11
+ import numpy as np
12
+ import numpy.typing as npt
13
+ from scipy.interpolate import CubicSpline
14
+
15
+ from arepytools.geometry.curve_protocols import RealTwiceDifferentiableFunction
16
+ from arepytools.timing.precisedatetime import PreciseDateTime
17
+
18
+
19
+ class InterpolationOutOfBoundaries(ValueError):
20
+ """Could not perform interpolation on input value because it's out of validity boundaries"""
21
+
22
+
23
+ class InvertedTimeBoundaries(RuntimeError):
24
+ """Inverted time boundaries provided for interpolator domain definition"""
25
+
26
+
27
+ class PolynomialWrapper:
28
+ """Polynomial Wrapper implementation"""
29
+
30
+ def __init__(self, coeff: npt.ArrayLike) -> None:
31
+ """Polynomial wrapper inputs.
32
+
33
+ Polynomial in the form:
34
+
35
+ .. math::
36
+
37
+ a_{n}\\cdot x^{n} + a_{n-1}\\cdot x^{n-1} + ... + a_2\\cdot x^2 + a_1\\cdot x + a_0
38
+
39
+ Parameters
40
+ ----------
41
+ coeff : npt.ArrayLike
42
+ polynomial coefficients to build the polynomial interpolator,
43
+ coefficients must be provided from the highers order to the lower
44
+ the last coefficient is the constant term
45
+ """
46
+ self.poly_coefficients: np.ndarray = np.asarray(coeff)
47
+
48
+ def evaluate(self, coords: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
49
+ """Evaluating the input polynomial at the specified variable values.
50
+
51
+ Polynomial in the form:
52
+
53
+ .. math::
54
+
55
+ a_{n}\\cdot x^{n} + a_{n-1}\\cdot x^{n-1} + ... + a_2\\cdot x^2 + a_1\\cdot x + a_0
56
+
57
+ Parameters
58
+ ----------
59
+ coords : Union[float, npt.ArrayLike]
60
+ values of the variable at which evaluate the polynomial
61
+
62
+ Returns
63
+ -------
64
+ Union[float, npt.ArrayLike]
65
+ polynomial computed at each input variable value
66
+ """
67
+
68
+ coords = np.asarray(coords).astype("float64")
69
+
70
+ # evaluating variable powers for each term of the polynomial at the input coordinate
71
+ variable_values = np.flip([coords**c for c in range(self.poly_coefficients.size)], axis=0)
72
+
73
+ return np.dot(self.poly_coefficients, variable_values)
74
+
75
+ def evaluate_first_derivative(self, coords: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
76
+ """Evaluating the input polynomial first derivative at the specified variable values.
77
+ Polynomial derivative in the form:
78
+
79
+ .. math::
80
+
81
+ n\\cdot a_{n}\\cdot x^{n-1} + (n-1)\\cdot a_{n-1}\\cdot x^{n-2} + ... + 2\\cdot a_2\\cdot x + a_1
82
+
83
+ Parameters
84
+ ----------
85
+ coords : Union[float, npt.ArrayLike]
86
+ values of the variable at which evaluate the polynomial
87
+
88
+ Returns
89
+ -------
90
+ Union[float, npt.ArrayLike]
91
+ polynomial derivative computed at each input variable value
92
+ """
93
+
94
+ coords = np.asarray(coords).astype("float64")
95
+ # evaluating the derivative polynomial n-coefficients: n*a^(n-1)
96
+ poly_der_coeff = np.flip(range(1, self.poly_coefficients.size))
97
+ coeff = self.poly_coefficients[:-1]
98
+ # multiplying each polynomial variable term by its coefficient
99
+ variable_values = np.flip([coords**c for c in range(self.poly_coefficients.size - 1)], axis=0)
100
+
101
+ # multiplying each polynomial variable term by its derivative coefficient and the polynomial coefficient
102
+ return np.dot(poly_der_coeff * coeff, variable_values)
103
+
104
+ def evaluate_second_derivative(self, coords: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
105
+ """Evaluating the input polynomial second derivative at the specified variable values.
106
+
107
+ Polynomial derivative in the form:
108
+
109
+ .. math::
110
+
111
+ n\\cdot (n-1)\\cdot a_{n}\\cdot x^{n-2} + (n-1)\\cdot (n-2)\\cdot a_{n-1}\\cdot x^{n-3} + ... + 2\\cdot a_2
112
+
113
+ Parameters
114
+ ----------
115
+ coords : Union[float, npt.ArrayLike]
116
+ values of the variable at which evaluate the polynomial
117
+
118
+ Returns
119
+ -------
120
+ Union[float, npt.ArrayLike]
121
+ polynomial derivative computed at each input variable value
122
+ """
123
+
124
+ coords = np.asarray(coords).astype("float64")
125
+ # evaluating the derivative polynomial n-coefficients: n*a^(n-1)
126
+ poly_der_coeff = np.flip(range(2, self.poly_coefficients.size))
127
+ # evaluating the derivative polynomial n-coefficients: n-1*a^(n-2)
128
+ poly_der2_coeff = np.flip(range(1, self.poly_coefficients.size - 1))
129
+ coeff = self.poly_coefficients[:-2]
130
+
131
+ # multiplying each polynomial variable term by its coefficient
132
+ # evaluating variable powers for each term of the polynomial evaluated in the point provided
133
+ variable_values = np.flip([coords**c for c in range(self.poly_coefficients.size - 2)], axis=0)
134
+
135
+ # evaluating variable powers for each term of the polynomial evaluated in the point provided
136
+ # multiplying each polynomial variable term by its derivative coefficient and the polynomial coefficient
137
+ return np.dot(poly_der_coeff * poly_der2_coeff * coeff, variable_values)
138
+
139
+
140
+ class SplineWrapper:
141
+ """Spline wrapper implementation"""
142
+
143
+ def __init__(self, axis: npt.ArrayLike, values: npt.ArrayLike) -> None:
144
+ """Spline wrapper inputs.
145
+
146
+ Parameters
147
+ ----------
148
+ axis : npt.ArrayLike
149
+ axis array to build the spline interpolator
150
+ values : npt.ArrayLike
151
+ values of the spline at each point of the axis to build the spline interpolator
152
+ """
153
+ self.spline_interpolator = CubicSpline(np.asarray(axis), np.asarray(values))
154
+
155
+ def evaluate(self, coords: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
156
+ """Evaluating the interpolated spline at the specified variable values.
157
+
158
+ Parameters
159
+ ----------
160
+ coords : Union[float, npt.ArrayLike]
161
+ values of the variable at which evaluate the spline
162
+
163
+ Returns
164
+ -------
165
+ Union[float, npt.ArrayLike]
166
+ spline computed at each input variable value
167
+ """
168
+ coords = np.asarray(coords).astype("float64")
169
+
170
+ return self.spline_interpolator(coords, 0, extrapolate=False)
171
+
172
+ def evaluate_first_derivative(self, coords: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
173
+ """Evaluating the interpolated spline first derivative at the specified variable values.
174
+
175
+ Parameters
176
+ ----------
177
+ coords : Union[float, npt.ArrayLike]
178
+ values of the variable at which evaluate the spline first derivative
179
+
180
+ Returns
181
+ -------
182
+ Union[float, npt.ArrayLike]
183
+ first derivative of interpolated spline computed at each input variable value
184
+ """
185
+ coords = np.asarray(coords).astype("float64")
186
+
187
+ return self.spline_interpolator(coords, 1, extrapolate=False)
188
+
189
+ def evaluate_second_derivative(self, coords: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
190
+ """Evaluating the interpolated spline second derivative at the specified variable values.
191
+
192
+ Parameters
193
+ ----------
194
+ coords : Union[float, npt.ArrayLike]
195
+ values of the variable at which evaluate the spline second derivative
196
+
197
+ Returns
198
+ -------
199
+ Union[float, npt.ArrayLike]
200
+ second derivative of interpolated spline computed at each input variable value
201
+ """
202
+ coords = np.asarray(coords).astype("float64")
203
+
204
+ return self.spline_interpolator(coords, 2, extrapolate=False)
205
+
206
+
207
+ class Generic3DCurve:
208
+ """Implementation of a generic 3D curve from twice differentiable functions"""
209
+
210
+ def __init__(
211
+ self,
212
+ x_func: RealTwiceDifferentiableFunction,
213
+ y_func: RealTwiceDifferentiableFunction,
214
+ z_func: RealTwiceDifferentiableFunction,
215
+ t_ref: PreciseDateTime,
216
+ time_boundaries: Tuple[PreciseDateTime, PreciseDateTime],
217
+ ) -> None:
218
+ """Generic twice differentiable 3D curve with a given domain of existence/interpolation.
219
+ Must not extrapolate values outside of boundaries.
220
+
221
+ Parameters
222
+ ----------
223
+ x_func : RealTwiceDifferentiableFunction
224
+ twice differentiable function defining the curve behaviour along x, time definition is relative to t_ref
225
+ y_func : RealTwiceDifferentiableFunction
226
+ twice differentiable function defining the curve behaviour along y, time definition is relative to t_ref
227
+ z_func : RealTwiceDifferentiableFunction
228
+ twice differentiable function defining the curve behaviour along z, time definition is relative to t_ref
229
+ t_ref : PreciseDateTime
230
+ reference time of the 3D curve, aka the lower boundary of the maximum domain of definition
231
+ time_boundaries : tuple[PreciseDateTime, PreciseDateTime]
232
+ time boundaries of curve validity (domain)
233
+ """
234
+ self.x_func = x_func
235
+ self.y_func = y_func
236
+ self.z_func = z_func
237
+ self.time_ref = t_ref
238
+ # evaluating relative time boundaries
239
+ self.time_boundaries = tuple(t - t_ref for t in time_boundaries)
240
+ if not self.time_boundaries[1] > self.time_boundaries[0]:
241
+ raise InvertedTimeBoundaries("Wrong time boundaries order")
242
+
243
+ def evaluate(self, coordinates: Union[PreciseDateTime, npt.ArrayLike]) -> np.ndarray:
244
+ """Evaluate x, y, z polynomial at given times.
245
+
246
+ Parameters
247
+ ----------
248
+ coordinates : Union[PreciseDateTime, npt.ArrayLike]
249
+ time points
250
+
251
+ Returns
252
+ -------
253
+ np.ndarray
254
+ values of the polynomials at given input times (N, 3)
255
+ """
256
+
257
+ # computing relative times
258
+ times = np.asarray(coordinates)
259
+ times = times - self.time_ref
260
+ self._check_time_validity(relative_times=times)
261
+
262
+ # evaluating polynomials at given times
263
+ return np.stack(
264
+ [
265
+ self.x_func.evaluate(times),
266
+ self.y_func.evaluate(times),
267
+ self.z_func.evaluate(times),
268
+ ],
269
+ axis=-1,
270
+ )
271
+
272
+ def evaluate_first_derivatives(self, coordinates: Union[PreciseDateTime, npt.ArrayLike]) -> np.ndarray:
273
+ """Evaluate x, y, z polynomial first derivatives at given times.
274
+
275
+ Parameters
276
+ ----------
277
+ coordinates : Union[PreciseDateTime, npt.ArrayLike]
278
+ time points
279
+
280
+ Returns
281
+ -------
282
+ np.ndarray
283
+ values of the polynomials first derivatives at given input times (N, 3)
284
+ """
285
+
286
+ # computing relative times
287
+ times = np.asarray(coordinates)
288
+ times = times - self.time_ref
289
+ self._check_time_validity(relative_times=times)
290
+
291
+ # evaluating polynomials at given times
292
+ return np.stack(
293
+ [
294
+ self.x_func.evaluate_first_derivative(times),
295
+ self.y_func.evaluate_first_derivative(times),
296
+ self.z_func.evaluate_first_derivative(times),
297
+ ],
298
+ axis=-1,
299
+ )
300
+
301
+ def evaluate_second_derivatives(self, coordinates: Union[PreciseDateTime, npt.ArrayLike]) -> np.ndarray:
302
+ """Evaluate x, y, z polynomial second derivatives at given times.
303
+
304
+ Parameters
305
+ ----------
306
+ coordinates : Union[PreciseDateTime, npt.ArrayLike]
307
+ time points
308
+
309
+ Returns
310
+ -------
311
+ np.ndarray
312
+ values of the polynomials second derivatives at given input times (N, 3)
313
+ """
314
+
315
+ # computing relative times
316
+ times = np.asarray(coordinates)
317
+ times = times - self.time_ref
318
+ self._check_time_validity(relative_times=times)
319
+
320
+ # evaluating polynomials at given times
321
+ return np.stack(
322
+ [
323
+ self.x_func.evaluate_second_derivative(times),
324
+ self.y_func.evaluate_second_derivative(times),
325
+ self.z_func.evaluate_second_derivative(times),
326
+ ],
327
+ axis=-1,
328
+ )
329
+
330
+ def _check_time_validity(self, relative_times: Union[float, npt.ArrayLike]) -> None:
331
+ """Check input times validity with respect to the time validity boundaries.
332
+
333
+ Parameters
334
+ ----------
335
+ relative_times : Union[float, npt.ArrayLike]
336
+ relative time points at which evaluate the polynomial
337
+
338
+ Raises
339
+ ------
340
+ PolynomialInterpolationOutOfBoundaries
341
+ if relative time is out of validity boundaries this error is raised (interpolation cannot be performed)
342
+ """
343
+ if ~np.any((relative_times > self.time_boundaries[0]) & (relative_times < self.time_boundaries[1])):
344
+ raise InterpolationOutOfBoundaries("Interpolation failed. Times are outside domain")
@@ -0,0 +1,113 @@
1
+ # SPDX-FileCopyrightText: Aresys S.r.l. <info@aresys.it>
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ """
5
+ Curve protocols definition
6
+ --------------------------
7
+ """
8
+
9
+ from typing import Any, Protocol, Union, runtime_checkable
10
+
11
+ import numpy as np
12
+ import numpy.typing as npt
13
+
14
+ from arepytools.timing.precisedatetime import PreciseDateTime
15
+
16
+
17
+ @runtime_checkable
18
+ class TwiceDifferentiable3DCurve(Protocol):
19
+ """Custom 3D curve container with evaluation method for curve and first two derivatives.
20
+ f: R | PreciseDateTime -> R^3"""
21
+
22
+ @property
23
+ def domain(self) -> tuple[Any, Any]:
24
+ """Curve domain boundaries, min and max values"""
25
+
26
+ def evaluate(self, coordinates: Union[PreciseDateTime, float, npt.ArrayLike]) -> np.ndarray:
27
+ """Evaluate curve value at given input coordinates.
28
+
29
+ Parameters
30
+ ----------
31
+ coordinates : Union[PreciseDateTime, float, npt.ArrayLike]
32
+ coordinates (PreciseDateTime) or float where to evaluate the curve
33
+
34
+ Returns
35
+ -------
36
+ np.ndarray
37
+ values of the curve at given input values (N, 3)
38
+ """
39
+
40
+ def evaluate_first_derivatives(self, coordinates: Union[PreciseDateTime, float, npt.ArrayLike]) -> np.ndarray:
41
+ """Evaluate curve first derivatives values at given input coordinates.
42
+
43
+ Parameters
44
+ ----------
45
+ coordinates : Union[PreciseDateTime, float, npt.ArrayLike]
46
+ coordinates (PreciseDateTime) or float where to evaluate the derivatives
47
+
48
+ Returns
49
+ -------
50
+ np.ndarray
51
+ values of the curve derivatives at given input values (N, 3)
52
+ """
53
+
54
+ def evaluate_second_derivatives(self, coordinates: Union[PreciseDateTime, float, npt.ArrayLike]) -> np.ndarray:
55
+ """Evaluate curve second derivatives values at given input coordinates.
56
+
57
+ Parameters
58
+ ----------
59
+ coordinates : Union[PreciseDateTime, float, npt.ArrayLike]
60
+ coordinates (PreciseDateTime) or float where to evaluate the derivatives
61
+
62
+ Returns
63
+ -------
64
+ np.ndarray
65
+ values of the polynomials second derivatives at given input times (N, 3)
66
+ """
67
+
68
+
69
+ @runtime_checkable
70
+ class RealTwiceDifferentiableFunction(Protocol):
71
+ """Generic protocol for a f: R -> R function twice differentiable with derivative evaluation methods implemented"""
72
+
73
+ def evaluate(self, coordinates: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
74
+ """Evaluate function value at given coordinates.
75
+
76
+ Parameters
77
+ ----------
78
+ coordinates : Union[float, npt.ArrayLike]
79
+ input coordinates where to evaluate the function
80
+
81
+ Returns
82
+ -------
83
+ Union[float, npt.ArrayLike]
84
+ value of function at each input coordinate
85
+ """
86
+
87
+ def evaluate_first_derivative(self, coordinates: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
88
+ """Evaluate function first derivative at given coordinates.
89
+
90
+ Parameters
91
+ ----------
92
+ coordinates : Union[float, npt.ArrayLike]
93
+ input coordinates where to evaluate the function derivative
94
+
95
+ Returns
96
+ -------
97
+ Union[float, npt.ArrayLike]
98
+ values of function first derivative at each input coordinate
99
+ """
100
+
101
+ def evaluate_second_derivative(self, coordinates: Union[float, npt.ArrayLike]) -> Union[float, npt.ArrayLike]:
102
+ """Evaluate function second derivative at given coordinates.
103
+
104
+ Parameters
105
+ ----------
106
+ coordinates : Union[float, npt.ArrayLike]
107
+ input coordinates where to evaluate the function derivative
108
+
109
+ Returns
110
+ -------
111
+ Union[float, npt.ArrayLike]
112
+ values of function second derivative at each input coordinate
113
+ """