/** * \file MagneticModel.hpp * \brief Header for GeographicLib::MagneticModel class * * Copyright (c) Charles Karney (2011-2021) and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ **********************************************************************/ #if !defined(GEOGRAPHICLIB_MAGNETICMODEL_HPP) #define GEOGRAPHICLIB_MAGNETICMODEL_HPP 1 #include #include #include #if defined(_MSC_VER) // Squelch warnings about dll vs vector # pragma warning (push) # pragma warning (disable: 4251) #endif namespace GeographicLib { class MagneticCircle; /** * \brief Model of the earth's magnetic field * * Evaluate the earth's magnetic field according to a model. At present only * internal magnetic fields are handled. These are due to the earth's code * and crust; these vary slowly (over many years). Excluded are the effects * of currents in the ionosphere and magnetosphere which have daily and * annual variations. * * See \ref magnetic for details of how to install the magnetic models and * the data format. * * See * - General information: * - http://geomag.org/models/index.html * - WMM2010: * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2010/WMM2010COF.zip * - WMM2015 (deprecated): * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015COF.zip * - WMM2015V2: * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2015/WMM2015v2COF.zip * - WMM2020: * - https://ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml * - https://ngdc.noaa.gov/geomag/WMM/data/WMM2020/WMM2020COF.zip * - IGRF11: * - https://ngdc.noaa.gov/IAGA/vmod/igrf.html * - https://ngdc.noaa.gov/IAGA/vmod/igrf11coeffs.txt * - https://ngdc.noaa.gov/IAGA/vmod/geomag70_linux.tar.gz * - EMM2010: * - https://ngdc.noaa.gov/geomag/EMM/index.html * - https://ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2010_Sph_Windows_Linux.zip * - EMM2015: * - https://ngdc.noaa.gov/geomag/EMM/index.html * - https://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2015_Sph_Linux.zip * - EMM2017: * - https://ngdc.noaa.gov/geomag/EMM/index.html * - https://www.ngdc.noaa.gov/geomag/EMM/data/geomag/EMM2017_Sph_Linux.zip * * Example of use: * \include example-MagneticModel.cpp * * MagneticField is a command-line utility * providing access to the functionality of MagneticModel and MagneticCircle. **********************************************************************/ class GEOGRAPHICLIB_EXPORT MagneticModel { private: typedef Math::real real; static const int idlength_ = 8; std::string _name, _dir, _description, _date, _filename, _id; real _t0, _dt0, _tmin, _tmax, _a, _hmin, _hmax; int _Nmodels, _Nconstants, _nmx, _mmx; SphericalHarmonic::normalization _norm; Geocentric _earth; std::vector< std::vector > _G; std::vector< std::vector > _H; std::vector _harm; void Field(real t, real lat, real lon, real h, bool diffp, real& Bx, real& By, real& Bz, real& Bxt, real& Byt, real& Bzt) const; void ReadMetadata(const std::string& name); // copy constructor not allowed MagneticModel(const MagneticModel&) = delete; // nor copy assignment MagneticModel& operator=(const MagneticModel&) = delete; public: /** \name Setting up the magnetic model **********************************************************************/ ///@{ /** * Construct a magnetic model. * * @param[in] name the name of the model. * @param[in] path (optional) directory for data file. * @param[in] earth (optional) Geocentric object for converting * coordinates; default Geocentric::WGS84(). * @param[in] Nmax (optional) if non-negative, truncate the degree of the * model this value. * @param[in] Mmax (optional) if non-negative, truncate the order of the * model this value. * @exception GeographicErr if the data file cannot be found, is * unreadable, or is corrupt, or if \e Mmax > \e Nmax. * @exception std::bad_alloc if the memory necessary for storing the model * can't be allocated. * * A filename is formed by appending ".wmm" (World Magnetic Model) to the * name. If \e path is specified (and is non-empty), then the file is * loaded from directory, \e path. Otherwise the path is given by the * DefaultMagneticPath(). * * This file contains the metadata which specifies the properties of the * model. The coefficients for the spherical harmonic sums are obtained * from a file obtained by appending ".cof" to metadata file (so the * filename ends in ".wwm.cof"). * * The model is not tied to a particular ellipsoidal model of the earth. * The final earth argument to the constructor specifies an ellipsoid to * allow geodetic coordinates to the transformed into the spherical * coordinates used in the spherical harmonic sum. * * If \e Nmax ≥ 0 and \e Mmax < 0, then \e Mmax is set to \e Nmax. * After the model is loaded, the maximum degree and order of the model can * be found by the Degree() and Order() methods. **********************************************************************/ explicit MagneticModel(const std::string& name, const std::string& path = "", const Geocentric& earth = Geocentric::WGS84(), int Nmax = -1, int Mmax = -1); ///@} /** \name Compute the magnetic field **********************************************************************/ ///@{ /** * Evaluate the components of the geomagnetic field. * * @param[in] t the time (years). * @param[in] lat latitude of the point (degrees). * @param[in] lon longitude of the point (degrees). * @param[in] h the height of the point above the ellipsoid (meters). * @param[out] Bx the easterly component of the magnetic field (nanotesla). * @param[out] By the northerly component of the magnetic field * (nanotesla). * @param[out] Bz the vertical (up) component of the magnetic field * (nanotesla). **********************************************************************/ void operator()(real t, real lat, real lon, real h, real& Bx, real& By, real& Bz) const { real dummy; Field(t, lat, lon, h, false, Bx, By, Bz, dummy, dummy, dummy); } /** * Evaluate the components of the geomagnetic field and their time * derivatives * * @param[in] t the time (years). * @param[in] lat latitude of the point (degrees). * @param[in] lon longitude of the point (degrees). * @param[in] h the height of the point above the ellipsoid (meters). * @param[out] Bx the easterly component of the magnetic field (nanotesla). * @param[out] By the northerly component of the magnetic field * (nanotesla). * @param[out] Bz the vertical (up) component of the magnetic field * (nanotesla). * @param[out] Bxt the rate of change of \e Bx (nT/yr). * @param[out] Byt the rate of change of \e By (nT/yr). * @param[out] Bzt the rate of change of \e Bz (nT/yr). **********************************************************************/ void operator()(real t, real lat, real lon, real h, real& Bx, real& By, real& Bz, real& Bxt, real& Byt, real& Bzt) const { Field(t, lat, lon, h, true, Bx, By, Bz, Bxt, Byt, Bzt); } /** * Create a MagneticCircle object to allow the geomagnetic field at many * points with constant \e lat, \e h, and \e t and varying \e lon to be * computed efficiently. * * @param[in] t the time (years). * @param[in] lat latitude of the point (degrees). * @param[in] h the height of the point above the ellipsoid (meters). * @exception std::bad_alloc if the memory necessary for creating a * MagneticCircle can't be allocated. * @return a MagneticCircle object whose MagneticCircle::operator()(real * lon) member function computes the field at particular values of \e * lon. * * If the field at several points on a circle of latitude need to be * calculated then creating a MagneticCircle and using its member functions * will be substantially faster, especially for high-degree models. **********************************************************************/ MagneticCircle Circle(real t, real lat, real h) const; /** * Compute the magnetic field in geocentric coordinate. * * @param[in] t the time (years). * @param[in] X geocentric coordinate (meters). * @param[in] Y geocentric coordinate (meters). * @param[in] Z geocentric coordinate (meters). * @param[out] BX the \e X component of the magnetic field (nT). * @param[out] BY the \e Y component of the magnetic field (nT). * @param[out] BZ the \e Z component of the magnetic field (nT). * @param[out] BXt the rate of change of \e BX (nT/yr). * @param[out] BYt the rate of change of \e BY (nT/yr). * @param[out] BZt the rate of change of \e BZ (nT/yr). **********************************************************************/ void FieldGeocentric(real t, real X, real Y, real Z, real& BX, real& BY, real& BZ, real& BXt, real& BYt, real& BZt) const; /** * Compute various quantities dependent on the magnetic field. * * @param[in] Bx the \e x (easterly) component of the magnetic field (nT). * @param[in] By the \e y (northerly) component of the magnetic field (nT). * @param[in] Bz the \e z (vertical, up positive) component of the magnetic * field (nT). * @param[out] H the horizontal magnetic field (nT). * @param[out] F the total magnetic field (nT). * @param[out] D the declination of the field (degrees east of north). * @param[out] I the inclination of the field (degrees down from * horizontal). **********************************************************************/ static void FieldComponents(real Bx, real By, real Bz, real& H, real& F, real& D, real& I) { real Ht, Ft, Dt, It; FieldComponents(Bx, By, Bz, real(0), real(1), real(0), H, F, D, I, Ht, Ft, Dt, It); } /** * Compute various quantities dependent on the magnetic field and its rate * of change. * * @param[in] Bx the \e x (easterly) component of the magnetic field (nT). * @param[in] By the \e y (northerly) component of the magnetic field (nT). * @param[in] Bz the \e z (vertical, up positive) component of the magnetic * field (nT). * @param[in] Bxt the rate of change of \e Bx (nT/yr). * @param[in] Byt the rate of change of \e By (nT/yr). * @param[in] Bzt the rate of change of \e Bz (nT/yr). * @param[out] H the horizontal magnetic field (nT). * @param[out] F the total magnetic field (nT). * @param[out] D the declination of the field (degrees east of north). * @param[out] I the inclination of the field (degrees down from * horizontal). * @param[out] Ht the rate of change of \e H (nT/yr). * @param[out] Ft the rate of change of \e F (nT/yr). * @param[out] Dt the rate of change of \e D (degrees/yr). * @param[out] It the rate of change of \e I (degrees/yr). **********************************************************************/ static void FieldComponents(real Bx, real By, real Bz, real Bxt, real Byt, real Bzt, real& H, real& F, real& D, real& I, real& Ht, real& Ft, real& Dt, real& It); ///@} /** \name Inspector functions **********************************************************************/ ///@{ /** * @return the description of the magnetic model, if available, from the * Description file in the data file; if absent, return "NONE". **********************************************************************/ const std::string& Description() const { return _description; } /** * @return date of the model, if available, from the ReleaseDate field in * the data file; if absent, return "UNKNOWN". **********************************************************************/ const std::string& DateTime() const { return _date; } /** * @return full file name used to load the magnetic model. **********************************************************************/ const std::string& MagneticFile() const { return _filename; } /** * @return "name" used to load the magnetic model (from the first argument * of the constructor, but this may be overridden by the model file). **********************************************************************/ const std::string& MagneticModelName() const { return _name; } /** * @return directory used to load the magnetic model. **********************************************************************/ const std::string& MagneticModelDirectory() const { return _dir; } /** * @return the minimum height above the ellipsoid (in meters) for which * this MagneticModel should be used. * * Because the model will typically provide useful results * slightly outside the range of allowed heights, no check of \e t * argument is made by MagneticModel::operator()() or * MagneticModel::Circle. **********************************************************************/ Math::real MinHeight() const { return _hmin; } /** * @return the maximum height above the ellipsoid (in meters) for which * this MagneticModel should be used. * * Because the model will typically provide useful results * slightly outside the range of allowed heights, no check of \e t * argument is made by MagneticModel::operator()() or * MagneticModel::Circle. **********************************************************************/ Math::real MaxHeight() const { return _hmax; } /** * @return the minimum time (in years) for which this MagneticModel should * be used. * * Because the model will typically provide useful results * slightly outside the range of allowed times, no check of \e t * argument is made by MagneticModel::operator()() or * MagneticModel::Circle. **********************************************************************/ Math::real MinTime() const { return _tmin; } /** * @return the maximum time (in years) for which this MagneticModel should * be used. * * Because the model will typically provide useful results * slightly outside the range of allowed times, no check of \e t * argument is made by MagneticModel::operator()() or * MagneticModel::Circle. **********************************************************************/ Math::real MaxTime() const { return _tmax; } /** * @return \e a the equatorial radius of the ellipsoid (meters). This is * the value of \e a inherited from the Geocentric object used in the * constructor. **********************************************************************/ Math::real EquatorialRadius() const { return _earth.EquatorialRadius(); } /** * @return \e f the flattening of the ellipsoid. This is the value * inherited from the Geocentric object used in the constructor. **********************************************************************/ Math::real Flattening() const { return _earth.Flattening(); } /** * @return \e Nmax the maximum degree of the components of the model. **********************************************************************/ int Degree() const { return _nmx; } /** * @return \e Mmax the maximum order of the components of the model. **********************************************************************/ int Order() const { return _mmx; } /** * \deprecated An old name for EquatorialRadius(). **********************************************************************/ GEOGRAPHICLIB_DEPRECATED("Use EquatorialRadius()") Math::real MajorRadius() const { return EquatorialRadius(); } ///@} /** * @return the default path for magnetic model data files. * * This is the value of the environment variable * GEOGRAPHICLIB_MAGNETIC_PATH, if set; otherwise, it is * $GEOGRAPHICLIB_DATA/magnetic if the environment variable * GEOGRAPHICLIB_DATA is set; otherwise, it is a compile-time default * (/usr/local/share/GeographicLib/magnetic on non-Windows systems and * C:/ProgramData/GeographicLib/magnetic on Windows systems). **********************************************************************/ static std::string DefaultMagneticPath(); /** * @return the default name for the magnetic model. * * This is the value of the environment variable * GEOGRAPHICLIB_MAGNETIC_NAME, if set; otherwise, it is "wmm2020". The * MagneticModel class does not use this function; it is just provided as a * convenience for a calling program when constructing a MagneticModel * object. **********************************************************************/ static std::string DefaultMagneticName(); }; } // namespace GeographicLib #if defined(_MSC_VER) # pragma warning (pop) #endif #endif // GEOGRAPHICLIB_MAGNETICMODEL_HPP