Loading...
Searching...
No Matches
spherical_harmonics.hpp
Go to the documentation of this file.
1
2#pragma once
3#include "grid/grid_types.hpp"
6
7namespace terra::shell {
8
9/// @brief Class providing methods for evaluation of Spherical Harmonics
10///
11/// @note If you are looking for unit-sphere **grids with interpolated spherical harmonics coefficients**, there are
12/// helper functions that perform the evaluation and copy the resulting fields to the device (Kokkos::Views)
13/// if required. See, e.g., \ref spherical_harmonics_coefficients_grid.
14///
15/// This class provides routines for the evaluation and calculation of
16/// spherical harmonics. It is a C++ adaptation of old TERRA routines.
18{
19 public:
20 using real_t = double;
21 using uint_t = unsigned int;
22
23 private:
24 template < typename T >
25 static real_t real_c( T t )
26 {
27 return static_cast< real_t >( t );
28 }
29
30 template < typename T >
31 static uint_t uint_c( T t )
32 {
33 return static_cast< uint_t >( t );
34 }
35
36 struct
37 {
38 real_t *f1, *f2, *fac1, *fac2, *srt;
39 } plm0_;
40
41 /// Remember, if we have initialized plmbar
42 bool initialized_;
43
44 /// Remember largest degree used in intialisation
45 uint_t maxDegree_;
46
47 /// Dynamic array for evaluating associated Legendre functions
48 // real_t* plm_;
49 real_t* plm_;
50
51 /// Dynamic array for evaluating associated Legendre functions derivatives
52 real_t* dplm_;
53
54 /// Dynamic array for evaluating sine/cosine parts of \f$Y_l^m\f$
55 real_t** csm_;
56
57 /// @brief Compute derivatives of associated Legendre functions
58 ///
59 /// The method evaluates the derivative \f$ dP_l^m(\cos(\theta)) / d\theta \f$
60 /// for all associated Legendre functions for given \f$\theta\f$ up to a
61 /// specified degree. The computation of the derivatives is based on the
62 /// identity
63 ///
64 /// \f[
65 /// 2\frac{d P_l^m}{d \theta}(\cos(\theta)) =
66 /// (l+m)(l-m+1)P_l^{m-1}(\cos(\theta)) - P_l^{m+1}(\cos(\theta))
67 /// \f]
68 ///
69 /// which holds for orders (m>0) and the un-normalised associated Legendre
70 /// functions. For details see <em>W. Bosch, On the Computation of
71 /// Derivatives of Legendre Functions, Phys. Chem. Earth (A), vol. 25,
72 /// no. 9-11, pp. 655-659, 2000</em>. Note that (A8) in that paper is missing
73 /// a \f$\sqrt{2}\f$ term.
74 ///
75 /// Implemented is a slightly modified version which holds for the associated
76 /// Legendre functions normalised in the Geodesy fashion. This version is
77 /// also described in Bosch (2000).
78 ///
79 /// \param dplm array for storing computed derivative values
80 /// \param plm array containing values of \f$P_l^m\cos(\theta)\f$,
81 /// implicitely defines co-latitude
82 /// \param lmax maximal degree of spherical harmonics
83 void dplmbar( real_t* dplm, real_t* plm, uint_t lmax );
84
85 /// Determine position of value of Legendre function in internal array
86 uint_t getArrayIndex( uint_t deg, uint_t ord )
87 {
88 int idx = 0;
89 for ( uint_t i = 0; i <= deg; ++i )
90 {
91 for ( uint_t j = 0; j <= i; ++j )
92 {
93 idx++;
94 if ( i == deg && j == ord )
95 goto loopEnd;
96 }
97 }
98 loopEnd:
99 // correct for 0-based indexing
100 idx--;
101 return idx;
102 }
103
104 public:
107
108 /// Evaluate scalar function described by spherical harmonics coefficients
109 /// at given cartesian coordinates. The point has to be on the sphere.
110 ///
111 /// \param sphdata Storing the data in sph format. Indices as follows:
112 /// @code
113 /// sphdata[kk][ir][ll][mm][cs]
114 /// kk: For vector data, kk=0..nk-1
115 /// ir: radial layer, counting outwards, 0..nr-1.
116 /// ll: Spherical harmonic coefficients, 0..lmax
117 /// mm: Spherical harmonic coefficients, 0..ll
118 /// cs: We need two coefficients, for the sine and for
119 /// the cosine, 0..1
120 /// @endcode
121 /// \param x x-coordinate of evaluation node
122 /// \param y y-coordinate of evaluation node
123 /// \param z z-coordinate of evaluation node
124 /// \param ir radial index in array sphdata
125 /// \param lmax largest spherical harmonics degree
126 /// \param kk index kk in array sphdata
127 real_t shconvert_eval( real_t***** sphdata, real_t x, real_t y, real_t z, uint_t ir, uint_t lmax, uint_t kk );
128
129 /// Evaluate a single spherical harmonics function of given degree and order
130
131 /// Evaluate a single spherical harmonics function of specified degree and
132 /// order (l,m) at given cartesian coordinates (x,y,z). For positive argument
133 /// ord we use the sine variant, otherwise the cosine variant.
134 ///
135 /// \param deg degree l
136 /// \param ord order m (also decides on sin/cos)
137 /// \param x x-coordinate of evaluation node
138 /// \param y y-coordinate of evaluation node
139 /// \param z z-coordinate of evaluation node
140 real_t shconvert_eval( uint_t deg, int ord, real_t x, real_t y, real_t z );
141
142 /// Evaluate scalar function described by spherical harmonics coefficients
143 /// at given cartesian coordinates. In this variant we perform linear
144 /// interpolation in radial direction between the different radial layers,
145 /// for which the spherical harmonics expansion was computed.
146 ///
147 /// \param sphdata Storing the data in sph format. Indices as follows:
148 /// @code
149 /// sphdata[kk][ir][ll][mm][cs]
150 /// kk: For vector data, kk=0..nk-1
151 /// ir: radial layer, counting outwards, 0..nr.
152 /// ll: Spherical harmonic coefficients, 0..lmax
153 /// mm: Spherical harmonic coefficients, 0..ll
154 /// cs: We need two coefficients, for the sine and for
155 /// the cosine, 0..1
156 /// @endcode
157 /// \param x x-coordinate of evaluation node
158 /// \param y y-coordinate of evaluation node
159 /// \param z z-coordinate of evaluation node
160 /// \param rmin radius of innermost shell of expansion
161 /// \param rmax radius of outermost shell of expansion
162 /// \param nr radial index in outermost shell in array sphdata
163 /// \param lmax largest spherical harmonics degree
164 /// \param kk index kk in array sphdata
166 real_t***** sphdata,
167 real_t x,
168 real_t y,
169 real_t z,
170 real_t rmin,
171 real_t rmax,
172 uint_t nr,
173 uint_t lmax,
174 uint_t kk );
175
176 /// Evaluate associated Legendre functions
177 ///
178 /// The subroutine evaluates all associated Legendre functions \f$ P_l^m \f$
179 /// of the 1st kind for a given argument up to a given degree l.
180 ///
181 /// #### Normalisation ####
182 /// Normalisation of the associated Legendre functions is done in the
183 /// following way:
184 /// - We do not include the Condon-Shortley phase \f$ (-1)^m \f$.
185 /// - We normalise such that the associated real-valued spherical harmonics
186 /// functions (trig being either sin or cos)
187 /// \f[
188 /// Y_l^m(\theta,\phi) = P_l^m(\cos(\theta)) \,\mbox{trig}\,(m \phi)
189 /// \f]
190 /// satisfy
191 /// \f[
192 /// \int_S Y_l^m(\theta,\phi)\cdot Y_l^m(\theta,\phi) = 4 \pi
193 /// \f]
194 /// Here \f$(\theta, \phi)\f$ represent colatitude and longitude. The
195 /// normalisation is the one preferred in Geodesy. The normalisation factor
196 /// in detail is given by
197 /// \f[
198 /// \sqrt{2-\delta_{0,m}}\sqrt{(2l+1)\frac{(l-m)!}{(l+m)!}}
199 /// \f]
200 ///
201 /// #### Algorithm ####
202 /// The computation of the associated Legendre functions employs the so called
203 /// <b>Forward Column Method</b>, see e.g. *Holmes & Featherstone, 2002, J. of
204 /// Geodesy*. This is based on the three-term recurrence relation
205 ///
206 /// \f[
207 /// (l-m)P_l^m(z) = z(2l-1)P_{l-1}^m(z) - (l+m-1)P_{l-2}^m(z)
208 /// \f]
209 ///
210 /// After computing \f$P_m^m\f$ and \f$P_{m+1}^m\f$ to initiate the recurrence
211 /// we compute \f$P_l^m\f$ by increasing l while keeping m fixed.
212 ///
213 /// #### Storage ####
214 /// - Dimension in the calling part of the program must be
215 /// p( (lmax+1)*(lmax+2)/2 ) and the same for array dp.
216 /// - p(k) contains p(l,m) with k=(l+1)*l/2+m+1; i.e. m increments through
217 /// range 0 to l before incrementing l.
218 ///
219 /// #### Original comments in Terra ####
220 /// > Routine is stable in single and real_t precision to l,m = 511 at least;
221 /// > timing is proportional to lmax**2 R.J.O'Connell 7 Sept. 1989;
222 /// > added dp(z) 10 Jan. 1990
223 /// > Added precalculation and storage of square roots srl(k) 31 Dec 1992
224 ///
225 /// \param p array for storing values \f$ P_l^m(z) \f$
226 /// \param lmax we evaluate all functions up to degree lmax
227 /// \param z argument to \f$ P_l^m \f$, i.e. z = cos(colatitude)
228 void plmbar( real_t* p, uint_t lmax, real_t z );
229
230 /// Compute derivatives of associated Legendre functions
231
232 /// This public method first evaluates the associated Legendre functions up
233 /// to the specified degree for the given co-latitude and then their
234 /// derivatives with respect to co-latitude. The actual computations are
235 /// performed by the private internal methods
236 ///
237 /// \param dplm array to store derivative values
238 /// \param lmax maximal degree up to which to compute
239 /// \param z \f$\cos(\theta)\f$, i.e. cosine of co-latitude
240 void dplmbar( real_t* dplm, uint_t lmax, real_t z );
241
242 /// Method for evaluating vector spherical harmonics
243
244 /** We use vector spherical harmonics given by
245 * \f[ \begin{split}
246 * \mathcal{Y}_{lm}^0(\theta,\phi) &= \nu_0 \vec{e}_r \\
247 * \mathcal{Y}_{lm}^1(\theta,\phi) &= \nu_1 \vec{e}_\theta +
248 * \nu_2 \vec{e}_\phi \\
249 * \mathcal{Y}_{lm}^2(\theta,\phi) &= - \nu_2 \vec{e}_\theta
250 * + \nu_1 \vec{e}_\phi
251 * \end{split} \f]
252 * where \f$\{\vec{e}_r,\vec{e}_\theta,\vec{e}_\phi\}\f$ is the local
253 * triad at the point \f$(\theta,\phi)\f$ on the unit sphere and the
254 * coefficient functions are given by
255 * \f[ \begin{split}
256 * \nu_0(\theta,\phi) &= Y_{lm}(\theta,\phi) \\
257 * \nu_1(\theta,\phi) &= \frac{1}{\sqrt{l(l+1)}}\cdot
258 * \frac{\partial}{\partial \theta} Y_{lm}(\theta,\phi) \\
259 * \nu_2(\theta,\phi) &= \frac{1}{\sqrt{l(l+1)}}\cdot
260 * \frac{1}{\sin\theta}\frac{\partial}{\partial \phi}
261 * Y_{lm}(\theta,\phi)
262 * \end{split} \f]
263 * Here \f$Y_{lm}\f$ is the scalar spherical harmonics function.
264 *
265 * \param deg degree l
266 * \param ord order m
267 * \param x x-coordinate of evaluation node
268 * \param y y-coordinate of evaluation node
269 * \param z z-coordinate of evaluation node
270 * \param ind index for choosing vector from \f$\{\mathcal{Y}_{lm}^0,
271 * \mathcal{Y}_{lm}^1,\mathcal{Y}_{lm}^2\}\f$
272 * \param comp choosing 0th, 1st or 2nd vector component
273 *
274 * \note
275 * - For positive order we use scalar spherical harmonics with a
276 * \f$\sin(m\theta)\f$ factor, otherwise with \f$\cos(m\theta)\f$.
277 * - If \f$p=(x,y,z)\f$ is a point on the unit sphere, then we can
278 * express the vectors of the local triad by
279 * - As all methods of this class, also this one employs Geodesy style
280 * normalisation.
281 * \f[
282 * \vec{e}_r = \begin{pmatrix} x \\ y \\ z \end{pmatrix}
283 * \enspace,\quad
284 * \vec{e}_\theta = \begin{pmatrix} zx/\varrho \\ zy/\varrho \\
285 * -\varrho \end{pmatrix}
286 * \enspace,\quad
287 * \vec{e}_\phi = \begin{pmatrix} -y/\varrho \\ x/\varrho \\ 0 \end{pmatrix}
288 * \enspace,\quad
289 * \varrho = \sqrt{x^2 + y^2}
290 * \f]
291 **/
292 real_t evalVSH( uint_t deg, int ord, real_t x, real_t y, real_t z, uint_t ind, uint_t comp );
293};
294
295/// @brief Interpolates spherical harmonics coefficients of a specific order and degree into a grid (on the host),
296/// then copies it to the device, then returns the device view.
297///
298/// @param degree_l spherical harmonics degree
299/// @param order_m spherical harmonics order
300/// @param coords_shell coordinates of the nodes of the unit sphere - compute with
301/// \ref terra::grid::shell::subdomain_unit_sphere_single_shell_coords
302/// @return Scalar 3D grid with spherical harmonics coefficients on the sphere:
303/// @code grid[local_subdomain_id][i][j] = coeff @endcode
304template < std::floating_point ScalarTypeCoeff, std::floating_point ScalarTypeGrid >
306 const int degree_l,
307 const int order_m,
308 const grid::Grid3DDataVec< ScalarTypeGrid, 3 >& coords_shell )
309{
311 "sph_coeffs_degree_l_" + std::to_string( degree_l ) + "_order_m_" + std::to_string( order_m ),
312 coords_shell.extent( 0 ),
313 coords_shell.extent( 1 ),
314 coords_shell.extent( 2 ) );
315
316 auto sph_coeffs_host = Kokkos::create_mirror_view( Kokkos::HostSpace{}, sph_coeffs );
317 auto coords_shell_host = Kokkos::create_mirror_view( Kokkos::HostSpace{}, coords_shell );
318
319 SphericalHarmonicsTool sph_tool( degree_l );
320
321 // Plain loop since I am not sure if the sph tool can be used in parallel.
322 for ( int local_subdomain_id = 0; local_subdomain_id < sph_coeffs.extent( 0 ); ++local_subdomain_id )
323 {
324 for ( int i = 0; i < sph_coeffs.extent( 1 ); ++i )
325 {
326 for ( int j = 0; j < sph_coeffs.extent( 2 ); ++j )
327 {
328 const auto x = coords_shell_host( local_subdomain_id, i, j, 0 );
329 const auto y = coords_shell_host( local_subdomain_id, i, j, 1 );
330 const auto z = coords_shell_host( local_subdomain_id, i, j, 2 );
331 const auto coeff = sph_tool.shconvert_eval( degree_l, order_m, x, y, z );
332 sph_coeffs_host( local_subdomain_id, i, j ) = coeff;
333 }
334 }
335 }
336
337 // Copy to device.
338 Kokkos::deep_copy( sph_coeffs, sph_coeffs_host );
339
340 return sph_coeffs;
341}
342
343} // namespace terra::shell
Class providing methods for evaluation of Spherical Harmonics.
Definition spherical_harmonics.hpp:18
real_t evalVSH(uint_t deg, int ord, real_t x, real_t y, real_t z, uint_t ind, uint_t comp)
Method for evaluating vector spherical harmonics.
Definition spherical_harmonics.cpp:452
real_t * f1
Definition spherical_harmonics.hpp:38
real_t * fac1
Definition spherical_harmonics.hpp:38
void plmbar(real_t *p, uint_t lmax, real_t z)
Definition spherical_harmonics.cpp:244
real_t * srt
Definition spherical_harmonics.hpp:38
double real_t
Definition spherical_harmonics.hpp:20
SphericalHarmonicsTool(uint_t lmax)
Definition spherical_harmonics.cpp:12
real_t * fac2
Definition spherical_harmonics.hpp:38
unsigned int uint_t
Definition spherical_harmonics.hpp:21
real_t * f2
Definition spherical_harmonics.hpp:38
real_t shconvert_eval(real_t *****sphdata, real_t x, real_t y, real_t z, uint_t ir, uint_t lmax, uint_t kk)
Definition spherical_harmonics.cpp:50
~SphericalHarmonicsTool()
Definition spherical_harmonics.cpp:30
Kokkos::View< ScalarType ***[VecDim], Layout > Grid3DDataVec
Definition grid_types.hpp:40
Kokkos::View< ScalarType ***, Layout > Grid3DDataScalar
Definition grid_types.hpp:22
Definition radial_profiles.hpp:10
grid::Grid3DDataScalar< ScalarTypeCoeff > spherical_harmonics_coefficients_grid(const int degree_l, const int order_m, const grid::Grid3DDataVec< ScalarTypeGrid, 3 > &coords_shell)
Interpolates spherical harmonics coefficients of a specific order and degree into a grid (on the host...
Definition spherical_harmonics.hpp:305
double real_t
Definition types.hpp:4