SphericalHarmonic2.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /**
  2. * \file SphericalHarmonic2.hpp
  3. * \brief Header for GeographicLib::SphericalHarmonic2 class
  4. *
  5. * Copyright (c) Charles Karney (2011-2012) <charles@karney.com> and licensed
  6. * under the MIT/X11 License. For more information, see
  7. * https://geographiclib.sourceforge.io/
  8. **********************************************************************/
  9. #if !defined(GEOGRAPHICLIB_SPHERICALHARMONIC2_HPP)
  10. #define GEOGRAPHICLIB_SPHERICALHARMONIC2_HPP 1
  11. #include <vector>
  12. #include <GeographicLib/Constants.hpp>
  13. #include <GeographicLib/SphericalEngine.hpp>
  14. #include <GeographicLib/CircularEngine.hpp>
  15. namespace GeographicLib {
  16. /**
  17. * \brief Spherical harmonic series with two corrections to the coefficients
  18. *
  19. * This classes is similar to SphericalHarmonic, except that the coefficients
  20. * <i>C</i><sub><i>nm</i></sub> are replaced by
  21. * <i>C</i><sub><i>nm</i></sub> + \e tau' <i>C'</i><sub><i>nm</i></sub> + \e
  22. * tau'' <i>C''</i><sub><i>nm</i></sub> (and similarly for
  23. * <i>S</i><sub><i>nm</i></sub>).
  24. *
  25. * Example of use:
  26. * \include example-SphericalHarmonic2.cpp
  27. **********************************************************************/
  28. // Don't include the GEOGRPAHIC_EXPORT because this header-only class isn't
  29. // used by any other classes in the library.
  30. class /*GEOGRAPHICLIB_EXPORT*/ SphericalHarmonic2 {
  31. public:
  32. /**
  33. * Supported normalizations for associate Legendre polynomials.
  34. **********************************************************************/
  35. enum normalization {
  36. /**
  37. * Fully normalized associated Legendre polynomials. See
  38. * SphericalHarmonic::FULL for documentation.
  39. *
  40. * @hideinitializer
  41. **********************************************************************/
  42. FULL = SphericalEngine::FULL,
  43. /**
  44. * Schmidt semi-normalized associated Legendre polynomials. See
  45. * SphericalHarmonic::SCHMIDT for documentation.
  46. *
  47. * @hideinitializer
  48. **********************************************************************/
  49. SCHMIDT = SphericalEngine::SCHMIDT,
  50. };
  51. private:
  52. typedef Math::real real;
  53. SphericalEngine::coeff _c[3];
  54. real _a;
  55. unsigned _norm;
  56. public:
  57. /**
  58. * Constructor with a full set of coefficients specified.
  59. *
  60. * @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
  61. * @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
  62. * @param[in] N the maximum degree and order of the sum
  63. * @param[in] C1 the coefficients <i>C'</i><sub><i>nm</i></sub>.
  64. * @param[in] S1 the coefficients <i>S'</i><sub><i>nm</i></sub>.
  65. * @param[in] N1 the maximum degree and order of the first correction
  66. * coefficients <i>C'</i><sub><i>nm</i></sub> and
  67. * <i>S'</i><sub><i>nm</i></sub>.
  68. * @param[in] C2 the coefficients <i>C''</i><sub><i>nm</i></sub>.
  69. * @param[in] S2 the coefficients <i>S''</i><sub><i>nm</i></sub>.
  70. * @param[in] N2 the maximum degree and order of the second correction
  71. * coefficients <i>C'</i><sub><i>nm</i></sub> and
  72. * <i>S'</i><sub><i>nm</i></sub>.
  73. * @param[in] a the reference radius appearing in the definition of the
  74. * sum.
  75. * @param[in] norm the normalization for the associated Legendre
  76. * polynomials, either SphericalHarmonic2::FULL (the default) or
  77. * SphericalHarmonic2::SCHMIDT.
  78. * @exception GeographicErr if \e N and \e N1 do not satisfy \e N &ge;
  79. * \e N1 &ge; &minus;1, and similarly for \e N2.
  80. * @exception GeographicErr if any of the vectors of coefficients is not
  81. * large enough.
  82. *
  83. * See SphericalHarmonic for the way the coefficients should be stored. \e
  84. * N1 and \e N2 should satisfy \e N1 &le; \e N and \e N2 &le; \e N.
  85. *
  86. * The class stores <i>pointers</i> to the first elements of \e C, \e S, \e
  87. * C', \e S', \e C'', and \e S''. These arrays should not be altered or
  88. * destroyed during the lifetime of a SphericalHarmonic object.
  89. **********************************************************************/
  90. SphericalHarmonic2(const std::vector<real>& C,
  91. const std::vector<real>& S,
  92. int N,
  93. const std::vector<real>& C1,
  94. const std::vector<real>& S1,
  95. int N1,
  96. const std::vector<real>& C2,
  97. const std::vector<real>& S2,
  98. int N2,
  99. real a, unsigned norm = FULL)
  100. : _a(a)
  101. , _norm(norm) {
  102. if (!(N1 <= N && N2 <= N))
  103. throw GeographicErr("N1 and N2 cannot be larger that N");
  104. _c[0] = SphericalEngine::coeff(C, S, N);
  105. _c[1] = SphericalEngine::coeff(C1, S1, N1);
  106. _c[2] = SphericalEngine::coeff(C2, S2, N2);
  107. }
  108. /**
  109. * Constructor with a subset of coefficients specified.
  110. *
  111. * @param[in] C the coefficients <i>C</i><sub><i>nm</i></sub>.
  112. * @param[in] S the coefficients <i>S</i><sub><i>nm</i></sub>.
  113. * @param[in] N the degree used to determine the layout of \e C and \e S.
  114. * @param[in] nmx the maximum degree used in the sum. The sum over \e n is
  115. * from 0 thru \e nmx.
  116. * @param[in] mmx the maximum order used in the sum. The sum over \e m is
  117. * from 0 thru min(\e n, \e mmx).
  118. * @param[in] C1 the coefficients <i>C'</i><sub><i>nm</i></sub>.
  119. * @param[in] S1 the coefficients <i>S'</i><sub><i>nm</i></sub>.
  120. * @param[in] N1 the degree used to determine the layout of \e C' and \e
  121. * S'.
  122. * @param[in] nmx1 the maximum degree used for \e C' and \e S'.
  123. * @param[in] mmx1 the maximum order used for \e C' and \e S'.
  124. * @param[in] C2 the coefficients <i>C''</i><sub><i>nm</i></sub>.
  125. * @param[in] S2 the coefficients <i>S''</i><sub><i>nm</i></sub>.
  126. * @param[in] N2 the degree used to determine the layout of \e C'' and \e
  127. * S''.
  128. * @param[in] nmx2 the maximum degree used for \e C'' and \e S''.
  129. * @param[in] mmx2 the maximum order used for \e C'' and \e S''.
  130. * @param[in] a the reference radius appearing in the definition of the
  131. * sum.
  132. * @param[in] norm the normalization for the associated Legendre
  133. * polynomials, either SphericalHarmonic2::FULL (the default) or
  134. * SphericalHarmonic2::SCHMIDT.
  135. * @exception GeographicErr if the parameters do not satisfy \e N &ge; \e
  136. * nmx &ge; \e mmx &ge; &minus;1; \e N1 &ge; \e nmx1 &ge; \e mmx1 &ge;
  137. * &minus;1; \e N &ge; \e N1; \e nmx &ge; \e nmx1; \e mmx &ge; \e mmx1;
  138. * and similarly for \e N2, \e nmx2, and \e mmx2.
  139. * @exception GeographicErr if any of the vectors of coefficients is not
  140. * large enough.
  141. *
  142. * The class stores <i>pointers</i> to the first elements of \e C, \e S, \e
  143. * C', \e S', \e C'', and \e S''. These arrays should not be altered or
  144. * destroyed during the lifetime of a SphericalHarmonic object.
  145. **********************************************************************/
  146. SphericalHarmonic2(const std::vector<real>& C,
  147. const std::vector<real>& S,
  148. int N, int nmx, int mmx,
  149. const std::vector<real>& C1,
  150. const std::vector<real>& S1,
  151. int N1, int nmx1, int mmx1,
  152. const std::vector<real>& C2,
  153. const std::vector<real>& S2,
  154. int N2, int nmx2, int mmx2,
  155. real a, unsigned norm = FULL)
  156. : _a(a)
  157. , _norm(norm) {
  158. if (!(nmx1 <= nmx && nmx2 <= nmx))
  159. throw GeographicErr("nmx1 and nmx2 cannot be larger that nmx");
  160. if (!(mmx1 <= mmx && mmx2 <= mmx))
  161. throw GeographicErr("mmx1 and mmx2 cannot be larger that mmx");
  162. _c[0] = SphericalEngine::coeff(C, S, N, nmx, mmx);
  163. _c[1] = SphericalEngine::coeff(C1, S1, N1, nmx1, mmx1);
  164. _c[2] = SphericalEngine::coeff(C2, S2, N2, nmx2, mmx2);
  165. }
  166. /**
  167. * A default constructor so that the object can be created when the
  168. * constructor for another object is initialized. This default object can
  169. * then be reset with the default copy assignment operator.
  170. **********************************************************************/
  171. SphericalHarmonic2() {}
  172. /**
  173. * Compute a spherical harmonic sum with two correction terms.
  174. *
  175. * @param[in] tau1 multiplier for correction coefficients \e C' and \e S'.
  176. * @param[in] tau2 multiplier for correction coefficients \e C'' and \e
  177. * S''.
  178. * @param[in] x cartesian coordinate.
  179. * @param[in] y cartesian coordinate.
  180. * @param[in] z cartesian coordinate.
  181. * @return \e V the spherical harmonic sum.
  182. *
  183. * This routine requires constant memory and thus never throws an
  184. * exception.
  185. **********************************************************************/
  186. Math::real operator()(real tau1, real tau2, real x, real y, real z)
  187. const {
  188. real f[] = {1, tau1, tau2};
  189. real v = 0;
  190. real dummy;
  191. switch (_norm) {
  192. case FULL:
  193. v = SphericalEngine::Value<false, SphericalEngine::FULL, 3>
  194. (_c, f, x, y, z, _a, dummy, dummy, dummy);
  195. break;
  196. case SCHMIDT:
  197. default: // To avoid compiler warnings
  198. v = SphericalEngine::Value<false, SphericalEngine::SCHMIDT, 3>
  199. (_c, f, x, y, z, _a, dummy, dummy, dummy);
  200. break;
  201. }
  202. return v;
  203. }
  204. /**
  205. * Compute a spherical harmonic sum with two correction terms and its
  206. * gradient.
  207. *
  208. * @param[in] tau1 multiplier for correction coefficients \e C' and \e S'.
  209. * @param[in] tau2 multiplier for correction coefficients \e C'' and \e
  210. * S''.
  211. * @param[in] x cartesian coordinate.
  212. * @param[in] y cartesian coordinate.
  213. * @param[in] z cartesian coordinate.
  214. * @param[out] gradx \e x component of the gradient
  215. * @param[out] grady \e y component of the gradient
  216. * @param[out] gradz \e z component of the gradient
  217. * @return \e V the spherical harmonic sum.
  218. *
  219. * This is the same as the previous function, except that the components of
  220. * the gradients of the sum in the \e x, \e y, and \e z directions are
  221. * computed. This routine requires constant memory and thus never throws
  222. * an exception.
  223. **********************************************************************/
  224. Math::real operator()(real tau1, real tau2, real x, real y, real z,
  225. real& gradx, real& grady, real& gradz) const {
  226. real f[] = {1, tau1, tau2};
  227. real v = 0;
  228. switch (_norm) {
  229. case FULL:
  230. v = SphericalEngine::Value<true, SphericalEngine::FULL, 3>
  231. (_c, f, x, y, z, _a, gradx, grady, gradz);
  232. break;
  233. case SCHMIDT:
  234. default: // To avoid compiler warnings
  235. v = SphericalEngine::Value<true, SphericalEngine::SCHMIDT, 3>
  236. (_c, f, x, y, z, _a, gradx, grady, gradz);
  237. break;
  238. }
  239. return v;
  240. }
  241. /**
  242. * Create a CircularEngine to allow the efficient evaluation of several
  243. * points on a circle of latitude at fixed values of \e tau1 and \e tau2.
  244. *
  245. * @param[in] tau1 multiplier for correction coefficients \e C' and \e S'.
  246. * @param[in] tau2 multiplier for correction coefficients \e C'' and \e
  247. * S''.
  248. * @param[in] p the radius of the circle.
  249. * @param[in] z the height of the circle above the equatorial plane.
  250. * @param[in] gradp if true the returned object will be able to compute the
  251. * gradient of the sum.
  252. * @exception std::bad_alloc if the memory for the CircularEngine can't be
  253. * allocated.
  254. * @return the CircularEngine object.
  255. *
  256. * SphericalHarmonic2::operator()() exchanges the order of the sums in the
  257. * definition, i.e., &sum;<sub><i>n</i> = 0..<i>N</i></sub>
  258. * &sum;<sub><i>m</i> = 0..<i>n</i></sub> becomes &sum;<sub><i>m</i> =
  259. * 0..<i>N</i></sub> &sum;<sub><i>n</i> = <i>m</i>..<i>N</i></sub>..
  260. * SphericalHarmonic2::Circle performs the inner sum over degree \e n
  261. * (which entails about <i>N</i><sup>2</sup> operations). Calling
  262. * CircularEngine::operator()() on the returned object performs the outer
  263. * sum over the order \e m (about \e N operations).
  264. *
  265. * See SphericalHarmonic::Circle for an example of its use.
  266. **********************************************************************/
  267. CircularEngine Circle(real tau1, real tau2, real p, real z, bool gradp)
  268. const {
  269. real f[] = {1, tau1, tau2};
  270. switch (_norm) {
  271. case FULL:
  272. return gradp ?
  273. SphericalEngine::Circle<true, SphericalEngine::FULL, 3>
  274. (_c, f, p, z, _a) :
  275. SphericalEngine::Circle<false, SphericalEngine::FULL, 3>
  276. (_c, f, p, z, _a);
  277. break;
  278. case SCHMIDT:
  279. default: // To avoid compiler warnings
  280. return gradp ?
  281. SphericalEngine::Circle<true, SphericalEngine::SCHMIDT, 3>
  282. (_c, f, p, z, _a) :
  283. SphericalEngine::Circle<false, SphericalEngine::SCHMIDT, 3>
  284. (_c, f, p, z, _a);
  285. break;
  286. }
  287. }
  288. /**
  289. * @return the zeroth SphericalEngine::coeff object.
  290. **********************************************************************/
  291. const SphericalEngine::coeff& Coefficients() const
  292. { return _c[0]; }
  293. /**
  294. * @return the first SphericalEngine::coeff object.
  295. **********************************************************************/
  296. const SphericalEngine::coeff& Coefficients1() const
  297. { return _c[1]; }
  298. /**
  299. * @return the second SphericalEngine::coeff object.
  300. **********************************************************************/
  301. const SphericalEngine::coeff& Coefficients2() const
  302. { return _c[2]; }
  303. };
  304. } // namespace GeographicLib
  305. #endif // GEOGRAPHICLIB_SPHERICALHARMONIC2_HPP