/****************************************************************************/ /* */ /* NGDC's Geomagnetic Field Modeling software for the IGRF and WMM */ /* */ /****************************************************************************/ /* */ /* Disclaimer: This program has undergone limited testing. It is */ /* being distributed unoffically. The National Geophysical Data */ /* Center does not guarantee it's correctness. */ /* */ /****************************************************************************/ /* */ /* Version 7.0: */ /* - input file format changed to */ /* -- accept new DGRF2005 coeffs with 0.01 nT precision */ /* -- make sure all values are separated by blanks */ /* -- swapped n and m: first is degree, second is order */ /* - new my_isnan function improves portablility */ /* - corrected feet to km conversion factor */ /* - fixed date conversion errors for yyyy,mm,dd format */ /* - fixed lon/lat conversion errors for deg,min,sec format */ /* - simplified leap year identification */ /* - changed comment: units of ddot and idot are arc-min/yr */ /* - added note that this program computes the secular variation as */ /* the 1-year difference, rather than the instantaneous change, */ /* which can be slightly different */ /* - clarified that height is above ellipsoid, not above mean sea level */ /* although the difference is negligible for magnetics */ /* - changed main(argv,argc) to usual definition main(argc,argv) */ /* - corrected rounding of angles close to 60 minutes */ /* Thanks to all who provided bug reports and suggested fixes */ /* */ /* Stefan Maus Jan-25-2010 */ /* */ /****************************************************************************/ /* */ /* Version 6.1: */ /* Included option to read coordinates from a file and output the */ /* results to a new file, repeating the input and adding columns */ /* for the output */ /* Stefan Maus Jan-31-2008 */ /* */ /****************************************************************************/ /* */ /* Version 6.0: */ /* Bug fixes for the interpolation between models. Also added warnings */ /* for declination at low H and corrected behaviour at geogr. poles. */ /* Placed print-out commands into separate routines to facilitate */ /* fine-tuning of the tables */ /* Stefan Maus Aug-24-2004 */ /* */ /****************************************************************************/ /* */ /* This program calculates the geomagnetic field values from */ /* a spherical harmonic model. Inputs required by the user are: */ /* a spherical harmonic model data file, coordinate preference, */ /* altitude, date/range-step, latitude, and longitude. */ /* */ /* Spherical Harmonic */ /* Model Data File : Name of the data file containing the */ /* spherical harmonic coefficients of */ /* the chosen model. The model and path */ /* must be less than PATH chars. */ /* */ /* Coordinate Preference : Geodetic (WGS84 latitude and altitude */ /* above ellipsoid (WGS84), */ /* or geocentric (spherical, altitude */ /* measured from the center of the Earth). */ /* */ /* Altitude : Altitude above ellipsoid (WGS84). The */ /* program asks for altitude above mean */ /* sea level, because the altitude above */ /* ellipsoid is not known to most users. */ /* The resulting error is very small and */ /* negligible for most practical purposes. */ /* If geocentric coordinate preference is */ /* used, then the altitude must be in the */ /* range of 6370.20 km - 6971.20 km as */ /* measured from the center of the earth. */ /* Enter altitude in kilometers, meters, */ /* or feet */ /* */ /* Date : Date, in decimal years, for which to */ /* calculate the values of the magnetic */ /* field. The date must be within the */ /* limits of the model chosen. */ /* */ /* Latitude : Entered in decimal degrees in the */ /* form xxx.xxx. Positive for northern */ /* hemisphere, negative for the southern */ /* hemisphere. */ /* */ /* Longitude : Entered in decimal degrees in the */ /* form xxx.xxx. Positive for eastern */ /* hemisphere, negative for the western */ /* hemisphere. */ /* */ /****************************************************************************/ /* */ /* Subroutines called : degrees_to_decimal,julday,getshc,interpsh, */ /* extrapsh,shval3,dihf,safegets */ /* */ /****************************************************************************/ #include #include #include #include #include int my_isnan(double d) { return (d != d); /* IEEE: only NaN is not equal to itself */ } #define NaN log(-1.0) #define FT2KM (1.0/0.0003048) #define PI 3.141592654 #define RAD2DEG (180.0/PI) #ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #define IEXT 0 #define FALSE 0 #define TRUE 1 /* constants */ #define RECL 81 #define MAXINBUFF RECL+14 /** Max size of in buffer **/ #define MAXREAD MAXINBUFF-2 /** Max to read 2 less than total size (just to be safe) **/ #define MAXMOD 30 /** Max number of models in a file **/ #define PATH MAXREAD /** Max path and filename length **/ #define EXT_COEFF1 (double)0 #define EXT_COEFF2 (double)0 #define EXT_COEFF3 (double)0 #define MAXDEG 13 #define MAXCOEFF (MAXDEG*(MAXDEG+2)+1) /* index starts with 1!, (from old Fortran?) */ double gh1[MAXCOEFF]; double gh2[MAXCOEFF]; double gha[MAXCOEFF]; /* Geomag global variables */ double ghb[MAXCOEFF]; double d=0,f=0,h=0,i=0; double dtemp,ftemp,htemp,itemp; double x=0,y=0,z=0; double xtemp,ytemp,ztemp; FILE *stream = NULL; /* Pointer to specified model data file */ /****************************************************************************/ /* */ /* Program Geomag */ /* */ /****************************************************************************/ /* */ /* This program, originally written in FORTRAN, was developed using */ /* subroutines written by */ /* A. Zunde */ /* USGS, MS 964, Box 25046 Federal Center, Denver, Co. 80225 */ /* and */ /* S.R.C. Malin & D.R. Barraclough */ /* Institute of Geological Sciences, United Kingdom. */ /* */ /* Translated */ /* into C by : Craig H. Shaffer */ /* 29 July, 1988 */ /* */ /* Rewritten by : David Owens */ /* For Susan McLean */ /* */ /* Maintained by: Adam Woods */ /* Contact : geomag.models@noaa.gov */ /* National Geophysical Data Center */ /* World Data Center-A for Solid Earth Geophysics */ /* NOAA, E/GC1, 325 Broadway, */ /* Boulder, CO 80303 */ /* */ /* */ /****************************************************************************/ /* */ /* Some variables used in this program */ /* */ /* Name Type Usage */ /* ------------------------------------------------------------------------ */ /* */ /* a2,b2 Scalar Double Squares of semi-major and semi-minor */ /* axes of the reference spheroid used */ /* for transforming between geodetic or */ /* geocentric coordinates. */ /* */ /* minalt Double array of MAXMOD Minimum height of model. */ /* */ /* altmin Double Minimum height of selected model. */ /* */ /* altmax Double array of MAXMOD Maximum height of model. */ /* */ /* maxalt Double Maximum height of selected model. */ /* */ /* d Scalar Double Declination of the field from the */ /* geographic north (deg). */ /* */ /* sdate Scalar Double start date inputted */ /* */ /* ddot Scalar Double annual rate of change of decl. */ /* (arc-min/yr) */ /* */ /* alt Scalar Double altitude above WGS84 Ellipsoid */ /* */ /* epoch Double array of MAXMOD epoch of model. */ /* */ /* ext Scalar Double Three 1st-degree external coeff. */ /* */ /* latitude Scalar Double Latitude. */ /* */ /* longitude Scalar Double Longitude. */ /* */ /* gh1 Double array Schmidt quasi-normal internal */ /* spherical harmonic coeff. */ /* */ /* gh2 Double array Schmidt quasi-normal internal */ /* spherical harmonic coeff. */ /* */ /* gha Double array Coefficients of resulting model. */ /* */ /* ghb Double array Coefficients of rate of change model.*/ /* */ /* i Scalar Double Inclination (deg). */ /* */ /* idot Scalar Double Rate of change of i (arc-min/yr). */ /* */ /* igdgc Integer Flag for geodetic or geocentric */ /* coordinate choice. */ /* */ /* inbuff Char a of MAXINBUF Input buffer. */ /* */ /* irec_pos Integer array of MAXMOD Record counter for header */ /* */ /* stream Integer File handles for an opened file. */ /* */ /* fileline Integer Current line in file (for errors) */ /* */ /* max1 Integer array of MAXMOD Main field coefficient. */ /* */ /* max2 Integer array of MAXMOD Secular variation coefficient. */ /* */ /* max3 Integer array of MAXMOD Acceleration coefficient. */ /* */ /* mdfile Character array of PATH Model file name. */ /* */ /* minyr Double Min year of all models */ /* */ /* maxyr Double Max year of all models */ /* */ /* yrmax Double array of MAXMOD Max year of model. */ /* */ /* yrmin Double array of MAXMOD Min year of model. */ /* */ /****************************************************************************/ int main(int argc, char**argv) { #ifdef MAC ccommand(argc, argv); #endif /* Variable declaration */ /* Control variables */ int again = 1; int decyears = 3; int units = 4; int decdeg = 3; int range = -1; int counter = 0; int warn_H, warn_H_strong, warn_P; int modelI; /* Which model (Index) */ int nmodel; /* Number of models in file */ int max1[MAXMOD]; int max2[MAXMOD]; int max3[MAXMOD]; int nmax; int igdgc=3; int isyear=-1; int ismonth=-1; int isday=-1; int ieyear=-1; int iemonth=-1; int ieday=-1; int ilat_deg=200; int ilat_min=200; int ilat_sec=200; int ilon_deg=200; int ilon_min=200; int ilon_sec=200; int fileline; long irec_pos[MAXMOD]; int coords_from_file = 0; int arg_err = 0; int need_to_read_model = 1; char mdfile[PATH]; char inbuff[MAXINBUFF]; char model[MAXMOD][9]; char *begin; char *rest; char args[7][MAXREAD]; int iarg; char coord_fname[PATH]; char out_fname[PATH]; FILE *coordfile,*outfile; int iline=0; int read_flag; double epoch[MAXMOD]; double yrmin[MAXMOD]; double yrmax[MAXMOD]; double minyr; double maxyr; double altmin[MAXMOD]; double altmax[MAXMOD]; double minalt; double maxalt; double alt=-999999; double sdate=-1; double step=-1; double syr; double edate=-1; double latitude=200; double longitude=200; double ddot; double fdot; double hdot; double idot; double xdot; double ydot; double zdot; double warn_H_val, warn_H_strong_val; /* Subroutines used */ void print_dashed_line(); void print_long_dashed_line(void); void print_header(); void print_result(double date, double d, double i, double h, double x, double y, double z, double f); void print_header_sv(); void print_result_sv(double date, double ddot, double idot, double hdot, double xdot, double ydot, double zdot, double fdot); void print_result_file(FILE *outf, double d, double i, double h, double x, double y, double z, double f, double ddot, double idot, double hdot, double xdot, double ydot, double zdot, double fdot); double degrees_to_decimal(); double julday(); int interpsh(); int extrapsh(); int shval3(); int dihf(); int safegets(char *buffer,int n); int getshc(); /* Initializations. */ inbuff[MAXREAD+1]='\0'; /* Just to protect mem. */ inbuff[MAXINBUFF-1]='\0'; /* Just to protect mem. */ for (iarg=0; iarg=3 && argc !=5 && *(args[2])=='f') { printf("\n\nERROR in 'f' switch option: wrong number of arguments\n"); } if ((argc==3)||(argc==4)||(argc==6)) { printf("\n\nUSAGE:\n"); printf("interactive: geomag\n"); printf("command line: geomag model_file date coord alt lat lon\n"); printf("coordinate file: geomag model_file f input_file output_file\n"); printf("or for help: geomag h \n\n"); } /* missing arguments (not fatal) */ while (again == 1) { if (coords_from_file) { argc = 7; read_flag = fscanf(coordfile,"%s%s%s%s%s%*[^\n]",args[2],args[3],args[4],args[5],args[6]); if (read_flag == EOF) goto reached_EOF; fprintf(outfile,"%s %s %s %s %s ",args[2],args[3],args[4],args[5],args[6]);fflush(outfile); iline++; } /* coords_from_file */ /* Switch on how many arguments are supplied. */ /* Note that there are no 'breaks' after the cases, so these are entry points */ switch(argc) { case 7 : strncpy(inbuff, args[6], MAXREAD); if ((rest=strchr(inbuff, ','))) /* If it contains a comma */ { decdeg=2; /* Then not decimal degrees */ begin=inbuff; rest[0]='\0'; /* Chop into sub string */ rest++; /* Move to next substring */ ilon_deg=atoi(begin); begin=rest; if ((rest=strchr(begin, ','))) { rest[0]='\0'; rest++; ilon_min=atoi(begin); ilon_sec=atoi(rest); } else { ilon_min=0; ilon_sec=0; } } else { decdeg=1; /* Else it's decimal */ longitude=atof(args[6]); } case 6 : strncpy(inbuff, args[5], MAXREAD); if ((rest=strchr(inbuff, ','))) { decdeg=2; begin=inbuff; rest[0]='\0'; rest++; ilat_deg=atoi(begin); begin=rest; if ((rest=strchr(begin, ','))) { rest[0]='\0'; rest++; ilat_min=atoi(begin); ilat_sec=atoi(rest); } else { ilat_min=0; ilat_sec=0; } } else { decdeg=1; latitude=atof(args[5]); } case 5 : strncpy(inbuff, args[4], MAXREAD); inbuff[0]=toupper(inbuff[0]); if (inbuff[0]=='K') units=1; else if (inbuff[0]=='M') units=2; else if (inbuff[0]=='F') units=3; if (strlen(inbuff)>1) { inbuff[0]='\0'; begin=inbuff+1; alt=atof(begin); } case 4 : strncpy(inbuff, args[3], MAXREAD); inbuff[0]=toupper(inbuff[0]); if (inbuff[0]=='D') igdgc=1; else if (inbuff[0]=='C') igdgc=2; case 3 : strncpy(inbuff, args[2], MAXREAD); if ((rest=strchr(inbuff, '-'))) /* If it contains a dash */ { range = 2; /* They want a range */ rest[0]='\0'; /* Sep dates */ rest++; begin=rest; if ((rest=strchr(begin, '-'))) /* If it contains 2 dashs */ { rest[0]='\0'; /* Sep step */ rest++; step=atof(rest); /* Get step size */ } if ((rest=strchr(begin, ','))) /* If it contains a comma */ { decyears=2; /* It's not decimal years */ rest[0]='\0'; rest++; ieyear=atoi(begin); begin=rest; if ((rest=strchr(begin, ','))) { rest[0]='\0'; rest++; iemonth=atoi(begin); ieday=atoi(rest); } else { iemonth=0; ieday=0; } if ((rest=strchr(inbuff, ','))) { begin=inbuff; rest[0]='\0'; rest++; isyear=atoi(begin); begin=rest; if ((rest=strchr(begin, ','))) { rest[0]='\0'; rest++; ismonth=atoi(begin); isday=atoi(rest); } else { ismonth=0; isday=0; } } else { sdate=atof(inbuff); } } else { decyears=1; /* Else it's decimal years */ sdate=atof(inbuff); edate=atof(begin); } } else { range = 1; if ((rest=strchr(inbuff, ','))) /* If it contains a comma */ { decyears=2; /* It's not decimal years */ begin=inbuff; rest[0]='\0'; rest++; isyear=atoi(begin); begin=rest; if ((rest=strchr(begin, ','))) { rest[0]='\0'; rest++; ismonth=atoi(begin); isday=atoi(rest); } else { ismonth=0; isday=0; } sdate = julday(ismonth,isday,isyear); } else { decyears=1; /* Else it's decimal years */ sdate=atof(args[2]); } } if (sdate==0) { /* If date not valid */ decyears=-1; range=-1; } case 2 : if (need_to_read_model) { strncpy(mdfile,args[1],MAXREAD); stream=fopen(mdfile, "rt"); } break; } if (range == 2 && coords_from_file) { printf("Error in line %1d, date = %s: date ranges not allowed for file option\n\n",iline,args[2]); exit(2); } /* Obtain the desired model file and read the data */ warn_H = 0; warn_H_val = 99999.0; warn_H_strong = 0; warn_H_strong_val = 99999.0; warn_P = 0; if (need_to_read_model) { while (stream == NULL) { printf("\n\n"); printf("What is the name of the model data file to be opened? ==> "); safegets(inbuff,MAXREAD); strcpy(mdfile, inbuff); if (!(stream = fopen(mdfile, "rt"))) printf("\nError opening file %s.", mdfile); } rewind(stream); fileline = 0; /* First line will be 1 */ modelI = -1; /* First model will be 0 */ while (fgets(inbuff,MAXREAD,stream)) /* While not end of file * read to end of line or buffer */ { fileline++; /* On new line */ if (strlen(inbuff) != RECL) /* IF incorrect record size */ { printf("Corrupt record in file %s on line %d.\n", mdfile, fileline); fclose(stream); exit(5); } /* old statement Dec 1999 */ /* if (!strncmp(inbuff," ",4)){ /* If 1st 4 chars are spaces */ /* New statement Dec 1999 changed by wmd required by year 2000 models */ if (!strncmp(inbuff," ",3)) /* If 1st 3 chars are spaces */ { modelI++; /* New model */ if (modelI > MAXMOD) /* If too many headers */ { printf("Too many models in file %s on line %d.", mdfile, fileline); fclose(stream); exit(6); } irec_pos[modelI]=ftell(stream); /* Get fields from buffer into individual vars. */ sscanf(inbuff, "%s%lg%d%d%d%lg%lg%lg%lg", model[modelI], &epoch[modelI], &max1[modelI], &max2[modelI], &max3[modelI], &yrmin[modelI], &yrmax[modelI], &altmin[modelI], &altmax[modelI]); /* Compute date range for all models */ if (modelI == 0) /*If first model */ { minyr=yrmin[0]; maxyr=yrmax[0]; } else { if (yrmin[modelI]maxyr){ maxyr=yrmax[modelI]; } } /* if modelI != 0 */ } /* If 1st 3 chars are spaces */ } /* While not end of model file */ nmodel = modelI + 1; fclose(stream); /* if date specified in command line then warn if past end of validity */ if ((sdate>maxyr)&&(sdate "); safegets(inbuff, MAXREAD); decyears=atoi(inbuff); } if (coords_from_file && !arg_err && range != 1) {printf("\nError: unrecognized date %s in coordinate file line %1d\n\n",args[2],iline); arg_err = 1;} while ((range!=1)&&(range!=2)) { printf("\nWould you like output for a single date or for a range of dates?\n"); printf(" 1) A single date.\n"); printf(" 2) A range of dates.\n"); printf("\n ==> "); safegets(inbuff, MAXREAD); range=atoi(inbuff); } if (range == 1) { if (coords_from_file && !arg_err && (sdate < minyr || sdate > maxyr+1)) {printf("\nError: unrecognized date %s in coordinate file line %1d\n\n",args[2],iline); arg_err = 1;} while ((sdatemaxyr+1)) { if (decyears==1) { printf("\nEnter the decimal date (%4.2f to %4.0f): ",minyr, maxyr); safegets(inbuff, MAXREAD); sdate=atof(inbuff); } else { while ((isyear>(int)maxyr+1)||(isyear<(int)minyr)) { printf("\nEnter the date (%4.2f to %4.2f)\n ", minyr, maxyr); printf("\n Year (%d to %d): ",(int)minyr,(int)maxyr); safegets(inbuff, MAXREAD); isyear=atoi(inbuff); } while ((ismonth>12)||(ismonth<1)) { printf("\n Month (1-12): "); safegets(inbuff, MAXREAD); ismonth=atoi(inbuff); } while ((isday>31)||(isday<1)) { printf("\n Day (1-31): "); safegets(inbuff, MAXREAD); isday=atoi(inbuff); } sdate = julday(ismonth,isday,isyear); } if ((sdate=maxyr+1)) { ismonth=isday=isyear=0; printf("\nError: The date %4.2f is out of range.\n", sdate); } if ((sdate>maxyr)&&(sdatemaxyr)) { if (decyears==1) { printf("\nEnter the decimal start date (%4.2f to %4.0f): ",minyr, maxyr); safegets(inbuff, MAXREAD); sdate=atof(inbuff); } else { while ((isyear>(int)maxyr)||(isyear<(int)minyr)) { ismonth=isday=isyear=0; printf("\nEnter the start date (%4.2f to %4.2f)\n ", minyr, maxyr); printf("\n Year (%d to %d): ",(int)minyr,(int)(maxyr)); safegets(inbuff, MAXREAD); isyear=atoi(inbuff); } while ((ismonth>12)||(ismonth<1)) { printf("\n Month (1-12): "); safegets(inbuff, MAXREAD); ismonth=atoi(inbuff); } while ((isday>31)||(isday<1)) { printf("\n Day (1-31): "); safegets(inbuff, MAXREAD); isday=atoi(inbuff); } sdate = julday(ismonth,isday,isyear); if ((sdatemaxyr)) { printf("\nThe start date %4.2f is out of range.\n", sdate); } } } /* WHILE ((sdatemaxyr)) */ while ((edate<=sdate)||(edate>maxyr+1)) { if (decyears==1) { printf("\nEnter the decimal end date (%4.2f to %4.0f): ",sdate, maxyr); safegets(inbuff, MAXREAD); edate=atof(inbuff); } else { while ((ieyear>(int)maxyr)||(ieyear<(int)sdate)) { iemonth=ieday=ieyear=0; printf("\nEnter the end date (%4.2f to %4.0f)\n ", sdate, maxyr); printf("\n Year (%d to %d): ",(int)sdate,(int)(maxyr)); safegets(inbuff, MAXREAD); ieyear=atoi(inbuff); } while ((iemonth>12)||(iemonth<1)) { printf("\n Month (1-12): "); safegets(inbuff, MAXREAD); iemonth=atoi(inbuff); } while ((ieday>31)||(ieday<1)) { printf("\n Day (1-31): "); safegets(inbuff, MAXREAD); ieday=atoi(inbuff); } edate = julday(iemonth,ieday,ieyear); } if ((edatemaxyr+1)) { printf("\nThe date %4.2f is out of range.\n", edate); } if (edate>maxyr && edate<=maxyr+1) { printf("\nWarning: The end date %4.2f is out of range,\n", edate); printf(" but still within one year of model expiration date.\n"); printf(" An updated model file is available before 1.1.%4.0f\n",maxyr); } } /* while ((edate<=sdate)||(edate>maxyr+1)) */ while ((step<=0)||(step>(edate-sdate))) { printf("\nEnter the step size in years. (0 to %4.2f): ",edate-sdate); safegets(inbuff, MAXREAD); step=atof(inbuff); } } /* if (range == 2) */ /* Pick model */ for (modelI=0; modelI "); safegets(inbuff, MAXREAD); igdgc=atoi(inbuff); } /* If needed modify ranges to reflect coords. */ if (igdgc==2) { minalt+=6371.2; /* Add radius to ranges. */ maxalt+=6371.2; } /* Get unit prefs */ if (igdgc==1) { if (coords_from_file && !arg_err && (units > 3 || units < 1)) {printf("\nError: unrecognized altitude units %s in coordinate file line %1d\n\n",args[4],iline); arg_err = 1;} while ((units>3)||(units<1)) { printf("\n\nEnter Unit Preferences:"); printf("\n 1) Kilometers"); printf("\n 2) Meters"); printf("\n 3) Feet\n"); printf("\n ==> "); safegets(inbuff, MAXREAD); units=atoi(inbuff); } } else units = 1; /* geocentric always in km */ /* Do unit conversions if neccessary */ if (units==2) { minalt*=1000.0; maxalt*=1000.0; } else if (units==3) { minalt*=FT2KM; maxalt*=FT2KM; } /* Get altitude */ if (coords_from_file && !arg_err && (alt < minalt || alt > maxalt)) {printf("\nError: unrecognized altitude %s in coordinate file line %1d\n\n",args[4],iline); arg_err = 1;} while ((altmaxalt)) { if (igdgc==2) printf("\n\nEnter geocentric altitude in km (%.2f to %.2f): ", minalt, maxalt); if (igdgc==1 && units==1) printf("\n\nEnter geodetic altitude above mean sea level in km (%.2f to %.2f): ", minalt, maxalt); if (igdgc==1 && units==2) printf("\n\nEnter geodetic altitude above mean sea level in meters (%.2f to %.2f): ", minalt, maxalt); if (igdgc==1 && units==3) printf("\n\nEnter geodetic altitude above mean sea level in feet (%.2f to %.2f): ", minalt, maxalt); safegets(inbuff, MAXREAD); alt=atof(inbuff); } /* Convert altitude to km */ if (units==2) { alt *= 0.001; } else if (units==3) { alt /= FT2KM; } /* Get lat/long prefs */ if (coords_from_file && !arg_err && (decdeg != 1 && decdeg != 2)) {printf("\nError: unrecognized lat %s or lon %s in coordinate file line %1d\n\n",args[5],args[6],iline); arg_err = 1;} while ((decdeg!=1)&&(decdeg!=2)) { printf("\n\nHow would you like to enter the latitude and longitude?:"); printf("\n 1) In decimal degrees."); printf("\n 2) In degrees, minutes, and seconds.\n"); printf("\n ==> "); safegets(inbuff, MAXREAD); decdeg=atoi(inbuff); } /* Get lat/lon */ if (decdeg==1) { if (coords_from_file && !arg_err && (latitude < -90 || latitude > 90)) {printf("\nError: unrecognized latitude %s in coordinate file line %1d\n\n",args[6],iline); arg_err = 1;} while ((latitude<-90)||(latitude>90)) { printf("\n\nEnter the decimal latitude (-90 to 90) (- for Southern hemisphere).\n"); safegets(inbuff, MAXREAD); latitude=atof(inbuff); } if (coords_from_file && !arg_err && (longitude < -180 || longitude > 180)) {printf("\nError: unrecognized longitude %s in coordinate file line %1d\n\n",args[6],iline); arg_err = 1;} while ((longitude<-180)||(longitude>180)) { printf("\n\nEnter the decimal longitude (-180 to 180) (- for Western hemisphere).\n"); safegets(inbuff, MAXREAD); longitude=atof(inbuff); } } /* if (decdeg==1) */ else { latitude=degrees_to_decimal(ilat_deg,ilat_min,ilat_sec); longitude=degrees_to_decimal(ilon_deg,ilon_min,ilon_sec); if (coords_from_file && !arg_err && (latitude < -90 || latitude > 90)) {printf("\nError: unrecognized latitude %s in coordinate file line %1d\n\n",args[6],iline); arg_err = 1;} while ((latitude<-90)||(latitude>90)) { ilat_deg=ilat_min=ilat_sec=200; printf("\n\nEnter the decimal latitude (-90 to 90) (- for Southern hemisphere).\n"); while ((ilat_deg<-90)||(ilat_deg>90)) { printf("\nDegrees (-90 to 90): "); safegets(inbuff, MAXREAD); ilat_deg=atoi(inbuff); } while ((ilat_min<-59)||(ilat_min>59)) { printf("\nMinutes (-59 to 59): "); safegets(inbuff, MAXREAD); ilat_min=atoi(inbuff); } while ((ilat_sec<-59)||(ilat_sec>59)) { printf("\nSeconds (-59 to 59): "); safegets(inbuff, MAXREAD); ilat_sec=atoi(inbuff); } latitude=degrees_to_decimal(ilat_deg,ilat_min,ilat_sec); if ((latitude<-90)||(latitude>90)) { printf("\nThe latitude %3.2f is out of range", latitude); } } /* while ((latitude<-90)||(latitude>90)) */ if (coords_from_file && !arg_err && (longitude < -180 || longitude > 180)) {printf("\nError: unrecognized longitude %s in coordinate file line %1d\n\n",args[6],iline); arg_err = 1;} while ((longitude<-180)||(longitude>180)) { ilon_deg=ilon_min=ilon_sec=200; printf("\n\nEnter the decimal longitude (-180 to 180) (- for Western hemisphere).\n"); while ((ilon_deg<-180)||(ilon_deg>180)) { printf("\nDegrees (-180 to 180): "); safegets(inbuff, MAXREAD); ilon_deg=atoi(inbuff); } while ((ilon_min<-59)||(ilon_min>59)) { printf("\nMinutes (0 to 59): "); safegets(inbuff, MAXREAD); ilon_min=atoi(inbuff); } while ((ilon_sec<-59)||(ilon_sec>59)) { printf("\nSeconds (0 to 59): "); safegets(inbuff, MAXREAD); ilon_sec=atoi(inbuff); } longitude=degrees_to_decimal(ilon_deg,ilon_min,ilon_sec); if ((longitude<-180)||(longitude>180)) { printf("\nThe longitude %3.2f is out of range", longitude); } } /* while ((longitude<-180)||(longitude>180)) */ } /* if (decdeg != 1) */ /** This will compute everything needed for 1 point in time. **/ if (max2[modelI] == 0) { getshc(mdfile, 1, irec_pos[modelI], max1[modelI], 1); getshc(mdfile, 1, irec_pos[modelI+1], max1[modelI+1], 2); nmax = interpsh(sdate, yrmin[modelI], max1[modelI], yrmin[modelI+1], max1[modelI+1], 3); nmax = interpsh(sdate+1, yrmin[modelI] , max1[modelI], yrmin[modelI+1], max1[modelI+1],4); } else { getshc(mdfile, 1, irec_pos[modelI], max1[modelI], 1); getshc(mdfile, 0, irec_pos[modelI], max2[modelI], 2); nmax = extrapsh(sdate, epoch[modelI], max1[modelI], max2[modelI], 3); nmax = extrapsh(sdate+1, epoch[modelI], max1[modelI], max2[modelI], 4); } /* Do the first calculations */ shval3(igdgc, latitude, longitude, alt, nmax, 3, IEXT, EXT_COEFF1, EXT_COEFF2, EXT_COEFF3); dihf(3); shval3(igdgc, latitude, longitude, alt, nmax, 4, IEXT, EXT_COEFF1, EXT_COEFF2, EXT_COEFF3); dihf(4); ddot = ((dtemp - d)*RAD2DEG); if (ddot > 180.0) ddot -= 360.0; if (ddot <= -180.0) ddot += 360.0; ddot *= 60.0; idot = ((itemp - i)*RAD2DEG)*60; d = d*(RAD2DEG); i = i*(RAD2DEG); hdot = htemp - h; xdot = xtemp - x; ydot = ytemp - y; zdot = ztemp - z; fdot = ftemp - f; /* deal with geographic and magnetic poles */ if (h < 100.0) /* at magnetic poles */ { d = NaN; ddot = NaN; /* while rest is ok */ } if (h < 1000.0) { warn_H = 0; warn_H_strong = 1; if (hedate)&&(edate!=(syr-step))) { syr=edate; print_long_dashed_line(); } /* Do the calculations */ for (counter=0;counteryrmin[modelI+1]){ /* And past model boundary */ modelI++; /* Get next model */ } } } /* for counter */ if (max2[modelI] == 0) /*If still not last element */ { getshc(mdfile, 1, irec_pos[modelI], max1[modelI], 1); getshc(mdfile, 1, irec_pos[modelI+1], max1[modelI+1], 2); nmax = interpsh(syr, yrmin[modelI], max1[modelI], yrmin[modelI+1], max1[modelI+1], 3); nmax = interpsh(syr+1, yrmin[modelI] , max1[modelI], yrmin[modelI+1], max1[modelI+1],4); } else { getshc(mdfile, 1, irec_pos[modelI], max1[modelI], 1); getshc(mdfile, 0, irec_pos[modelI], max2[modelI], 2); nmax = extrapsh(syr, epoch[modelI], max1[modelI], max2[modelI], 3); nmax = extrapsh(syr+1, epoch[modelI], max1[modelI], max2[modelI], 4); } shval3(igdgc, latitude, longitude, alt, nmax, 3, IEXT, EXT_COEFF1, EXT_COEFF2, EXT_COEFF3); dihf(3); shval3(igdgc, latitude, longitude, alt, nmax, 4, IEXT, EXT_COEFF1, EXT_COEFF2, EXT_COEFF3); dihf(4); ddot = ((dtemp - d)*RAD2DEG); if (ddot > 180.0) ddot -= 360.0; if (ddot <= -180.0) ddot += 360.0; ddot *= 60.0; idot = ((itemp - i)*RAD2DEG)*60.; d = d*(RAD2DEG); i = i*(RAD2DEG); hdot = htemp - h; xdot = xtemp - x; ydot = ytemp - y; zdot = ztemp - z; fdot = ftemp - f; /* deal with geographic and magnetic poles */ if (h < 100.0) /* at magnetic poles */ { d = NaN; ddot = NaN; /* while rest is ok */ } if (90.0-fabs(latitude) <= 0.001) /* at geographic poles */ { x = NaN; y = NaN; d = NaN; xdot = NaN; ydot = NaN; ddot = NaN; warn_P = 1; warn_H = 0; warn_H_strong = 0; /* while rest is ok */ } print_result(syr, d, i, h, x, y, z, f); } /* for syr */ print_long_dashed_line(); print_header_sv(); print_result_sv(edate,ddot,idot,hdot,xdot,ydot,zdot,fdot); print_dashed_line(); } /* if range > 1 */ if (warn_H) { printf("\nWarning: The horizontal field strength at this location is only %6.1f nT\n",warn_H_val); printf(" Compass readings have large uncertainties in areas where H is\n"); printf(" smaller than 5000 nT\n\n"); } if (warn_H_strong) { printf("\nWarning: The horizontal field strength at this location is only %6.1f nT\n",warn_H_strong_val); printf(" Compass readings have VERY LARGE uncertainties in areas where H is\n"); printf(" smaller than 1000 nT\n\n"); } if (warn_P) { printf("\nWarning: Location is at geographic pole where X, Y, and declination are not computed\n\n"); } } /* if not coords_from_file */ if (coords_from_file) again = !feof(coordfile) && !arg_err; else { if (argc==7) again = 0; /* run command line only once */ else do { printf("\n Enter"); printf("\n 0) to quit."); printf("\n 1) to select a new model input file."); printf("\n 2) to compute for a new point using same data file."); printf("\n\n ==> "); safegets(inbuff, MAXREAD); again=atoi(inbuff); if (again == 1) { need_to_read_model = 1; stream = NULL;} if (again == 2) { need_to_read_model = 0; again = 1;} } while (again != 0 && again != 1); } /* if not coords_from_file */ if (again == 1) { /* Reset defaults to catch on all while loops */ igdgc=decyears=units=decdeg=-1; ismonth=isday=isyear=sdate=edate=range=step=-1; latitude=ilat_deg=ilat_min=ilat_sec=200; longitude=ilon_deg=ilon_min=ilon_sec=200; alt=-9999999; argc = 1; } } /* while (again == 1) */ reached_EOF: if (coords_from_file) printf("\n Processed %1d lines\n\n",iline); if (coords_from_file && !feof(coordfile) && arg_err) printf("Terminated prematurely due to argument error in coordinate file\n\n"); if (argc<7) { printf("\nThe same result could have been generated with the following command:\n"); printf("%s %s ", args[0], mdfile); if (range == 1) { if (decyears==1) { printf("%4.2f ", sdate); } else { printf("%d,%d,%d ", isyear,ismonth,isday); } } else { if (decyears==1) { printf("%4.2f-%4.2f-%4.2f ", sdate,edate,step); } else { printf("%d,%d,%d-%d,%d,%d-%4.2f ", isyear,ismonth,isday,ieyear,iemonth,ieday,step); } } if (igdgc==1) { printf("D "); } else { printf("C "); } if (units==1) { printf("K%.2f ", alt); } else if (units==2) { printf("M%.2f ", alt*1000.0); } else { printf("F%.2f ", (alt*FT2KM)); } if (decdeg==1) { printf("%3.2f %4.2f\n\n", latitude, longitude); } else { printf("%d,%d,%d %d,%d,%d\n\n", ilat_deg, ilat_min, ilat_sec, ilon_deg, ilon_min, ilon_sec); } } return 0; } void print_dashed_line(void) { printf(" -------------------------------------------------------------------------------\n"); return; } void print_long_dashed_line(void) { printf(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); return; } void print_header(void) { print_dashed_line(); printf(" Date D I H X Y Z F\n"); printf(" (yr) (deg min) (deg min) (nT) (nT) (nT) (nT) (nT)\n"); return; } void print_result(double date, double d, double i, double h, double x, double y, double z, double f) { int ddeg,ideg; double dmin,imin; /* Change d and i to deg and min */ ddeg=(int)d; dmin=(d-(double)ddeg)*60; if (d > 0 && dmin >= 59.5) { dmin -= 60.0; ddeg++; } if (d < 0 && dmin <= -59.5) { dmin += 60.0; ddeg--; } if (ddeg!=0) dmin=fabs(dmin); ideg=(int)i; imin=(i-(double)ideg)*60; if (i > 0 && imin >= 59.5) { imin -= 60.0; ideg++; } if (i < 0 && imin <= -59.5) { imin += 60.0; ideg--; } if (ideg!=0) imin=fabs(imin); if (my_isnan(d)) { if (my_isnan(x)) printf(" %4.2f NaN %4dd %3.0fm %8.1f NaN NaN %8.1f %8.1f\n",date,ideg,imin,h,z,f); else printf(" %4.2f NaN %4dd %3.0fm %8.1f %8.1f %8.1f %8.1f %8.1f\n",date,ideg,imin,h,x,y,z,f); } else printf(" %4.2f %4dd %3.0fm %4dd %3.0fm %8.1f %8.1f %8.1f %8.1f %8.1f\n",date,ddeg,dmin,ideg,imin,h,x,y,z,f); return; } /* print_result */ void print_header_sv(void) { printf(" Date dD dI dH dX dY dZ dF\n"); printf(" (yr) (min/yr) (min/yr) (nT/yr) (nT/yr) (nT/yr) (nT/yr) (nT/yr)\n"); } /* print_header_sv */ void print_result_sv(double date, double ddot, double idot, double hdot, double xdot, double ydot, double zdot, double fdot) { if (my_isnan(ddot)) { if (my_isnan(xdot)) printf(" %4.2f NaN %7.1f %8.1f NaN NaN %8.1f %8.1f\n",date,idot,hdot,zdot,fdot); else printf(" %4.2f NaN %7.1f %8.1f %8.1f %8.1f %8.1f %8.1f\n",date,idot,hdot,xdot,ydot,zdot,fdot); } else printf(" %4.2f %7.1f %7.1f %8.1f %8.1f %8.1f %8.1f %8.1f\n",date,ddot,idot,hdot,xdot,ydot,zdot,fdot); return; } /* print_result_sv */ void print_result_file(FILE *outf, double d, double i, double h, double x, double y, double z, double f, double ddot, double idot, double hdot, double xdot, double ydot, double zdot, double fdot) { int ddeg,ideg; double dmin,imin; /* Change d and i to deg and min */ ddeg=(int)d; dmin=(d-(double)ddeg)*60; if (ddeg!=0) dmin=fabs(dmin); ideg=(int)i; imin=(i-(double)ideg)*60; if (ideg!=0) imin=fabs(imin); if (my_isnan(d)) { if (my_isnan(x)) fprintf(outf," NaN %4dd %2.0fm %8.1f NaN NaN %8.1f %8.1f",ideg,imin,h,z,f); else fprintf(outf," NaN %4dd %2.0fm %8.1f %8.1f %8.1f %8.1f %8.1f",ideg,imin,h,x,y,z,f); } else fprintf(outf," %4dd %2.0fm %4dd %2.0fm %8.1f %8.1f %8.1f %8.1f %8.1f",ddeg,dmin,ideg,imin,h,x,y,z,f); if (my_isnan(ddot)) { if (my_isnan(xdot)) fprintf(outf," NaN %7.1f %8.1f NaN NaN %8.1f %8.1f\n",idot,hdot,zdot,fdot); else fprintf(outf," NaN %7.1f %8.1f %8.1f %8.1f %8.1f %8.1f\n",idot,hdot,xdot,ydot,zdot,fdot); } else fprintf(outf," %7.1f %7.1f %8.1f %8.1f %8.1f %8.1f %8.1f\n",ddot,idot,hdot,xdot,ydot,zdot,fdot); return; } /* print_result_file */ /****************************************************************************/ /* */ /* Subroutine safegets */ /* */ /****************************************************************************/ /* */ /* Gets characters from stdin untill it has reached n characters or \n, */ /* whichever comes first. \n is converted to \0. */ /* */ /* Input: n - Integer number of chars */ /* *buffer - Character array ptr which can contain n+1 characters */ /* */ /* Output: size - integer size of sting in buffer */ /* */ /* Note: All strings will be null terminated. */ /* */ /* By: David Owens */ /* dio@ngdc.noaa.gov */ /****************************************************************************/ int safegets(char *buffer,int n){ char *ptr; /** ptr used for finding '\n' **/ buffer[0] = '\0'; fgets(buffer,n,stdin); /** Get n chars **/ buffer[n+1]='\0'; /** Set last char to null **/ ptr=strchr(buffer,'\n'); /** If string contains '\n' **/ if (ptr!=NULL){ /** If string contains '\n' **/ ptr[0]='\0'; /** Change char to '\0' **/ if (buffer[0] == '\0') printf("\n ... no entry ...\n"); } return strlen(buffer); /** Return the length **/ } /****************************************************************************/ /* */ /* Subroutine degrees_to_decimal */ /* */ /****************************************************************************/ /* */ /* Converts degrees,minutes, seconds to decimal degrees. */ /* */ /* Input: */ /* degrees - Integer degrees */ /* minutes - Integer minutes */ /* seconds - Integer seconds */ /* */ /* Output: */ /* decimal - degrees in decimal degrees */ /* */ /* C */ /* C. H. Shaffer */ /* Lockheed Missiles and Space Company, Sunnyvale CA */ /* August 12, 1988 */ /* */ /****************************************************************************/ double degrees_to_decimal(int degrees,int minutes,int seconds) { double deg; double min; double sec; double decimal; deg = degrees; min = minutes/60.0; sec = seconds/3600.0; decimal = fabs(sec) + fabs(min) + fabs(deg); if (deg < 0) { decimal = -decimal; } else if (deg == 0){ if (min < 0){ decimal = -decimal; } else if (min == 0){ if (sec<0){ decimal = -decimal; } } } return(decimal); } /****************************************************************************/ /* */ /* Subroutine julday */ /* */ /****************************************************************************/ /* */ /* Computes the decimal day of year from month, day, year. */ /* Supplied by Daniel Bergstrom */ /* */ /* References: */ /* */ /* 1. Nachum Dershowitz and Edward M. Reingold, Calendrical Calculations, */ /* Cambridge University Press, 3rd edition, ISBN 978-0-521-88540-9. */ /* */ /* 2. Claus Tøndering, Frequently Asked Questions about Calendars, */ /* Version 2.9, http://www.tondering.dk/claus/calendar.html */ /* */ /****************************************************************************/ double julday(month, day, year) int month; int day; int year; { int days[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; int leap_year = (((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0))); double day_in_year = (days[month - 1] + day + (month > 2 ? leap_year : 0)); return ((double)year + (day_in_year / (365.0 + leap_year))); } /****************************************************************************/ /* */ /* Subroutine getshc */ /* */ /****************************************************************************/ /* */ /* Reads spherical harmonic coefficients from the specified */ /* model into an array. */ /* */ /* Input: */ /* stream - Logical unit number */ /* iflag - Flag for SV equal to ) or not equal to 0 */ /* for designated read statements */ /* strec - Starting record number to read from model */ /* nmax_of_gh - Maximum degree and order of model */ /* */ /* Output: */ /* gh1 or 2 - Schmidt quasi-normal internal spherical */ /* harmonic coefficients */ /* */ /* FORTRAN */ /* Bill Flanagan */ /* NOAA CORPS, DESDIS, NGDC, 325 Broadway, Boulder CO. 80301 */ /* */ /* C */ /* C. H. Shaffer */ /* Lockheed Missiles and Space Company, Sunnyvale CA */ /* August 15, 1988 */ /* */ /****************************************************************************/ int getshc(file, iflag, strec, nmax_of_gh, gh) char file[PATH]; int iflag; long int strec; int nmax_of_gh; int gh; { char inbuff[MAXINBUFF]; char irat[9]; int ii,m,n,mm,nn; int ios; int line_num; double g,hh; double trash; stream = fopen(file, "rt"); if (stream == NULL) { printf("\nError on opening file %s", file); } else { ii = 0; ios = 0; fseek(stream,strec,SEEK_SET); for ( nn = 1; nn <= nmax_of_gh; ++nn) { for (mm = 0; mm <= nn; ++mm) { if (iflag == 1) { fgets(inbuff, MAXREAD, stream); sscanf(inbuff, "%d%d%lg%lg%lg%lg%s%d", &n, &m, &g, &hh, &trash, &trash, irat, &line_num); } else { fgets(inbuff, MAXREAD, stream); sscanf(inbuff, "%d%d%lg%lg%lg%lg%s%d", &n, &m, &trash, &trash, &g, &hh, irat, &line_num); } if ((nn != n) || (mm != m)) { ios = -2; fclose(stream); return(ios); } ii = ii + 1; switch(gh) { case 1: gh1[ii] = g; break; case 2: gh2[ii] = g; break; default: printf("\nError in subroutine getshc"); break; } if (m != 0) { ii = ii+ 1; switch(gh) { case 1: gh1[ii] = hh; break; case 2: gh2[ii] = hh; break; default: printf("\nError in subroutine getshc"); break; } } } } } fclose(stream); return(ios); } /****************************************************************************/ /* */ /* Subroutine extrapsh */ /* */ /****************************************************************************/ /* */ /* Extrapolates linearly a spherical harmonic model with a */ /* rate-of-change model. */ /* */ /* Input: */ /* date - date of resulting model (in decimal year) */ /* dte1 - date of base model */ /* nmax1 - maximum degree and order of base model */ /* gh1 - Schmidt quasi-normal internal spherical */ /* harmonic coefficients of base model */ /* nmax2 - maximum degree and order of rate-of-change model */ /* gh2 - Schmidt quasi-normal internal spherical */ /* harmonic coefficients of rate-of-change model */ /* */ /* Output: */ /* gha or b - Schmidt quasi-normal internal spherical */ /* harmonic coefficients */ /* nmax - maximum degree and order of resulting model */ /* */ /* FORTRAN */ /* A. Zunde */ /* USGS, MS 964, box 25046 Federal Center, Denver, CO. 80225 */ /* */ /* C */ /* C. H. Shaffer */ /* Lockheed Missiles and Space Company, Sunnyvale CA */ /* August 16, 1988 */ /* */ /****************************************************************************/ int extrapsh(date, dte1, nmax1, nmax2, gh) double date; double dte1; int nmax1; int nmax2; int gh; { int nmax; int k, l; int ii; double factor; factor = date - dte1; if (nmax1 == nmax2) { k = nmax1 * (nmax1 + 2); nmax = nmax1; } else { if (nmax1 > nmax2) { k = nmax2 * (nmax2 + 2); l = nmax1 * (nmax1 + 2); switch(gh) { case 3: for ( ii = k + 1; ii <= l; ++ii) { gha[ii] = gh1[ii]; } break; case 4: for ( ii = k + 1; ii <= l; ++ii) { ghb[ii] = gh1[ii]; } break; default: printf("\nError in subroutine extrapsh"); break; } nmax = nmax1; } else { k = nmax1 * (nmax1 + 2); l = nmax2 * (nmax2 + 2); switch(gh) { case 3: for ( ii = k + 1; ii <= l; ++ii) { gha[ii] = factor * gh2[ii]; } break; case 4: for ( ii = k + 1; ii <= l; ++ii) { ghb[ii] = factor * gh2[ii]; } break; default: printf("\nError in subroutine extrapsh"); break; } nmax = nmax2; } } switch(gh) { case 3: for ( ii = 1; ii <= k; ++ii) { gha[ii] = gh1[ii] + factor * gh2[ii]; } break; case 4: for ( ii = 1; ii <= k; ++ii) { ghb[ii] = gh1[ii] + factor * gh2[ii]; } break; default: printf("\nError in subroutine extrapsh"); break; } return(nmax); } /****************************************************************************/ /* */ /* Subroutine interpsh */ /* */ /****************************************************************************/ /* */ /* Interpolates linearly, in time, between two spherical harmonic */ /* models. */ /* */ /* Input: */ /* date - date of resulting model (in decimal year) */ /* dte1 - date of earlier model */ /* nmax1 - maximum degree and order of earlier model */ /* gh1 - Schmidt quasi-normal internal spherical */ /* harmonic coefficients of earlier model */ /* dte2 - date of later model */ /* nmax2 - maximum degree and order of later model */ /* gh2 - Schmidt quasi-normal internal spherical */ /* harmonic coefficients of internal model */ /* */ /* Output: */ /* gha or b - coefficients of resulting model */ /* nmax - maximum degree and order of resulting model */ /* */ /* FORTRAN */ /* A. Zunde */ /* USGS, MS 964, box 25046 Federal Center, Denver, CO. 80225 */ /* */ /* C */ /* C. H. Shaffer */ /* Lockheed Missiles and Space Company, Sunnyvale CA */ /* August 17, 1988 */ /* */ /****************************************************************************/ int interpsh(date, dte1, nmax1, dte2, nmax2, gh) double date; double dte1; int nmax1; double dte2; int nmax2; int gh; { int nmax; int k, l; int ii; double factor; factor = (date - dte1) / (dte2 - dte1); if (nmax1 == nmax2) { k = nmax1 * (nmax1 + 2); nmax = nmax1; } else { if (nmax1 > nmax2) { k = nmax2 * (nmax2 + 2); l = nmax1 * (nmax1 + 2); switch(gh) { case 3: for ( ii = k + 1; ii <= l; ++ii) { gha[ii] = gh1[ii] + factor * (-gh1[ii]); } break; case 4: for ( ii = k + 1; ii <= l; ++ii) { ghb[ii] = gh1[ii] + factor * (-gh1[ii]); } break; default: printf("\nError in subroutine extrapsh"); break; } nmax = nmax1; } else { k = nmax1 * (nmax1 + 2); l = nmax2 * (nmax2 + 2); switch(gh) { case 3: for ( ii = k + 1; ii <= l; ++ii) { gha[ii] = factor * gh2[ii]; } break; case 4: for ( ii = k + 1; ii <= l; ++ii) { ghb[ii] = factor * gh2[ii]; } break; default: printf("\nError in subroutine extrapsh"); break; } nmax = nmax2; } } switch(gh) { case 3: for ( ii = 1; ii <= k; ++ii) { gha[ii] = gh1[ii] + factor * (gh2[ii] - gh1[ii]); } break; case 4: for ( ii = 1; ii <= k; ++ii) { ghb[ii] = gh1[ii] + factor * (gh2[ii] - gh1[ii]); } break; default: printf("\nError in subroutine extrapsh"); break; } return(nmax); } /****************************************************************************/ /* */ /* Subroutine shval3 */ /* */ /****************************************************************************/ /* */ /* Calculates field components from spherical harmonic (sh) */ /* models. */ /* */ /* Input: */ /* igdgc - indicates coordinate system used; set equal */ /* to 1 if geodetic, 2 if geocentric */ /* latitude - north latitude, in degrees */ /* longitude - east longitude, in degrees */ /* elev - WGS84 altitude above ellipsoid (igdgc=1), or */ /* radial distance from earth's center (igdgc=2) */ /* a2,b2 - squares of semi-major and semi-minor axes of */ /* the reference spheroid used for transforming */ /* between geodetic and geocentric coordinates */ /* or components */ /* nmax - maximum degree and order of coefficients */ /* iext - external coefficients flag (=0 if none) */ /* ext1,2,3 - the three 1st-degree external coefficients */ /* (not used if iext = 0) */ /* */ /* Output: */ /* x - northward component */ /* y - eastward component */ /* z - vertically-downward component */ /* */ /* based on subroutine 'igrf' by D. R. Barraclough and S. R. C. Malin, */ /* report no. 71/1, institute of geological sciences, U.K. */ /* */ /* FORTRAN */ /* Norman W. Peddie */ /* USGS, MS 964, box 25046 Federal Center, Denver, CO. 80225 */ /* */ /* C */ /* C. H. Shaffer */ /* Lockheed Missiles and Space Company, Sunnyvale CA */ /* August 17, 1988 */ /* */ /****************************************************************************/ int shval3(igdgc, flat, flon, elev, nmax, gh, iext, ext1, ext2, ext3) int igdgc; double flat; double flon; double elev; int nmax; int gh; int iext; double ext1; double ext2; double ext3; { double earths_radius = 6371.2; double dtr = 0.01745329; double slat; double clat; double ratio; double aa, bb, cc, dd; double sd; double cd; double r; double a2; double b2; double rr; double fm,fn; double sl[14]; double cl[14]; double p[119]; double q[119]; int ii,j,k,l,m,n; int npq; int ios; double argument; double power; a2 = 40680631.59; /* WGS84 */ b2 = 40408299.98; /* WGS84 */ ios = 0; r = elev; argument = flat * dtr; slat = sin( argument ); if ((90.0 - flat) < 0.001) { aa = 89.999; /* 300 ft. from North pole */ } else { if ((90.0 + flat) < 0.001) { aa = -89.999; /* 300 ft. from South pole */ } else { aa = flat; } } argument = aa * dtr; clat = cos( argument ); argument = flon * dtr; sl[1] = sin( argument ); cl[1] = cos( argument ); switch(gh) { case 3: x = 0; y = 0; z = 0; break; case 4: xtemp = 0; ytemp = 0; ztemp = 0; break; default: printf("\nError in subroutine shval3"); break; } sd = 0.0; cd = 1.0; l = 1; n = 0; m = 1; npq = (nmax * (nmax + 3)) / 2; if (igdgc == 1) { aa = a2 * clat * clat; bb = b2 * slat * slat; cc = aa + bb; argument = cc; dd = sqrt( argument ); argument = elev * (elev + 2.0 * dd) + (a2 * aa + b2 * bb) / cc; r = sqrt( argument ); cd = (elev + dd) / r; sd = (a2 - b2) / dd * slat * clat / r; aa = slat; slat = slat * cd - clat * sd; clat = clat * cd + aa * sd; } ratio = earths_radius / r; argument = 3.0; aa = sqrt( argument ); p[1] = 2.0 * slat; p[2] = 2.0 * clat; p[3] = 4.5 * slat * slat - 1.5; p[4] = 3.0 * aa * clat * slat; q[1] = -clat; q[2] = slat; q[3] = -3.0 * clat * slat; q[4] = aa * (slat * slat - clat * clat); for ( k = 1; k <= npq; ++k) { if (n < m) { m = 0; n = n + 1; argument = ratio; power = n + 2; rr = pow(argument,power); fn = n; } fm = m; if (k >= 5) { if (m == n) { argument = (1.0 - 0.5/fm); aa = sqrt( argument ); j = k - n - 1; p[k] = (1.0 + 1.0/fm) * aa * clat * p[j]; q[k] = aa * (clat * q[j] + slat/fm * p[j]); sl[m] = sl[m-1] * cl[1] + cl[m-1] * sl[1]; cl[m] = cl[m-1] * cl[1] - sl[m-1] * sl[1]; } else { argument = fn*fn - fm*fm; aa = sqrt( argument ); argument = ((fn - 1.0)*(fn-1.0)) - (fm * fm); bb = sqrt( argument )/aa; cc = (2.0 * fn - 1.0)/aa; ii = k - n; j = k - 2 * n + 1; p[k] = (fn + 1.0) * (cc * slat/fn * p[ii] - bb/(fn - 1.0) * p[j]); q[k] = cc * (slat * q[ii] - clat/fn * p[ii]) - bb * q[j]; } } switch(gh) { case 3: aa = rr * gha[l]; break; case 4: aa = rr * ghb[l]; break; default: printf("\nError in subroutine shval3"); break; } if (m == 0) { switch(gh) { case 3: x = x + aa * q[k]; z = z - aa * p[k]; break; case 4: xtemp = xtemp + aa * q[k]; ztemp = ztemp - aa * p[k]; break; default: printf("\nError in subroutine shval3"); break; } l = l + 1; } else { switch(gh) { case 3: bb = rr * gha[l+1]; cc = aa * cl[m] + bb * sl[m]; x = x + cc * q[k]; z = z - cc * p[k]; if (clat > 0) { y = y + (aa * sl[m] - bb * cl[m]) * fm * p[k]/((fn + 1.0) * clat); } else { y = y + (aa * sl[m] - bb * cl[m]) * q[k] * slat; } l = l + 2; break; case 4: bb = rr * ghb[l+1]; cc = aa * cl[m] + bb * sl[m]; xtemp = xtemp + cc * q[k]; ztemp = ztemp - cc * p[k]; if (clat > 0) { ytemp = ytemp + (aa * sl[m] - bb * cl[m]) * fm * p[k]/((fn + 1.0) * clat); } else { ytemp = ytemp + (aa * sl[m] - bb * cl[m]) * q[k] * slat; } l = l + 2; break; default: printf("\nError in subroutine shval3"); break; } } m = m + 1; } if (iext != 0) { aa = ext2 * cl[1] + ext3 * sl[1]; switch(gh) { case 3: x = x - ext1 * clat + aa * slat; y = y + ext2 * sl[1] - ext3 * cl[1]; z = z + ext1 * slat + aa * clat; break; case 4: xtemp = xtemp - ext1 * clat + aa * slat; ytemp = ytemp + ext2 * sl[1] - ext3 * cl[1]; ztemp = ztemp + ext1 * slat + aa * clat; break; default: printf("\nError in subroutine shval3"); break; } } switch(gh) { case 3: aa = x; x = x * cd + z * sd; z = z * cd - aa * sd; break; case 4: aa = xtemp; xtemp = xtemp * cd + ztemp * sd; ztemp = ztemp * cd - aa * sd; break; default: printf("\nError in subroutine shval3"); break; } return(ios); } /****************************************************************************/ /* */ /* Subroutine dihf */ /* */ /****************************************************************************/ /* */ /* Computes the geomagnetic d, i, h, and f from x, y, and z. */ /* */ /* Input: */ /* x - northward component */ /* y - eastward component */ /* z - vertically-downward component */ /* */ /* Output: */ /* d - declination */ /* i - inclination */ /* h - horizontal intensity */ /* f - total intensity */ /* */ /* FORTRAN */ /* A. Zunde */ /* USGS, MS 964, box 25046 Federal Center, Denver, CO. 80225 */ /* */ /* C */ /* C. H. Shaffer */ /* Lockheed Missiles and Space Company, Sunnyvale CA */ /* August 22, 1988 */ /* */ /****************************************************************************/ int dihf (gh) int gh; { int ios; int j; double sn; double h2; double hpx; double argument, argument2; ios = gh; sn = 0.0001; switch(gh) { case 3: for (j = 1; j <= 1; ++j) { h2 = x*x + y*y; argument = h2; h = sqrt(argument); /* calculate horizontal intensity */ argument = h2 + z*z; f = sqrt(argument); /* calculate total intensity */ if (f < sn) { d = NaN; /* If d and i cannot be determined, */ i = NaN; /* set equal to NaN */ } else { argument = z; argument2 = h; i = atan2(argument,argument2); if (h < sn) { d = NaN; } else { hpx = h + x; if (hpx < sn) { d = PI; } else { argument = y; argument2 = hpx; d = 2.0 * atan2(argument,argument2); } } } } break; case 4: for (j = 1; j <= 1; ++j) { h2 = xtemp*xtemp + ytemp*ytemp; argument = h2; htemp = sqrt(argument); argument = h2 + ztemp*ztemp; ftemp = sqrt(argument); if (ftemp < sn) { dtemp = NaN; /* If d and i cannot be determined, */ itemp = NaN; /* set equal to 999.0 */ } else { argument = ztemp; argument2 = htemp; itemp = atan2(argument,argument2); if (htemp < sn) { dtemp = NaN; } else { hpx = htemp + xtemp; if (hpx < sn) { dtemp = PI; } else { argument = ytemp; argument2 = hpx; dtemp = 2.0 * atan2(argument,argument2); } } } } break; default: printf("\nError in subroutine dihf"); break; } return(ios); }