IAP GITLAB

Skip to content
Snippets Groups Projects
Commit 5701379d authored by André Schmidt's avatar André Schmidt Committed by ralfulrich
Browse files

Update WMM.hpp

parent 8f0c9b6b
No related branches found
No related tags found
1 merge request!404adding Geomagnetic Models
......@@ -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
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment