ParametricGeoMagneticField.cc
Go to the documentation of this file.
2 
3 #include <utl/AugerUnits.h>
4 #include <utl/SVector.h>
5 #include <utl/Vector.h>
6 #include <utl/Point.h>
7 
8 #include <fwk/LocalCoordinateSystem.h>
9 #include <fwk/CoordinateSystemRegistry.h>
10 
11 #include <iostream>
12 
13 
14 namespace fwk {
15 
16  ParametricGeoMagneticField::ParametricGeoMagneticField(const double baseyear, const size_t order,
17  const double g[], const double h[]) :
18  fBaseYear(baseyear),
19  fOrder(order),
20  fG(std::valarray<double>(g, order*(order+1)/2)),
21  fH(std::valarray<double>(h, order*(order+1)/2))
22  { }
23 
24 
26  ParametricGeoMagneticField::GetXYZ(const double latitude, const double longitude, const double elevation)
27  const
28  {
29  // Implementation follows the reference implementation
30  // of the [IGRF](http://www.ngdc.noaa.gov/IAGA/vmod/igrf.html)
31 
32  using namespace utl;
33  double sl[fOrder];
34  double cl[fOrder];
35  {
36  const double sin_longitude = sl[0] = sin(longitude);
37  const double cos_longitude = cl[0] = cos(longitude);
38  for (size_t i = 1; i < fOrder; ++i) {
39  sl[i] = sl[i-1] * cos_longitude + cl[i-1] * sin_longitude;
40  cl[i] = cl[i-1] * cos_longitude - sl[i-1] * sin_longitude;
41  }
42  }
43 
44  const size_t npq = (fOrder * (fOrder + 3)) / 2;
45  double p[npq];
46  double q[npq];
47 
48  const double sin_latitude = sin(latitude);
49  const double cos_latitude = cos(latitude);
50  p[0] = 2 * sin_latitude;
51  p[1] = 2 * cos_latitude;
52  p[2] = 4.5 * sin_latitude * sin_latitude - 1.5;
53  p[3] = 3 * sqrt(3) * cos_latitude * sin_latitude;
54  q[0] = -cos_latitude;
55  q[1] = sin_latitude;
56  q[2] = -3 * cos_latitude * sin_latitude;
57  q[3] = sqrt(3) * (sin_latitude*sin_latitude - cos_latitude * cos_latitude);
58 
59  for (size_t k = 4, n = 2, m = 2; k < npq; ++k, ++m) {
60  if (n < m) {
61  m = 0;
62  ++n;
63  }
64  if (m == n) {
65  const double aa = sqrt(1 - 0.5/n);
66  const size_t j = k - n - 1;
67  p[k] = aa * (1 + 1./n) * cos_latitude * p[j];
68  q[k] = aa * (cos_latitude * q[j] + sin_latitude/n * p[j]);
69  } else {
70  const double fn = n;
71  const double fm = m;
72  const double aa = sqrt (fn*fn - fm*fm);
73  const double bb = sqrt ((fn - 1)*(fn - 1) - (fm*fm)) / aa;
74  const double cc = (2*fn - 1) / aa;
75  const size_t i = k - n;
76  const size_t j = k - 2*n + 1;
77  p[k] = (fn + 1) * (cc * sin_latitude / fn * p[i] - bb/(fn - 1) * p[j]);
78  q[k] = cc * (sin_latitude * q[i] - cos_latitude / fn * p[i]) - bb * q[j];
79  }
80  }
81 
82  double x = 0;
83  double y = 0;
84  double z = 0;
85 
86  const double earth_radius = 6371.2 * utl::kilometer;
87  const double ratio = earth_radius / elevation;
88 
89  for (size_t n = 1, k = 0; n < fOrder; ++n) {
90  const double rr = pow(ratio, n + 2);
91  const double aa = rr * fG[k];
92 
93  x += aa * q[k];
94  z -= aa * p[k];
95 
96  ++k;
97  for (size_t m = 0; m < n; ++m, ++k) {
98  const double aa = rr * fG[k];
99  const double bb = rr * fH[k];
100  const double cc = aa * cl[m] + bb * sl[m];
101 
102  x += cc * q[k];
103  z -= cc * p[k];
104 
105  if (cos_latitude > 0) {
106  const double fm = m + 1;
107  const double fn = n;
108  y += (aa * sl[m] - bb * cl[m]) * fm * p[k] / ((fn + 1) * cos_latitude);
109  } else
110  y += (aa * sl[m] - bb * cl[m]) * q[k] * sin_latitude;
111  }
112  }
113 
114  const double r[] = { x*nano*tesla, y*nano*tesla, z*nano*tesla };
116  return result;
117  }
118 
119 
120  double
122  const
123  {
125  return Get(where).GetPhi(cs) - 90*utl::degree; // magnetic field declination in WEST direction
126  }
127 
128 
131  const
132  {
134 
135  // alas ...
136  // double longitude = where.GetTheta(earthCS);
137  // double latitude = where.GetPhi(earthCS);
138  const double x = where.GetX(earthCS);
139  const double y = where.GetY(earthCS);
140  const double z = where.GetZ(earthCS);
141 
142  const double longitude = atan2(y, x);
143  const double rho = where.GetRho(earthCS); // sqrt(x*x + y*y);
144  const double latitude = atan2(z, rho);
145  const double height = where.GetR(earthCS); // sqrt(x*x + y*y + z*z);
146 
147  const utl::SVector<3, double> xyz = GetXYZ(latitude, longitude, height);
148 
150  return utl::Vector(xyz[1], xyz[0], -xyz[2], localCS);
151  }
152 
153 
154  void
156  {
157  if (order < fOrder)
158  WARNING("Forgetting coefficients by shrinking model. You asked for it.");
159 
160  fOrder = order;
161  fG.resize(order*(order+1) / 2, 0.);
162  fH.resize(order*(order+1) / 2, 0.);
163  }
164 
165 
168  const ParametricGeoMagneticField& later)
169  const
170  {
171  assert(year > fBaseYear);
172  assert(year < later.GetBaseYear());
173 
174  const double factor = (year - fBaseYear) / (later.GetBaseYear() - fBaseYear);
175 
176  ParametricGeoMagneticField model = *this; // copy
177 
178  if (later.fOrder > model.fOrder)
179  model.Grow(later.fOrder);
180 
181  if (model.fOrder == later.fOrder) {
182  model.fG += factor * (later.fG - model.fG);
183  model.fH += factor * (later.fH - model.fH);
184  return model;
185  }
186 
187  // unlikely and maybe senseless case
188  ERROR("Order adaption of shrinking models unimplemented (laziness failure)");
189  abort();
190  }
191 
192 
193  /* Meant for testing
194  Parameters should rather be read from file/db.
195  */
198  {
199  double g[] = {
200  -29496.50,
201  -1585.90,
202  -2396.60,
203  3026.00,
204  1668.60,
205  1339.70,
206  -2326.30,
207  1231.70,
208  634.20,
209  912.60,
210  809.00,
211  166.60,
212  -357.10,
213  89.70,
214  -231.10,
215  357.20,
216  200.30,
217  -141.20,
218  -163.10,
219  -7.70,
220  72.80,
221  68.60,
222  76.00,
223  -141.40,
224  -22.90,
225  13.10,
226  -77.90,
227  80.40,
228  -75.00,
229  -4.70,
230  45.30,
231  14.00,
232  10.40,
233  1.60,
234  4.90,
235  24.30,
236  8.20,
237  -14.50,
238  -5.70,
239  -19.30,
240  11.60,
241  10.90,
242  -14.10,
243  -3.70,
244  5.40,
245  9.40,
246  3.40,
247  -5.30,
248  3.10,
249  -12.40,
250  -0.80,
251  8.40,
252  -8.40,
253  -10.10,
254  -2.00,
255  -6.30,
256  0.90,
257  -1.10,
258  -0.20,
259  2.50,
260  -0.30,
261  2.20,
262  3.10,
263  -1.00,
264  -2.80,
265  3.00,
266  -1.50,
267  -2.10,
268  1.60,
269  -0.50,
270  0.50,
271  -0.80,
272  0.40,
273  1.80,
274  0.20,
275  0.80,
276  3.80,
277  -2.10,
278  -0.20,
279  0.30,
280  1.00,
281  -0.70,
282  0.90,
283  -0.10,
284  0.50,
285  -0.40,
286  -0.40,
287  0.20,
288  -0.80,
289  0.00,
290  -0.20,
291  -0.90,
292  0.30,
293  0.40,
294  -0.40,
295  1.10,
296  -0.30,
297  0.80,
298  -0.20,
299  0.40,
300  0.00,
301  0.40,
302  -0.30,
303  -0.30
304  };
305 
306  double h[] = {
307  0,
308  4945.10,
309  0.00,
310  -2707.70,
311  -575.40,
312  0.00,
313  -160.50,
314  251.70,
315  -536.80,
316  0.00,
317  286.40,
318  -211.20,
319  164.40,
320  -309.20,
321  0.00,
322  44.70,
323  188.90,
324  -118.10,
325  0.10,
326  100.90,
327  0.00,
328  -20.80,
329  44.20,
330  61.50,
331  -66.30,
332  3.10,
333  54.90,
334  0.00,
335  -57.80,
336  -21.20,
337  6.60,
338  24.90,
339  7.00,
340  -27.70,
341  -3.40,
342  0.00,
343  10.90,
344  -20.00,
345  11.90,
346  -17.40,
347  16.70,
348  7.10,
349  -10.80,
350  1.70,
351  0.00,
352  -20.50,
353  11.60,
354  12.80,
355  -7.20,
356  -7.40,
357  8.00,
358  2.20,
359  -6.10,
360  7.00,
361  0.00,
362  2.80,
363  -0.10,
364  4.70,
365  4.40,
366  -7.20,
367  -1.00,
368  -4.00,
369  -2.00,
370  -2.00,
371  -8.30,
372  0.00,
373  0.10,
374  1.70,
375  -0.60,
376  -1.80,
377  0.90,
378  -0.40,
379  -2.50,
380  -1.30,
381  -2.10,
382  -1.90,
383  -1.80,
384  0.00,
385  -0.80,
386  0.30,
387  2.20,
388  -2.50,
389  0.50,
390  0.60,
391  0.00,
392  0.10,
393  0.30,
394  -0.90,
395  -0.20,
396  0.80,
397  0.00,
398  -0.80,
399  0.30,
400  1.70,
401  -0.60,
402  -1.20,
403  -0.10,
404  0.50,
405  0.10,
406  0.50,
407  0.40,
408  -0.20,
409  -0.50,
410  -0.80
411  };
412 
413  return ParametricGeoMagneticField(2010, 14, g, h);
414  }
415 
416 }
Point object.
Definition: Point.h:32
double GetPhi(const CoordinateSystemPtr &coordinateSystem) const
azimuth (phi) angle in spherical and cylindrical coordinates
Definition: BasicVector.h:254
const double tesla
Definition: GalacticUnits.h:40
double GetR(const CoordinateSystemPtr &coordinateSystem) const
radius r in spherical coordinates coordinates (distance to origin)
Definition: BasicVector.h:257
ParametricGeoMagneticField Interpolate(const double year, const ParametricGeoMagneticField &later) const
Interpolate between two models Given a time as decimal year, interpolate coefficients between this an...
double pow(const double x, const unsigned int i)
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
const Data result[]
constexpr double degree
constexpr double g
Definition: AugerUnits.h:200
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
double GetRho(const CoordinateSystemPtr &coordinateSystem) const
radius r in cylindrical coordinates (distance to z axis)
Definition: BasicVector.h:263
Spherical harmonics parametrisation of geomagnetic field.
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
constexpr double kilometer
Definition: AugerUnits.h:93
Vector object.
Definition: Vector.h:30
utl::CoordinateSystemPtr Get(const std::string &id)
Get a well-known Coordinate System.
static ParametricGeoMagneticField IGRF2010()
Named constructor for 2010 IGRF model This is meant for testing. Coefficients should rather be read f...
double GetDeclination(const utl::Point &where) const
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
static Policy::type Create(const utl::Point &theOrigin)
Create the standard local coordinate system for a Point.
constexpr double nano
Definition: AugerUnits.h:64
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
utl::SVector< 3, double > GetXYZ(const double latitude, const double longitude, const double elevation) const
Get magnetic field components from geocentric(!) coordinates Given the position relative to the earth...
utl::Vector Get(const utl::Point &where) const
ParametricGeoMagneticField(const double baseyear, const size_t order, const double g[], const double h[])
const double year
Definition: GalacticUnits.h:22

, generated on Tue Sep 26 2023.