00001
00002 #include <stdio.h>
00003 #include <string.h>
00004 #include <math.h>
00005 #include <stdlib.h>
00006 #include <ctype.h>
00007 #include <assert.h>
00008 #include "GeomagnetismHeader.h"
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 int MAG_Geomag(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic,
00122 MAGtype_MagneticModel *TimedMagneticModel, MAGtype_GeoMagneticElements *GeoMagneticElements)
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 {
00147 MAGtype_LegendreFunction *LegendreFunction;
00148 MAGtype_SphericalHarmonicVariables *SphVariables;
00149 int NumTerms;
00150 MAGtype_MagneticResults MagneticResultsSph, MagneticResultsGeo, MagneticResultsSphVar, MagneticResultsGeoVar;
00151
00152 NumTerms = ((TimedMagneticModel->nMax + 1) * (TimedMagneticModel->nMax + 2) / 2);
00153 LegendreFunction = MAG_AllocateLegendreFunctionMemory(NumTerms);
00154 SphVariables = MAG_AllocateSphVarMemory(TimedMagneticModel->nMax);
00155 MAG_ComputeSphericalHarmonicVariables(Ellip, CoordSpherical, TimedMagneticModel->nMax, SphVariables);
00156 MAG_AssociatedLegendreFunction(CoordSpherical, TimedMagneticModel->nMax, LegendreFunction);
00157 MAG_Summation(LegendreFunction, TimedMagneticModel, *SphVariables, CoordSpherical, &MagneticResultsSph);
00158 MAG_SecVarSummation(LegendreFunction, TimedMagneticModel, *SphVariables, CoordSpherical, &MagneticResultsSphVar);
00159 MAG_RotateMagneticVector(CoordSpherical, CoordGeodetic, MagneticResultsSph, &MagneticResultsGeo);
00160 MAG_RotateMagneticVector(CoordSpherical, CoordGeodetic, MagneticResultsSphVar, &MagneticResultsGeoVar);
00161 MAG_CalculateGeoMagneticElements(&MagneticResultsGeo, GeoMagneticElements);
00162 MAG_CalculateSecularVariationElements(MagneticResultsGeoVar, GeoMagneticElements);
00163
00164 MAG_FreeLegendreMemory(LegendreFunction);
00165 MAG_FreeSphVarMemory(SphVariables);
00166
00167 return TRUE;
00168 }
00169
00170 int MAG_Grid(MAGtype_CoordGeodetic minimum, MAGtype_CoordGeodetic maximum, double
00171 cord_step_size, double altitude_step_size, double time_step, MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid
00172 *Geoid, MAGtype_Ellipsoid Ellip, MAGtype_Date StartDate, MAGtype_Date EndDate, int ElementOption, int PrintOption, char *OutputFile)
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233 {
00234 int NumTerms;
00235 double a, b, c, d, PrintElement;
00236
00237 MAGtype_MagneticModel *TimedMagneticModel;
00238 MAGtype_CoordSpherical CoordSpherical;
00239 MAGtype_MagneticResults MagneticResultsSph, MagneticResultsGeo, MagneticResultsSphVar, MagneticResultsGeoVar;
00240 MAGtype_SphericalHarmonicVariables *SphVariables;
00241 MAGtype_GeoMagneticElements GeoMagneticElements;
00242 MAGtype_LegendreFunction *LegendreFunction;
00243
00244 FILE *fileout = NULL;
00245
00246 if(PrintOption == 1)
00247 {
00248 fileout = fopen(OutputFile, "w");
00249 if(!fileout)
00250 {
00251 printf("Error opening %s to write", OutputFile);
00252 return FALSE;
00253 }
00254 }
00255
00256
00257
00258 if(fabs(cord_step_size) < 1.0e-10) cord_step_size = 99999.0;
00259 if(fabs(altitude_step_size) < 1.0e-10) altitude_step_size = 99999.0;
00260 if(fabs(time_step) < 1.0e-10) time_step = 99999.0;
00261
00262
00263 NumTerms = ((MagneticModel->nMax + 1) * (MagneticModel->nMax + 2) / 2);
00264 TimedMagneticModel = MAG_AllocateModelMemory(NumTerms);
00265 LegendreFunction = MAG_AllocateLegendreFunctionMemory(NumTerms);
00266 SphVariables = MAG_AllocateSphVarMemory(MagneticModel->nMax);
00267 a = minimum.HeightAboveGeoid;
00268 b = minimum.phi;
00269 c = minimum.lambda;
00270 d = StartDate.DecimalYear;
00271
00272
00273
00274 for(minimum.HeightAboveGeoid = a; minimum.HeightAboveGeoid <= maximum.HeightAboveGeoid; minimum.HeightAboveGeoid += altitude_step_size)
00275 {
00276
00277 for(minimum.phi = b; minimum.phi <= maximum.phi; minimum.phi += cord_step_size)
00278 {
00279
00280 for(minimum.lambda = c; minimum.lambda <= maximum.lambda; minimum.lambda += cord_step_size)
00281 {
00282 if(Geoid->UseGeoid == 1)
00283 MAG_ConvertGeoidToEllipsoidHeight(&minimum, Geoid);
00284 else
00285 minimum.HeightAboveEllipsoid = minimum.HeightAboveGeoid;
00286 MAG_GeodeticToSpherical(Ellip, minimum, &CoordSpherical);
00287 MAG_ComputeSphericalHarmonicVariables(Ellip, CoordSpherical, MagneticModel->nMax, SphVariables);
00288 MAG_AssociatedLegendreFunction(CoordSpherical, MagneticModel->nMax, LegendreFunction);
00289
00290 for(StartDate.DecimalYear = d; StartDate.DecimalYear <= EndDate.DecimalYear; StartDate.DecimalYear += time_step)
00291 {
00292
00293 MAG_TimelyModifyMagneticModel(StartDate, MagneticModel, TimedMagneticModel);
00294 MAG_Summation(LegendreFunction, TimedMagneticModel, *SphVariables, CoordSpherical, &MagneticResultsSph);
00295 MAG_SecVarSummation(LegendreFunction, TimedMagneticModel, *SphVariables, CoordSpherical, &MagneticResultsSphVar);
00296 MAG_RotateMagneticVector(CoordSpherical, minimum, MagneticResultsSph, &MagneticResultsGeo);
00297 MAG_RotateMagneticVector(CoordSpherical, minimum, MagneticResultsSphVar, &MagneticResultsGeoVar);
00298 MAG_CalculateGeoMagneticElements(&MagneticResultsGeo, &GeoMagneticElements);
00299 MAG_CalculateSecularVariationElements(MagneticResultsGeoVar, &GeoMagneticElements);
00300
00301 switch(ElementOption) {
00302 case 1:
00303 PrintElement = GeoMagneticElements.Decl;
00304 break;
00305 case 2:
00306 PrintElement = GeoMagneticElements.Incl;
00307 break;
00308 case 3:
00309 PrintElement = GeoMagneticElements.F;
00310 break;
00311 case 4:
00312 PrintElement = GeoMagneticElements.H;
00313 break;
00314 case 5:
00315 PrintElement = GeoMagneticElements.X;
00316 break;
00317 case 6:
00318 PrintElement = GeoMagneticElements.Y;
00319 break;
00320 case 7:
00321 PrintElement = GeoMagneticElements.Z;
00322 break;
00323 case 8:
00324 PrintElement = GeoMagneticElements.GV;
00325 break;
00326 case 9:
00327 PrintElement = GeoMagneticElements.Decldot;
00328 break;
00329 case 10:
00330 PrintElement = GeoMagneticElements.Incldot;
00331 break;
00332 case 11:
00333 PrintElement = GeoMagneticElements.Fdot;
00334 break;
00335 case 12:
00336 PrintElement = GeoMagneticElements.Hdot;
00337 break;
00338 case 13:
00339 PrintElement = GeoMagneticElements.Xdot;
00340 break;
00341 case 14:
00342 PrintElement = GeoMagneticElements.Ydot;
00343 break;
00344 case 15:
00345 PrintElement = GeoMagneticElements.Zdot;
00346 break;
00347 case 16:
00348 PrintElement = GeoMagneticElements.GVdot;
00349 ;
00350 break;
00351 default:
00352 PrintElement = GeoMagneticElements.Decl;
00353 }
00354
00355 if(Geoid->UseGeoid == 1)
00356 {
00357 if(PrintOption == 1) fprintf(fileout, "%5.2lf %6.2lf %8.4lf %7.2lf %10.2lf\n", minimum.phi, minimum.lambda, minimum.HeightAboveGeoid, StartDate.DecimalYear, PrintElement);
00358 else printf("%5.2lf %6.2lf %8.4lf %7.2lf %10.2lf\n", minimum.phi, minimum.lambda, minimum.HeightAboveGeoid, StartDate.DecimalYear, PrintElement);
00359 } else
00360 {
00361 if(PrintOption == 1) fprintf(fileout, "%5.2lf %6.2lf %8.4lf %7.2lf %10.2lf\n", minimum.phi, minimum.lambda, minimum.HeightAboveEllipsoid, StartDate.DecimalYear, PrintElement);
00362 else printf("%5.2lf %6.2lf %8.4lf %7.2lf %10.2lf\n", minimum.phi, minimum.lambda, minimum.HeightAboveEllipsoid, StartDate.DecimalYear, PrintElement);
00363 }
00364
00365
00366
00367
00368
00369 }
00370
00371 }
00372
00373 }
00374
00375 }
00376 if(PrintOption == 1) fclose(fileout);
00377
00378
00379 MAG_FreeMagneticModelMemory(TimedMagneticModel);
00380 MAG_FreeLegendreMemory(LegendreFunction);
00381 MAG_FreeSphVarMemory(SphVariables);
00382
00383 return TRUE;
00384 }
00385
00386 int MAG_SetDefaults(MAGtype_Ellipsoid *Ellip, MAGtype_Geoid *Geoid)
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 {
00397
00398
00399 Ellip->a = 6378.137;
00400 Ellip->b = 6356.7523142;
00401 Ellip->fla = 1 / 298.257223563;
00402 Ellip->eps = sqrt(1 - (Ellip->b * Ellip->b) / (Ellip->a * Ellip->a));
00403 Ellip->epssq = (Ellip->eps * Ellip->eps);
00404 Ellip->re = 6371.2;
00405
00406
00407 Geoid->NumbGeoidCols = 1441;
00408 Geoid->NumbGeoidRows = 721;
00409 Geoid->NumbHeaderItems = 6;
00410 Geoid->ScaleFactor = 4;
00411 Geoid->NumbGeoidElevs = Geoid->NumbGeoidCols * Geoid->NumbGeoidRows;
00412 Geoid->Geoid_Initialized = 0;
00413 Geoid->UseGeoid = MAG_USE_GEOID;
00414
00415 return TRUE;
00416 }
00417
00418 int MAG_robustReadMagneticModel_Large(char *filename, char *filenameSV, MAGtype_MagneticModel **MagneticModel, int array_size)
00419 {
00420 char line[MAXLINELENGTH], ModelName[] = "Enhanced Magnetic Model";
00421 int n, nMax = 0, nMaxSV = 0, num_terms, a, epochlength=5, i;
00422 FILE *MODELFILE;
00423 MODELFILE = fopen(filename, "r");
00424 fgets(line, MAXLINELENGTH, MODELFILE);
00425 do
00426 {
00427 if(NULL == fgets(line, MAXLINELENGTH, MODELFILE))
00428 break;
00429 a = sscanf(line, "%d", &n);
00430 if(n > nMax && (n < 99999 && a == 1 && n > 0))
00431 nMax = n;
00432 } while(n < 99999 && a == 1);
00433 fclose(MODELFILE);
00434 MODELFILE = fopen(filenameSV, "r");
00435 n = 0;
00436 fgets(line, MAXLINELENGTH, MODELFILE);
00437 do
00438 {
00439 if(NULL == fgets(line, MAXLINELENGTH, MODELFILE))
00440 break;
00441 a = sscanf(line, "%d", &n);
00442 if(n > nMaxSV && (n < 99999 && a == 1 && n > 0))
00443 nMaxSV = n;
00444 } while(n < 99999 && a == 1);
00445 fclose(MODELFILE);
00446 num_terms = CALCULATE_NUMTERMS(nMax);
00447 *MagneticModel = MAG_AllocateModelMemory(num_terms);
00448 (*MagneticModel)->nMax = nMax;
00449 (*MagneticModel)->nMaxSecVar = nMaxSV;
00450 if(nMaxSV > 0) (*MagneticModel)->SecularVariationUsed = TRUE;
00451 for(i = 0; i < num_terms; i++) {
00452 (*MagneticModel)->Main_Field_Coeff_G[i] = 0;
00453 (*MagneticModel)->Main_Field_Coeff_H[i] = 0;
00454 (*MagneticModel)->Secular_Var_Coeff_G[i] = 0;
00455 (*MagneticModel)->Secular_Var_Coeff_H[i] = 0;
00456 }
00457 MAG_readMagneticModel_Large(filename, filenameSV, *MagneticModel);
00458 (*MagneticModel)->CoefficientFileEndDate = (*MagneticModel)->epoch + epochlength;
00459 strcpy((*MagneticModel)->ModelName, ModelName);
00460 (*MagneticModel)->EditionDate = (*MagneticModel)->epoch;
00461 return 1;
00462 }
00463
00464 int MAG_robustReadMagModels(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size)
00465 {
00466 char line[MAXLINELENGTH];
00467 int n, nMax = 0, num_terms, a;
00468 FILE *MODELFILE;
00469 MODELFILE = fopen(filename, "r");
00470 fgets(line, MAXLINELENGTH, MODELFILE);
00471 if(line[0] == '%')
00472 MAG_readMagneticModel_SHDF(filename, magneticmodels, array_size);
00473 else if(array_size == 1)
00474 {
00475
00476 do
00477 {
00478 if(NULL == fgets(line, MAXLINELENGTH, MODELFILE))
00479 break;
00480 a = sscanf(line, "%d", &n);
00481 if(n > nMax && (n < 99999 && a == 1 && n > 0))
00482 nMax = n;
00483 } while(n < 99999 && a == 1);
00484 num_terms = CALCULATE_NUMTERMS(nMax);
00485 (*magneticmodels)[0] = MAG_AllocateModelMemory(num_terms);
00486 (*magneticmodels)[0]->nMax = nMax;
00487 (*magneticmodels)[0]->nMaxSecVar = nMax;
00488 MAG_readMagneticModel(filename, (*magneticmodels)[0]);
00489 (*magneticmodels)[0]->CoefficientFileEndDate = (*magneticmodels)[0]->epoch + 5;
00490
00491 } else return 0;
00492 fclose(MODELFILE);
00493 return 1;
00494 }
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 void MAG_Error(int control)
00506
00507
00508
00509
00510
00511
00512
00513 {
00514 switch(control) {
00515 case 1:
00516 printf("\nError allocating in MAG_LegendreFunctionMemory.\n");
00517 break;
00518 case 2:
00519 printf("\nError allocating in MAG_AllocateModelMemory.\n");
00520 break;
00521 case 3:
00522 printf("\nError allocating in MAG_InitializeGeoid\n");
00523 break;
00524 case 4:
00525 printf("\nError in setting default values.\n");
00526 break;
00527 case 5:
00528 printf("\nError initializing Geoid.\n");
00529 break;
00530 case 6:
00531 printf("\nError opening WMM.COF\n.");
00532 break;
00533 case 7:
00534 printf("\nError opening WMMSV.COF\n.");
00535 break;
00536 case 8:
00537 printf("\nError reading Magnetic Model.\n");
00538 break;
00539 case 9:
00540 printf("\nError printing Command Prompt introduction.\n");
00541 break;
00542 case 10:
00543 printf("\nError converting from geodetic co-ordinates to spherical co-ordinates.\n");
00544 break;
00545 case 11:
00546 printf("\nError in time modifying the Magnetic model\n");
00547 break;
00548 case 12:
00549 printf("\nError in Geomagnetic\n");
00550 break;
00551 case 13:
00552 printf("\nError printing user data\n");\
00553 break;
00554 case 14:
00555 printf("\nError allocating in MAG_SummationSpecial\n");
00556 break;
00557 case 15:
00558 printf("\nError allocating in MAG_SecVarSummationSpecial\n");
00559 break;
00560 case 16:
00561 printf("\nError in opening EGM9615.BIN file\n");
00562 break;
00563 case 17:
00564 printf("\nError: Latitude OR Longitude out of range in MAG_GetGeoidHeight\n");
00565 break;
00566 case 18:
00567 printf("\nError allocating in MAG_PcupHigh\n");
00568 break;
00569 case 19:
00570 printf("\nError allocating in MAG_PcupLow\n");
00571 break;
00572 case 20:
00573 printf("\nError opening coefficient file\n");
00574 break;
00575 case 21:
00576 printf("\nError: UnitDepth too large\n");
00577 break;
00578 case 22:
00579 printf("\nYour system needs Big endian version of EGM9615.BIN. \n");
00580 printf("Please download this file from http://www.ngdc.noaa.gov/geomag/WMM/DoDWMM.shtml. \n");
00581 printf("Replace the existing EGM9615.BIN file with the downloaded one\n");
00582 break;
00583 }
00584 }
00585
00586 char MAG_GeomagIntroduction_EMM(MAGtype_MagneticModel *MagneticModel, char* VersionDate)
00587 {
00588 char ans = 'h';
00589 printf("\n\n Welcome to the Enhanced Magnetic Model (EMM) %d C-Program\n\n", (int) MagneticModel->epoch);
00590 printf(" --- Model Release Date: 15 Dec 2009 ---\n");
00591 printf(" --- Software Release Date: %s ---\n\n", VersionDate);
00592 printf("\n This program estimates the strength and direction of ");
00593 printf("\n Earth's main Magnetic field and crustal variation for a given point/area.");
00594 while(ans != 'c' && ans != 'C')
00595 {
00596 printf("\n Enter h for help and contact information or c to continue.");
00597 printf("\n >");
00598 scanf("%c%*[^\n]", &ans);
00599 getchar();
00600
00601 if((ans == 'h') || (ans == 'H'))
00602 {
00603 printf("\n Help information ");
00604
00605 printf("\n The Enhanced Magnetic Model (EMM) for %d", (int) MagneticModel->epoch);
00606 printf("\n is a model of Earth's main Magnetic and crustal field. The EMM");
00607 printf("\n is recomputed every five (5) years, in years divisible by ");
00608 printf("\n five (i.e. 2005, 2010). See the contact information below");
00609 printf("\n to obtain more information on the EMM and associated software.");
00610 printf("\n ");
00611 printf("\n Input required is the location in geodetic latitude and");
00612 printf("\n longitude (positive for northern latitudes and eastern ");
00613 printf("\n longitudes), geodetic altitude in meters, and the date of ");
00614 printf("\n interest in years.");
00615
00616 printf("\n\n\n The program computes the estimated Magnetic Declination");
00617 printf("\n (Decl) which is sometimes called MagneticVAR, Inclination (Incl), Total");
00618 printf("\n Intensity (F or TI), Horizontal Intensity (H or HI), Vertical");
00619 printf("\n Intensity (Z), and Grid Variation (GV). Declination and Grid");
00620 printf("\n Variation are measured in units of degrees and are considered");
00621 printf("\n positive when east or north. Inclination is measured in units");
00622 printf("\n of degrees and is considered positive when pointing down (into");
00623 printf("\n the Earth). The WMM is reference to the WGS-84 ellipsoid and");
00624 printf("\n is valid for 5 years after the base epoch.");
00625
00626 printf("\n\n\n It is very important to note that a degree and order 720 model,");
00627 printf("\n such as EMM, describes the long wavelength spatial Magnetic ");
00628 printf("\n fluctuations due to Earth's core. Also included in the EMM series");
00629 printf("\n models are intermediate and short wavelength spatial fluctuations ");
00630 printf("\n that originate in Earth's mantle and crust. Not included in");
00631 printf("\n the model are temporal fluctuations of Magnetospheric and ionospheric");
00632 printf("\n origin. On the days during and immediately following Magnetic storms,");
00633 printf("\n temporal fluctuations can cause substantial deviations of the Geomagnetic");
00634 printf("\n field from model values. If the required declination accuracy is");
00635 printf("\n more stringent than the EMM series of models provide, the user is");
00636 printf("\n advised to request special (regional or local) surveys be performed");
00637 printf("\n and models prepared. Please make requests of this nature to the");
00638 printf("\n National Geospatial-Intelligence Agency (NGA) at the address below.");
00639
00640 printf("\n\n\n Contact Information");
00641
00642 printf("\n Software and Model Support");
00643 printf("\n National Geophysical Data Center");
00644 printf("\n NOAA EGC/2");
00645 printf("\n 325 Broadway");
00646 printf("\n Boulder, CO 80303 USA");
00647 printf("\n Attn: Manoj Nair or Stefan Maus");
00648 printf("\n Phone: (303) 497-4642 or -6522");
00649 printf("\n Email: Manoj.C.Nair@noaa.gov or Stefan.Maus@noaa.gov \n");
00650 }
00651 }
00652 return ans;
00653 }
00654
00655 char MAG_GeomagIntroduction_WMM(MAGtype_MagneticModel *MagneticModel, char *VersionDate)
00656
00657
00658
00659
00660
00661
00662 {
00663 char help = 'h';
00664 char ans;
00665 printf("\n\n Welcome to the World Magnetic Model (WMM) %d C-Program\n\n", (int) MagneticModel->epoch);
00666 printf(" --- Model Release Date: 15 Dec 2009 ---\n");
00667 printf(" --- Software Release Date: %s ---\n\n", VersionDate);
00668 printf("\n This program estimates the strength and direction of ");
00669 printf("\n Earth's main Magnetic field for a given point/area.");
00670 while(help != 'c' && help != 'C')
00671 {
00672 printf("\n Enter h for help and contact information or c to continue.");
00673 printf("\n >");
00674 scanf("%c%*[^\n]", &help);
00675 getchar();
00676
00677 if((help == 'h') || (help == 'H'))
00678 {
00679 printf("\n Help information ");
00680
00681 printf("\n The World Magnetic Model (WMM) for %d", (int) MagneticModel->epoch);
00682 printf("\n is a model of Earth's main Magnetic field. The WMM");
00683 printf("\n is recomputed every five (5) years, in years divisible by ");
00684 printf("\n five (i.e. 2005, 2010). See the contact information below");
00685 printf("\n to obtain more information on the WMM and associated software.");
00686 printf("\n ");
00687 printf("\n Input required is the location in geodetic latitude and");
00688 printf("\n longitude (positive for northern latitudes and eastern ");
00689 printf("\n longitudes), geodetic altitude in meters, and the date of ");
00690 printf("\n interest in years.");
00691
00692 printf("\n\n\n The program computes the estimated Magnetic Declination");
00693 printf("\n (Decl) which is sometimes called MagneticVAR, Inclination (Incl), Total");
00694 printf("\n Intensity (F or TI), Horizontal Intensity (H or HI), Vertical");
00695 printf("\n Intensity (Z), and Grid Variation (GV). Declination and Grid");
00696 printf("\n Variation are measured in units of degrees and are considered");
00697 printf("\n positive when east or north. Inclination is measured in units");
00698 printf("\n of degrees and is considered positive when pointing down (into");
00699 printf("\n the Earth). The WMM is reference to the WGS-84 ellipsoid and");
00700 printf("\n is valid for 5 years after the base epoch.");
00701
00702 printf("\n\n\n It is very important to note that a degree and order 12 model,");
00703 printf("\n such as WMM, describes only the long wavelength spatial Magnetic ");
00704 printf("\n fluctuations due to Earth's core. Not included in the WMM series");
00705 printf("\n models are intermediate and short wavelength spatial fluctuations ");
00706 printf("\n that originate in Earth's mantle and crust. Consequently, isolated");
00707 printf("\n angular errors at various positions on the surface (primarily over");
00708 printf("\n land, along continental margins and over oceanic sea-mounts, ridges and");
00709 printf("\n trenches) of several degrees may be expected. Also not included in");
00710 printf("\n the model are temporal fluctuations of Magnetospheric and ionospheric");
00711 printf("\n origin. On the days during and immediately following Magnetic storms,");
00712 printf("\n temporal fluctuations can cause substantial deviations of the Geomagnetic");
00713 printf("\n field from model values. If the required declination accuracy is");
00714 printf("\n more stringent than the WMM series of models provide, the user is");
00715 printf("\n advised to request special (regional or local) surveys be performed");
00716 printf("\n and models prepared. Please make requests of this nature to the");
00717 printf("\n National Geospatial-Intelligence Agency (NGA) at the address below.");
00718
00719 printf("\n\n\n Contact Information");
00720
00721 printf("\n Software and Model Support");
00722 printf("\n National Geophysical Data Center");
00723 printf("\n NOAA EGC/2");
00724 printf("\n 325 Broadway");
00725 printf("\n Boulder, CO 80303 USA");
00726 printf("\n Attn: Manoj Nair or Stefan Maus");
00727 printf("\n Phone: (303) 497-4642 or -6522");
00728 printf("\n Email: Manoj.C.Nair@noaa.gov or Stefan.Maus@noaa.gov \n");
00729 }
00730 }
00731 ans = help;
00732 return ans;
00733 }
00734
00735
00736 int MAG_GetUserGrid(MAGtype_CoordGeodetic *minimum, MAGtype_CoordGeodetic *maximum, double *step_size, double *a_step_size, double *step_time, MAGtype_Date
00737 *StartDate, MAGtype_Date *EndDate, int *ElementOption, int *PrintOption, char *OutputFile, MAGtype_Geoid *Geoid)
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 {
00760 FILE *fileout;
00761 char filename[] = "GridProgramDirective.txt";
00762 char buffer[20];
00763 int dummy;
00764
00765 printf("Please Enter Minimum Latitude (in decimal degrees):\n");
00766 fgets(buffer, 20, stdin);
00767 sscanf(buffer, "%lf", &minimum->phi);
00768 strcpy(buffer, "");
00769 printf("Please Enter Maximum Latitude (in decimal degrees):\n");
00770 fgets(buffer, 20, stdin);
00771 sscanf(buffer, "%lf", &maximum->phi);
00772 strcpy(buffer, "");
00773 printf("Please Enter Minimum Longitude (in decimal degrees):\n");
00774 fgets(buffer, 20, stdin);
00775 sscanf(buffer, "%lf", &minimum->lambda);
00776 strcpy(buffer, "");
00777 printf("Please Enter Maximum Longitude (in decimal degrees):\n");
00778 fgets(buffer, 20, stdin);
00779 sscanf(buffer, "%lf", &maximum->lambda);
00780 strcpy(buffer, "");
00781 printf("Please Enter Step Size (in decimal degrees):\n");
00782 fgets(buffer, 20, stdin);
00783 sscanf(buffer, "%lf", step_size);
00784 strcpy(buffer, "");
00785 printf("Select height (default : above MSL) \n1. Above Mean Sea Level\n2. Above WGS-84 Ellipsoid \n");
00786 fgets(buffer, 20, stdin);
00787 sscanf(buffer, "%d", &dummy);
00788 if(dummy == 2) Geoid->UseGeoid = 0;
00789 else Geoid->UseGeoid = 1;
00790 strcpy(buffer, "");
00791 if(Geoid->UseGeoid == 1)
00792 {
00793 printf("Please Enter Minimum Height above MSL (in km):\n");
00794 fgets(buffer, 20, stdin);
00795 sscanf(buffer, "%lf", &minimum->HeightAboveGeoid);
00796 strcpy(buffer, "");
00797 printf("Please Enter Maximum Height above MSL (in km):\n");
00798 fgets(buffer, 20, stdin);
00799 sscanf(buffer, "%lf", &maximum->HeightAboveGeoid);
00800 strcpy(buffer, "");
00801 printf("Please Enter height step size (in km):\n");
00802 fgets(buffer, 20, stdin);
00803 sscanf(buffer, "%lf", a_step_size);
00804 strcpy(buffer, "");
00805 } else
00806 {
00807 printf("Please Enter Minimum Height above the WGS-84 Ellipsoid (in km):\n");
00808 fgets(buffer, 20, stdin);
00809 sscanf(buffer, "%lf", &minimum->HeightAboveGeoid);
00810 minimum->HeightAboveEllipsoid = minimum->HeightAboveGeoid;
00811 strcpy(buffer, "");
00812 printf("Please Enter Maximum Height above the WGS-84 Ellipsoid (in km):\n");
00813 fgets(buffer, 20, stdin);
00814 sscanf(buffer, "%lf", &maximum->HeightAboveGeoid);
00815 maximum->HeightAboveEllipsoid = minimum->HeightAboveGeoid;
00816 strcpy(buffer, "");
00817 printf("Please Enter height step size (in km):\n");
00818 fgets(buffer, 20, stdin);
00819 sscanf(buffer, "%lf", a_step_size);
00820 strcpy(buffer, "");
00821 }
00822 printf("\nPlease Enter the decimal year starting time:\n");
00823 fgets(buffer, 20, stdin);
00824 sscanf(buffer, "%lf", &StartDate->DecimalYear);
00825 strcpy(buffer, "");
00826 printf("Please Enter the decimal year ending time:\n");
00827 fgets(buffer, 20, stdin);
00828 sscanf(buffer, "%lf", &EndDate->DecimalYear);
00829 strcpy(buffer, "");
00830 printf("Please Enter the time step size:\n");
00831 fgets(buffer, 20, stdin);
00832 sscanf(buffer, "%lf", step_time);
00833 strcpy(buffer, "");
00834 printf("Enter a geomagnetic element to print. Your options are :\n");
00835 printf(" 1. Declination 9. Ddot\n 2. Inclination 10. Idot\n 3. F 11. Fdot\n 4. H 12. Hdot\n 5. X 13. Xdot\n 6. Y 14. Ydot\n 7. Z 15. Zdot\n 8. GV 16. GVdot\n");
00836 fgets(buffer, 20, stdin);
00837 sscanf(buffer, "%d", ElementOption);
00838 strcpy(buffer, "");
00839 printf("Select output :\n");
00840 printf(" 1. Print to a file \n 2. Print to Screen\n");
00841 fgets(buffer, 20, stdin);
00842 sscanf(buffer, "%d", PrintOption);
00843 strcpy(buffer, "");
00844 fileout = fopen(filename, "a");
00845 if(*PrintOption == 1)
00846 {
00847 printf("Please enter output filename\nfor default ('GridResults.txt') press enter:\n");
00848 fgets(buffer, 20, stdin);
00849 if(strlen(buffer) <= 1)
00850 {
00851 strcpy(OutputFile, "GridResults.txt");
00852 fprintf(fileout, "\nResults printed in: GridResults.txt\n");
00853 strcpy(OutputFile, "GridResults.txt");
00854 } else
00855 {
00856 sscanf(buffer, "%s", OutputFile);
00857 fprintf(fileout, "\nResults printed in: %s\n", OutputFile);
00858 }
00859
00860 strcpy(buffer, "");
00861
00862 } else
00863 fprintf(fileout, "\nResults printed in Console\n");
00864 fprintf(fileout, "Minimum Latitude: %lf\t\tMaximum Latitude: %lf\t\tStep Size: %lf\nMinimum Longitude: %lf\t\tMaximum Longitude: %lf\t\tStep Size: %lf\n", minimum->phi, maximum->phi, *step_size, minimum->lambda, maximum->lambda, *step_size);
00865 if(Geoid->UseGeoid == 1)
00866 fprintf(fileout, "Minimum Altitude above MSL: %lf\tMaximum Altitude above MSL: %lf\tStep Size: %lf\n", minimum->HeightAboveGeoid, maximum->HeightAboveGeoid, *a_step_size);
00867 else
00868 fprintf(fileout, "Minimum Altitude above MSL: %lf\tMaximum Altitude above WGS-84 Ellipsoid: %lf\tStep Size: %lf\n", minimum->HeightAboveEllipsoid, maximum->HeightAboveEllipsoid, *a_step_size);
00869 fprintf(fileout, "Starting Date: %lf\t\tEnding Date: %lf\t\tStep Time: %lf\n\n\n", StartDate->DecimalYear, EndDate->DecimalYear, *step_time);
00870 fclose(fileout);
00871 return TRUE;
00872 }
00873
00874 int MAG_GetUserInput(MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid, MAGtype_CoordGeodetic *CoordGeodetic, MAGtype_Date *MagneticDate)
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 {
00905 char Error_Message[255];
00906 char buffer[40];
00907 char tmp;
00908 int i, j, a, b, c, done = 0;
00909 strcpy(buffer, "");
00910 printf("\nPlease enter latitude");
00911 printf("\nNorth Latitude positive, For example:");
00912 printf("\n30, 30, 30 (D,M,S) or 30.508 (Decimal Degrees) (both are north)\n");
00913 fgets(buffer, 40, stdin);
00914 for(i = 0, done = 0, j = 0; i <= 40 && !done; i++)
00915 {
00916 if(buffer[i] == '.')
00917 {
00918 j = sscanf(buffer, "%lf", &CoordGeodetic->phi);
00919 if(j == 1)
00920 done = 1;
00921 else
00922 done = -1;
00923 }
00924 if(buffer[i] == ',')
00925 {
00926 if(MAG_ValidateDMSstringlat(buffer, Error_Message))
00927 {
00928 MAG_DMSstringToDegree(buffer, &CoordGeodetic->phi);
00929 done = 1;
00930 } else
00931 done = -1;
00932 }
00933 if(buffer[i] == ' ')
00934
00935 {
00936 if(MAG_ValidateDMSstringlat(buffer, Error_Message))
00937 {
00938 MAG_DMSstringToDegree(buffer, &CoordGeodetic->phi);
00939 done = 1;
00940 } else
00941 done = -1;
00942 }
00943 if(buffer[i] == '\0' || done == -1)
00944 {
00945 if(MAG_ValidateDMSstringlat(buffer, Error_Message) && done != -1)
00946 {
00947 sscanf(buffer, "%lf", &CoordGeodetic->phi);
00948 done = 1;
00949 } else
00950 {
00951 printf("%s", Error_Message);
00952 strcpy(buffer, "");
00953 printf("\nError encountered, please re-enter as '(-)DDD,MM,SS' or in Decimal Degrees DD.ddd:\n");
00954 fgets(buffer, 40, stdin);
00955 i = -1;
00956 done = 0;
00957 }
00958 }
00959 }
00960 strcpy(buffer, "");
00961 printf("\nPlease enter longitude");
00962 printf("\nEast longitude positive, West negative. For example:");
00963 printf("\n-100.5 or -100, 30, 0 for 100.5 degrees west\n");
00964 fgets(buffer, 40, stdin);
00965 for(i = 0, done = 0, j = 0; i <= 40 && !done; i++)
00966 {
00967 if(buffer[i] == '.')
00968 {
00969 j = sscanf(buffer, "%lf", &CoordGeodetic->lambda);
00970 if(j == 1)
00971 done = 1;
00972 else
00973 done = -1;
00974 }
00975 if(buffer[i] == ',')
00976 {
00977 if(MAG_ValidateDMSstringlong(buffer, Error_Message))
00978 {
00979 MAG_DMSstringToDegree(buffer, &CoordGeodetic->lambda);
00980 done = 1;
00981 } else
00982 done = -1;
00983 }
00984 if(buffer[i] == ' ')
00985 {
00986 if(MAG_ValidateDMSstringlong(buffer, Error_Message))
00987 {
00988 MAG_DMSstringToDegree(buffer, &CoordGeodetic->lambda);
00989 done = 1;
00990 } else
00991 done = -1;
00992 }
00993 if(buffer[i] == '\0' || done == -1)
00994 {
00995 MAG_ValidateDMSstringlong(buffer, Error_Message);
00996 if(MAG_ValidateDMSstringlong(buffer, Error_Message) && done != -1)
00997 {
00998 sscanf(buffer, "%lf", &CoordGeodetic->lambda);
00999 done = 1;
01000 } else
01001 {
01002 printf("%s", Error_Message);
01003 strcpy(buffer, "");
01004 printf("\nError encountered, please re-enter as '(-)DDD,MM,SS' or in Decimal Degrees DD.ddd:\n");
01005 fgets(buffer, 40, stdin);
01006 i = -1;
01007 done = 0;
01008 }
01009 }
01010 }
01011 printf("\nPlease enter height above mean sea level (in kilometers):\n[For height above WGS-84 Ellipsoid prefix E, for example (E20.1)]\n");
01012 done = 0;
01013 while(!done)
01014 {
01015 strcpy(buffer, "");
01016 fgets(buffer, 40, stdin);
01017 j = 0;
01018 if(buffer[0] == 'e' || buffer[0] == 'E')
01019 {
01020 j = sscanf(buffer, "%c%lf", &tmp, &CoordGeodetic->HeightAboveEllipsoid);
01021 if(j == 2)
01022 j = 1;
01023 Geoid->UseGeoid = 0;
01024
01025 } else
01026 {
01027 Geoid->UseGeoid = 1;
01028 j = sscanf(buffer, "%lf", &CoordGeodetic->HeightAboveGeoid);
01029 MAG_ConvertGeoidToEllipsoidHeight(CoordGeodetic, Geoid);
01030 }
01031 if(j == 1)
01032 done = 1;
01033 else
01034 printf("\nIllegal Format, please re-enter as '(-)HHH.hhh:'\n");
01035 if(CoordGeodetic->HeightAboveEllipsoid < -10.0 && done == 1)
01036 switch(MAG_Warnings(3, CoordGeodetic->HeightAboveEllipsoid, MagneticModel)) {
01037 case 0:
01038 return 0;
01039 case 1:
01040 done = 0;
01041 printf("Please enter height above sea level (in kilometers):\n");
01042 break;
01043 case 2:
01044 break;
01045 }
01046 }
01047 strcpy(buffer, "");
01048 printf("\nPlease enter the decimal year or calendar date\n (YYYY.yyy, MM DD YYYY or MM/DD/YYYY):\n");
01049 fgets(buffer, 40, stdin);
01050 for(i = 0, done = 0; i <= 40 && !done; i++)
01051 {
01052 if(buffer[i] == '.')
01053 {
01054 j = sscanf(buffer, "%lf", &MagneticDate->DecimalYear);
01055 if(j == 1)
01056 done = 1;
01057 else
01058 buffer[i] = '\0';
01059 }
01060 if(buffer[i] == '/')
01061 {
01062 sscanf(buffer, "%d/%d/%d", &MagneticDate->Month, &MagneticDate->Day, &MagneticDate->Year);
01063 if(!MAG_DateToYear(MagneticDate, Error_Message))
01064 {
01065 printf("%s", Error_Message);
01066 printf("\nPlease re-enter Date in MM/DD/YYYY or MM DD YYYY format, or as a decimal year\n");
01067 fgets(buffer, 40, stdin);
01068 i = 0;
01069 } else
01070 done = 1;
01071 }
01072 if((buffer[i] == ' ' && buffer[i + 1] != '/') || buffer[i] == '\0')
01073 {
01074 if(3 == sscanf(buffer, "%d %d %d", &a, &b, &c))
01075 {
01076 MagneticDate->Month = a;
01077 MagneticDate->Day = b;
01078 MagneticDate->Year = c;
01079 MagneticDate->DecimalYear = 99999;
01080 } else if(1 == sscanf(buffer, "%d %d %d", &a, &b, &c))
01081 {
01082 MagneticDate->DecimalYear = a;
01083 done = 1;
01084 }
01085 if(!(MagneticDate->DecimalYear == a))
01086 {
01087 if(!MAG_DateToYear(MagneticDate, Error_Message))
01088 {
01089 printf("%s", Error_Message);
01090 strcpy(buffer, "");
01091 printf("\nError encountered, please re-enter Date in MM/DD/YYYY or MM DD YYYY format, or as a decimal year\n");
01092 fgets(buffer, 40, stdin);
01093 i = -1;
01094 } else
01095 done = 1;
01096 }
01097 }
01098 if(buffer[i] == '\0' && i != -1 && done != 1)
01099 {
01100 strcpy(buffer, "");
01101 printf("\nError encountered, please re-enter as MM/DD/YYYY, MM DD YYYY, or as YYYY.yyy:\n");
01102 fgets(buffer, 40, stdin);
01103 i = -1;
01104 }
01105 if(done)
01106 {
01107 if(MagneticDate->DecimalYear > MagneticModel->CoefficientFileEndDate || MagneticDate->DecimalYear < MagneticModel->epoch)
01108 {
01109 switch(MAG_Warnings(4, MagneticDate->DecimalYear, MagneticModel)) {
01110 case 0:
01111 return 0;
01112 case 1:
01113 done = 0;
01114 i = -1;
01115 strcpy(buffer, "");
01116 printf("\nPlease enter the decimal year or calendar date\n (YYYY.yyy, MM DD YYYY or MM/DD/YYYY):\n");
01117 fgets(buffer, 40, stdin);
01118 break;
01119 case 2:
01120 break;
01121 }
01122 }
01123 }
01124 }
01125 return 1;
01126 }
01127
01128 void MAG_PrintUserData(MAGtype_GeoMagneticElements GeomagElements, MAGtype_CoordGeodetic SpaceInput, MAGtype_Date TimeInput, MAGtype_MagneticModel *MagneticModel, MAGtype_Geoid *Geoid)
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171 {
01172 char DeclString[100];
01173 char InclString[100];
01174 MAG_DegreeToDMSstring(GeomagElements.Incl, 2, InclString);
01175 if(GeomagElements.H < 5000 && GeomagElements.H > 1000)
01176 MAG_Warnings(1, GeomagElements.H, MagneticModel);
01177 if(GeomagElements.H < 1000)
01178 MAG_Warnings(2, GeomagElements.H, MagneticModel);
01179 if(MagneticModel->SecularVariationUsed == TRUE)
01180 {
01181 MAG_DegreeToDMSstring(GeomagElements.Decl, 2, DeclString);
01182 printf("\n Results For \n\n");
01183 if(SpaceInput.phi < 0)
01184 printf("Latitude %.2lfS\n", -SpaceInput.phi);
01185 else
01186 printf("Latitude %.2lfN\n", SpaceInput.phi);
01187 if(SpaceInput.lambda < 0)
01188 printf("Longitude %.2lfW\n", -SpaceInput.lambda);
01189 else
01190 printf("Longitude %.2lfE\n", SpaceInput.lambda);
01191 if(Geoid->UseGeoid == 1)
01192 printf("Altitude: %.2lf Kilometers above mean sea level\n", SpaceInput.HeightAboveGeoid);
01193 else
01194 printf("Altitude: %.2lf Kilometers above the WGS-84 ellipsoid\n", SpaceInput.HeightAboveEllipsoid);
01195 printf("Date: %.1lf\n", TimeInput.DecimalYear);
01196 printf("\n Main Field\t\t\tSecular Change\n");
01197 printf("F = %-9.1lf nT\t\t Fdot = %.1lf\tnT/yr\n", GeomagElements.F, GeomagElements.Fdot);
01198 printf("H = %-9.1lf nT\t\t Hdot = %.1lf\tnT/yr\n", GeomagElements.H, GeomagElements.Hdot);
01199 printf("X = %-9.1lf nT\t\t Xdot = %.1lf\tnT/yr\n", GeomagElements.X, GeomagElements.Xdot);
01200 printf("Y = %-9.1lf nT\t\t Ydot = %.1lf\tnT/yr\n", GeomagElements.Y, GeomagElements.Ydot);
01201 printf("Z = %-9.1lf nT\t\t Zdot = %.1lf\tnT/yr\n", GeomagElements.Z, GeomagElements.Zdot);
01202 if(GeomagElements.Decl < 0)
01203 printf("Decl =%20s (WEST)\t Ddot = %.1lf\tMin/yr\n", DeclString, 60 * GeomagElements.Decldot);
01204 else
01205 printf("Decl =%20s (EAST)\t Ddot = %.1lf\tMin/yr\n", DeclString, 60 * GeomagElements.Decldot);
01206 if(GeomagElements.Incl < 0)
01207 printf("Incl =%20s (UP)\t Idot = %.1lf\tMin/yr\n", InclString, 60 * GeomagElements.Incldot);
01208 else
01209 printf("Incl =%20s (DOWN)\t Idot = %.1lf\tMin/yr\n", InclString, 60 * GeomagElements.Incldot);
01210 } else
01211 {
01212 MAG_DegreeToDMSstring(GeomagElements.Decl, 2, DeclString);
01213 printf("\n Results For \n\n");
01214 if(SpaceInput.phi < 0)
01215 printf("Latitude %.2lfS\n", -SpaceInput.phi);
01216 else
01217 printf("Latitude %.2lfN\n", SpaceInput.phi);
01218 if(SpaceInput.lambda < 0)
01219 printf("Longitude %.2lfW\n", -SpaceInput.lambda);
01220 else
01221 printf("Longitude %.2lfE\n", SpaceInput.lambda);
01222 if(Geoid->UseGeoid == 1)
01223 printf("Altitude: %.2lf Kilometers above MSL\n", SpaceInput.HeightAboveGeoid);
01224 else
01225 printf("Altitude: %.2lf Kilometers above WGS-84 Ellipsoid\n", SpaceInput.HeightAboveEllipsoid);
01226 printf("Date: %.1lf\n", TimeInput.DecimalYear);
01227 printf("\n Main Field\n");
01228 printf("F = %-9.1lf nT\n", GeomagElements.F);
01229 printf("H = %-9.1lf nT\n", GeomagElements.H);
01230 printf("X = %-9.1lf nT\n", GeomagElements.X);
01231 printf("Y = %-9.1lf nT\n", GeomagElements.Y);
01232 printf("Z = %-9.1lf nT\n", GeomagElements.Z);
01233 if(GeomagElements.Decl < 0)
01234 printf("Decl =%20s (WEST)\n", DeclString);
01235 else
01236 printf("Decl =%20s (EAST)\n", DeclString);
01237 if(GeomagElements.Incl < 0)
01238 printf("Incl =%20s (UP)\n", InclString);
01239 else
01240 printf("Incl =%20s (DOWN)\n", InclString);
01241 }
01242
01243 if(SpaceInput.phi <= -55 || SpaceInput.phi >= 55)
01244
01245 {
01246 MAG_DegreeToDMSstring(GeomagElements.GV, 2, InclString);
01247 printf("\n\n Grid variation =%20s\n", InclString);
01248 }
01249
01250 }
01251
01252 int MAG_ValidateDMSstringlat(char *input, char *Error)
01253
01254
01255
01256
01257
01258
01259
01260
01261 {
01262 int degree, minute, second, j = 0, n, max_minute = 60, max_second = 60;
01263 int i;
01264 degree = -1000;
01265 minute = -1;
01266 second = -1;
01267 n = (int) strlen(input);
01268
01269 for(i = 0; i <= n - 1; i++)
01270 {
01271 if((input[i] < '0' || input[i] > '9') && (input[i] != ',' && input[i] != ' ' && input[i] != '-' && input[i] != '\0' && input[i] != '\n'))
01272 {
01273 strcpy(Error, "\nError: Input contains an illegal character, legal characters for Degree, Minute, Second format are:\n '0-9' ',' '-' '[space]' '[Enter]'\n");
01274 return FALSE;
01275 }
01276 if(input[i] == ',')
01277 j++;
01278 }
01279 if(j == 2)
01280 j = sscanf(input, "%d, %d, %d", °ree, &minute, &second);
01281 else
01282 j = sscanf(input, "%d %d %d", °ree, &minute, &second);
01283 if(j == 1)
01284 {
01285 minute = 0;
01286 second = 0;
01287 j = 3;
01288 }
01289 if(j != 3)
01290 {
01291 strcpy(Error, "\nError: Not enough numbers used for Degrees, Minutes, Seconds format\n or they were incorrectly formatted\n The legal format is DD,MM,SS or DD MM SS\n");
01292 return FALSE;
01293 }
01294 if(degree > 90 || degree < -90)
01295 {
01296 strcpy(Error, "\nError: Degree input is outside legal range for latitude\n The legal range is from -90 to 90\n");
01297 return FALSE;
01298 }
01299 if(abs(degree) == 90)
01300 max_minute = 0;
01301 if(minute > max_minute || minute < 0)
01302 {
01303 strcpy(Error, "\nError: Minute input is outside legal range\n The legal minute range is from 0 to 60\n");
01304 return FALSE;
01305 }
01306 if(minute == max_minute)
01307 max_second = 0;
01308 if(second > max_second || second < 0)
01309 {
01310 strcpy(Error, "\nError: Second input is outside legal range\n The legal second range is from 0 to 60\n");
01311 return FALSE;
01312 }
01313 return TRUE;
01314 }
01315
01316 int MAG_ValidateDMSstringlong(char *input, char *Error)
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326 {
01327 int degree, minute, second, j = 0, max_minute = 60, max_second = 60, n;
01328 int i;
01329 degree = -1000;
01330 minute = -1;
01331 second = -1;
01332 n = (int) strlen(input);
01333
01334 for(i = 0; i <= n - 1; i++)
01335 {
01336 if((input[i] < '0' || input[i] > '9') && (input[i] != ',' && input[i] != ' ' && input[i] != '-' && input[i] != '\0' && input[i] != '\n'))
01337 {
01338 strcpy(Error, "\nError: Input contains an illegal character, legal characters for Degree, Minute, Second format are:\n '0-9' ',' '-' '[space]' '[Enter]'\n");
01339 return FALSE;
01340 }
01341 if(input[i] == ',')
01342 j++;
01343 }
01344 if(j >= 2)
01345 j = sscanf(input, "%d, %d, %d", °ree, &minute, &second);
01346 else
01347 j = sscanf(input, "%d %d %d", °ree, &minute, &second);
01348 if(j == 1)
01349 {
01350 minute = 0;
01351 second = 0;
01352 j = 3;
01353 }
01354 if(j != 3)
01355 {
01356 strcpy(Error, "\nError: Not enough numbers read for Degrees, Minutes, Seconds format\n or they were incorrectly formatted\n The legal format is DD,MM,SS or DD MM SS\n");
01357 return FALSE;
01358 }
01359 sscanf(input, "%d, %d, %d", °ree, &minute, &second);
01360 if(degree > 360 || degree < -180)
01361 {
01362 strcpy(Error, "\nError: Degree input is outside legal range\n The legal range is from -180 to 360\n");
01363 return FALSE;
01364 }
01365 if(degree == 360 || degree == -180)
01366 max_minute = 0;
01367 if(minute > max_minute || minute < 0)
01368 {
01369 strcpy(Error, "\nError: Minute input is outside legal range\n The legal minute range is from 0 to 60\n");
01370 return FALSE;
01371 }
01372 if(minute == max_minute)
01373 max_second = 0;
01374 if(second > max_second || second < 0)
01375 {
01376 strcpy(Error, "\nError: Second input is outside legal range\n The legal second range is from 0 to 60\n");
01377 return FALSE;
01378 }
01379 return TRUE;
01380 }
01381
01382 int MAG_Warnings(int control, double value, MAGtype_MagneticModel *MagneticModel)
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395 {
01396 char ans[20];
01397 strcpy(ans, "");
01398 switch(control) {
01399 case 1:
01400 printf("\nWarning: The Horizontal Field strength at this location is only %lf\n", value);
01401 printf(" Compass readings have large uncertainties in areas where H\n is smaller than 5000 nT\n");
01402 printf("Press enter to continue...\n");
01403 fgets(ans, 20, stdin);
01404 break;
01405 case 2:
01406 printf("\nWarning: The Horizontal Field strength at this location is only %lf\n", value);
01407 printf(" Compass readings have VERY LARGE uncertainties in areas where\n where H is smaller than 1000 nT\n");
01408 printf("Press enter to continue...\n");
01409 fgets(ans, 20, stdin);
01410 break;
01411 case 3:
01412 printf("\nWarning: The value you have entered of %lf km for the elevation is outside of the recommended range.\n Elevations above -10.0 km are recommended for accurate results. \n", value);
01413 while(1)
01414 {
01415 printf("\nPlease press 'C' to continue, 'G' to get new data or 'X' to exit...\n");
01416 fgets(ans, 20, stdin);
01417 switch(ans[0]) {
01418 case 'X':
01419 case 'x':
01420 return 0;
01421 case 'G':
01422 case 'g':
01423 return 1;
01424 case 'C':
01425 case 'c':
01426 return 2;
01427 default:
01428 printf("\nInvalid input %c\n", ans[0]);
01429 break;
01430 }
01431 }
01432 break;
01433
01434 case 4:
01435 printf("\nWARNING - TIME EXTENDS BEYOND INTENDED USAGE RANGE\n CONTACT NGDC FOR PRODUCT UPDATES:\n");
01436 printf(" National Geophysical Data Center\n");
01437 printf(" NOAA EGC/2\n");
01438 printf(" 325 Broadway\n");
01439 printf(" Attn: Manoj Nair or Stefan Maus\n");
01440 printf(" Phone: (303) 497-4642 or -6522\n");
01441 printf(" Email: Manoj.C.Nair@noaa.gov\n");
01442 printf(" or\n");
01443 printf(" Stefan.Maus@noaa.gov\n");
01444 printf(" Web: http://www.ngdc.noaa.gov/Geomagnetic/WMM/DoDWMM.shtml\n");
01445 printf("\n VALID RANGE = %d - %d\n", (int) MagneticModel->epoch, (int) MagneticModel->CoefficientFileEndDate);
01446 printf(" TIME = %lf\n", value);
01447 while(1)
01448 {
01449 printf("\nPlease press 'C' to continue, 'N' to enter new data or 'X' to exit...\n");
01450 fgets(ans, 20, stdin);
01451 switch(ans[0]) {
01452 case 'X':
01453 case 'x':
01454 return 0;
01455 case 'N':
01456 case 'n':
01457 return 1;
01458 case 'C':
01459 case 'c':
01460 return 2;
01461 default:
01462 printf("\nInvalid input %c\n", ans[0]);
01463 break;
01464 }
01465 }
01466 break;
01467 }
01468 return 2;
01469 }
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481 MAGtype_LegendreFunction *MAG_AllocateLegendreFunctionMemory(int NumTerms)
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498 {
01499 MAGtype_LegendreFunction *LegendreFunction;
01500
01501 LegendreFunction = (MAGtype_LegendreFunction *) calloc(1, sizeof (MAGtype_LegendreFunction));
01502
01503 if(!LegendreFunction)
01504 {
01505 MAG_Error(1);
01506
01507 return FALSE;
01508 }
01509 LegendreFunction->Pcup = (double *) malloc((NumTerms + 1) * sizeof ( double));
01510 if(LegendreFunction->Pcup == 0)
01511 {
01512 MAG_Error(1);
01513
01514 return FALSE;
01515 }
01516 LegendreFunction->dPcup = (double *) malloc((NumTerms + 1) * sizeof ( double));
01517 if(LegendreFunction->dPcup == 0)
01518 {
01519 MAG_Error(1);
01520
01521 return FALSE;
01522 }
01523 return LegendreFunction;
01524 }
01525
01526 MAGtype_MagneticModel *MAG_AllocateModelMemory(int NumTerms)
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549 {
01550 MAGtype_MagneticModel *MagneticModel;
01551
01552
01553 MagneticModel = (MAGtype_MagneticModel *) calloc(1, sizeof (MAGtype_MagneticModel));
01554
01555 if(MagneticModel == NULL)
01556 {
01557 MAG_Error(2);
01558
01559 return FALSE;
01560 }
01561
01562 MagneticModel->Main_Field_Coeff_G = (double *) malloc((NumTerms + 1) * sizeof ( double));
01563
01564 if(MagneticModel->Main_Field_Coeff_G == NULL)
01565 {
01566 MAG_Error(2);
01567
01568 return FALSE;
01569 }
01570
01571 MagneticModel->Main_Field_Coeff_H = (double *) malloc((NumTerms + 1) * sizeof ( double));
01572
01573 if(MagneticModel->Main_Field_Coeff_H == NULL)
01574 {
01575 MAG_Error(2);
01576
01577 return FALSE;
01578 }
01579 MagneticModel->Secular_Var_Coeff_G = (double *) malloc((NumTerms + 1) * sizeof ( double));
01580 if(MagneticModel->Secular_Var_Coeff_G == NULL)
01581 {
01582 MAG_Error(2);
01583
01584 return FALSE;
01585 }
01586 MagneticModel->Secular_Var_Coeff_H = (double *) malloc((NumTerms + 1) * sizeof ( double));
01587 if(MagneticModel->Secular_Var_Coeff_H == NULL)
01588 {
01589 MAG_Error(2);
01590
01591 return FALSE;
01592 }
01593 return MagneticModel;
01594
01595 }
01596
01597 MAGtype_SphericalHarmonicVariables* MAG_AllocateSphVarMemory(int nMax)
01598 {
01599 MAGtype_SphericalHarmonicVariables* SphVariables;
01600 SphVariables = (MAGtype_SphericalHarmonicVariables*) calloc(1, sizeof(MAGtype_SphericalHarmonicVariables));
01601 SphVariables->RelativeRadiusPower = (double *) malloc((nMax + 1) * sizeof ( double));
01602 SphVariables->cos_mlambda = (double *) malloc((nMax + 1) * sizeof (double));
01603 SphVariables->sin_mlambda = (double *) malloc((nMax + 1) * sizeof (double));
01604 return SphVariables;
01605 }
01606
01607 void MAG_AssignHeaderValues(MAGtype_MagneticModel *model, char values[][MAXLINELENGTH])
01608 {
01609
01610 strcpy(model->ModelName, values[MODELNAME]);
01611
01612
01613
01614
01615
01616
01617
01618 model->epoch = atof(values[MODELSTARTYEAR]);
01619 model->nMax = atoi(values[INTSTATICDEG]);
01620 model->nMaxSecVar = atoi(values[INTSECVARDEG]);
01621 model->CoefficientFileEndDate = atof(values[MODELENDYEAR]);
01622 if(model->nMaxSecVar > 0)
01623 model->SecularVariationUsed = 1;
01624 else
01625 model->SecularVariationUsed = 0;
01626 }
01627
01628 void MAG_AssignMagneticModelCoeffs(MAGtype_MagneticModel *Assignee, MAGtype_MagneticModel *Source, int nMax, int nMaxSecVar)
01629
01630
01631 {
01632 int n, m, index;
01633 assert(nMax <= Source->nMax);
01634 assert(nMax <= Assignee->nMax);
01635 assert(nMaxSecVar <= Source->nMaxSecVar);
01636 assert(nMaxSecVar <= Assignee->nMaxSecVar);
01637 for(n = 1; n <= nMaxSecVar; n++)
01638 {
01639 for(m = 0; m <= n; m++)
01640 {
01641 index = (n * (n + 1) / 2 + m);
01642 Assignee->Main_Field_Coeff_G[index] = Source->Main_Field_Coeff_G[index];
01643 Assignee->Main_Field_Coeff_H[index] = Source->Main_Field_Coeff_H[index];
01644 Assignee->Secular_Var_Coeff_G[index] = Source->Secular_Var_Coeff_G[index];
01645 Assignee->Secular_Var_Coeff_H[index] = Source->Secular_Var_Coeff_H[index];
01646 }
01647 }
01648 for(n = nMaxSecVar + 1; n <= nMax; n++)
01649 {
01650 for(m = 0; m <= n; m++)
01651 {
01652 index = (n * (n + 1) / 2 + m);
01653 Assignee->Main_Field_Coeff_G[index] = Source->Main_Field_Coeff_G[index];
01654 Assignee->Main_Field_Coeff_H[index] = Source->Main_Field_Coeff_H[index];
01655 }
01656 }
01657 return;
01658 }
01659
01660 int MAG_FreeMemory(MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel, MAGtype_LegendreFunction *LegendreFunction)
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685 {
01686 if(MagneticModel->Main_Field_Coeff_G)
01687 {
01688 free(MagneticModel->Main_Field_Coeff_G);
01689 MagneticModel->Main_Field_Coeff_G = NULL;
01690 }
01691 if(MagneticModel->Main_Field_Coeff_H)
01692 {
01693 free(MagneticModel->Main_Field_Coeff_H);
01694 MagneticModel->Main_Field_Coeff_H = NULL;
01695 }
01696 if(MagneticModel->Secular_Var_Coeff_G)
01697 {
01698 free(MagneticModel->Secular_Var_Coeff_G);
01699 MagneticModel->Secular_Var_Coeff_G = NULL;
01700 }
01701 if(MagneticModel->Secular_Var_Coeff_H)
01702 {
01703 free(MagneticModel->Secular_Var_Coeff_H);
01704 MagneticModel->Secular_Var_Coeff_H = NULL;
01705 }
01706 if(MagneticModel)
01707 {
01708 free(MagneticModel);
01709 MagneticModel = NULL;
01710 }
01711
01712 if(TimedMagneticModel->Main_Field_Coeff_G)
01713 {
01714 free(TimedMagneticModel->Main_Field_Coeff_G);
01715 TimedMagneticModel->Main_Field_Coeff_G = NULL;
01716 }
01717 if(TimedMagneticModel->Main_Field_Coeff_H)
01718 {
01719 free(TimedMagneticModel->Main_Field_Coeff_H);
01720 TimedMagneticModel->Main_Field_Coeff_H = NULL;
01721 }
01722 if(TimedMagneticModel->Secular_Var_Coeff_G)
01723 {
01724 free(TimedMagneticModel->Secular_Var_Coeff_G);
01725 TimedMagneticModel->Secular_Var_Coeff_G = NULL;
01726 }
01727 if(TimedMagneticModel->Secular_Var_Coeff_H)
01728 {
01729 free(TimedMagneticModel->Secular_Var_Coeff_H);
01730 TimedMagneticModel->Secular_Var_Coeff_H = NULL;
01731 }
01732
01733 if(TimedMagneticModel)
01734 {
01735 free(TimedMagneticModel);
01736 TimedMagneticModel = NULL;
01737 }
01738
01739 if(LegendreFunction->Pcup)
01740 {
01741 free(LegendreFunction->Pcup);
01742 LegendreFunction->Pcup = NULL;
01743 }
01744 if(LegendreFunction->dPcup)
01745 {
01746 free(LegendreFunction->dPcup);
01747 LegendreFunction->dPcup = NULL;
01748 }
01749 if(LegendreFunction)
01750 {
01751 free(LegendreFunction);
01752 LegendreFunction = NULL;
01753 }
01754
01755 return TRUE;
01756 }
01757
01758 int MAG_FreeMagneticModelMemory(MAGtype_MagneticModel *MagneticModel)
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778 {
01779 if(MagneticModel->Main_Field_Coeff_G)
01780 {
01781 free(MagneticModel->Main_Field_Coeff_G);
01782 MagneticModel->Main_Field_Coeff_G = NULL;
01783 }
01784 if(MagneticModel->Main_Field_Coeff_H)
01785 {
01786 free(MagneticModel->Main_Field_Coeff_H);
01787 MagneticModel->Main_Field_Coeff_H = NULL;
01788 }
01789 if(MagneticModel->Secular_Var_Coeff_G)
01790 {
01791 free(MagneticModel->Secular_Var_Coeff_G);
01792 MagneticModel->Secular_Var_Coeff_G = NULL;
01793 }
01794 if(MagneticModel->Secular_Var_Coeff_H)
01795 {
01796 free(MagneticModel->Secular_Var_Coeff_H);
01797 MagneticModel->Secular_Var_Coeff_H = NULL;
01798 }
01799 if(MagneticModel)
01800 {
01801 free(MagneticModel);
01802 MagneticModel = NULL;
01803 }
01804
01805 return TRUE;
01806 }
01807
01808 int MAG_FreeLegendreMemory(MAGtype_LegendreFunction *LegendreFunction)
01809
01810
01811
01812
01813
01814
01815
01816
01817
01818
01819 {
01820 if(LegendreFunction->Pcup)
01821 {
01822 free(LegendreFunction->Pcup);
01823 LegendreFunction->Pcup = NULL;
01824 }
01825 if(LegendreFunction->dPcup)
01826 {
01827 free(LegendreFunction->dPcup);
01828 LegendreFunction->dPcup = NULL;
01829 }
01830 if(LegendreFunction)
01831 {
01832 free(LegendreFunction);
01833 LegendreFunction = NULL;
01834 }
01835
01836 return TRUE;
01837 }
01838
01839 int MAG_FreeSphVarMemory(MAGtype_SphericalHarmonicVariables *SphVar)
01840
01841
01842
01843
01844
01845
01846
01847
01848
01849 {
01850 if(SphVar->RelativeRadiusPower)
01851 {
01852 free(SphVar->RelativeRadiusPower);
01853 SphVar->RelativeRadiusPower = NULL;
01854 }
01855 if(SphVar->cos_mlambda)
01856 {
01857 free(SphVar->cos_mlambda);
01858 SphVar->cos_mlambda = NULL;
01859 }
01860 if(SphVar->sin_mlambda)
01861 {
01862 free(SphVar->sin_mlambda);
01863 SphVar->sin_mlambda = NULL;
01864 }
01865 if(SphVar)
01866 {
01867 free(SphVar);
01868 SphVar = NULL;
01869 }
01870
01871 return TRUE;
01872 }
01873
01874 void MAG_PrintWMMFormat(char *filename, MAGtype_MagneticModel *MagneticModel)
01875 {
01876 int index, n, m;
01877 FILE *OUT;
01878 MAGtype_Date Date;
01879 char Datestring[11];
01880
01881 Date.DecimalYear = MagneticModel->EditionDate;
01882 MAG_YearToDate(&Date);
01883 sprintf(Datestring, "%d/%d/%d", Date.Month, Date.Day, Date.Year);
01884 OUT = fopen(filename, "w");
01885 fprintf(OUT, " %.1lf %s %s\n", MagneticModel->epoch, MagneticModel->ModelName, Datestring);
01886 for(n = 1; n <= MagneticModel->nMax; n++)
01887 {
01888 for(m = 0; m <= n; m++)
01889 {
01890 index = (n * (n + 1) / 2 + m);
01891 if(m != 0)
01892 fprintf(OUT, " %2d %2d %9.1lf %9.1lf %9.1lf %9.1lf\n", n, m, MagneticModel->Main_Field_Coeff_G[index], MagneticModel->Main_Field_Coeff_H[index], MagneticModel->Secular_Var_Coeff_G[index], MagneticModel->Secular_Var_Coeff_H[index]);
01893 else
01894 fprintf(OUT, " %2d %2d %9.1lf %9.1lf %9.1lf %9.1lf\n", n, m, MagneticModel->Main_Field_Coeff_G[index], 0.0, MagneticModel->Secular_Var_Coeff_G[index], 0.0);
01895 }
01896 }
01897 fclose(OUT);
01898 }
01899
01900 void MAG_PrintEMMFormat(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel)
01901 {
01902 int index, n, m;
01903 FILE *OUT;
01904 MAGtype_Date Date;
01905 char Datestring[11];
01906
01907 Date.DecimalYear = MagneticModel->EditionDate;
01908 MAG_YearToDate(&Date);
01909 sprintf(Datestring, "%d/%d/%d", Date.Month, Date.Day, Date.Year);
01910 OUT = fopen(filename, "w");
01911 fprintf(OUT, " %.1lf %s %s\n", MagneticModel->epoch, MagneticModel->ModelName, Datestring);
01912 for(n = 1; n <= MagneticModel->nMax; n++)
01913 {
01914 for(m = 0; m <= n; m++)
01915 {
01916 index = (n * (n + 1) / 2 + m);
01917 if(m != 0)
01918 fprintf(OUT, " %2d %2d %9.4lf %9.4lf\n", n, m, MagneticModel->Main_Field_Coeff_G[index], MagneticModel->Main_Field_Coeff_H[index]);
01919 else
01920 fprintf(OUT, " %2d %2d %9.4lf %9.4lf\n", n, m, MagneticModel->Main_Field_Coeff_G[index], 0.0);
01921 }
01922 }
01923 fclose(OUT);
01924 OUT = fopen(filenameSV, "w");
01925 for(n = 1; n <= MagneticModel->nMaxSecVar; n++)
01926 {
01927 for(m = 0; m <= n; m++)
01928 {
01929 index = (n * (n + 1) / 2 + m);
01930 if(m != 0)
01931 fprintf(OUT, " %2d %2d %9.4lf %9.4lf\n", n, m, MagneticModel->Secular_Var_Coeff_G[index], MagneticModel->Secular_Var_Coeff_H[index]);
01932 else
01933 fprintf(OUT, " %2d %2d %9.4lf %9.4lf\n", n, m, MagneticModel->Secular_Var_Coeff_G[index], 0.0);
01934 }
01935 }
01936 fclose(OUT);
01937 return;
01938 }
01939
01940 int MAG_readMagneticModel(char *filename, MAGtype_MagneticModel * MagneticModel)
01941 {
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958 FILE *MAG_COF_File;
01959 char c_str[81], c_new[5];
01960 int i, icomp, m, n, EOF_Flag = 0, index;
01961 double epoch, gnm, hnm, dgnm, dhnm;
01962 MAG_COF_File = fopen(filename, "r");
01963 if(MAG_COF_File == NULL)
01964 {
01965 MAG_Error(20);
01966
01967 return FALSE;
01968
01969 }
01970 MagneticModel->Main_Field_Coeff_H[0] = 0.0;
01971 MagneticModel->Main_Field_Coeff_G[0] = 0.0;
01972 MagneticModel->Secular_Var_Coeff_H[0] = 0.0;
01973 MagneticModel->Secular_Var_Coeff_G[0] = 0.0;
01974 fgets(c_str, 80, MAG_COF_File);
01975 sscanf(c_str, "%lf%s", &epoch, MagneticModel->ModelName);
01976 MagneticModel->epoch = epoch;
01977 while(EOF_Flag == 0)
01978 {
01979 fgets(c_str, 80, MAG_COF_File);
01980
01981 for(i = 0; i < 4 && (c_str[i] != '\0'); i++)
01982 {
01983 c_new[i] = c_str[i];
01984 c_new[i + 1] = '\0';
01985 }
01986 icomp = strcmp("9999", c_new);
01987 if(icomp == 0)
01988 {
01989 EOF_Flag = 1;
01990 break;
01991 }
01992
01993 sscanf(c_str, "%d%d%lf%lf%lf%lf", &n, &m, &gnm, &hnm, &dgnm, &dhnm);
01994 if(m <= n)
01995 {
01996 index = (n * (n + 1) / 2 + m);
01997 MagneticModel->Main_Field_Coeff_G[index] = gnm;
01998 MagneticModel->Secular_Var_Coeff_G[index] = dgnm;
01999 MagneticModel->Main_Field_Coeff_H[index] = hnm;
02000 MagneticModel->Secular_Var_Coeff_H[index] = dhnm;
02001 }
02002 }
02003
02004 fclose(MAG_COF_File);
02005 return TRUE;
02006 }
02007
02008 int MAG_readMagneticModel_Large(char *filename, char *filenameSV, MAGtype_MagneticModel *MagneticModel)
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026 {
02027 FILE *MAG_COF_File;
02028 FILE *MAG_COFSV_File;
02029 char c_str[81], c_str2[81];
02030 int i, m, n, index, a, b;
02031 double epoch, gnm, hnm, dgnm, dhnm;
02032 MAG_COF_File = fopen(filename, "r");
02033 MAG_COFSV_File = fopen(filenameSV, "r");
02034 if(MAG_COF_File == NULL || MAG_COFSV_File == NULL)
02035 {
02036 MAG_Error(20);
02037
02038 return FALSE;
02039 }
02040 MagneticModel->Main_Field_Coeff_H[0] = 0.0;
02041 MagneticModel->Main_Field_Coeff_G[0] = 0.0;
02042 MagneticModel->Secular_Var_Coeff_H[0] = 0.0;
02043 MagneticModel->Secular_Var_Coeff_G[0] = 0.0;
02044 fgets(c_str, 80, MAG_COF_File);
02045 sscanf(c_str, "%lf%s", &epoch, MagneticModel->ModelName);
02046 MagneticModel->epoch = epoch;
02047 a = (MagneticModel->nMaxSecVar * (MagneticModel->nMaxSecVar + 1) / 2 + MagneticModel->nMaxSecVar);
02048 b = (MagneticModel->nMax * (MagneticModel->nMax + 1) / 2 + MagneticModel->nMax);
02049
02050 for(i = 0; i <= a; i++)
02051 {
02052 fgets(c_str, 80, MAG_COF_File);
02053 sscanf(c_str, "%d%d%lf%lf", &n, &m, &gnm, &hnm);
02054 fgets(c_str2, 80, MAG_COFSV_File);
02055 sscanf(c_str2, "%d%d%lf%lf", &n, &m, &dgnm, &dhnm);
02056 if(m <= n)
02057 {
02058 index = (n * (n + 1) / 2 + m);
02059 MagneticModel->Main_Field_Coeff_G[index] = gnm;
02060 MagneticModel->Secular_Var_Coeff_G[index] = dgnm;
02061 MagneticModel->Main_Field_Coeff_H[index] = hnm;
02062 MagneticModel->Secular_Var_Coeff_H[index] = dhnm;
02063 }
02064 }
02065 for(i = a + 1; i < b; i++)
02066 {
02067 fgets(c_str, 80, MAG_COF_File);
02068 sscanf(c_str, "%d%d%lf%lf", &n, &m, &gnm, &hnm);
02069 if(m <= n)
02070 {
02071 index = (n * (n + 1) / 2 + m);
02072 MagneticModel->Main_Field_Coeff_G[index] = gnm;
02073
02074 MagneticModel->Main_Field_Coeff_H[index] = hnm;
02075
02076 }
02077 }
02078 if(MAG_COF_File != NULL && MAG_COFSV_File != NULL)
02079 {
02080 fclose(MAG_COF_File);
02081 fclose(MAG_COFSV_File);
02082 }
02083
02084 return TRUE;
02085 }
02086
02087 int MAG_readMagneticModel_SHDF(char *filename, MAGtype_MagneticModel *(*magneticmodels)[], int array_size)
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106 {
02107 char paramkeys[NOOFPARAMS][MAXLINELENGTH] = {
02108 "SHDF ",
02109 "ModelName: ",
02110 "Publisher: ",
02111 "ReleaseDate: ",
02112 "DataCutOff: ",
02113 "ModelStartYear: ",
02114 "ModelEndYear: ",
02115 "Epoch: ",
02116 "IntStaticDeg: ",
02117 "IntSecVarDeg: ",
02118 "ExtStaticDeg: ",
02119 "ExtSecVarDeg: ",
02120 "GeoMagRefRad: ",
02121 "Normalization: ",
02122 "SpatBasFunc: "
02123 };
02124
02125 char paramvalues[NOOFPARAMS][MAXLINELENGTH];
02126 char *line = (char *) malloc(MAXLINELENGTH);
02127 char *ptrreset;
02128 char paramvalue[MAXLINELENGTH];
02129 int paramvaluelength = 0;
02130 int paramkeylength = 0;
02131 int i = 0, j = 0;
02132 int newrecord = 1;
02133 int header_index = -1;
02134 int numterms;
02135 int tempint;
02136 int allocationflag = 0;
02137 char coefftype;
02138
02139
02140 int n, m;
02141 double gnm, hnm, dgnm, dhnm, cutoff;
02142 int index;
02143
02144
02145
02146 FILE *stream;
02147 ptrreset = line;
02148 stream = fopen(filename, READONLYMODE);
02149 if(stream == NULL)
02150 {
02151 perror("File open error");
02152 return header_index;
02153 }
02154
02155
02156 while(fgets(line, MAXLINELENGTH, stream) != NULL)
02157 {
02158 j++;
02159 if(strlen(MAG_Trim(line)) == 0)
02160 continue;
02161 if(*line == '%')
02162 {
02163 line++;
02164 if(newrecord)
02165 {
02166 if(header_index > -1)
02167 {
02168 MAG_AssignHeaderValues((*magneticmodels)[header_index], paramvalues);
02169 }
02170 header_index++;
02171 if(header_index >= array_size)
02172 {
02173 fprintf(stderr, "Header limit exceeded - too many models in model file. (%d)\n", header_index);
02174 return array_size + 1;
02175 }
02176 newrecord = 0;
02177 allocationflag = 0;
02178 }
02179 for(i = 0; i < NOOFPARAMS; i++)
02180 {
02181
02182 paramkeylength = strlen(paramkeys[i]);
02183 if(!strncmp(line, paramkeys[i], paramkeylength))
02184 {
02185 paramvaluelength = strlen(line) - paramkeylength;
02186 strncpy(paramvalue, line + paramkeylength, paramvaluelength);
02187 paramvalue[paramvaluelength] = '\0';
02188 strcpy(paramvalues[i], paramvalue);
02189 if(!strcmp(paramkeys[i], paramkeys[INTSTATICDEG]) || !strcmp(paramkeys[i], paramkeys[EXTSTATICDEG]))
02190 {
02191 tempint = atoi(paramvalues[i]);
02192 if(tempint > 0 && allocationflag == 0)
02193 {
02194 numterms = CALCULATE_NUMTERMS(tempint);
02195 (*magneticmodels)[header_index] = MAG_AllocateModelMemory(numterms);
02196
02197 allocationflag = 1;
02198 }
02199 }
02200 break;
02201 }
02202 }
02203 line--;
02204 } else if(*line == '#')
02205 {
02206
02207
02208 } else if(sscanf(line, "%c,%d,%d", &coefftype, &n, &m) == 3)
02209 {
02210 if(m == 0)
02211 {
02212 sscanf(line, "%c,%d,%d,%lf,,%lf,", &coefftype, &n, &m, &gnm, &dgnm);
02213 hnm = 0;
02214 dhnm = 0;
02215 } else
02216 sscanf(line, "%c,%d,%d,%lf,%lf,%lf,%lf", &coefftype, &n, &m, &gnm, &hnm, &dgnm, &dhnm);
02217 newrecord = 1;
02218 if(!allocationflag)
02219 {
02220 fprintf(stderr, "Degree not found in model. Memory cannot be allocated.\n");
02221 return _DEGREE_NOT_FOUND;
02222 }
02223 if(m <= n)
02224 {
02225 index = (n * (n + 1) / 2 + m);
02226 (*magneticmodels)[header_index]->Main_Field_Coeff_G[index] = gnm;
02227 (*magneticmodels)[header_index]->Secular_Var_Coeff_G[index] = dgnm;
02228 (*magneticmodels)[header_index]->Main_Field_Coeff_H[index] = hnm;
02229 (*magneticmodels)[header_index]->Secular_Var_Coeff_H[index] = dhnm;
02230 }
02231 }
02232 }
02233 if(header_index > -1)
02234 MAG_AssignHeaderValues((*magneticmodels)[header_index], paramvalues);
02235 fclose(stream);
02236
02237 cutoff = (*magneticmodels)[array_size - 1]->CoefficientFileEndDate;
02238
02239 for(i = 0; i < array_size; i++) (*magneticmodels)[i]->CoefficientFileEndDate = cutoff;
02240
02241 free(ptrreset);
02242 line = NULL;
02243 ptrreset = NULL;
02244 return header_index + 1;
02245 }
02246
02247 char *MAG_Trim(char *str)
02248 {
02249 char *end;
02250
02251 while(isspace(*str))
02252 str++;
02253
02254 if(*str == 0)
02255 return str;
02256
02257 end = str + strlen(str) - 1;
02258 while(end > str && isspace(*end))
02259 end--;
02260
02261 *(end + 1) = 0;
02262
02263 return str;
02264 }
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278 int MAG_CalculateGeoMagneticElements(MAGtype_MagneticResults *MagneticResultsGeo, MAGtype_GeoMagneticElements *GeoMagneticElements)
02279
02280
02281
02282
02283
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295 {
02296 GeoMagneticElements->X = MagneticResultsGeo->Bx;
02297 GeoMagneticElements->Y = MagneticResultsGeo->By;
02298 GeoMagneticElements->Z = MagneticResultsGeo->Bz;
02299
02300 GeoMagneticElements->H = sqrt(MagneticResultsGeo->Bx * MagneticResultsGeo->Bx + MagneticResultsGeo->By * MagneticResultsGeo->By);
02301 GeoMagneticElements->F = sqrt(GeoMagneticElements->H * GeoMagneticElements->H + MagneticResultsGeo->Bz * MagneticResultsGeo->Bz);
02302 GeoMagneticElements->Decl = RAD2DEG(atan2(GeoMagneticElements->Y, GeoMagneticElements->X));
02303 GeoMagneticElements->Incl = RAD2DEG(atan2(GeoMagneticElements->Z, GeoMagneticElements->H));
02304
02305 return TRUE;
02306 }
02307
02308 int MAG_CalculateGridVariation(MAGtype_CoordGeodetic location, MAGtype_GeoMagneticElements *elements)
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328 {
02329 MAGtype_UTMParameters UTMParameters;
02330 if(location.phi >= MAG_PS_MAX_LAT_DEGREE)
02331 {
02332 elements->GV = elements->Decl - location.lambda;
02333 return 1;
02334 } else if(location.phi <= MAG_PS_MIN_LAT_DEGREE)
02335 {
02336 elements->GV = elements->Decl + location.lambda;
02337 return 1;
02338 } else
02339 {
02340 MAG_GetTransverseMercator(location, &UTMParameters);
02341 elements->GV = elements->Decl - UTMParameters.ConvergenceOfMeridians;
02342 }
02343 return 0;
02344 }
02345
02346 int MAG_CalculateSecularVariationElements(MAGtype_MagneticResults MagneticVariation, MAGtype_GeoMagneticElements *MagneticElements)
02347
02348
02349
02350
02351
02352
02353
02354
02355
02356
02357
02358
02359
02360
02361
02362
02363
02364 {
02365 MagneticElements->Xdot = MagneticVariation.Bx;
02366 MagneticElements->Ydot = MagneticVariation.By;
02367 MagneticElements->Zdot = MagneticVariation.Bz;
02368 MagneticElements->Hdot = (MagneticElements->X * MagneticElements->Xdot + MagneticElements->Y * MagneticElements->Ydot) / MagneticElements->H;
02369 MagneticElements->Fdot = (MagneticElements->X * MagneticElements->Xdot + MagneticElements->Y * MagneticElements->Ydot + MagneticElements->Z * MagneticElements->Zdot) / MagneticElements->F;
02370 MagneticElements->Decldot = 180.0 / M_PI * (MagneticElements->X * MagneticElements->Ydot - MagneticElements->Y * MagneticElements->Xdot) / (MagneticElements->H * MagneticElements->H);
02371 MagneticElements->Incldot = 180.0 / M_PI * (MagneticElements->H * MagneticElements->Zdot - MagneticElements->Z * MagneticElements->Hdot) / (MagneticElements->F * MagneticElements->F);
02372 MagneticElements->GVdot = MagneticElements->Decldot;
02373 return TRUE;
02374 }
02375
02376 int MAG_DateToYear(MAGtype_Date *CalendarDate, char *Error)
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387
02388
02389
02390
02391 {
02392 int temp = 0;
02393 int MonthDays[13];
02394 int ExtraDay = 0;
02395 int i;
02396 if(CalendarDate->Month == 0)
02397 {
02398 CalendarDate->DecimalYear = CalendarDate->Year;
02399 return TRUE;
02400 }
02401 if((CalendarDate->Year % 4 == 0 && CalendarDate->Year % 100 != 0) || CalendarDate->Year % 400 == 0)
02402 ExtraDay = 1;
02403 MonthDays[0] = 0;
02404 MonthDays[1] = 31;
02405 MonthDays[2] = 28 + ExtraDay;
02406 MonthDays[3] = 31;
02407 MonthDays[4] = 30;
02408 MonthDays[5] = 31;
02409 MonthDays[6] = 30;
02410 MonthDays[7] = 31;
02411 MonthDays[8] = 31;
02412 MonthDays[9] = 30;
02413 MonthDays[10] = 31;
02414 MonthDays[11] = 30;
02415 MonthDays[12] = 31;
02416
02417
02418 if(CalendarDate->Month <= 0 || CalendarDate->Month > 12)
02419 {
02420 strcpy(Error, "\nError: The Month entered is invalid, valid months are '1 to 12'\n");
02421 return 0;
02422 }
02423 if(CalendarDate->Day <= 0 || CalendarDate->Day > MonthDays[CalendarDate->Month])
02424 {
02425 printf("\nThe number of days in month %d is %d\n", CalendarDate->Month, MonthDays[CalendarDate->Month]);
02426 strcpy(Error, "\nError: The day entered is invalid\n");
02427 return 0;
02428 }
02429
02430 for(i = 1; i <= CalendarDate->Month; i++)
02431 temp += MonthDays[i - 1];
02432 temp += CalendarDate->Day;
02433 CalendarDate->DecimalYear = CalendarDate->Year + (temp - 1) / (365.0 + ExtraDay);
02434 return TRUE;
02435
02436 }
02437
02438 void MAG_DegreeToDMSstring(double DegreesOfArc, int UnitDepth, char *DMSstring)
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449 {
02450 int DMS[3], i;
02451 double temp = DegreesOfArc;
02452 char tempstring[20] = "";
02453 char tempstring2[20] = "";
02454 strcpy(DMSstring, "");
02455 if(UnitDepth >= 3)
02456 MAG_Error(21);
02457 for(i = 0; i < UnitDepth; i++)
02458 {
02459 DMS[i] = (int) temp;
02460 switch(i) {
02461 case 0:
02462 strcpy(tempstring2, "Deg");
02463 break;
02464 case 1:
02465 strcpy(tempstring2, "Min");
02466 break;
02467 case 2:
02468 strcpy(tempstring2, "Sec");
02469 break;
02470 }
02471 temp = (temp - DMS[i])*60;
02472 if(i == UnitDepth - 1 && temp >= 30)
02473 DMS[i]++;
02474 else if(i == UnitDepth - 1 && temp <= -30)
02475 DMS[i]--;
02476 sprintf(tempstring, "%4d%4s", DMS[i], tempstring2);
02477 strcat(DMSstring, tempstring);
02478 }
02479 }
02480
02481 void MAG_DMSstringToDegree(char *DMSstring, double *DegreesOfArc)
02482
02483
02484
02485
02486
02487
02488 {
02489 int second, minute, degree, sign = 1, j = 0;
02490 j = sscanf(DMSstring, "%d, %d, %d", °ree, &minute, &second);
02491 if(j != 3)
02492 sscanf(DMSstring, "%d %d %d", °ree, &minute, &second);
02493 if(degree < 0)
02494 sign = -1;
02495 degree = degree * sign;
02496 *DegreesOfArc = sign * (degree + minute / 60.0 + second / 3600.0);
02497 }
02498
02499 int MAG_GeodeticToSpherical(MAGtype_Ellipsoid Ellip, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_CoordSpherical *CoordSpherical)
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525 {
02526 double CosLat, SinLat, rc, xp, zp;
02527
02528
02529
02530
02531
02532
02533
02534 CosLat = cos(DEG2RAD(CoordGeodetic.phi));
02535 SinLat = sin(DEG2RAD(CoordGeodetic.phi));
02536
02537
02538
02539 rc = Ellip.a / sqrt(1.0 - Ellip.epssq * SinLat * SinLat);
02540
02541
02542
02543 xp = (rc + CoordGeodetic.HeightAboveEllipsoid) * CosLat;
02544 zp = (rc * (1.0 - Ellip.epssq) + CoordGeodetic.HeightAboveEllipsoid) * SinLat;
02545
02546
02547
02548 CoordSpherical->r = sqrt(xp * xp + zp * zp);
02549 CoordSpherical->phig = RAD2DEG(asin(zp / CoordSpherical->r));
02550 CoordSpherical->lambda = CoordGeodetic.lambda;
02551
02552 return TRUE;
02553 }
02554
02555 int MAG_GetTransverseMercator(MAGtype_CoordGeodetic CoordGeodetic, MAGtype_UTMParameters *UTMParameters)
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568 {
02569
02570 double Eps, Epssq;
02571 double Acoeff[8];
02572 double Lam0, K0, falseE, falseN;
02573 double K0R4, K0R4oa;
02574 double Lambda, Phi;
02575 int XYonly;
02576 double X, Y, pscale, CoM;
02577 int Zone;
02578 char Hemisphere;
02579
02580
02581
02582
02583
02584 Lambda = DEG2RAD(CoordGeodetic.lambda);
02585 Phi = DEG2RAD(CoordGeodetic.phi);
02586
02587 MAG_GetUTMParameters(Phi, Lambda, &Zone, &Hemisphere, &Lam0);
02588 K0 = 0.9996;
02589
02590
02591
02592 if(Hemisphere == 'n' || Hemisphere == 'N')
02593 {
02594 falseN = 0;
02595 }
02596 if(Hemisphere == 's' || Hemisphere == 'S')
02597 {
02598 falseN = 10000000;
02599 }
02600
02601 falseE = 500000;
02602
02603
02604
02605
02606 Eps = 0.081819190842621494335;
02607 Epssq = 0.0066943799901413169961;
02608 K0R4 = 6367449.1458234153093;
02609 K0R4oa = 0.99832429843125277950;
02610
02611
02612 Acoeff[0] = 8.37731820624469723600E-04;
02613 Acoeff[1] = 7.60852777357248641400E-07;
02614 Acoeff[2] = 1.19764550324249124400E-09;
02615 Acoeff[3] = 2.42917068039708917100E-12;
02616 Acoeff[4] = 5.71181837042801392800E-15;
02617 Acoeff[5] = 1.47999793137966169400E-17;
02618 Acoeff[6] = 4.10762410937071532000E-20;
02619 Acoeff[7] = 1.21078503892257704200E-22;
02620
02621
02622
02623
02624
02625
02626 XYonly = 0;
02627
02628 MAG_TMfwd4(Eps, Epssq, K0R4, K0R4oa, Acoeff,
02629 Lam0, K0, falseE, falseN,
02630 XYonly,
02631 Lambda, Phi,
02632 &X, &Y, &pscale, &CoM);
02633
02634
02635
02636 UTMParameters->Easting = X;
02637 UTMParameters->Northing = Y;
02638 UTMParameters->Zone = Zone;
02639 UTMParameters->HemiSphere = Hemisphere;
02640 UTMParameters->CentralMeridian = RAD2DEG(Lam0);
02641 UTMParameters->ConvergenceOfMeridians = RAD2DEG(CoM);
02642 UTMParameters->PointScale = pscale;
02643
02644 return 0;
02645 }
02646
02647 int MAG_GetUTMParameters(double Latitude,
02648 double Longitude,
02649 int *Zone,
02650 char *Hemisphere,
02651 double *CentralMeridian)
02652 {
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663
02664
02665
02666 long Lat_Degrees;
02667 long Long_Degrees;
02668 long temp_zone;
02669 int Error_Code = 0;
02670
02671
02672
02673 if((Latitude < DEG2RAD(MAG_UTM_MIN_LAT_DEGREE)) || (Latitude > DEG2RAD(MAG_UTM_MAX_LAT_DEGREE)))
02674 {
02675 MAG_Error(23);
02676 Error_Code = 1;
02677 }
02678 if((Longitude < -M_PI) || (Longitude > (2 * M_PI)))
02679 {
02680 MAG_Error(24);
02681 Error_Code = 1;
02682 }
02683 if(!Error_Code)
02684 {
02685 if(Longitude < 0)
02686 Longitude += (2 * M_PI) + 1.0e-10;
02687 Lat_Degrees = (long) (Latitude * 180.0 / M_PI);
02688 Long_Degrees = (long) (Longitude * 180.0 / M_PI);
02689
02690 if(Longitude < M_PI)
02691 temp_zone = (long) (31 + ((Longitude * 180.0 / M_PI) / 6.0));
02692 else
02693 temp_zone = (long) (((Longitude * 180.0 / M_PI) / 6.0) - 29);
02694 if(temp_zone > 60)
02695 temp_zone = 1;
02696
02697 if((Lat_Degrees > 55) && (Lat_Degrees < 64) && (Long_Degrees > -1)
02698 && (Long_Degrees < 3))
02699 temp_zone = 31;
02700 if((Lat_Degrees > 55) && (Lat_Degrees < 64) && (Long_Degrees > 2)
02701 && (Long_Degrees < 12))
02702 temp_zone = 32;
02703 if((Lat_Degrees > 71) && (Long_Degrees > -1) && (Long_Degrees < 9))
02704 temp_zone = 31;
02705 if((Lat_Degrees > 71) && (Long_Degrees > 8) && (Long_Degrees < 21))
02706 temp_zone = 33;
02707 if((Lat_Degrees > 71) && (Long_Degrees > 20) && (Long_Degrees < 33))
02708 temp_zone = 35;
02709 if((Lat_Degrees > 71) && (Long_Degrees > 32) && (Long_Degrees < 42))
02710 temp_zone = 37;
02711
02712 if(!Error_Code)
02713 {
02714 if(temp_zone >= 31)
02715 *CentralMeridian = (6 * temp_zone - 183) * M_PI / 180.0;
02716 else
02717 *CentralMeridian = (6 * temp_zone + 177) * M_PI / 180.0;
02718 *Zone = temp_zone;
02719 if(Latitude < 0) *Hemisphere = 'S';
02720 else *Hemisphere = 'N';
02721 }
02722 }
02723 return (Error_Code);
02724 }
02725
02726 int MAG_isNaN(double d)
02727 {
02728 return d != d;
02729 }
02730
02731 int MAG_RotateMagneticVector(MAGtype_CoordSpherical CoordSpherical, MAGtype_CoordGeodetic CoordGeodetic, MAGtype_MagneticResults MagneticResultsSph, MAGtype_MagneticResults *MagneticResultsGeo)
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756
02757
02758
02759
02760 {
02761 double Psi;
02762
02763 Psi = (M_PI / 180) * (CoordSpherical.phig - CoordGeodetic.phi);
02764
02765
02766 MagneticResultsGeo->Bz = MagneticResultsSph.Bx * sin(Psi) + MagneticResultsSph.Bz * cos(Psi);
02767 MagneticResultsGeo->Bx = MagneticResultsSph.Bx * cos(Psi) - MagneticResultsSph.Bz * sin(Psi);
02768 MagneticResultsGeo->By = MagneticResultsSph.By;
02769 return TRUE;
02770 }
02771
02772 void MAG_SphericalToCartesian(MAGtype_CoordSpherical CoordSpherical, double *x, double *y, double *z)
02773 {
02774 double radphi;
02775 double radlambda;
02776
02777 radphi = CoordSpherical.phig * (M_PI / 180);
02778 radlambda = CoordSpherical.lambda * (M_PI / 180);
02779
02780 *x = CoordSpherical.r * cos(radphi) * cos(radlambda);
02781 *y = CoordSpherical.r * cos(radphi) * sin(radlambda);
02782 *z = CoordSpherical.r * sin(radphi);
02783 return;
02784 }
02785
02786 void MAG_TMfwd4(double Eps, double Epssq, double K0R4, double K0R4oa,
02787 double Acoeff[], double Lam0, double K0, double falseE,
02788 double falseN, int XYonly, double Lambda, double Phi,
02789 double *X, double *Y, double *pscale, double *CoM)
02790 {
02791
02792
02793
02794
02795
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837 double Lam, CLam, SLam, CPhi, SPhi;
02838 double P, part1, part2, denom, CChi, SChi;
02839 double U, V;
02840 double T, Tsq, denom2;
02841 double c2u, s2u, c4u, s4u, c6u, s6u, c8u, s8u;
02842 double c2v, s2v, c4v, s4v, c6v, s6v, c8v, s8v;
02843 double Xstar, Ystar;
02844 double sig1, sig2, comroo;
02845
02846
02847
02848
02849
02850
02851
02852
02853
02854
02855 Lam = Lambda - Lam0;
02856 CLam = cos(Lam);
02857 SLam = sin(Lam);
02858
02859
02860
02861 CPhi = cos(Phi);
02862 SPhi = sin(Phi);
02863
02864
02865
02866
02867 P = exp(Eps * ATanH(Eps * SPhi));
02868 part1 = (1 + SPhi) / P;
02869 part2 = (1 - SPhi) * P;
02870 denom = 1 / (part1 + part2);
02871 CChi = 2 * CPhi * denom;
02872 SChi = (part1 - part2) * denom;
02873
02874
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884 T = CChi * SLam;
02885 U = ATanH(T);
02886 V = atan2(SChi, CChi * CLam);
02887
02888
02889
02890
02891
02892
02893
02894
02895
02896
02897
02898 Tsq = T * T;
02899 denom2 = 1 / (1 - Tsq);
02900 c2u = (1 + Tsq) * denom2;
02901 s2u = 2 * T * denom2;
02902 c2v = (-1 + CChi * CChi * (1 + CLam * CLam)) * denom2;
02903 s2v = 2 * CLam * CChi * SChi * denom2;
02904
02905 c4u = 1 + 2 * s2u * s2u;
02906 s4u = 2 * c2u * s2u;
02907 c4v = 1 - 2 * s2v * s2v;
02908 s4v = 2 * c2v * s2v;
02909
02910 c6u = c4u * c2u + s4u * s2u;
02911 s6u = s4u * c2u + c4u * s2u;
02912 c6v = c4v * c2v - s4v * s2v;
02913 s6v = s4v * c2v + c4v * s2v;
02914
02915 c8u = 1 + 2 * s4u * s4u;
02916 s8u = 2 * c4u * s4u;
02917 c8v = 1 - 2 * s4v * s4v;
02918 s8v = 2 * c4v * s4v;
02919
02920
02921
02922
02923
02924
02925
02926
02927 Xstar = Acoeff[3] * s8u * c8v;
02928 Xstar = Xstar + Acoeff[2] * s6u * c6v;
02929 Xstar = Xstar + Acoeff[1] * s4u * c4v;
02930 Xstar = Xstar + Acoeff[0] * s2u * c2v;
02931 Xstar = Xstar + U;
02932
02933 Ystar = Acoeff[3] * c8u * s8v;
02934 Ystar = Ystar + Acoeff[2] * c6u * s6v;
02935 Ystar = Ystar + Acoeff[1] * c4u * s4v;
02936 Ystar = Ystar + Acoeff[0] * c2u * s2v;
02937 Ystar = Ystar + V;
02938
02939
02940
02941 *X = K0R4 * Xstar + falseE;
02942 *Y = K0R4 * Ystar + falseN;
02943
02944
02945
02946
02947
02948 if(XYonly == 1)
02949 {
02950 *pscale = K0;
02951 *CoM = 0;
02952 } else
02953 {
02954 sig1 = 8 * Acoeff[3] * c8u * c8v;
02955 sig1 = sig1 + 6 * Acoeff[2] * c6u * c6v;
02956 sig1 = sig1 + 4 * Acoeff[1] * c4u * c4v;
02957 sig1 = sig1 + 2 * Acoeff[0] * c2u * c2v;
02958 sig1 = sig1 + 1;
02959
02960 sig2 = 8 * Acoeff[3] * s8u * s8v;
02961 sig2 = sig2 + 6 * Acoeff[2] * s6u * s6v;
02962 sig2 = sig2 + 4 * Acoeff[1] * s4u * s4v;
02963 sig2 = sig2 + 2 * Acoeff[0] * s2u * s2v;
02964
02965
02966 comroo = sqrt((1 - Epssq * SPhi * SPhi) * denom2 *
02967 (sig1 * sig1 + sig2 * sig2));
02968
02969 *pscale = K0R4oa * 2 * denom * comroo;
02970 *CoM = atan2(SChi * SLam, CLam) + atan2(sig2, sig1);
02971 }
02972 }
02973
02974 int MAG_YearToDate(MAGtype_Date *CalendarDate)
02975
02976
02977
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988 {
02989 int MonthDays[13], CumulativeDays = 0;
02990 int ExtraDay = 0;
02991 int i, DayOfTheYear;
02992
02993
02994 if(CalendarDate->DecimalYear == 0)
02995 {
02996 CalendarDate->Year = 0;
02997 CalendarDate->Month = 0;
02998 CalendarDate->Day = 0;
02999 return FALSE;
03000 }
03001
03002 CalendarDate->Year = (int) floor(CalendarDate->DecimalYear);
03003
03004
03005 if((CalendarDate->Year % 4 == 0 && CalendarDate->Year % 100 != 0) || CalendarDate->Year % 400 == 0)
03006 ExtraDay = 1;
03007
03008 DayOfTheYear = floor((CalendarDate->DecimalYear - (double) CalendarDate->Year) * (365.0 + (double) ExtraDay)+0.5) + 1;
03009
03010
03011
03012 MonthDays[0] = 0;
03013 MonthDays[1] = 31;
03014 MonthDays[2] = 28 + ExtraDay;
03015 MonthDays[3] = 31;
03016 MonthDays[4] = 30;
03017 MonthDays[5] = 31;
03018 MonthDays[6] = 30;
03019 MonthDays[7] = 31;
03020 MonthDays[8] = 31;
03021 MonthDays[9] = 30;
03022 MonthDays[10] = 31;
03023 MonthDays[11] = 30;
03024 MonthDays[12] = 31;
03025
03026
03027 for(i = 1; i <= 12; i++)
03028 {
03029 CumulativeDays = CumulativeDays + MonthDays[i];
03030
03031 if(DayOfTheYear <= CumulativeDays)
03032 {
03033 CalendarDate->Month = i;
03034 CalendarDate->Day = MonthDays[i] - (CumulativeDays - DayOfTheYear);
03035 break;
03036 }
03037
03038
03039 }
03040
03041
03042
03043
03044 return TRUE;
03045
03046 }
03047
03048
03049
03050
03051
03052
03053
03054
03055
03056 int MAG_AssociatedLegendreFunction(MAGtype_CoordSpherical CoordSpherical, int nMax, MAGtype_LegendreFunction *LegendreFunction)
03057
03058
03059
03060
03061
03062
03063
03064
03065
03066
03067
03068
03069
03070
03071
03072
03073 {
03074 double sin_phi;
03075 int FLAG = 1;
03076
03077 sin_phi = sin(DEG2RAD(CoordSpherical.phig));
03078
03079 if(nMax <= 16 || (1 - fabs(sin_phi)) < 1.0e-10)
03080 FLAG = MAG_PcupLow(LegendreFunction->Pcup, LegendreFunction->dPcup, sin_phi, nMax);
03081 else FLAG = MAG_PcupHigh(LegendreFunction->Pcup, LegendreFunction->dPcup, sin_phi, nMax);
03082 if(FLAG == 0)
03083 return FALSE;
03084
03085
03086 return TRUE;
03087 }
03088
03089 int MAG_CheckGeographicPole(MAGtype_CoordGeodetic *CoordGeodetic)
03090
03091
03092
03093
03094
03095
03096
03097
03098
03099
03100
03101
03102
03103
03104
03105
03106 {
03107 CoordGeodetic->phi = CoordGeodetic->phi < (-90.0 + MAG_GEO_POLE_TOLERANCE) ? (-90.0 + MAG_GEO_POLE_TOLERANCE) : CoordGeodetic->phi;
03108 CoordGeodetic->phi = CoordGeodetic->phi > (90.0 - MAG_GEO_POLE_TOLERANCE) ? (90.0 - MAG_GEO_POLE_TOLERANCE) : CoordGeodetic->phi;
03109 return TRUE;
03110 }
03111
03112 int MAG_ComputeSphericalHarmonicVariables(MAGtype_Ellipsoid Ellip, MAGtype_CoordSpherical CoordSpherical, int nMax, MAGtype_SphericalHarmonicVariables *SphVariables)
03113
03114
03115
03116
03117
03118
03119
03120
03121
03122
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136 {
03137 double cos_lambda, sin_lambda;
03138 int m, n;
03139 cos_lambda = cos(DEG2RAD(CoordSpherical.lambda));
03140 sin_lambda = sin(DEG2RAD(CoordSpherical.lambda));
03141
03142
03143 SphVariables->RelativeRadiusPower[0] = (Ellip.re / CoordSpherical.r) * (Ellip.re / CoordSpherical.r);
03144 for(n = 1; n <= nMax; n++)
03145 {
03146 SphVariables->RelativeRadiusPower[n] = SphVariables->RelativeRadiusPower[n - 1] * (Ellip.re / CoordSpherical.r);
03147 }
03148
03149
03150
03151
03152
03153
03154 SphVariables->cos_mlambda[0] = 1.0;
03155 SphVariables->sin_mlambda[0] = 0.0;
03156
03157 SphVariables->cos_mlambda[1] = cos_lambda;
03158 SphVariables->sin_mlambda[1] = sin_lambda;
03159 for(m = 2; m <= nMax; m++)
03160 {
03161 SphVariables->cos_mlambda[m] = SphVariables->cos_mlambda[m - 1] * cos_lambda - SphVariables->sin_mlambda[m - 1] * sin_lambda;
03162 SphVariables->sin_mlambda[m] = SphVariables->cos_mlambda[m - 1] * sin_lambda + SphVariables->sin_mlambda[m - 1] * cos_lambda;
03163 }
03164 return TRUE;
03165 }
03166
03167 int MAG_PcupHigh(double *Pcup, double *dPcup, double x, int nMax)
03168
03169
03170
03171
03172
03173
03174
03175
03176
03177
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209 {
03210 double pm2, pm1, pmm, plm, rescalem, z, scalef;
03211 double *f1, *f2, *PreSqr;
03212 int k, kstart, m, n, NumTerms;
03213
03214 NumTerms = ((nMax + 1) * (nMax + 2) / 2);
03215
03216
03217 if(fabs(x) == 1.0)
03218 {
03219 printf("Error in PcupHigh: derivative cannot be calculated at poles\n");
03220 return FALSE;
03221 }
03222
03223
03224 f1 = (double *) malloc((NumTerms + 1) * sizeof ( double));
03225 if(f1 == NULL)
03226 {
03227 MAG_Error(18);
03228
03229 return FALSE;
03230 }
03231
03232
03233 PreSqr = (double *) malloc((NumTerms + 1) * sizeof ( double));
03234
03235 if(PreSqr == NULL)
03236 {
03237 MAG_Error(18);
03238
03239 return FALSE;
03240 }
03241
03242 f2 = (double *) malloc((NumTerms + 1) * sizeof ( double));
03243
03244 if(f2 == NULL)
03245 {
03246 MAG_Error(18);
03247
03248 return FALSE;
03249 }
03250
03251 scalef = 1.0e-280;
03252
03253 for(n = 0; n <= 2 * nMax + 1; ++n)
03254 {
03255 PreSqr[n] = sqrt((double) (n));
03256 }
03257
03258 k = 2;
03259
03260 for(n = 2; n <= nMax; n++)
03261 {
03262 k = k + 1;
03263 f1[k] = (double) (2 * n - 1) / (double) (n);
03264 f2[k] = (double) (n - 1) / (double) (n);
03265 for(m = 1; m <= n - 2; m++)
03266 {
03267 k = k + 1;
03268 f1[k] = (double) (2 * n - 1) / PreSqr[n + m] / PreSqr[n - m];
03269 f2[k] = PreSqr[n - m - 1] * PreSqr[n + m - 1] / PreSqr[n + m] / PreSqr[n - m];
03270 }
03271 k = k + 2;
03272 }
03273
03274
03275 z = sqrt((1.0 - x)*(1.0 + x));
03276 pm2 = 1.0;
03277 Pcup[0] = 1.0;
03278 dPcup[0] = 0.0;
03279 if(nMax == 0)
03280 return FALSE;
03281 pm1 = x;
03282 Pcup[1] = pm1;
03283 dPcup[1] = z;
03284 k = 1;
03285
03286 for(n = 2; n <= nMax; n++)
03287 {
03288 k = k + n;
03289 plm = f1[k] * x * pm1 - f2[k] * pm2;
03290 Pcup[k] = plm;
03291 dPcup[k] = (double) (n) * (pm1 - x * plm) / z;
03292 pm2 = pm1;
03293 pm1 = plm;
03294 }
03295
03296 pmm = PreSqr[2] * scalef;
03297 rescalem = 1.0 / scalef;
03298 kstart = 0;
03299
03300 for(m = 1; m <= nMax - 1; ++m)
03301 {
03302 rescalem = rescalem*z;
03303
03304
03305 kstart = kstart + m + 1;
03306 pmm = pmm * PreSqr[2 * m + 1] / PreSqr[2 * m];
03307 Pcup[kstart] = pmm * rescalem / PreSqr[2 * m + 1];
03308 dPcup[kstart] = -((double) (m) * x * Pcup[kstart] / z);
03309 pm2 = pmm / PreSqr[2 * m + 1];
03310
03311 k = kstart + m + 1;
03312 pm1 = x * PreSqr[2 * m + 1] * pm2;
03313 Pcup[k] = pm1*rescalem;
03314 dPcup[k] = ((pm2 * rescalem) * PreSqr[2 * m + 1] - x * (double) (m + 1) * Pcup[k]) / z;
03315
03316 for(n = m + 2; n <= nMax; ++n)
03317 {
03318 k = k + n;
03319 plm = x * f1[k] * pm1 - f2[k] * pm2;
03320 Pcup[k] = plm*rescalem;
03321 dPcup[k] = (PreSqr[n + m] * PreSqr[n - m] * (pm1 * rescalem) - (double) (n) * x * Pcup[k]) / z;
03322 pm2 = pm1;
03323 pm1 = plm;
03324 }
03325 }
03326
03327
03328 rescalem = rescalem*z;
03329 kstart = kstart + m + 1;
03330 pmm = pmm / PreSqr[2 * nMax];
03331 Pcup[kstart] = pmm * rescalem;
03332 dPcup[kstart] = -(double) (nMax) * x * Pcup[kstart] / z;
03333 free(f1);
03334 free(PreSqr);
03335 free(f2);
03336
03337 return TRUE;
03338 }
03339
03340 int MAG_PcupLow(double *Pcup, double *dPcup, double x, int nMax)
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365 {
03366 int n, m, index, index1, index2, NumTerms;
03367 double k, z, *schmidtQuasiNorm;
03368 Pcup[0] = 1.0;
03369 dPcup[0] = 0.0;
03370
03371 z = sqrt((1.0 - x) * (1.0 + x));
03372
03373 NumTerms = ((nMax + 1) * (nMax + 2) / 2);
03374 schmidtQuasiNorm = (double *) malloc((NumTerms + 1) * sizeof ( double));
03375
03376 if(schmidtQuasiNorm == NULL)
03377 {
03378 MAG_Error(19);
03379
03380 return FALSE;
03381 }
03382
03383
03384 for(n = 1; n <= nMax; n++)
03385 {
03386 for(m = 0; m <= n; m++)
03387 {
03388 index = (n * (n + 1) / 2 + m);
03389 if(n == m)
03390 {
03391 index1 = (n - 1) * n / 2 + m - 1;
03392 Pcup [index] = z * Pcup[index1];
03393 dPcup[index] = z * dPcup[index1] + x * Pcup[index1];
03394 } else if(n == 1 && m == 0)
03395 {
03396 index1 = (n - 1) * n / 2 + m;
03397 Pcup[index] = x * Pcup[index1];
03398 dPcup[index] = x * dPcup[index1] - z * Pcup[index1];
03399 } else if(n > 1 && n != m)
03400 {
03401 index1 = (n - 2) * (n - 1) / 2 + m;
03402 index2 = (n - 1) * n / 2 + m;
03403 if(m > n - 2)
03404 {
03405 Pcup[index] = x * Pcup[index2];
03406 dPcup[index] = x * dPcup[index2] - z * Pcup[index2];
03407 } else
03408 {
03409 k = (double) (((n - 1) * (n - 1)) - (m * m)) / (double) ((2 * n - 1) * (2 * n - 3));
03410 Pcup[index] = x * Pcup[index2] - k * Pcup[index1];
03411 dPcup[index] = x * dPcup[index2] - z * Pcup[index2] - k * dPcup[index1];
03412 }
03413 }
03414 }
03415 }
03416
03417
03418
03419 schmidtQuasiNorm[0] = 1.0;
03420 for(n = 1; n <= nMax; n++)
03421 {
03422 index = (n * (n + 1) / 2);
03423 index1 = (n - 1) * n / 2;
03424
03425 schmidtQuasiNorm[index] = schmidtQuasiNorm[index1] * (double) (2 * n - 1) / (double) n;
03426
03427 for(m = 1; m <= n; m++)
03428 {
03429 index = (n * (n + 1) / 2 + m);
03430 index1 = (n * (n + 1) / 2 + m - 1);
03431 schmidtQuasiNorm[index] = schmidtQuasiNorm[index1] * sqrt((double) ((n - m + 1) * (m == 1 ? 2 : 1)) / (double) (n + m));
03432 }
03433
03434 }
03435
03436
03437
03438
03439
03440 for(n = 1; n <= nMax; n++)
03441 {
03442 for(m = 0; m <= n; m++)
03443 {
03444 index = (n * (n + 1) / 2 + m);
03445 Pcup[index] = Pcup[index] * schmidtQuasiNorm[index];
03446 dPcup[index] = -dPcup[index] * schmidtQuasiNorm[index];
03447
03448
03449 }
03450 }
03451
03452 if(schmidtQuasiNorm)
03453 free(schmidtQuasiNorm);
03454 return TRUE;
03455 }
03456
03457 int MAG_SecVarSummation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults)
03458 {
03459
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469 int m, n, index;
03470 double cos_phi;
03471 MagneticModel->SecularVariationUsed = TRUE;
03472 MagneticResults->Bz = 0.0;
03473 MagneticResults->By = 0.0;
03474 MagneticResults->Bx = 0.0;
03475 for(n = 1; n <= MagneticModel->nMaxSecVar; n++)
03476 {
03477 for(m = 0; m <= n; m++)
03478 {
03479 index = (n * (n + 1) / 2 + m);
03480
03481
03482
03483
03484
03485 MagneticResults->Bz -= SphVariables.RelativeRadiusPower[n] *
03486 (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.cos_mlambda[m] +
03487 MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.sin_mlambda[m])
03488 * (double) (n + 1) * LegendreFunction-> Pcup[index];
03489
03490
03491
03492
03493
03494 MagneticResults->By += SphVariables.RelativeRadiusPower[n] *
03495 (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.sin_mlambda[m] -
03496 MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.cos_mlambda[m])
03497 * (double) (m) * LegendreFunction-> Pcup[index];
03498
03499
03500
03501
03502
03503 MagneticResults->Bx -= SphVariables.RelativeRadiusPower[n] *
03504 (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.cos_mlambda[m] +
03505 MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.sin_mlambda[m])
03506 * LegendreFunction-> dPcup[index];
03507 }
03508 }
03509 cos_phi = cos(DEG2RAD(CoordSpherical.phig));
03510 if(fabs(cos_phi) > 1.0e-10)
03511 {
03512 MagneticResults->By = MagneticResults->By / cos_phi;
03513 } else
03514
03515 {
03516 MAG_SecVarSummationSpecial(MagneticModel, SphVariables, CoordSpherical, MagneticResults);
03517 }
03518 return TRUE;
03519 }
03520
03521 int MAG_SecVarSummationSpecial(MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults)
03522 {
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534 int n, index;
03535 double k, sin_phi, *PcupS, schmidtQuasiNorm1, schmidtQuasiNorm2, schmidtQuasiNorm3;
03536
03537 PcupS = (double *) malloc((MagneticModel->nMaxSecVar + 1) * sizeof (double));
03538
03539 if(PcupS == NULL)
03540 {
03541 MAG_Error(15);
03542
03543 return FALSE;
03544 }
03545
03546 PcupS[0] = 1;
03547 schmidtQuasiNorm1 = 1.0;
03548
03549 MagneticResults->By = 0.0;
03550 sin_phi = sin(DEG2RAD(CoordSpherical.phig));
03551
03552 for(n = 1; n <= MagneticModel->nMaxSecVar; n++)
03553 {
03554 index = (n * (n + 1) / 2 + 1);
03555 schmidtQuasiNorm2 = schmidtQuasiNorm1 * (double) (2 * n - 1) / (double) n;
03556 schmidtQuasiNorm3 = schmidtQuasiNorm2 * sqrt((double) (n * 2) / (double) (n + 1));
03557 schmidtQuasiNorm1 = schmidtQuasiNorm2;
03558 if(n == 1)
03559 {
03560 PcupS[n] = PcupS[n - 1];
03561 } else
03562 {
03563 k = (double) (((n - 1) * (n - 1)) - 1) / (double) ((2 * n - 1) * (2 * n - 3));
03564 PcupS[n] = sin_phi * PcupS[n - 1] - k * PcupS[n - 2];
03565 }
03566
03567
03568
03569
03570
03571
03572 MagneticResults->By += SphVariables.RelativeRadiusPower[n] *
03573 (MagneticModel->Secular_Var_Coeff_G[index] * SphVariables.sin_mlambda[1] -
03574 MagneticModel->Secular_Var_Coeff_H[index] * SphVariables.cos_mlambda[1])
03575 * PcupS[n] * schmidtQuasiNorm3;
03576 }
03577
03578 if(PcupS)
03579 free(PcupS);
03580 return TRUE;
03581 }
03582
03583 int MAG_Summation(MAGtype_LegendreFunction *LegendreFunction, MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults)
03584 {
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594
03595
03596
03597
03598
03599
03600
03601
03602
03603
03604
03605
03606
03607
03608
03609 int m, n, index;
03610 double cos_phi;
03611 MagneticResults->Bz = 0.0;
03612 MagneticResults->By = 0.0;
03613 MagneticResults->Bx = 0.0;
03614 for(n = 1; n <= MagneticModel->nMax; n++)
03615 {
03616 for(m = 0; m <= n; m++)
03617 {
03618 index = (n * (n + 1) / 2 + m);
03619
03620
03621
03622
03623
03624 MagneticResults->Bz -= SphVariables.RelativeRadiusPower[n] *
03625 (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.cos_mlambda[m] +
03626 MagneticModel->Main_Field_Coeff_H[index] * SphVariables.sin_mlambda[m])
03627 * (double) (n + 1) * LegendreFunction-> Pcup[index];
03628
03629
03630
03631
03632
03633 MagneticResults->By += SphVariables.RelativeRadiusPower[n] *
03634 (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.sin_mlambda[m] -
03635 MagneticModel->Main_Field_Coeff_H[index] * SphVariables.cos_mlambda[m])
03636 * (double) (m) * LegendreFunction-> Pcup[index];
03637
03638
03639
03640
03641
03642 MagneticResults->Bx -= SphVariables.RelativeRadiusPower[n] *
03643 (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.cos_mlambda[m] +
03644 MagneticModel->Main_Field_Coeff_H[index] * SphVariables.sin_mlambda[m])
03645 * LegendreFunction-> dPcup[index];
03646
03647
03648
03649 }
03650 }
03651
03652 cos_phi = cos(DEG2RAD(CoordSpherical.phig));
03653 if(fabs(cos_phi) > 1.0e-10)
03654 {
03655 MagneticResults->By = MagneticResults->By / cos_phi;
03656 } else
03657
03658
03659
03660
03661
03662 {
03663 MAG_SummationSpecial(MagneticModel, SphVariables, CoordSpherical, MagneticResults);
03664 }
03665 return TRUE;
03666 }
03667
03668 int MAG_SummationSpecial(MAGtype_MagneticModel *MagneticModel, MAGtype_SphericalHarmonicVariables SphVariables, MAGtype_CoordSpherical CoordSpherical, MAGtype_MagneticResults *MagneticResults)
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679 {
03680 int n, index;
03681 double k, sin_phi, *PcupS, schmidtQuasiNorm1, schmidtQuasiNorm2, schmidtQuasiNorm3;
03682
03683 PcupS = (double *) malloc((MagneticModel->nMax + 1) * sizeof (double));
03684 if(PcupS == 0)
03685 {
03686 MAG_Error(14);
03687
03688 return FALSE;
03689 }
03690
03691 PcupS[0] = 1;
03692 schmidtQuasiNorm1 = 1.0;
03693
03694 MagneticResults->By = 0.0;
03695 sin_phi = sin(DEG2RAD(CoordSpherical.phig));
03696
03697 for(n = 1; n <= MagneticModel->nMax; n++)
03698 {
03699
03700
03701
03702
03703
03704 index = (n * (n + 1) / 2 + 1);
03705 schmidtQuasiNorm2 = schmidtQuasiNorm1 * (double) (2 * n - 1) / (double) n;
03706 schmidtQuasiNorm3 = schmidtQuasiNorm2 * sqrt((double) (n * 2) / (double) (n + 1));
03707 schmidtQuasiNorm1 = schmidtQuasiNorm2;
03708 if(n == 1)
03709 {
03710 PcupS[n] = PcupS[n - 1];
03711 } else
03712 {
03713 k = (double) (((n - 1) * (n - 1)) - 1) / (double) ((2 * n - 1) * (2 * n - 3));
03714 PcupS[n] = sin_phi * PcupS[n - 1] - k * PcupS[n - 2];
03715 }
03716
03717
03718
03719
03720
03721
03722 MagneticResults->By += SphVariables.RelativeRadiusPower[n] *
03723 (MagneticModel->Main_Field_Coeff_G[index] * SphVariables.sin_mlambda[1] -
03724 MagneticModel->Main_Field_Coeff_H[index] * SphVariables.cos_mlambda[1])
03725 * PcupS[n] * schmidtQuasiNorm3;
03726 }
03727
03728 if(PcupS)
03729 free(PcupS);
03730 return TRUE;
03731 }
03732
03733 int MAG_TimelyModifyMagneticModel(MAGtype_Date UserDate, MAGtype_MagneticModel *MagneticModel, MAGtype_MagneticModel *TimedMagneticModel)
03734
03735
03736
03737
03738
03739
03740
03741
03742
03743
03744
03745
03746 {
03747 int n, m, index, a, b;
03748 TimedMagneticModel->EditionDate = MagneticModel->EditionDate;
03749 TimedMagneticModel->epoch = MagneticModel->epoch;
03750 TimedMagneticModel->nMax = MagneticModel->nMax;
03751 TimedMagneticModel->nMaxSecVar = MagneticModel->nMaxSecVar;
03752 a = TimedMagneticModel->nMaxSecVar;
03753 b = (a * (a + 1) / 2 + a);
03754 strcpy(TimedMagneticModel->ModelName, MagneticModel->ModelName);
03755 for(n = 1; n <= MagneticModel->nMax; n++)
03756 {
03757 for(m = 0; m <= n; m++)
03758 {
03759 index = (n * (n + 1) / 2 + m);
03760 if(index <= b)
03761 {
03762 TimedMagneticModel->Main_Field_Coeff_H[index] = MagneticModel->Main_Field_Coeff_H[index] + (UserDate.DecimalYear - MagneticModel->epoch) * MagneticModel->Secular_Var_Coeff_H[index];
03763 TimedMagneticModel->Main_Field_Coeff_G[index] = MagneticModel->Main_Field_Coeff_G[index] + (UserDate.DecimalYear - MagneticModel->epoch) * MagneticModel->Secular_Var_Coeff_G[index];
03764 TimedMagneticModel->Secular_Var_Coeff_H[index] = MagneticModel->Secular_Var_Coeff_H[index];
03765 TimedMagneticModel->Secular_Var_Coeff_G[index] = MagneticModel->Secular_Var_Coeff_G[index];
03766 } else
03767 {
03768 TimedMagneticModel->Main_Field_Coeff_H[index] = MagneticModel->Main_Field_Coeff_H[index];
03769 TimedMagneticModel->Main_Field_Coeff_G[index] = MagneticModel->Main_Field_Coeff_G[index];
03770 }
03771 }
03772 }
03773 return TRUE;
03774 }
03775
03776
03777
03778
03779
03780
03781
03782
03783
03784
03785
03786
03787 int MAG_ConvertGeoidToEllipsoidHeight(MAGtype_CoordGeodetic *CoordGeodetic, MAGtype_Geoid *Geoid)
03788
03789
03790
03791
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802 {
03803 double DeltaHeight;
03804 int Error_Code;
03805
03806 if(Geoid->UseGeoid == 1)
03807 {
03808 Error_Code = MAG_GetGeoidHeight(CoordGeodetic->phi, CoordGeodetic->lambda, &DeltaHeight, Geoid);
03809 CoordGeodetic->HeightAboveEllipsoid = CoordGeodetic->HeightAboveGeoid + DeltaHeight / 1000;
03810
03811 } else
03812 {
03813 CoordGeodetic->HeightAboveEllipsoid = CoordGeodetic->HeightAboveGeoid;
03814 Error_Code = TRUE;
03815 }
03816 return ( Error_Code);
03817 }
03818
03819 int MAG_GetGeoidHeight(double Latitude,
03820 double Longitude,
03821 double *DeltaHeight,
03822 MAGtype_Geoid *Geoid)
03823
03824
03825
03826
03827
03828
03829
03830
03831
03832
03833
03834
03835 {
03836 long Index;
03837 double DeltaX, DeltaY;
03838 double ElevationSE, ElevationSW, ElevationNE, ElevationNW;
03839 double OffsetX, OffsetY;
03840 double PostX, PostY;
03841 double UpperY, LowerY;
03842 int Error_Code = 0;
03843
03844 if(!Geoid->Geoid_Initialized)
03845 {
03846 MAG_Error(5);
03847
03848 return (FALSE);
03849 }
03850 if((Latitude < -90) || (Latitude > 90))
03851 {
03852 Error_Code |= 1;
03853 }
03854 if((Longitude < -180) || (Longitude > 360))
03855 {
03856 Error_Code |= 1;
03857 }
03858
03859 if(!Error_Code)
03860 {
03861
03862
03863 if(Longitude < 0.0)
03864 {
03865 OffsetX = (Longitude + 360.0) * Geoid->ScaleFactor;
03866 } else
03867 {
03868 OffsetX = Longitude * Geoid->ScaleFactor;
03869 }
03870 OffsetY = (90.0 - Latitude) * Geoid->ScaleFactor;
03871
03872
03873
03874
03875 PostX = floor(OffsetX);
03876 if((PostX + 1) == Geoid->NumbGeoidCols)
03877 PostX--;
03878 PostY = floor(OffsetY);
03879 if((PostY + 1) == Geoid->NumbGeoidRows)
03880 PostY--;
03881
03882 Index = (long) (PostY * Geoid->NumbGeoidCols + PostX);
03883 ElevationNW = (double) Geoid->GeoidHeightBuffer[ Index ];
03884 ElevationNE = (double) Geoid->GeoidHeightBuffer[ Index + 1 ];
03885
03886 Index = (long) ((PostY + 1) * Geoid->NumbGeoidCols + PostX);
03887 ElevationSW = (double) Geoid->GeoidHeightBuffer[ Index ];
03888 ElevationSE = (double) Geoid->GeoidHeightBuffer[ Index + 1 ];
03889
03890
03891
03892 DeltaX = OffsetX - PostX;
03893 DeltaY = OffsetY - PostY;
03894
03895 UpperY = ElevationNW + DeltaX * (ElevationNE - ElevationNW);
03896 LowerY = ElevationSW + DeltaX * (ElevationSE - ElevationSW);
03897
03898 *DeltaHeight = UpperY + DeltaY * (LowerY - UpperY);
03899 } else
03900 {
03901 MAG_Error(17);
03902
03903 return (FALSE);
03904 }
03905 return TRUE;
03906 }
03907
03908 int MAG_InitializeGeoid(MAGtype_Geoid *Geoid)
03909
03910
03911
03912
03913
03914
03915
03916
03917
03918
03919
03920
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930
03931
03932
03933
03934
03935 {
03936 int ElevationsRead, SwabType, Index;
03937 FILE *GeoidHeightFile;
03938
03939
03940 if(Geoid->Geoid_Initialized)
03941 {
03942 return (TRUE);
03943 } else
03944 {
03945
03946 Geoid->GeoidHeightBuffer = (float *) malloc((Geoid->NumbGeoidElevs + 1) * sizeof (float));
03947 if(!Geoid->GeoidHeightBuffer)
03948 {
03949 MAG_Error(3);
03950
03951 return (FALSE);
03952 }
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962 if((GeoidHeightFile = fopen("EGM9615.BIN", "rb")) == NULL)
03963 {
03964 MAG_Error(16);
03965
03966 return (FALSE);
03967 }
03968
03969 ElevationsRead = fread(Geoid->GeoidHeightBuffer, sizeof (float), Geoid->NumbGeoidElevs, GeoidHeightFile);
03970
03971 if(ElevationsRead != Geoid->NumbGeoidElevs)
03972 {
03973
03974 MAG_Error(3);
03975
03976 return ( FALSE);
03977
03978 }
03979 fclose(GeoidHeightFile);
03980
03981 SwabType = MAG_swab_type();
03982
03983
03984
03985
03986
03987
03988
03989 if(SwabType == 0)
03990 {
03991
03992 for(Index = 0; Index < ElevationsRead; Index++)
03993
03994 Geoid->GeoidHeightBuffer[Index] = (float) MAG_FloatSwap(Geoid->GeoidHeightBuffer[Index]);
03995
03996 }
03997
03998
03999
04000 Geoid->Geoid_Initialized = 1;
04001 }
04002 return ( TRUE);
04003 }
04004
04005
04006
04007
04008
04009
04010 int MAG_swab_type()
04011 {
04012
04013
04014
04015
04016
04017
04018
04019
04020
04021 union swabtest {
04022 unsigned long l;
04023 unsigned char c[4];
04024 } swabtest;
04025
04026 swabtest.l = 0xaabbccdd;
04027
04028 if((swabtest.c[0] == 0xaa) && (swabtest.c[1] == 0xbb) &&
04029 (swabtest.c[2] == 0xcc) && (swabtest.c[3] == 0xdd))
04030 {
04031
04032 return 0;
04033 } else if((swabtest.c[0] == 0xdd) && (swabtest.c[1] == 0xcc) &&
04034 (swabtest.c[2] == 0xbb) && (swabtest.c[3] == 0xaa))
04035 {
04036
04037 return 1;
04038 } else if((swabtest.c[0] == 0xbb) && (swabtest.c[1] == 0xaa) &&
04039 (swabtest.c[2] == 0xdd) && (swabtest.c[3] == 0xcc))
04040 {
04041
04042 return 2;
04043 } else
04044 {
04045
04046 return -1;
04047 }
04048 }
04049
04050 float MAG_FloatSwap(float f)
04051
04052
04053
04054 {
04055
04056 union {
04057 float f;
04058 unsigned char b[4];
04059 } dat1, dat2;
04060
04061 dat1.f = f;
04062 dat2.b[0] = dat1.b[3];
04063 dat2.b[1] = dat1.b[2];
04064 dat2.b[2] = dat1.b[1];
04065 dat2.b[3] = dat1.b[0];
04066 return dat2.f;
04067 }