MagneticModel.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /**
  2. * \file MagneticModel.hpp
  3. * \brief Header for GeographicLib::MagneticModel class
  4. *
  5. * Copyright (c) Charles Karney (2011-2021) <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_MAGNETICMODEL_HPP)
  10. #define GEOGRAPHICLIB_MAGNETICMODEL_HPP 1
  11. #include <GeographicLib/Constants.hpp>
  12. #include <GeographicLib/Geocentric.hpp>
  13. #include <GeographicLib/SphericalHarmonic.hpp>
  14. #if defined(_MSC_VER)
  15. // Squelch warnings about dll vs vector
  16. # pragma warning (push)
  17. # pragma warning (disable: 4251)
  18. #endif
  19. namespace GeographicLib {
  20. class MagneticCircle;
  21. /**
  22. * \brief Model of the earth's magnetic field
  23. *
  24. * Evaluate the earth's magnetic field according to a model. At present only
  25. * internal magnetic fields are handled. These are due to the earth's code
  26. * and crust; these vary slowly (over many years). Excluded are the effects
  27. * of currents in the ionosphere and magnetosphere which have daily and
  28. * annual variations.
  29. *
  30. * See \ref magnetic for details of how to install the magnetic models and
  31. * the data format.
  32. *
  33. * See
  34. * - General information:
  35. * - http://geomag.org/models/index.html
  36. * - WMM2010:
  37. * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
  38. * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2010/WMM2010COF.zip
  39. * - WMM2015 (deprecated):
  40. * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
  41. * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015COF.zip
  42. * - WMM2015V2:
  43. * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
  44. * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015v2COF.zip
  45. * - WMM2020:
  46. * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml
  47. * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2020/WMM2020COF.zip
  48. * - IGRF11:
  49. * - https://ngdc.noaa.gov/IAGA/vmod/igrf.html
  50. * - https://ngdc.noaa.gov/IAGA/vmod/igrf11coeffs.txt
  51. * - https://ngdc.noaa.gov/IAGA/vmod/geomag70_linux.tar.gz
  52. * - EMM2010:
  53. * - https://ngdc.noaa.gov/geomag/EMM/index.html
  54. * - https://ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2010_Sph_Windows_Linux.zip
  55. * - EMM2015:
  56. * - https://ngdc.noaa.gov/geomag/EMM/index.html
  57. * - https://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2015_Sph_Linux.zip
  58. * - EMM2017:
  59. * - https://ngdc.noaa.gov/geomag/EMM/index.html
  60. * - https://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2017_Sph_Linux.zip
  61. *
  62. * Example of use:
  63. * \include example-MagneticModel.cpp
  64. *
  65. * <a href="MagneticField.1.html">MagneticField</a> is a command-line utility
  66. * providing access to the functionality of MagneticModel and MagneticCircle.
  67. **********************************************************************/
  68. class GEOGRAPHICLIB_EXPORT MagneticModel {
  69. private:
  70. typedef Math::real real;
  71. static const int idlength_ = 8;
  72. std::string _name, _dir, _description, _date, _filename, _id;
  73. real _t0, _dt0, _tmin, _tmax, _a, _hmin, _hmax;
  74. int _Nmodels, _Nconstants, _nmx, _mmx;
  75. SphericalHarmonic::normalization _norm;
  76. Geocentric _earth;
  77. std::vector< std::vector<real> > _G;
  78. std::vector< std::vector<real> > _H;
  79. std::vector<SphericalHarmonic> _harm;
  80. void Field(real t, real lat, real lon, real h, bool diffp,
  81. real& Bx, real& By, real& Bz,
  82. real& Bxt, real& Byt, real& Bzt) const;
  83. void ReadMetadata(const std::string& name);
  84. // copy constructor not allowed
  85. MagneticModel(const MagneticModel&) = delete;
  86. // nor copy assignment
  87. MagneticModel& operator=(const MagneticModel&) = delete;
  88. public:
  89. /** \name Setting up the magnetic model
  90. **********************************************************************/
  91. ///@{
  92. /**
  93. * Construct a magnetic model.
  94. *
  95. * @param[in] name the name of the model.
  96. * @param[in] path (optional) directory for data file.
  97. * @param[in] earth (optional) Geocentric object for converting
  98. * coordinates; default Geocentric::WGS84().
  99. * @param[in] Nmax (optional) if non-negative, truncate the degree of the
  100. * model this value.
  101. * @param[in] Mmax (optional) if non-negative, truncate the order of the
  102. * model this value.
  103. * @exception GeographicErr if the data file cannot be found, is
  104. * unreadable, or is corrupt, or if \e Mmax > \e Nmax.
  105. * @exception std::bad_alloc if the memory necessary for storing the model
  106. * can't be allocated.
  107. *
  108. * A filename is formed by appending ".wmm" (World Magnetic Model) to the
  109. * name. If \e path is specified (and is non-empty), then the file is
  110. * loaded from directory, \e path. Otherwise the path is given by the
  111. * DefaultMagneticPath().
  112. *
  113. * This file contains the metadata which specifies the properties of the
  114. * model. The coefficients for the spherical harmonic sums are obtained
  115. * from a file obtained by appending ".cof" to metadata file (so the
  116. * filename ends in ".wwm.cof").
  117. *
  118. * The model is not tied to a particular ellipsoidal model of the earth.
  119. * The final earth argument to the constructor specifies an ellipsoid to
  120. * allow geodetic coordinates to the transformed into the spherical
  121. * coordinates used in the spherical harmonic sum.
  122. *
  123. * If \e Nmax &ge; 0 and \e Mmax < 0, then \e Mmax is set to \e Nmax.
  124. * After the model is loaded, the maximum degree and order of the model can
  125. * be found by the Degree() and Order() methods.
  126. **********************************************************************/
  127. explicit MagneticModel(const std::string& name,
  128. const std::string& path = "",
  129. const Geocentric& earth = Geocentric::WGS84(),
  130. int Nmax = -1, int Mmax = -1);
  131. ///@}
  132. /** \name Compute the magnetic field
  133. **********************************************************************/
  134. ///@{
  135. /**
  136. * Evaluate the components of the geomagnetic field.
  137. *
  138. * @param[in] t the time (years).
  139. * @param[in] lat latitude of the point (degrees).
  140. * @param[in] lon longitude of the point (degrees).
  141. * @param[in] h the height of the point above the ellipsoid (meters).
  142. * @param[out] Bx the easterly component of the magnetic field (nanotesla).
  143. * @param[out] By the northerly component of the magnetic field
  144. * (nanotesla).
  145. * @param[out] Bz the vertical (up) component of the magnetic field
  146. * (nanotesla).
  147. **********************************************************************/
  148. void operator()(real t, real lat, real lon, real h,
  149. real& Bx, real& By, real& Bz) const {
  150. real dummy;
  151. Field(t, lat, lon, h, false, Bx, By, Bz, dummy, dummy, dummy);
  152. }
  153. /**
  154. * Evaluate the components of the geomagnetic field and their time
  155. * derivatives
  156. *
  157. * @param[in] t the time (years).
  158. * @param[in] lat latitude of the point (degrees).
  159. * @param[in] lon longitude of the point (degrees).
  160. * @param[in] h the height of the point above the ellipsoid (meters).
  161. * @param[out] Bx the easterly component of the magnetic field (nanotesla).
  162. * @param[out] By the northerly component of the magnetic field
  163. * (nanotesla).
  164. * @param[out] Bz the vertical (up) component of the magnetic field
  165. * (nanotesla).
  166. * @param[out] Bxt the rate of change of \e Bx (nT/yr).
  167. * @param[out] Byt the rate of change of \e By (nT/yr).
  168. * @param[out] Bzt the rate of change of \e Bz (nT/yr).
  169. **********************************************************************/
  170. void operator()(real t, real lat, real lon, real h,
  171. real& Bx, real& By, real& Bz,
  172. real& Bxt, real& Byt, real& Bzt) const {
  173. Field(t, lat, lon, h, true, Bx, By, Bz, Bxt, Byt, Bzt);
  174. }
  175. /**
  176. * Create a MagneticCircle object to allow the geomagnetic field at many
  177. * points with constant \e lat, \e h, and \e t and varying \e lon to be
  178. * computed efficiently.
  179. *
  180. * @param[in] t the time (years).
  181. * @param[in] lat latitude of the point (degrees).
  182. * @param[in] h the height of the point above the ellipsoid (meters).
  183. * @exception std::bad_alloc if the memory necessary for creating a
  184. * MagneticCircle can't be allocated.
  185. * @return a MagneticCircle object whose MagneticCircle::operator()(real
  186. * lon) member function computes the field at particular values of \e
  187. * lon.
  188. *
  189. * If the field at several points on a circle of latitude need to be
  190. * calculated then creating a MagneticCircle and using its member functions
  191. * will be substantially faster, especially for high-degree models.
  192. **********************************************************************/
  193. MagneticCircle Circle(real t, real lat, real h) const;
  194. /**
  195. * Compute the magnetic field in geocentric coordinate.
  196. *
  197. * @param[in] t the time (years).
  198. * @param[in] X geocentric coordinate (meters).
  199. * @param[in] Y geocentric coordinate (meters).
  200. * @param[in] Z geocentric coordinate (meters).
  201. * @param[out] BX the \e X component of the magnetic field (nT).
  202. * @param[out] BY the \e Y component of the magnetic field (nT).
  203. * @param[out] BZ the \e Z component of the magnetic field (nT).
  204. * @param[out] BXt the rate of change of \e BX (nT/yr).
  205. * @param[out] BYt the rate of change of \e BY (nT/yr).
  206. * @param[out] BZt the rate of change of \e BZ (nT/yr).
  207. **********************************************************************/
  208. void FieldGeocentric(real t, real X, real Y, real Z,
  209. real& BX, real& BY, real& BZ,
  210. real& BXt, real& BYt, real& BZt) const;
  211. /**
  212. * Compute various quantities dependent on the magnetic field.
  213. *
  214. * @param[in] Bx the \e x (easterly) component of the magnetic field (nT).
  215. * @param[in] By the \e y (northerly) component of the magnetic field (nT).
  216. * @param[in] Bz the \e z (vertical, up positive) component of the magnetic
  217. * field (nT).
  218. * @param[out] H the horizontal magnetic field (nT).
  219. * @param[out] F the total magnetic field (nT).
  220. * @param[out] D the declination of the field (degrees east of north).
  221. * @param[out] I the inclination of the field (degrees down from
  222. * horizontal).
  223. **********************************************************************/
  224. static void FieldComponents(real Bx, real By, real Bz,
  225. real& H, real& F, real& D, real& I) {
  226. real Ht, Ft, Dt, It;
  227. FieldComponents(Bx, By, Bz, real(0), real(1), real(0),
  228. H, F, D, I, Ht, Ft, Dt, It);
  229. }
  230. /**
  231. * Compute various quantities dependent on the magnetic field and its rate
  232. * of change.
  233. *
  234. * @param[in] Bx the \e x (easterly) component of the magnetic field (nT).
  235. * @param[in] By the \e y (northerly) component of the magnetic field (nT).
  236. * @param[in] Bz the \e z (vertical, up positive) component of the magnetic
  237. * field (nT).
  238. * @param[in] Bxt the rate of change of \e Bx (nT/yr).
  239. * @param[in] Byt the rate of change of \e By (nT/yr).
  240. * @param[in] Bzt the rate of change of \e Bz (nT/yr).
  241. * @param[out] H the horizontal magnetic field (nT).
  242. * @param[out] F the total magnetic field (nT).
  243. * @param[out] D the declination of the field (degrees east of north).
  244. * @param[out] I the inclination of the field (degrees down from
  245. * horizontal).
  246. * @param[out] Ht the rate of change of \e H (nT/yr).
  247. * @param[out] Ft the rate of change of \e F (nT/yr).
  248. * @param[out] Dt the rate of change of \e D (degrees/yr).
  249. * @param[out] It the rate of change of \e I (degrees/yr).
  250. **********************************************************************/
  251. static void FieldComponents(real Bx, real By, real Bz,
  252. real Bxt, real Byt, real Bzt,
  253. real& H, real& F, real& D, real& I,
  254. real& Ht, real& Ft, real& Dt, real& It);
  255. ///@}
  256. /** \name Inspector functions
  257. **********************************************************************/
  258. ///@{
  259. /**
  260. * @return the description of the magnetic model, if available, from the
  261. * Description file in the data file; if absent, return "NONE".
  262. **********************************************************************/
  263. const std::string& Description() const { return _description; }
  264. /**
  265. * @return date of the model, if available, from the ReleaseDate field in
  266. * the data file; if absent, return "UNKNOWN".
  267. **********************************************************************/
  268. const std::string& DateTime() const { return _date; }
  269. /**
  270. * @return full file name used to load the magnetic model.
  271. **********************************************************************/
  272. const std::string& MagneticFile() const { return _filename; }
  273. /**
  274. * @return "name" used to load the magnetic model (from the first argument
  275. * of the constructor, but this may be overridden by the model file).
  276. **********************************************************************/
  277. const std::string& MagneticModelName() const { return _name; }
  278. /**
  279. * @return directory used to load the magnetic model.
  280. **********************************************************************/
  281. const std::string& MagneticModelDirectory() const { return _dir; }
  282. /**
  283. * @return the minimum height above the ellipsoid (in meters) for which
  284. * this MagneticModel should be used.
  285. *
  286. * Because the model will typically provide useful results
  287. * slightly outside the range of allowed heights, no check of \e t
  288. * argument is made by MagneticModel::operator()() or
  289. * MagneticModel::Circle.
  290. **********************************************************************/
  291. Math::real MinHeight() const { return _hmin; }
  292. /**
  293. * @return the maximum height above the ellipsoid (in meters) for which
  294. * this MagneticModel should be used.
  295. *
  296. * Because the model will typically provide useful results
  297. * slightly outside the range of allowed heights, no check of \e t
  298. * argument is made by MagneticModel::operator()() or
  299. * MagneticModel::Circle.
  300. **********************************************************************/
  301. Math::real MaxHeight() const { return _hmax; }
  302. /**
  303. * @return the minimum time (in years) for which this MagneticModel should
  304. * be used.
  305. *
  306. * Because the model will typically provide useful results
  307. * slightly outside the range of allowed times, no check of \e t
  308. * argument is made by MagneticModel::operator()() or
  309. * MagneticModel::Circle.
  310. **********************************************************************/
  311. Math::real MinTime() const { return _tmin; }
  312. /**
  313. * @return the maximum time (in years) for which this MagneticModel should
  314. * be used.
  315. *
  316. * Because the model will typically provide useful results
  317. * slightly outside the range of allowed times, no check of \e t
  318. * argument is made by MagneticModel::operator()() or
  319. * MagneticModel::Circle.
  320. **********************************************************************/
  321. Math::real MaxTime() const { return _tmax; }
  322. /**
  323. * @return \e a the equatorial radius of the ellipsoid (meters). This is
  324. * the value of \e a inherited from the Geocentric object used in the
  325. * constructor.
  326. **********************************************************************/
  327. Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); }
  328. /**
  329. * @return \e f the flattening of the ellipsoid. This is the value
  330. * inherited from the Geocentric object used in the constructor.
  331. **********************************************************************/
  332. Math::real Flattening() const { return _earth.Flattening(); }
  333. /**
  334. * @return \e Nmax the maximum degree of the components of the model.
  335. **********************************************************************/
  336. int Degree() const { return _nmx; }
  337. /**
  338. * @return \e Mmax the maximum order of the components of the model.
  339. **********************************************************************/
  340. int Order() const { return _mmx; }
  341. /**
  342. * \deprecated An old name for EquatorialRadius().
  343. **********************************************************************/
  344. GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()")
  345. Math::real MajorRadius() const { return EquatorialRadius(); }
  346. ///@}
  347. /**
  348. * @return the default path for magnetic model data files.
  349. *
  350. * This is the value of the environment variable
  351. * GEOGRAPHICLIB_MAGNETIC_PATH, if set; otherwise, it is
  352. * $GEOGRAPHICLIB_DATA/magnetic if the environment variable
  353. * GEOGRAPHICLIB_DATA is set; otherwise, it is a compile-time default
  354. * (/usr/local/share/GeographicLib/magnetic on non-Windows systems and
  355. * C:/ProgramData/GeographicLib/magnetic on Windows systems).
  356. **********************************************************************/
  357. static std::string DefaultMagneticPath();
  358. /**
  359. * @return the default name for the magnetic model.
  360. *
  361. * This is the value of the environment variable
  362. * GEOGRAPHICLIB_MAGNETIC_NAME, if set; otherwise, it is "wmm2020". The
  363. * MagneticModel class does not use this function; it is just provided as a
  364. * convenience for a calling program when constructing a MagneticModel
  365. * object.
  366. **********************************************************************/
  367. static std::string DefaultMagneticName();
  368. };
  369. } // namespace GeographicLib
  370. #if defined(_MSC_VER)
  371. # pragma warning (pop)
  372. #endif
  373. #endif // GEOGRAPHICLIB_MAGNETICMODEL_HPP