General Purpose Geodetic Library
SgMappingFunction.cpp
Go to the documentation of this file.
1 /*
2  *
3  * This file is a part of Space Geodetic Library. The library is used by
4  * nuSolve, a part of CALC/SOLVE system, and designed to make analysis of
5  * geodetic VLBI observations.
6  * Copyright (C) 2010-2020 Sergei Bolotin.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 
24 #include <math.h>
25 
26 
27 #include <SgLogger.h>
28 #include <SgMJD.h>
29 #include <SgMappingFunction.h>
30 #include <SgVlbiStationInfo.h>
31 
32 
33 /*=======================================================================================================
34 *
35 * METHODS:
36 *
37 *======================================================================================================*/
38 //
39 // static first:
41 {
42  return "SgMappingFunction";
43 };
44 
45 
46 
47 //
48 double SgMappingFunction::calc(const SgMeteoData&, double,
49  const SgVlbiStationInfo*, const SgMJD&)
50 {
51  return 1.0;
52 };
53 /*=====================================================================================================*/
54 
55 
56 
57 
58 
59 
60 /*=======================================================================================================
61 *
62 * SgDryMF_NMF:
63 *
64 *======================================================================================================*/
65 //
66 // static first:
67 const QString SgDryMF_NMF::className()
68 {
69  return "SgDryMF_NMF";
70 };
71 
72 
73 
74 //
75 double SgDryMF_NMF::linterpolate(double x1, double x2, double y1, double y2, double x)
76 {
77  double a = (y2-y1)/(x2-x1);
78  double b = y1 - a*x1;
79  return a*x + b;
80 };
81 
82 
83 
84 //
85 double SgDryMF_NMF::calc(const SgMeteoData&, double e,
86  const SgVlbiStationInfo* stnInfo, const SgMJD& epoch)
87 {
88  double a_dry_avg, a_dry_amp, b_dry_avg, b_dry_amp, c_dry_avg, c_dry_amp;
89  double phi(fabs(stnInfo->getLatitude()));
90 
97  double height(stnInfo->getHeight());
98  double beta, gamma;
99  double q;
100  double deltaM, d_deltaM_dx;
101  double sinE=sin(e);
102  double cosE=cos(e);
103  double a=2.53e-5;
104  double b=5.49e-3;
105  double c=1.14e-3;
106 
107  beta = b/(sinE + c );
108  gamma = a/(sinE + beta);
109  q = 1.0 + a/(1.0 + b/(1.0 + c));
110 
111  deltaM = (1.0/sinE - q/(sinE + gamma))*height/1000.0;
112 
113  d_deltaM_dx = (-cosE/sinE/sinE -
114  -q*cosE/(sinE + gamma)/(sinE + gamma)*
115  (1.0 - a/(sinE + beta)/(sinE + beta)*(1.0 - b/(sinE + c)/(sinE + c))) )*height/1000.0;
116 
117  if (phi <= modelArg_[0])
118  {
119  a_dry_avg = modelA_avg_[0];
120  a_dry_amp = modelA_amp_[0];
121  b_dry_avg = modelB_avg_[0];
122  b_dry_amp = modelB_amp_[0];
123  c_dry_avg = modelC_avg_[0];
124  c_dry_amp = modelC_amp_[0];
125  }
126  else if (phi >= modelArg_[4])
127  {
128  a_dry_avg = modelA_avg_[4];
129  a_dry_amp = modelA_amp_[4];
130  b_dry_avg = modelB_avg_[4];
131  b_dry_amp = modelB_amp_[4];
132  c_dry_avg = modelC_avg_[4];
133  c_dry_amp = modelC_amp_[4];
134  }
135  else
136  {
137  int i = 0;
138  while (++i<4 && phi>modelArg_[i]) ;
139 
140  a_dry_avg = linterpolate(modelArg_[i-1], modelArg_[i], modelA_avg_[i-1], modelA_avg_[i], phi);
141  a_dry_amp = linterpolate(modelArg_[i-1], modelArg_[i], modelA_amp_[i-1], modelA_amp_[i], phi);
142  b_dry_avg = linterpolate(modelArg_[i-1], modelArg_[i], modelB_avg_[i-1], modelB_avg_[i], phi);
143  b_dry_amp = linterpolate(modelArg_[i-1], modelArg_[i], modelB_amp_[i-1], modelB_amp_[i], phi);
144  c_dry_avg = linterpolate(modelArg_[i-1], modelArg_[i], modelC_avg_[i-1], modelC_avg_[i], phi);
145  c_dry_amp = linterpolate(modelArg_[i-1], modelArg_[i], modelC_amp_[i-1], modelC_amp_[i], phi);
146  };
147 
148  // Arthur's notation:
149  double cost;
150  //double t_doy = epoch.calcDayOfYear() + epoch.getTime();
151  double t_doy(epoch - SgMJD(1980, 1, 0));
152 
153  if (stnInfo->getLatitude()<0.0) // !
154  t_doy += 365.25/2.0;
155  t_doy -= 28.0;
156  // cost = cos(t_doy*2.0*3.14159265/365.25);
157  cost = cos(t_doy*2.0*M_PI/365.25);
158 
159  a = a_dry_avg - a_dry_amp*cost;
160  b = b_dry_avg - b_dry_amp*cost;
161  c = c_dry_avg - c_dry_amp*cost;
162  // a = a_dry_avg - a_dry_amp*cos(2.0*M_PI*(t_doy - 28.0)/365.25);
163  // b = b_dry_avg - b_dry_amp*cos(2.0*M_PI*(t_doy - 28.0)/365.25);
164  // c = c_dry_avg - c_dry_amp*cos(2.0*M_PI*(t_doy - 28.0)/365.25);
165 
166  beta = b/(sinE + c);
167  gamma = a/(sinE + beta);
168  q = 1.0 + a/(1.0 + b/(1.0 + c));
169 
170  m_ = q/(sinE + gamma) + deltaM;
171 
172  dM_dE_ = -q/(sinE + gamma)/(sinE + gamma) *
173  (cosE - a/(sinE + beta)/(sinE + beta)*cosE*(1.0 - b/(sinE + c)/(sinE + c))) + d_deltaM_dx;
174 
175 
177  {
178  QString str;
179  str.sprintf("Mapping Function (%s): lat.=%12.6f(d), elev.=%16.12f(d), h=%12.6f(m); epoch: %s",
180  qPrintable(stnInfo->getKey()), stnInfo->getLatitude()*RAD2DEG, e*RAD2DEG, height,
181  qPrintable(epoch.toString(SgMJD::F_YYYYMMDDHHMMSSSS)));
183  str.sprintf("Mapping Function (%s): doy = %16.12f, cost = %16.12f",
184  qPrintable(stnInfo->getKey()), t_doy, cost);
185  str.sprintf("Mapping Function (%s): a = %16.12f, b = %16.12f, c = %16.12f",
186  qPrintable(stnInfo->getKey()), a, b, c);
188  str.sprintf("Mapping Function result(%s): M=%20.16f",
189  qPrintable(stnInfo->getKey()), m_);
191  };
192  return m_;
193 };
194 /*=====================================================================================================*/
195 
196 
197 
198 
199 
200 
201 /*=======================================================================================================
202 *
203 * SgWetMF_NMF:
204 *
205 *======================================================================================================*/
206 //
207 // static first:
208 const QString SgWetMF_NMF::className()
209 {
210  return "SgWetMF_NMF";
211 };
212 
213 
214 
215 //
216 double SgWetMF_NMF::linterpolate(double x1, double x2, double y1, double y2, double x)
217 {
218  double a = (y2-y1)/(x2-x1);
219  double b = y1 - a*x1;
220  return a*x + b;
221 };
222 
223 
224 
225 //
226 double SgWetMF_NMF::calc(const SgMeteoData&, double e,
227  const SgVlbiStationInfo* stnInfo, const SgMJD&)
228 {
229  double a, b, c, q;
230  double phi=fabs(stnInfo->getLatitude());
231 
238  if (phi <= modelArg_[0])
239  {
240  a = modelA_avg_[0];
241  b = modelB_avg_[0];
242  c = modelC_avg_[0];
243  }
244  else if (phi >= modelArg_[4])
245  {
246  a = modelA_avg_[4];
247  b = modelB_avg_[4];
248  c = modelC_avg_[4];
249  }
250  else
251  {
252  int i=0;
253  while (++i<4 && phi>modelArg_[i]);
254 
255  a = linterpolate(modelArg_[i-1], modelArg_[i], modelA_avg_[i-1], modelA_avg_[i], phi);
256  b = linterpolate(modelArg_[i-1], modelArg_[i], modelB_avg_[i-1], modelB_avg_[i], phi);
257  c = linterpolate(modelArg_[i-1], modelArg_[i], modelC_avg_[i-1], modelC_avg_[i], phi);
258  };
259 
260  double beta, gamma;
261  double sinE=sin(e);
262  double cosE=cos(e);
263 
264  beta = b/(sinE + c);
265  gamma = a/(sinE + beta);
266  q = 1.0 + a/(1.0 + b/(1.0 + c));
267 
268  m_ = q/(sinE + gamma);
269 
270  dM_dE_ = -q/(sinE + gamma)/(sinE + gamma)*
271  (cosE - a/(sinE + beta)/(sinE + beta)*cosE*(1.0 - b/(sinE + c)/(sinE + c)));
272 
274  {
275  QString str;
276  str.sprintf("Mapping Function (%s): lat.=%12.6f(d), elev.=%16.12f(d)",
277  qPrintable(stnInfo->getKey()), stnInfo->getLatitude()*RAD2DEG, e*RAD2DEG);
279  str.sprintf("Mapping Function result(%s): M=%20.16f",
280  qPrintable(stnInfo->getKey()), m_);
282  };
283  return m_;
284 };
285 /*=====================================================================================================*/
286 
287 
288 
289 
290 
291 
292 /*=======================================================================================================
293 *
294 * SgGradMF_CH:
295 *
296 *======================================================================================================*/
297 //
298 // static first:
299 const QString SgGradMF_CH::className()
300 {
301  return "SgGradMF_CH";
302 };
303 
304 
305 
306 //
307 double SgGradMF_CH::calc(const SgMeteoData&, double e, const SgVlbiStationInfo*, const SgMJD&)
308 {
318  m_ = 1.0/(sin(e)*tan(e) + 0.0032);
319  return m_;
320 };
321 /*=====================================================================================================*/
322 
323 
324 
325 
326 
327 
328 
329 /*=======================================================================================================
330 *
331 * class SgDryMF_MMT implementation
332 *
333 =======================================================================================================*/
334 //
335 // static first:
336 const QString SgDryMF_MTT::className()
337 {
338  return "SgDryMF_MTT";
339 };
340 
341 
342 
343 //
344 double SgDryMF_MTT::calc(const SgMeteoData& meteo, double e, const SgVlbiStationInfo* stnInfo,
345  const SgMJD& epoch)
346 {
347  double cosPhi, sinE, height, a, b, c, tempC;
348  tempC = meteo.getTemperature();
349  cosPhi = cos(stnInfo->getLatitude());
350  height = stnInfo->getHeight()/1000.0; // height in km
351 
357  a = ( 1.2320 + 0.0139*cosPhi - 0.0209*height + 0.00215*(tempC - 10.0))*1.0e-3;
358  b = ( 3.1612 - 0.1600*cosPhi - 0.0331*height + 0.00206*(tempC - 10.0))*1.0e-3;
359  c = (71.244 - 4.293 *cosPhi - 0.149 *height - 0.0021 *(tempC - 10.0))*1.0e-3;
360 
361  sinE = sin(e);
362  m_ = (1.0 + a/(1.0 + b/(1.0 + c)))/(sinE + a/(sinE + b/(sinE + c)));
363 
364  return m_;
365 };
366 /*=====================================================================================================*/
367 
368 
369 
370 
371 
372 
373 /*=======================================================================================================
374 *
375 * class SgDryMF_MTT implementation
376 *
377 =======================================================================================================*/
378 //
379 // static first:
380 const QString SgWetMF_MTT::className()
381 {
382  return "SgWetMF_MTT";
383 };
384 
385 
386 
387 //
388 double SgWetMF_MTT::calc(const SgMeteoData& meteo, double e, const SgVlbiStationInfo* stnInfo,
389  const SgMJD& epoch)
390 {
391  double cosPhi, sinE, height, a, b, c, tempC;
392  tempC = meteo.getTemperature();
393  cosPhi = cos(stnInfo->getLatitude());
394  height = stnInfo->getHeight()/1000.0; // height in km
395 
401  a = ( 0.583 - 0.011 *cosPhi - 0.052 *height + 0.0014*(tempC - 10.0))*1.0e-3;
402  b = ( 1.402 - 0.102 *cosPhi - 0.101 *height + 0.0020*(tempC - 10.0))*1.0e-3;
403  c = (45.85 - 1.91 *cosPhi - 1.29 *height + 0.015 *(tempC - 10.0))*1.0e-3;
404 
405  sinE = sin(e);
406  m_ = (1.0 + a/(1.0 + b/(1.0 + c)))/(sinE + a/(sinE + b/(sinE + c)));
407  return m_;
408 };
409 /*=====================================================================================================*/
410 
411 
412 
413 
414 
415 
416 
417 
418 /*=====================================================================================================*/
419 
420 
421 
422 
423 
424 
425 
426 /*=======================================================================================================
427 *
428 * FRIENDS:
429 *
430 *======================================================================================================*/
431 //
432 
433 
434 
435 /*=====================================================================================================*/
436 //
437 // aux functions:
438 //
439 
440 
441 // i/o:
442 
443 
444 /*=====================================================================================================*/
445 //
446 // constants:
447 //
448 /*=====================================================================================================*/
449 // SgDryMF_NMF's:
450 const double SgDryMF_NMF::modelArg_[5]=
451 {
452  15.0*DEG2RAD, 30.0*DEG2RAD, 45.0*DEG2RAD, 60.0*DEG2RAD, 75.0*DEG2RAD
453 };
454 
455 const double SgDryMF_NMF::modelA_avg_[5]=
456 {
457  1.2769934e-3, 1.2683230e-3, 1.2465397e-3, 1.2196049e-3, 1.2045996e-3
458 };
459 
460 const double SgDryMF_NMF::modelB_avg_[5]=
461 {
462  2.9153695e-3, 2.9152299e-3, 2.9288445e-3, 2.9022565e-3, 2.9024912e-3
463 };
464 
465 const double SgDryMF_NMF::modelC_avg_[5]=
466 {
467  62.610505e-3, 62.837393e-3, 63.721774e-3, 63.824265e-3, 64.258455e-3
468 };
469 
470 const double SgDryMF_NMF::modelA_amp_[5]=
471 {
472  0.0, 1.2709626e-5, 2.6523662e-5, 3.4000452e-5, 4.1202191e-5
473 };
474 
475 const double SgDryMF_NMF::modelB_amp_[5]=
476 {
477  0.0, 2.1414979e-5, 3.0160779e-5, 7.2562722e-5, 11.723375e-5
478 };
479 
480 const double SgDryMF_NMF::modelC_amp_[5]=
481 {
482  0.0, 9.0128400e-5, 4.3497037e-5, 84.795348e-5, 170.37206e-5
483 };
484 
485 
486 
487 // SgWetMF_NMF's:
488 const double SgWetMF_NMF::modelArg_[5]=
489 {
490  15.0*DEG2RAD, 30.0*DEG2RAD, 45.0*DEG2RAD, 60.0*DEG2RAD, 75.0*DEG2RAD
491 };
492 
493 const double SgWetMF_NMF::modelA_avg_[5]=
494 {
495  5.8021897e-4, 5.6794847e-4, 5.8118019e-4, 5.9727542e-4, 6.1641693e-4
496 };
497 
498 const double SgWetMF_NMF::modelB_avg_[5]=
499 {
500  1.4275268e-3, 1.5138625e-3, 1.4572752e-3, 1.5007428e-3, 1.7599082e-3
501 };
502 
503 const double SgWetMF_NMF::modelC_avg_[5]=
504 {
505  4.3472961e-2, 4.6729510e-2, 4.3908931e-2, 4.4626982e-2, 5.4736038e-2
506 };
507 /*=====================================================================================================*/
SgLogger * logger
Definition: SgLogger.cpp:231
#define RAD2DEG
< radians to degrees:
Definition: SgMathSupport.h:32
#define DEG2RAD
hours to radians:
Definition: SgMathSupport.h:40
virtual double calc(const SgMeteoData &meteo, double e, const SgVlbiStationInfo *stnInfo, const SgMJD &epoch)
static const QString className()
static const double modelArg_[5]
static const double modelA_avg_[5]
static const double modelC_amp_[5]
static const QString className()
static const double modelA_amp_[5]
static const double modelB_amp_[5]
static const double modelC_avg_[5]
double linterpolate(double, double, double, double, double)
static const double modelB_avg_[5]
virtual double calc(const SgMeteoData &meteo, double e, const SgVlbiStationInfo *stnInfo, const SgMJD &epoch)
static const QString className()
virtual double calc(const SgMeteoData &meteo, double e, const SgVlbiStationInfo *stnInfo, const SgMJD &epoch)
virtual void write(LogLevel, quint32, const QString &, bool=false)
Definition: SgLogger.cpp:88
@ REFRACTION
Definition: SgLogger.h:82
bool isEligible(LogLevel lvl, quint32 f) const
Definition: SgLogger.h:151
Definition: SgMJD.h:59
@ F_YYYYMMDDHHMMSSSS
Long verbose: Fri, the 2nd of Apr, 2010; 17hr 02min 43.6400sec.
Definition: SgMJD.h:67
QString toString(Format format=F_Verbose) const
Definition: SgMJD.cpp:1007
virtual double calc(const SgMeteoData &meteo, double e, const SgVlbiStationInfo *stnInfo, const SgMJD &epoch)
static const QString className()
double getTemperature() const
Definition: SgMeteoData.h:234
const QString & getKey() const
Definition: SgObjectInfo.h:319
double getLatitude() const
double getHeight() const
virtual double calc(const SgMeteoData &meteo, double e, const SgVlbiStationInfo *stnInfo, const SgMJD &epoch)
static const QString className()
static const double modelArg_[5]
static const double modelC_avg_[5]
virtual double calc(const SgMeteoData &meteo, double e, const SgVlbiStationInfo *stnInfo, const SgMJD &epoch)
double linterpolate(double, double, double, double, double)
static const double modelA_avg_[5]
static const double modelB_avg_[5]
static const QString className()