From 5701379d88ed30e1d21c200dc654dc0b4a761d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schmidt?= <upwli@student.kit.edu> Date: Wed, 17 Nov 2021 10:42:19 +0000 Subject: [PATCH] Update WMM.hpp --- corsika/media/WMM.hpp | 60 +++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/corsika/media/WMM.hpp b/corsika/media/WMM.hpp index 9c4a790b9..6d15c51c1 100644 --- a/corsika/media/WMM.hpp +++ b/corsika/media/WMM.hpp @@ -6,27 +6,14 @@ * the license. */ +#include <boost/filesystem.hpp> +#include <boost/math/special_functions/factorials.hpp> #include <boost/math/special_functions/legendre.hpp> + #include <cmath> #include <corsika/framework/core/Logging.hpp> #include <corsika/framework/utility/CorsikaData.hpp> #include <fstream> -#include <iostream> -using namespace std; - -double factorial(int n) { - double factorial = 1; - if (n < 0) { - CORSIKA_LOG_ERROR("Factorial of a negative number does not exist."); - abort(); - } - else { - for(int i = 1; i <= n; ++i) { - factorial *= i; - } - } - return factorial; -} namespace corsika { MagneticFieldVector get_wmm(const CoordinateSystemPtr Cs, const double year, const LengthType altitude, const double latitude, const double longitude) { @@ -34,13 +21,13 @@ namespace corsika { CORSIKA_LOG_ERROR("Year has to be between 2020 and 2025."); abort(); } - if (altitude < -10_km || altitude > 3000_km) { + if (altitude < -1_km || altitude > 850_km) { CORSIKA_LOG_WARN("Altitude should be between -10_km and 3000_km."); } if (latitude < -90 || latitude > 90) { CORSIKA_LOG_ERROR("Latitude has to be between -90 and 90 degree."); abort(); - } else if (latitude < -82 || latitude > 82) { + } else if (latitude < -89.992 || latitude > 89.992) { CORSIKA_LOG_WARN("Latitude is close to the poles."); } if (longitude < -180 || longitude > 180) { @@ -48,14 +35,13 @@ namespace corsika { abort(); } - double lat_geo = latitude * constants::pi / 180; - double lon = longitude * constants::pi / 180; + const double lat_geo = latitude * constants::pi / 180; + const double lon = longitude * constants::pi / 180; // Transform into spherical coordinates - const LengthType A = 6378137_m; const double f = 1 / 298.257223563; const double e_squared = f * (2 - f); - LengthType R_c = A / sqrt(1 - e_squared * pow(sin(lat_geo), 2)); + LengthType R_c = constants::EarthRadius::Equatorial / sqrt(1 - e_squared * pow(sin(lat_geo), 2)); LengthType p = (R_c + altitude) * cos(lat_geo); LengthType z = sin(lat_geo) * (altitude + R_c * (1 - e_squared)); LengthType r = sqrt(p * p + z * z); @@ -63,49 +49,45 @@ namespace corsika { const int length = 90; double epoch, g[length], h[length], g_dot[length], h_dot[length]; - char model_name[7]; - char release_date[10]; + std::string model_name; + std::string release_date; int n[length], m[length]; - ifstream infile; // Read in coefficients boost::filesystem::path const path = corsika::corsika_data("GeoMag/WMM.COF"); - char mdfile[path.generic_string().size() + 1]; - strcpy(mdfile, path.generic_string().c_str()); //name and path of model file - infile.open(mdfile); + boost::filesystem::ifstream file(path, std::ios::in); // Exit if file opening failed - if (!infile.is_open()){ + if (!file.is_open()){ CORSIKA_LOG_ERROR("Failed opening WMM.COF."); abort(); } - infile >> epoch >> model_name >> release_date; + file >> epoch >> model_name >> release_date; for (int i = 0; i < length; i++) { - infile >> n[i] >> m[i] >> g[i] >> h[i] >> g_dot[i] >> h_dot[i]; + file >> n[i] >> m[i] >> g[i] >> h[i] >> g_dot[i] >> h_dot[i]; // Time interpolation g[i] = g[i] + (year - epoch) * g_dot[i]; h[i] = h[i] + (year - epoch) * h_dot[i]; } - infile.close(); + file.close(); double legendre, next_legendre, derivate_legendre; double magneticfield[3] = {0, 0, 0}; for (int j = 0; j < length; j++) { - // cout << assoc_legendre(n[0], m[0], sin(lat_sph)) << endl; legendre = boost::math::legendre_p(n[j], m[j], sin(lat_sph)); next_legendre = boost::math::legendre_p(n[j] + 1, m[j], sin(lat_sph)); // Schmidt semi-normalization and Condon-Shortley phase term if (m[j] > 0) { - legendre *= sqrt(2 * factorial(n[j] - m[j]) / factorial(n[j] + m[j])) * pow(-1, m[j]); - next_legendre *= sqrt(2 * factorial(n[j] + 1 - m[j]) / factorial(n[j] + 1 + m[j])) * pow(-1, m[j]); + legendre *= sqrt(2 * boost::math::factorial<double>(n[j] - m[j]) / boost::math::factorial<double>(n[j] + m[j])) * pow(-1, m[j]); + next_legendre *= sqrt(2 * boost::math::factorial<double>(n[j] + 1 - m[j]) / boost::math::factorial<double>(n[j] + 1 + m[j])) * pow(-1, m[j]); } derivate_legendre = (n[j] + 1) * tan(lat_sph) * legendre - sqrt(pow(n[j] + 1, 2) - pow(m[j], 2)) / cos(lat_sph) * next_legendre; - magneticfield[0] += pow(constants::EarthRadius::Mean / r, n[j] + 2) * (g[j] * cos(m[j] * lon) + h[j] * sin(m[j] * lon)) * derivate_legendre; - magneticfield[1] += pow(constants::EarthRadius::Mean / r, n[j] + 2) * m[j] * (g[j] * sin(m[j] * lon) - h[j] * cos(m[j] * lon)) * legendre; - magneticfield[2] += (n[j] + 1) * pow(constants::EarthRadius::Mean / r, n[j] + 2) * (g[j] * cos(m[j] * lon) + h[j] * sin(m[j] * lon)) * legendre; + magneticfield[0] += pow(constants::EarthRadius::Geomagnetic_reference / r, n[j] + 2) * (g[j] * cos(m[j] * lon) + h[j] * sin(m[j] * lon)) * derivate_legendre; + magneticfield[1] += pow(constants::EarthRadius::Geomagnetic_reference / r, n[j] + 2) * m[j] * (g[j] * sin(m[j] * lon) - h[j] * cos(m[j] * lon)) * legendre; + magneticfield[2] += (n[j] + 1) * pow(constants::EarthRadius::Geomagnetic_reference / r, n[j] + 2) * (g[j] * cos(m[j] * lon) + h[j] * sin(m[j] * lon)) * legendre; } magneticfield[0] *= -1; magneticfield[1] /= cos(lat_sph); @@ -119,4 +101,4 @@ namespace corsika { return MagneticFieldVector{Cs, magneticfield_geo[0] * 1_nT, magneticfield_geo[1] * 1_nT, magneticfield_geo[2] * -1_nT}; } -} \ No newline at end of file +} -- GitLab