GeographicLib
2.7
Toggle main menu visibility
Loading...
Searching...
No Matches
SphericalHarmonic.hpp
Go to the documentation of this file.
1
/**
2
* \file SphericalHarmonic.hpp
3
* \brief Header for GeographicLib::SphericalHarmonic class
4
*
5
* Copyright (c) Charles Karney (2011-2019) <karney@alum.mit.edu> and licensed
6
* under the MIT/X11 License. For more information, see
7
* https://geographiclib.sourceforge.io/
8
**********************************************************************/
9
10
#if !defined(GEOGRAPHICLIB_SPHERICALHARMONIC_HPP)
11
#define GEOGRAPHICLIB_SPHERICALHARMONIC_HPP 1
12
13
#include <vector>
14
#include <
GeographicLib/Constants.hpp
>
15
#include <
GeographicLib/SphericalEngine.hpp
>
16
#include <
GeographicLib/CircularEngine.hpp
>
17
18
namespace
GeographicLib
{
19
20
/**
21
* \brief Spherical harmonic series
22
*
23
* This class evaluates the spherical harmonic sum \verbatim
24
V(x, y, z) = sum(n = 0..N)[ q^(n+1) * sum(m = 0..n)[
25
(C[n,m] * cos(m*lambda) + S[n,m] * sin(m*lambda)) *
26
P[n,m](cos(theta)) ] ]
27
\endverbatim
28
* where
29
* - <i>p</i><sup>2</sup> = <i>x</i><sup>2</sup> + <i>y</i><sup>2</sup>,
30
* - <i>r</i><sup>2</sup> = <i>p</i><sup>2</sup> + <i>z</i><sup>2</sup>,
31
* - \e q = <i>a</i>/<i>r</i>,
32
* - θ = atan2(\e p, \e z) = the spherical \e colatitude,
33
* - λ = atan2(\e y, \e x) = the longitude.
34
* - P<sub><i>nm</i></sub>(\e t) is the associated Legendre polynomial of
35
* degree \e n and order \e m.
36
*
37
* Two normalizations are supported for P<sub><i>nm</i></sub>
38
* - fully normalized denoted by SphericalHarmonic::FULL.
39
* - Schmidt semi-normalized denoted by SphericalHarmonic::SCHMIDT.
40
*
41
* Clenshaw summation is used for the sums over both \e n and \e m. This
42
* allows the computation to be carried out without the need for any
43
* temporary arrays. See SphericalEngine.cpp for more information on the
44
* implementation.
45
*
46
* References:
47
* - C. W. Clenshaw,
48
* <a href="https://doi.org/10.1090/S0025-5718-1955-0071856-0">
49
* A note on the summation of Chebyshev series</a>,
50
* %Math. Tables Aids Comput. 9(51), 118--120 (1955).
51
* - R. E. Deakin, Derivatives of the earth's potentials, Geomatics
52
* Research Australasia 68, 31--60, (June 1998).
53
* - W. A. Heiskanen and H. Moritz, Physical Geodesy, (Freeman, San
54
* Francisco, 1967).
55
* https://archive.org/details/HeiskanenMoritz1967PhysicalGeodesy
56
* (See Sec. 1-14, for a definition of Pbar.)
57
* - S. A. Holmes and W. E. Featherstone,
58
* <a href="https://doi.org/10.1007/s00190-002-0216-2">
59
* A unified approach to the Clenshaw summation and the recursive
60
* computation of very high degree and order normalised associated Legendre
61
* functions</a>, J. Geodesy 76(5), 279--299 (2002).
62
* - C. C. Tscherning and K. Poder,
63
* <a href="http://cct.gfy.ku.dk/publ_cct/cct80.pdf">
64
* Some geodetic applications of Clenshaw summation</a>,
65
* Boll. Geod. Sci. Aff. 41(4), 349--375 (1982).
66
*
67
* Example of use:
68
* \include example-SphericalHarmonic.cpp
69
**********************************************************************/
70
71
class
GEOGRAPHICLIB_EXPORT
SphericalHarmonic
{
72
public
:
73
/**
74
* Supported normalizations for the associated Legendre polynomials.
75
**********************************************************************/
76
enum
normalization
{
77
/**
78
* Fully normalized associated Legendre polynomials.
79
*
80
* These are defined by
81
* <i>P</i><sub><i>nm</i></sub><sup>full</sup>(\e z)
82
* = (−1)<sup><i>m</i></sup>
83
* sqrt(\e k (2\e n + 1) (\e n − \e m)! / (\e n + \e m)!)
84
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), where
85
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers
86
* function (also known as the Legendre function on the cut or the
87
* associated Legendre polynomial) https://dlmf.nist.gov/14.7.E10 and
88
* \e k = 1 for \e m = 0 and \e k = 2 otherwise.
89
*
90
* The mean squared value of
91
* <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cosθ)
92
* cos(<i>m</i>λ) and
93
* <i>P</i><sub><i>nm</i></sub><sup>full</sup>(cosθ)
94
* sin(<i>m</i>λ) over the sphere is 1.
95
*
96
* @hideinitializer
97
**********************************************************************/
98
FULL
=
SphericalEngine::FULL
,
99
/**
100
* Schmidt semi-normalized associated Legendre polynomials.
101
*
102
* These are defined by
103
* <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(\e z)
104
* = (−1)<sup><i>m</i></sup>
105
* sqrt(\e k (\e n − \e m)! / (\e n + \e m)!)
106
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z), where
107
* <b>P</b><sub><i>n</i></sub><sup><i>m</i></sup>(\e z) is Ferrers
108
* function (also known as the Legendre function on the cut or the
109
* associated Legendre polynomial) https://dlmf.nist.gov/14.7.E10 and
110
* \e k = 1 for \e m = 0 and \e k = 2 otherwise.
111
*
112
* The mean squared value of
113
* <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cosθ)
114
* cos(<i>m</i>λ) and
115
* <i>P</i><sub><i>nm</i></sub><sup>schmidt</sup>(cosθ)
116
* sin(<i>m</i>λ) over the sphere is 1/(2\e n + 1).
117
*
118
* @hideinitializer
119
**********************************************************************/
120
SCHMIDT
=
SphericalEngine::SCHMIDT
,
121
};
122
123
private
:
124
typedef
Math::real
real
;
125
SphericalEngine::coeff
_c[1];
126
real
_a;
127
unsigned
_norm;
128
129
public
:
130
/**
131
* Constructor with a full set of coefficients specified.
132
*
133
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
134
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
135
* @param[in] N the maximum degree and order of the sum
136
* @param[in] a the reference radius appearing in the definition of the
137
* sum.
138
* @param[in] norm the normalization for the associated Legendre
139
* polynomials, either SphericalHarmonic::FULL (the default) or
140
* SphericalHarmonic::SCHMIDT.
141
* @exception GeographicErr if \e N does not satisfy \e N ≥ −1.
142
* @exception GeographicErr if \e C or \e S is not big enough to hold the
143
* coefficients.
144
*
145
* The coefficients <i>C</i><sub><i>nm</i></sub> and
146
* <i>S</i><sub><i>nm</i></sub> are stored in the one-dimensional vectors
147
* \e C and \e S which must contain (\e N + 1)(\e N + 2)/2 and \e N (\e N +
148
* 1)/2 elements, respectively, stored in "column-major" order. Thus for
149
* \e N = 3, the order would be:
150
* <i>C</i><sub>00</sub>,
151
* <i>C</i><sub>10</sub>,
152
* <i>C</i><sub>20</sub>,
153
* <i>C</i><sub>30</sub>,
154
* <i>C</i><sub>11</sub>,
155
* <i>C</i><sub>21</sub>,
156
* <i>C</i><sub>31</sub>,
157
* <i>C</i><sub>22</sub>,
158
* <i>C</i><sub>32</sub>,
159
* <i>C</i><sub>33</sub>.
160
* In general the (\e n,\e m) element is at index \e m \e N − \e m
161
* (\e m − 1)/2 + \e n. The layout of \e S is the same except that
162
* the first column is omitted (since the \e m = 0 terms never contribute
163
* to the sum) and the 0th element is <i>S</i><sub>11</sub>
164
*
165
* The class stores <i>pointers</i> to the first elements of \e C and \e S.
166
* These arrays should not be altered or destroyed during the lifetime of a
167
* SphericalHarmonic object.
168
**********************************************************************/
169
SphericalHarmonic
(
const
std::vector<real>& C,
170
const
std::vector<real>& S,
171
int
N, real a,
unsigned
norm =
FULL
)
172
: _a(a)
173
, _norm(norm)
174
{ _c[0] =
SphericalEngine::coeff
(C, S, N); }
175
176
/**
177
* Constructor with a subset of coefficients specified.
178
*
179
* @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
180
* @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
181
* @param[in] N the degree used to determine the layout of \e C and \e S.
182
* @param[in] nmx the maximum degree used in the sum. The sum over \e n is
183
* from 0 thru \e nmx.
184
* @param[in] mmx the maximum order used in the sum. The sum over \e m is
185
* from 0 thru min(\e n, \e mmx).
186
* @param[in] a the reference radius appearing in the definition of the
187
* sum.
188
* @param[in] norm the normalization for the associated Legendre
189
* polynomials, either SphericalHarmonic::FULL (the default) or
190
* SphericalHarmonic::SCHMIDT.
191
* @exception GeographicErr if \e N, \e nmx, and \e mmx do not satisfy
192
* \e N ≥ \e nmx ≥ \e mmx ≥ −1.
193
* @exception GeographicErr if \e C or \e S is not big enough to hold the
194
* coefficients.
195
*
196
* The class stores <i>pointers</i> to the first elements of \e C and \e S.
197
* These arrays should not be altered or destroyed during the lifetime of a
198
* SphericalHarmonic object.
199
**********************************************************************/
200
SphericalHarmonic
(
const
std::vector<real>& C,
201
const
std::vector<real>& S,
202
int
N,
int
nmx,
int
mmx,
203
real a,
unsigned
norm =
FULL
)
204
: _a(a)
205
, _norm(norm)
206
{ _c[0] =
SphericalEngine::coeff
(C, S, N, nmx, mmx); }
207
208
/**
209
* A default constructor so that the object can be created when the
210
* constructor for another object is initialized. This default object can
211
* then be reset with the default copy assignment operator.
212
**********************************************************************/
213
SphericalHarmonic
() {}
214
215
/**
216
* Compute the spherical harmonic sum.
217
*
218
* @param[in] x cartesian coordinate.
219
* @param[in] y cartesian coordinate.
220
* @param[in] z cartesian coordinate.
221
* @return \e V the spherical harmonic sum.
222
*
223
* This routine requires constant memory and thus never throws an
224
* exception.
225
**********************************************************************/
226
Math::real
operator()
(real x, real y, real z)
const
{
227
real f[] = {1};
228
real v = 0;
229
real dummy;
230
switch
(_norm) {
231
case
FULL
:
232
v =
SphericalEngine::Value<false, SphericalEngine::FULL, 1>
233
(_c, f, x, y, z, _a, dummy, dummy, dummy);
234
break
;
235
case
SCHMIDT
:
236
default
:
// To avoid compiler warnings
237
v =
SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 1>
238
(_c, f, x, y, z, _a, dummy, dummy, dummy);
239
break
;
240
}
241
return
v;
242
}
243
244
/**
245
* Compute a spherical harmonic sum and its gradient.
246
*
247
* @param[in] x cartesian coordinate.
248
* @param[in] y cartesian coordinate.
249
* @param[in] z cartesian coordinate.
250
* @param[out] gradx \e x component of the gradient
251
* @param[out] grady \e y component of the gradient
252
* @param[out] gradz \e z component of the gradient
253
* @return \e V the spherical harmonic sum.
254
*
255
* This is the same as the previous function, except that the components of
256
* the gradients of the sum in the \e x, \e y, and \e z directions are
257
* computed. This routine requires constant memory and thus never throws
258
* an exception.
259
**********************************************************************/
260
Math::real
operator()
(real x, real y, real z,
261
real& gradx, real& grady, real& gradz)
const
{
262
real f[] = {1};
263
real v = 0;
264
switch
(_norm) {
265
case
FULL
:
266
v =
SphericalEngine::Value<true, SphericalEngine::FULL, 1>
267
(_c, f, x, y, z, _a, gradx, grady, gradz);
268
break
;
269
case
SCHMIDT
:
270
default
:
// To avoid compiler warnings
271
v =
SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 1>
272
(_c, f, x, y, z, _a, gradx, grady, gradz);
273
break
;
274
}
275
return
v;
276
}
277
278
/**
279
* Create a CircularEngine to allow the efficient evaluation of several
280
* points on a circle of latitude.
281
*
282
* @param[in] p the radius of the circle.
283
* @param[in] z the height of the circle above the equatorial plane.
284
* @param[in] gradp if true the returned object will be able to compute the
285
* gradient of the sum.
286
* @exception std::bad_alloc if the memory for the CircularEngine can't be
287
* allocated.
288
* @return the CircularEngine object.
289
*
290
* SphericalHarmonic::operator()() exchanges the order of the sums in the
291
* definition, i.e., ∑<sub><i>n</i> = 0..<i>N</i></sub>
292
* ∑<sub><i>m</i> = 0..<i>n</i></sub> becomes ∑<sub><i>m</i> =
293
* 0..<i>N</i></sub> ∑<sub><i>n</i> = <i>m</i>..<i>N</i></sub>.
294
* SphericalHarmonic::Circle performs the inner sum over degree \e n (which
295
* entails about <i>N</i><sup>2</sup> operations). Calling
296
* CircularEngine::operator()() on the returned object performs the outer
297
* sum over the order \e m (about \e N operations).
298
*
299
* Here's an example of computing the spherical sum at a sequence of
300
* longitudes without using a CircularEngine object \code
301
SphericalHarmonic h(...); // Create the SphericalHarmonic object
302
double r = 2, lat = 33, lon0 = 44, dlon = 0.01;
303
double
304
phi = lat * Math::degree<double>(),
305
z = r * sin(phi), p = r * cos(phi);
306
for (int i = 0; i <= 100; ++i) {
307
real
308
lon = lon0 + i * dlon,
309
lam = lon * Math::degree<double>();
310
std::cout << lon << " " << h(p * cos(lam), p * sin(lam), z) << "\n";
311
}
312
\endcode
313
* Here is the same calculation done using a CircularEngine object. This
314
* will be about <i>N</i>/2 times faster. \code
315
SphericalHarmonic h(...); // Create the SphericalHarmonic object
316
double r = 2, lat = 33, lon0 = 44, dlon = 0.01;
317
double
318
phi = lat * Math::degree<double>(),
319
z = r * sin(phi), p = r * cos(phi);
320
CircularEngine c(h(p, z, false)); // Create the CircularEngine object
321
for (int i = 0; i <= 100; ++i) {
322
real
323
lon = lon0 + i * dlon;
324
std::cout << lon << " " << c(lon) << "\n";
325
}
326
\endcode
327
**********************************************************************/
328
CircularEngine
Circle
(real p, real z,
bool
gradp)
const
{
329
real f[] = {1};
330
switch
(_norm) {
331
case
FULL
:
332
return
gradp ?
333
SphericalEngine::Circle<true, SphericalEngine::FULL, 1>
334
(_c, f, p, z, _a) :
335
SphericalEngine::Circle<false, SphericalEngine::FULL, 1>
336
(_c, f, p, z, _a);
337
break
;
338
case
SCHMIDT
:
339
default
:
// To avoid compiler warnings
340
return
gradp ?
341
SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 1>
342
(_c, f, p, z, _a) :
343
SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 1>
344
(_c, f, p, z, _a);
345
break
;
346
}
347
}
348
349
/**
350
* @return the zeroth SphericalEngine::coeff object.
351
**********************************************************************/
352
const
SphericalEngine::coeff
&
Coefficients
()
const
353
{
return
_c[0]; }
354
};
355
356
}
// namespace GeographicLib
357
358
#endif
// GEOGRAPHICLIB_SPHERICALHARMONIC_HPP
CircularEngine.hpp
Header for GeographicLib::CircularEngine class.
Constants.hpp
Header for GeographicLib::Constants class.
GEOGRAPHICLIB_EXPORT
#define GEOGRAPHICLIB_EXPORT
Definition
Constants.hpp:59
real
GeographicLib::Math::real real
Definition
Geod3Solve.cpp:25
SphericalEngine.hpp
Header for GeographicLib::SphericalEngine class.
GeographicLib::CircularEngine
Spherical harmonic sums for a circle.
Definition
CircularEngine.hpp:52
GeographicLib::Math::real
double real
Definition
Math.hpp:115
GeographicLib::SphericalEngine::coeff
Package up coefficients for SphericalEngine.
Definition
SphericalEngine.hpp:99
GeographicLib::SphericalEngine::Value
static Math::real Value(const coeff c[], const real f[], real x, real y, real z, real a, real &gradx, real &grady, real &gradz)
Definition
SphericalEngine.cpp:152
GeographicLib::SphericalEngine::SCHMIDT
@ SCHMIDT
Definition
SphericalEngine.hpp:84
GeographicLib::SphericalEngine::FULL
@ FULL
Definition
SphericalEngine.hpp:77
GeographicLib::SphericalEngine::Circle
static CircularEngine Circle(const coeff c[], const real f[], real p, real z, real a)
Definition
SphericalEngine.cpp:296
GeographicLib::SphericalHarmonic::operator()
Math::real operator()(real x, real y, real z) const
Definition
SphericalHarmonic.hpp:226
GeographicLib::SphericalHarmonic::operator()
Math::real operator()(real x, real y, real z, real &gradx, real &grady, real &gradz) const
Definition
SphericalHarmonic.hpp:260
GeographicLib::SphericalHarmonic::SphericalHarmonic
SphericalHarmonic(const std::vector< real > &C, const std::vector< real > &S, int N, int nmx, int mmx, real a, unsigned norm=FULL)
Definition
SphericalHarmonic.hpp:200
GeographicLib::SphericalHarmonic::SphericalHarmonic
SphericalHarmonic()
Definition
SphericalHarmonic.hpp:213
GeographicLib::SphericalHarmonic::normalization
normalization
Definition
SphericalHarmonic.hpp:76
GeographicLib::SphericalHarmonic::SCHMIDT
@ SCHMIDT
Definition
SphericalHarmonic.hpp:120
GeographicLib::SphericalHarmonic::FULL
@ FULL
Definition
SphericalHarmonic.hpp:98
GeographicLib::SphericalHarmonic::Coefficients
const SphericalEngine::coeff & Coefficients() const
Definition
SphericalHarmonic.hpp:352
GeographicLib::SphericalHarmonic::Circle
CircularEngine Circle(real p, real z, bool gradp) const
Definition
SphericalHarmonic.hpp:328
GeographicLib::SphericalHarmonic::SphericalHarmonic
SphericalHarmonic(const std::vector< real > &C, const std::vector< real > &S, int N, real a, unsigned norm=FULL)
Definition
SphericalHarmonic.hpp:169
GeographicLib
Namespace for GeographicLib.
Definition
Accumulator.cpp:12
include
GeographicLib
SphericalHarmonic.hpp
Generated by
1.17.0