WarpTwin
Documentation for WarpTwin models and classes.
Loading...
Searching...
No Matches
magneticFieldUtils.hpp
Go to the documentation of this file.
1/******************************************************************************
2* Copyright (c) ATTX INC 2025. All Rights Reserved.
3*
4* This software and associated documentation (the "Software") are the
5* proprietary and confidential information of ATTX INC. The Software is
6* furnished under a license agreement between ATTX and the user organization
7* and may be used or copied only in accordance with the terms of the agreement.
8* Refer to 'license/attx_license.adoc' for standard license terms.
9*
10* EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
11* INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION
12* REGULATIONS (EAR99). No part of the Software may be used, reproduced, or
13* transmitted in any form or by any means, for any purpose, without the express
14* written permission of ATTX INC.
15******************************************************************************/
16#ifndef UTILS_MAGNETIC_FIELD_UTILS_H
17#define UTILS_MAGNETIC_FIELD_UTILS_H
18
19#include <string>
20#include <cmath>
21#include <fstream>
22#include <sstream>
23#include <mutex>
24#include "utils/fileutils.h"
26
27namespace warptwin {
28 // Constants for spherical harmonics
31
57 int readWMMCoefficientsFile(const std::string &filename,
60 double gdot[NUMBER_OF_READ_COEFFICIENTS],
61 double hdot[NUMBER_OF_READ_COEFFICIENTS],
62 double &epoch) {
63
64 // First verify our file exists, then open
65 if(!fileExist(filename)) {return ERROR_NOT_FOUND;}
66 std::ifstream infile(filename.c_str());
67 if (!infile.is_open()) {return ERROR_NOT_FOUND;}
68
69 // Get the epoch from the header line
70 std::string line;
71 if (!std::getline(infile, line)) return ERROR_INVALID_RANGE; // File empty
72 std::istringstream header_stream(line);
73 header_stream >> epoch;
74
75 // Loop through each line until the end-of-data line is reached
76 int index = 0;
77 while (index < NUMBER_OF_READ_COEFFICIENTS && std::getline(infile, line)) {
78 // Stop if at the end-of-data line
79 if (line.find("9999999999") == 0) {break;}
80
81 // Read data from line
82 int n, m;
83 double g_val, h_val, gdot_val, hdot_val;
84 std::istringstream iss(line);
85 if (!(iss >> n >> m >> g_val >> h_val >> gdot_val >> hdot_val)) {
86 // Malformed line, skipping
87 continue;
88 }
89
90 // Save variables
91 g[index] = g_val;
92 h[index] = h_val;
93 gdot[index] = gdot_val;
94 hdot[index] = hdot_val;
95 ++index;
96 }
97
98 // Close file to prevent data leaks
99 infile.close();
100
101 return NO_ERROR;
102
103 }
104
119 double muWMM(double input) {
120 return std::sin(input);
121 }
122
136 double dmuWMM(double input) {
137 return std::cos(input);
138 }
139
152 int schmidtSemiNormLegendreWMM(int N, double x, double *Pcup, double *dPcup) {
153
154 // Check input values to confirm they are in valid range
155 if (N < 1 or std::abs(x) > 1.0) {return ERROR_INVALID_RANGE;}
156
157 // Static cache for normalization factors
158 static std::vector<double> norm;
159 static int cached_N = -1;
160
161 // Only recompute if N changes
162 if (N != cached_N) {
163 const int NumTerms = (N + 1) * (N + 2) / 2;
164 norm.assign(NumTerms + 1, 1.0);
165
166 auto idx = [](int n, int m) { return n * (n + 1) / 2 + m; };
167 norm[0] = 1.0;
168 for (int n = 1; n <= N; ++n) {
169 int base = idx(n, 0);
170 int prev = idx(n - 1, 0);
171 norm[base] = norm[prev] * (2.0 * n - 1) / n;
172 for (int m = 1; m <= n; ++m) {
173 int i = idx(n, m);
174 int ip = idx(n, m - 1);
175 double numer = (n - m + 1) * (m == 1 ? 2.0 : 1.0);
176 double denom = n + m;
177 norm[i] = norm[ip] * std::sqrt(numer / denom);
178 }
179 }
180 cached_N = N;
181 }
182
183 // Initialize the iterative algorithm
184 const double z = std::sqrt(1.0 - x * x);
185 Pcup[0] = 1.0;
186 dPcup[0] = 0.0;
187
188 // Lambda function for getting the index
189 auto idx = [](int n, int m) { return n * (n + 1) / 2 + m; };
190
191 // Compute Gauss-normalized associated Legendre functions
192 for (int n = 1; n <= N; ++n) {
193 for (int m = 0; m <= n; ++m) {
194 const int i = idx(n, m);
195 if (n == m) {
196 const int i1 = idx(n - 1, m - 1);
197 Pcup[i] = z * Pcup[i1];
198 dPcup[i] = z * dPcup[i1] + x * Pcup[i1];
199 } else if (n == 1 && m == 0) {
200 const int i1 = idx(0, 0);
201 Pcup[i] = x * Pcup[i1];
202 dPcup[i] = x * dPcup[i1] - z * Pcup[i1];
203 } else {
204 const int i1 = idx(n - 2, m);
205 const int i2 = idx(n - 1, m);
206 if (m > n - 2) {
207 Pcup[i] = x * Pcup[i2];
208 dPcup[i] = x * dPcup[i2] - z * Pcup[i2];
209 } else {
210 const double k = ((n - 1.0) * (n - 1.0) - m * m) / ((2.0 * n - 1) * (2.0 * n - 3));
211 Pcup[i] = x * Pcup[i2] - k * Pcup[i1];
212 dPcup[i] = x * dPcup[i2] - z * Pcup[i2] - k * dPcup[i1];
213 }
214 }
215 }
216 }
217
218 // Apply normalization and sign change for derivative
219 for (int n = 1; n <= N; ++n) {
220 for (int m = 0; m <= n; ++m) {
221 int i = idx(n, m);
222 double scale = norm[i];
223 Pcup[i] *= scale;
224 dPcup[i] = -dPcup[i] * scale;
225 }
226 }
227
228 return NO_ERROR;
229
230 }
231
243 int schmidtSemiNormLegendreSingularityWMM(int N, double x, double *PcupS) {
244
245 // Check input values to confirm they are in valid range
246 if (N < 1 || std::abs(x) > 1.0) return ERROR_INVALID_RANGE;
247
248 // Static cache for normalization factors
249 static std::vector<double> normS;
250 static int cached_N = -1;
251
252 // Only recompute if N changes
253 if (N != cached_N) {
254 normS.assign(N + 1, 1.0);
255 double schmidtQuasiNorm1 = 1.0;
256 for (int n = 1; n <= N; ++n) {
257 double schmidtQuasiNorm2 = schmidtQuasiNorm1 * (2.0 * n - 1) / n;
258 double schmidtQuasiNorm3 = schmidtQuasiNorm2 * std::sqrt((double)(n * 2) / (n + 1));
259 normS[n] = schmidtQuasiNorm3;
260 schmidtQuasiNorm1 = schmidtQuasiNorm2;
261 }
262 cached_N = N;
263 }
264
265
266 // Deal with the singularities at the geographic poles, see section 1.4 in WMM technical report
267 PcupS[0] = 1.0;
268 for (int n = 1; n <= N; ++n) {
269 /* Compute the ratio between the Gauss-normalized associated Legendre
270 functions and the Schmidt quasi-normalized version. This is equivalent to
271 sqrt((m==0?1:2)*(n-m)!/(n+m!))*(2n-1)!!/(n-m)! */
272 // Compute normalization factors
273 if (n == 1) {
274 PcupS[n] = PcupS[n - 1];
275 } else {
276 double k = ((n - 1) * (n - 1) - 1.0) / ((2.0 * n - 1) * (2.0 * n - 3));
277 PcupS[n] = (x * PcupS[n - 1] - k * PcupS[n - 2]) * normS[n];
278 }
279 }
280
281 return NO_ERROR;
282
283 }
284
285}
286
287#endif
#define ERROR_INVALID_RANGE
Definition clockwerkerrors.h:53
#define ERROR_NOT_FOUND
Error in the case where dynamics model overruns steps or gets out of whack.
Definition clockwerkerrors.h:163
Class to propagate CR3BP dynamics in characteristic units.
Definition statistics.hpp:22
int schmidtSemiNormLegendreWMM(int N, double x, double *Pcup, double *dPcup)
Computes the Schmidt Semi-Normalized Legendre function outputs provided the maximum degree (N) as a p...
Definition magneticFieldUtils.hpp:152
int schmidtSemiNormLegendreSingularityWMM(int N, double x, double *PcupS)
Computes the Schmidt Semi-Normalized Legendre function outputs provided the maximum degree (N) as a p...
Definition magneticFieldUtils.hpp:243
const int MAX_HARMONIC_COEFFICIENTS
Definition magneticFieldUtils.hpp:29
const int NUMBER_OF_READ_COEFFICIENTS
Definition magneticFieldUtils.hpp:30
double dmuWMM(double input)
Unary functional input to the associated Legendre function specific to the WMM modelm,...
Definition magneticFieldUtils.hpp:136
bool fileExist(const std::string &name)
Function to quickly check and verify whether a file exists.
Definition fileutils.cpp:26
double muWMM(double input)
Unary functional input to the associated Legendre function specific to the WMM model....
Definition magneticFieldUtils.hpp:119
const int NO_ERROR
Definition simlicense.cpp:30
int readWMMCoefficientsFile(const std::string &filename, double g[NUMBER_OF_READ_COEFFICIENTS], double h[NUMBER_OF_READ_COEFFICIENTS], double gdot[NUMBER_OF_READ_COEFFICIENTS], double hdot[NUMBER_OF_READ_COEFFICIENTS], double &epoch)
Reads magnetic field coefficients for WMM from a file and stores them in provided matrices.
Definition magneticFieldUtils.hpp:57