/********************************************************************* HEADER.H HEADER.H CONTAINS ALL THE PERTINENT GLOBAL INFORMATION FOR STARTING UP THE OCEAN CLIMATE LABORATORY OCEANIOC C SUBROUTINE FILE. PERTINENT INFORMATION INCLUDES WHICH LIBRARIES ARE TO BE INCLUDED, DEFINING SYSTEM CONSTANTS AND EXTERNAL VARIABLES, AS WELL AS STRUCTURES WHICH ARE USED REPEATEDLY THROUGHOUT THE DATA ACCESS SYSTEM. *********************************************************************/ /******************************************************************** INCLUDED LIBRARIES: STDIO.H - STANDARD I/O LIBRARY. CONTAINS ALL INPUT AND OUTPUT ROUTINES. STDLIB - STANDARD LIBRARY. STANDARD C ROUTINES, SUCH AS THE SORTING ROUTINES. STRING.H - CHARACTER STRING FUNCTIONS SYS/FILE.H - SYSTEM CALLS ARPA/INET.H - FOR CONVERTING BIGENDIAN TO LITTLEENDIAN **********************************************************************/ #include #include #include #include #include #include /* TOB 20-Mar-2003 for get_pid */ #include /* TOB 20-Mar-2003 for get_pid */ #include /* for 64 bit integers */ /*#include */ #include /********************************************************************* SET CHARACTER ARRAY *MAINBRANCH, THE MAIN PATHNAME TO THE DATA SYSTEM **********************************************************************/ char MAINBRANCH[] = "./\0 "; /********************************************************************* CONSTANTS: MAXLEV - MAXIMUM NUMBER OF LEVELS ALLOWED IN SYSTEM MAXFILE - MAXIMUM NUMBER OF FILE IDENTIFICATION NUMBERS MAXCALC - THE MAXIMUM NUMBER OF MEASURED AND CALCULATED PARAMETERS ALLOWED IN THE OCL SYSTEM. NPROBE - THE MAXIMUM NUMBER OF PROBE TYPES ALLOWED IN THE OCL SYSTEM. MAXSHIP - MAXIMUM NUMBER OF SHIP CODES ALLOWED IN OCL SYSTEM MAXMASK - MAXIMUM NUMBER OF MASKS IN OCL SYSTEM. NOFFSET - OFFSET BETWEEN BIO AND SEC HEADER DATA AND THEIR SET DATA MAXSECS - maximum number of second header variables MAXVARSPEC - maximum number of variable specific second headers MAXBIOH - maximum number of biological headers MAXTAXVAR - maximum number of taxa variables **********************************************************************/ #define MAXFILE 511 #define maxlev 6000 #define maxcalc 200 #define nprobe 100 #define maxship 20000 #define MAXMASK 100 #define noffset 200 #define MAXVARSPEC 26 #define MAXSECS 100 #define MAXBIOH 100 #define MAXTAXVAR 50 /* SPOT CONSTANTS ARE THE CUMULATIVE MAXIMUM CODE NUMBERS FOR EACH VARIABLE TYPE */ #define MAXSECSPOT 50000 #define MAXVARSPECSPOT 50000 #define MAXBIOSPOT 3000 #define MAXTAXASPOT 10000 /* INDIV CONSTANTS ARE CUMULATIVE NUMBER OF CHARACTER DEFINITIONS FOR INDIVIDUAL CODE VALUES */ #define MAXSECINDIV 50000 #define MAXVARSINDIV 50000 #define MAXBIOINDIV 20000 #define MAXTAXINDIV 10000 #define MAXITIS 100000 /* MAXWHOI IS SPECIAL FOR WHOI ARCHIVING PROGRAM */ #define maxwhoi 500 /* filetemplate is for setting temporary files */ #define filetemplate "XXXXXX" /* expt(a,n)=a^n for integer n */ /*#ifdef POW_NOT_TRUSTWORTHY if roundoff errors in pow cause problems, use this: double expt(a, n) double a; register int n; { double x; x = 1.; if (n>0) for (; n>0; n--) x *= a; else for (; n<0; n++) x /= a; return x; } #else # define expt(a, n) pow(a, (double)(n)) #endif */ /********************************************************************* GLOBAL VARIABLES: *FP - C FILE VARIABLE FTRACK - TRACKS BUSY AND AVAILABLE FILE IDENTIFICATION NUMBERS MFN - FILE ID NUMBERS FOR EACH PARAMETER FOR EACH FILE SET *PNAME - HOLDS FULL PARAMETER NAME (MAX 15 LETTERS) WHICH IS USED AS THE FILE NAME FOR PARAMETER DATA *PNAME1 - HOLDS 1-3 LETTER PARAMETER CODE USED IN AUXILARY FILE NAMES SUCH AS ANALYZED DATA FILE NAMES. *PNAME4 - HOLDS 1-6 LETTER PARAMETER ABBREVIATION USED IN IDENTIFYING PARAMETER DATA IN PRINTED PROFILES. *PROBENAME - HOLDS 1-11 LETTER NAME FOR PROBE TYPE. USED IN DIRECTORY STRUCTURE FOR PLACING DATA. *AREANAME - HOLDS 1-28 LETTER OCEAN BASIN NAME. *SCODE - NODC SHIP CODE *SNAME - SHIP NAME JPRESENT - HOLDS PRESENT PROFILE NUMBER WHICH A MASK IS POINTING AT. GPRESENT - HOLDS PRESENT SECONDARY NUMBER (GEOGRAPHIC,DATE) WHICH A MASK IS POINTING AT. *CHEADER IS A CHARACTER ARRAY USED TO READ IN DATA IN A CONVERSION ROUTINE SURFHEAD CONTAINS VARIABLE CODES FOR LAT,LON,TIME RESPECTIVELY SURFPROBE MARKS SURFACE ONLY PROBES WITH A 1 FILENAMETEMP CONTAINS FILE NAMES FOR TEMPORARY FILES OTHER GLOBAL VARIABLES ARE IDENTIFIED IN THE SUBROUTINE IN WHICH THEY ARE USED. *******************************************************************/ extern FILE *fp[]; extern int ftrack[]; extern int mfn[]; extern char *pname[],*pname1[],*pname4[]; extern char *prettyname[],*prettyareaname[]; extern char *whoicruise[],*whoipi[],*whoipurpose[],*whoiwhere[]; extern char *probename[]; extern char *areaname[]; extern char *scode[],*sname[]; extern char *nname[]; extern int jpresent[]; extern int gpresent[]; extern char *cheader; extern int surfhead[]; extern int surfprobe[]; extern char *filenametemp[]; /**************************************************************** FUNCTIONS *****************************************************************/ extern int compstrn( char[], char[], int); /***************************************************************** STRUCTURE HEADERDATA: THIS STRUCTURE CONTAINS THE MAJOR PROFILE INFORMATION SUCH AS DATE AND POSITION OF A PROFILE. THIS INFORMATION IS THE SAME FOR ALL TYPES OF DATA. THE VARIABLE WHICH HAS THIS STRUCTURE IS CALLED 'HEADER'. ******************************************************************/ struct headerdata { char cc[2]; /* NODC COUNTRY CODE, CONSISTS OF TWO CHARACTERS. SEE APPENDIX IN OCL DATA SYSTEMS INTRODUCTION MANUAL FOR CODE DESCRIPTIONS. VALUE IS BLANK OR '99' IF NOT RECORDED. */ float lat; /* LATITUDE OF PROFILE, IN DEGREES TO HUNDREDTHS. NEGATIVE VALUES ARE SOUTHERN LATITUDES. SEE VARIABLE LATP IN SECOND HEADER FOR PRECISION INFORMATION. -99.99 IF NOT RECORDED. */ float lon; /* LONGITUDE OF PROFILE, IN DEGREES TO HUNDREDTHS. NEGATIVE VALUES ARE WESTERN LONGITUDES. LOOK TO VARIABLE LONP IN SECOND HEADER FOR PRECISION INFORMATION. -999.99 IF NOT RECORDED. */ int year; /* YEAR OF PROFILE (FOUR DIGITS), ZERO IF NOT RECORDED. */ int month; /* MONTH OF PROFILE (TWO DIGITS), ZERO IF NOT RECORDED. */ int day; /* DAY OF PROFILE (TWO DIGITS), ZERO IF NOT RECORDED. */ float time; /* GREENWICH MEAN TIME OF PROFILE IN HOURS TO HUNDREDTHS. IF NOT RECORDED, VALUE IS -9.99. IF ONLY WHOLE HOURS ARE RECORDED, VALUE IS -'HOURS'.95 */ int cruise; /* NODC ASSIGNED CRUISE NUMBER, ONLY FOR USNODC ARCHIVED DATA. ZERO OTHERWISE */ int numdepo; /* NUMBER OF OBSERVED LEVELS MEASURED IN PROFILE. */ int numdeps; /* NUMBER OF STANDARD LEVELS IN PROFILE. */ } header; /********************************************************** WRITE STRUCTURES: ALTHOUGH NAMED WRITE STRUCTURES, THESE STRUCTURES ARE USED TO READ AND WRITE TWO AND THREE INTEGER VARIABLE SETS ( WRITE2 AND WRITE3) AND ONE INTEGER, ONE REAL VARIABLE SETS (WRITE2F). THESE STRUCTURES ARE USED MOSTLY FOR MASK DATA. OTHER STRUCTURES ARE: WRITE2C - READS AND WRITES AN INTEGER AND A THIRTY CHARACTER ARRAY WRITE1C - READS AND WRITES AN EIGHT CHARACTER ARRAY WRITE2C2 - READS AND WRITES A FOUR CHARACTER ARRAY AND A EIGHTY CHARACTER ARRAY. ************************************************************/ struct write2 { int num; /* FIRST INTEGER */ int rec; /* SECOND INTEGER */ }; struct write3 { int num; /* FIRST INTEGER */ int rec; /* SECOND INTEGER */ int geo; /* THIRD INTEGER */ }; struct write4 { int num; /* FIRST INTEGER */ int num2; /* SECOND INTEGER */ int rec; /* THIRD INTEGER */ int geo; /* FOURTH INTEGER */ }; struct write5 { int num; /* FIRST INTEGER */ int num2; /* SECOND INTEGER */ int rec; /* THIRD INTEGER */ int geo; /* FOURTH INTEGER */ int nfive; /* FIFTH INTEGER */ }; struct write2ri { int num; /* INTEGER */ float rec; /* FIRST REAL */ float geo; /* SECOND REAL */ }; struct write2r2i { int num; /* FIRST INTEGER */ int num2; /* SECOND INTEGER */ float rec; /* FIRST REAL */ float geo; /* SECOND REAL */ }; struct write2f { int num; /* INTEGER */ float rec; /* REAL */ }; struct write2fs { short int num; /* SHORT INTEGER */ float rec; /* REAL */ }; extern struct write2fs twodata2[]; struct write3fs { int num; /* INTEGER */ short int geo; /* SHORT INTEGER */ float rec; /* REAL */ }; struct write2if { int num; /* INTEGER */ int geo; /* INTEGER */ float rec; /* REAL */ }; struct write2c { int num; /* INTEGER */ char carr[15]; /* CHARACTER ARRAY */ }; struct writec80 { int num; /* INTEGER */ char carr[80]; /* CHARACTER ARRAY */ }; struct write1c { char carr[80]; /* CHARACTER ARRAY */ }; struct write2c2 { char carr1[5]; /* CHARACTER ARRAY 1 */ char carr2[80]; /* CHARACTER ARRAY 2 */ }; struct writec2i { int num; /* FIRST INTEGER */ char carr1[5]; /* CHARACTER ARRAY 1 */ char carr2[80]; /* CHARACTER ARRAY 2 */ }; double nicenum(); struct charenter { int haschars; /* IF 0 - NO SET OF DESCRIPTIONS FOR VARIABLE IF 1 - NAME OF VARIABLE PRESENT, NO OTHER INFORMATION IF 2 - NAME OF VARIABLE, UNITS NAME PRESENT IF 3 - NAME OF VARIABLE, INDIVIDUAL VALUE DESCRIPTIONS PRESENT, NO UNITS NAME IF 4 - NAME OF VARIALBE, UNITS NAME, DESCRIPTIONS OF INDIVIDUAL VALUES PRESENT */ char *name; /* VARIABLE NAME FOR VARIABLE */ char *unitname; /* UNIT NAME FOR VARIABLE */ int count; /* NUMBER OF INDIVIDUAL VALUES FOR VARIABLE */ int start; /* STARTING POINT FOR VALUES IN SPOT ARRAY */ int minrange; /* SMALLEST ALLOWABLE VALUE */ int maxrange; /* LARGEST ALLOWABLE VALUE */ }; extern struct charenter secondcharinf[]; extern struct charenter varspeccharinf[]; extern struct charenter biocharinf[]; extern struct charenter taxacharinf[]; struct charstore { char *indivchar; /* INDIVIDUAL VALUE DEFINITION */ int indival; /* INDIVIDUAL NUMERICAL CODE */ }; extern struct charstore *secondstore; extern struct charstore *varspecstore; extern struct charstore *biostore; extern struct charstore *taxastore; extern int *secondcharspot; extern int *varspeccharspot; extern int *biocharspot; extern int *taxacharspot; struct instrumentstore { char *instrument3; /* 3 CHARACTER INSTRUMENT CODE */ char *instrumentname; /* FULL INSTRUMENT NAME */ }; extern int numberofinstruments; extern struct instrumentstore *instrumentation; struct itisstore { int number; /* ITIS CODE */ char *name; /*ITIS NAME */ }; extern struct itisstore *itis; struct indextax { int number; /* TAXA DIVISION (INCREMENTS OF 100) */ int first; /* POSITION IN ITIS ARRAY OF FIRST TAXA FOR THIS DIVISION */ int last; /* POSITION IN ITIS ARRAY OF LAST TAXA FOR THIS DIVISION */ }; extern struct indextax *splittaxa; extern struct indextax taxaboundary; /************************************************************************ SUBROUTINE ALLOCATOR ALLOCATOR ALLOCATES THE PROPER AMOUNT OF STORAGE FOR AN ARRAY OF TWO INTEGER STRUCTURES. *************************************************************************/ /************************************************************** DEFINE *PREP AS A TWO INTEGER STRUCTURE. DEFINE *PREP2 AS A TWO INTEGER STRUCTURE. DEFINE *PREPF AS AN INTEGER, REAL STRUCTURE. DEFINE *PREP0 AS A REAL. DEFINE *PREPI AS AN INTEGER DEFINE *PREPSI AS A SHORT INTEGER DEFINE *PREP3 AS A THREE INTEGER STRUCTURE DEFINE *PREP4 AS A FOUR INTEGER STRUCTURE DEFINE *PREP5 AS A FIVE INTEGER STRUCTURE DEFINE *PREPFS AS A ONE REAL, ONE SHORT INTEGER STRUCTURE DEFINE *PREPIFS AS A ONE REAL, ONE INTEGER, ONE SHORT INTEGER STRUCTURE DEFINE *PREP2IF AS 2 INTEGERS AND ONE REAL ***************************************************************/ struct write2 *prep,*prep2; struct write2f *prepf; struct write3 *prep3; struct write4 *prep4; struct write4 *prep4; struct write5 *prep5; struct write2if *prep2if; float *prep0; int *prepi,*prepi2; short int *prepsi; struct write2fs *prepfs; struct write3fs *prepifs; allocator_( int *indicator, /* WHICH TYPE OF STRUCTURE TO ALLOCATE SPACE FOR: 0 - PREP0 (ONE REAL) 1 - WRITE2 (TWO INTEGERS) 2 - WRITE2F ( INTEGER,REAL) 3 - PREPI (ONE INTEGER) 4 - WRITE3 (THREE INTEGERS) 5 - PREP2 (TWO INTEGERS), SECOND WRITE2 STRUCTURE 6 - WRITE2FS - (ONE REAL, ONE SHORT INTEGER) 7 - WRITE3FS - (ONE REAL, ONE INTEGER, ONE SHORT INTEGER) 8 - PREPSI - (ONE SHORT INTEGER) 9 - PREP2IF - (TWO INTEGERS,ONE REAL) 10 - PREP4 (FOUR INTEGERS) 11 - PREP5 (FIVE INTEGERS) */ int *numpros /* NUMBER OF STRUCTURES FOR WHICH SPACE WILL BE ALLOCATED */ ) { int npros= *numpros+1; if ( *indicator == 0 ) { if ( (prep0 = malloc( npros * sizeof (float) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 1 ) { if ( (prep = calloc( npros, 2 * sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 2 ) { if ( (prepf = calloc( npros, sizeof( float )+ sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 3 ) { if ( (prepi = malloc( npros * sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 4 ) { if ( (prep3 = calloc( npros , 3*sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 5 ) { if ( (prep2 = calloc( npros, 2 * sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 6 ) { if ( (prepfs = calloc( npros, sizeof( struct write2fs ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 7 ) { if ( (prepifs = calloc( npros, sizeof( struct write3fs ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 8 ) { if ( (prepsi = calloc( npros, sizeof( short int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 9 ) { if ( (prep2if = calloc( npros, sizeof( struct write2if ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 10 ) { if ( (prep4 = calloc( npros, sizeof( struct write4 ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 11 ) { if ( (prep5 = calloc( npros, sizeof( struct write5 ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } } /***************************************************** FUNCTION CHANGEMAINBRANCH CHANGEMAINBRANCH CHANGES THE CHARACTER STRING MAINBRANCH IF INSTRUCTED TO DO SO BY THE EXISTENCE OF FILE 'changemainbranch.d' MAINBRANCH IS THE ROOT FILE NAME FOR THE DATABASE *****************************************************/ #define MAXLINE 80 changemainbranch_( int *haschanged /* HASCHANGED IS SET TO ONE IF A MAINBRANCH OTHER THAN THE DEFAULT MAINBRANCH HAS BEEN SET */ ) { FILE *fpmain; char othermain[MAXLINE]; int i = 0; *haschanged = 0; if ( (fpmain = fopen("changemainbranch.d\0","r\0")) != NULL ) { while ( ( othermain[i++] = getc( fpmain ) ) != '\n' && !feof(fpmain)); if ( i > 0 ) { i--; othermain[i] = '\0'; strcpy(MAINBRANCH,othermain); *haschanged = i; } system("rm changemainbranch.d"); } } /************************************************************** SUBROUTINE CHECKWHICHDEPTHFILE CHECKWHICHDEPTHFILE CHECKS WHICH SET OF DEPTHS IS BEING USED AND PASSES THE NAME OF THE FILE OUT OF THE SUBROUTINE *******************************************************************/ checkwhichdepthfile_( char *depthset /* NAME OF DEPTH SET TO USE */ ) { FILE *fpcheck; int in_num,istrc=0; char filename[80]; /* GET INFORMATION ON WHICH SET OF STANDARD DEPTHS */ if ( (fpcheck = fopen("whichdepthset.inf\0","r")) ==NULL ) { sprintf(filename,"%ssys.inf/whichdepthset.inf\0",MAINBRANCH); if ( (fpcheck = fopen(filename,"r")) ==NULL ) { /* printf(" unable to open %s\n",filename); return; */ strcpy(depthset,"orig\0"); istrc = 1; } } if ( istrc != 1 ) { fscanf(fpcheck,"%s",depthset); in_num= fclose(fpcheck); } } /*************************************************************** SUBROUTINE CNAME CNAME SETS THREE PARAMETER CHARACTER ARRAYS GLOBALLY IN C. THE THREE GLOBAL VARIABLES AND THEIR CORRESPONDING INPUT VARIABLES ARE: *PNAME (*NAME) - MAXIMUM FIFTEEN LETTER PARAMETER NAME INPUT FROM PROBEFILE.D. THIS ARRAY IS USED AS THE FILE NAME UNDER WHICH THE ACTUAL DATA IS STORED AS WELL AS A DIRECTORY NAME WHERE ALL MASK FILES ARE STORED FOR EACH PROBE. *PNAME1 (*NAME1) - MAXIMUM THREE LETTER (USUALLY ONE LETTER) PARAMETER CODE WHICH IS USED TO NAME AUXILARY FILES SUCH AS ANALYZED DATA FILES. *PNAME4 (*NAME4) - MAXIMUM FOUR LETTER PARAMETER CODE WHICH IS USED AS AN IDENTIFIER IN OUTPUT ASCII PROFILES. MAXCALC IS THE MAXIMUM NUMBER OF MEASURED AND CALCULATED PARAMETERS WHICH CAN BE PROCESSED IN THE OCL SYSTEM. ****************************************************************/ char *pname[maxlev]; char *pname1[maxlev]; char *pname4[maxlev]; cname_( char *name, /* SEE DESCRIPTION ABOVE */ char *name1, /* SEE DESCRIPTION ABOVE */ char *name4, /* SEE DESCRIPTION ABOVE */ int *n /* PARAMETER CODE AS SET IN PROBEFILE.D */ ) { pname[*n] = name; pname1[*n] = name1; pname4[*n] = name4; } /*********************************************************** SUBROUTINE CNAME2 CNAME2 SETS PROBE CHARACTER ARRAYS GLOBALLY IN C. THE ARRAY (GLOBAL NAME PROBENAME, INPUT NAME *NAME), IS INPUT INITIALLY FROM PROBEFILE.D. IT SHOULD NOT BE MORE THAN TEN CHARACTERS LONG. IT IS USED AS A DIRECTORY NAME IN THE OCL SYSTEM. THE DIRECTORY CONTAINS ALL INFORMATION, PARAMETER AND MASK, FOR A PARTICULAR PROBE. NPROBE IS THE MAXIMUM NUMBER OF PROBES THE OCL SYSTEM CAN HANDLE. *************************************************************/ char *probename_[nprobe]; cname2_( char *name, /* SEE ABOVE DESCRIPTION */ int *n /* PROBE CODE NUMBER, AS SET IN PROBEFILE.D */ ) { probename_[*n] = name; /* printf(" subroutine cname2 ... probename_[%d] = %s \n ",*n,probename_[*n]); */ } /********************************************************** FUNCTION COMPARE COMPARE IS A FUNCTION USED BY QSORT TO SORT A WRITE2 STRUCTURE (TWO INTEGERS) BY ITS SECOND INTEGER. TWO STRUCTURES ARE COMPARED. IF THE FIRST IS GREATER THAN THE SECOND, A ONE IS RETURNED, IF THE SECOND IS GREATER THAN THE FIRST A -1 IS RETURNED, IF THEY ARE THE SAME, A ZERO IS RETURNED. THE GOAL IS TO GET ALL STRUCTURES IN ASCENDING ORDER OF THEIR SECOND INTEGER, I.E. ALL V1S GREATER THAN ALL V2S. ***********************************************************/ int compare( const void *e1, const void *e2 ) { int v1 = ((struct write2 *)e1)->rec; int v2 = ((struct write2 *)e2)->rec; return (v1v2) ? 1 : 0; } /**************************************************** SUBROUTINE COMPAREM COMPAREM IS USED BY QSORT AS A GUIDE TO SORT AN ARRAY. IF A RETURNED VALUE IS -1, THE POSITION OF THE TWO COMPARED PARAMETERS IS SWITCHED. IF THE RETURNED VALUE IS 0 OR 1, NOTHING IS DONE. *******************************************************/ int comparem( const void *e1, /* FIRST VALUE TO COMPARE */ const void *e2 /* SECOND VALUE TO COMPARE */ ) { /**************************************************** I - RETURNED VALUE: -1 IF E1 < E2 0 IF E1 = E2 1 IF E1 > E2 *****************************************************/ int i = 0; int eone = *(int *)e1; int etwo = *(int *)e2; if ( eone < etwo ) i = -1; else if ( eone > etwo ) i = 1; return i; } /**************************************************** SUBROUTINE COMPAREM2 COMPAREM2 IS USED BY QSORT AS A GUIDE TO SORT AN ARRAY OF TWO INTEGER STRUCTURES BY THEIR FIRST VALUE. IF A RETURNED VALUE IS -1, THE POSITION OF THE TWO COMPARED PARAMETERS IS SWITCHED. IF THE RETURNED VALUE IS 0 OR 1, NOTHING IS DONE. *******************************************************/ int comparem2( const void *e1, /* FIRST VALUE TO COMPARE */ const void *e2 /* SECOND VALUE TO COMPARE */ ) { /**************************************************** I - RETURNED VALUE: -1 IF E1 < E2 0 IF E1 = E2 1 IF E1 > E2 *****************************************************/ int i = 0; int eone = ((struct write2 *)e1)->num; int etwo = ((struct write2 *)e2)->num; if ( eone < etwo ) i = -1; else if ( eone > etwo ) i = 1; return i; } /**************************************************** SUBROUTINE COMPAREM2 COMPAREM3 IS USED BY QSORT AS A GUIDE TO SORT AN ARRAY OF THREE INTEGER STRUCTURES BY THEIR FIRST VALUE AND SECOND VALUES. IF A RETURNED VALUE IS -1, THE POSITION OF THE TWO COMPARED PARAMETERS IS SWITCHED. IF THE RETURNED VALUE IS 0 OR 1, NOTHING IS DONE. *******************************************************/ int comparem3( const void *e1, /* FIRST VALUE TO COMPARE */ const void *e2 /* SECOND VALUE TO COMPARE */ ) { /**************************************************** I - RETURNED VALUE: -1 IF E1 < E2 or E1 = E2 && E1.second < E2.second 0 IF E1 = E2 and E1.second <= E2.second 1 IF E1 > E2 or E1 = E2 && E1.second > E2.second *****************************************************/ int i = 0; int eonenum = ((struct write3 *)e1)->num; int etwonum = ((struct write3 *)e2)->num; int eonerec = ((struct write3 *)e1)->rec; int etworec = ((struct write3 *)e2)->rec; if ( eonenum < etwonum ) i = -1; else if ( eonenum > etwonum ) i = 1; else if ( eonenum == etwonum ) { if ( eonerec < etworec ) i = -1; else if ( eonerec > etworec ) i = 1; } return i; } /********************************************************************* SUBROUTINE DENSESURFFILENAME DENSESURFFILENAME CONSTRUCTS A FULL FILENAME FOR A VARIABLE ON A DENSITY SURFACE. THE FILE NAME IS CONSTRUCTED AS FOLLOWS: /MAIN BRANCH DIRECTORY/PROBE TYPE/'DENSESURF'/FILENAME MAIN BRANCH DIRECTORY IS A GLOBAL CONSTANT. PROBE TYPE IS A GLOBAL C CHARACTER ARRAY TAKEN FROM PROBEFILE.D FILENAME CONTAINS A PARAMETER TYPE WHICH IS ALSO A GLOBAL C ARRAY FROM PROBEFILE.D FILE NAME IS USER INPUT FILE NAME *********************************************************************/ densesurffilename_( char *type, /* REQUESTED FILE NAME */ int *ptype, /* PROBE CODE NUMBER */ char *filename /* CONSTRUCTED FILE NAME */ ) { sprintf( filename,"%sdata/%s/densesurf/%s\0",MAINBRANCH, probename_[*ptype],type); } /********************************************************************* SUBROUTINE DEPTHMASK DEPTHMASK MASKS OUT INDIVIDUAL DEPTHS ACCORDING TO INFORMATION IN MASK FILES. **********************************************************************/ /********************************************************************* DEFINE TWOREAD AS A WRITE2 (TWO INTEGER) STRUCTURE. TWOREAD WILL HAVE TWO INTEGERS, TWOREAD.NUM WHICH IS PROFILE RECORD NUMBER AND TWOREAD.REC WHICH IS DEPTH NUMBER. DEFINE GPRESENT AS AN INTEGER ARRAY OF SIZE MAXMASK. THIS WILL HOLD THE PRESENT DEPTH NUMBER. **********************************************************************/ struct write2 tworead; int gpresent[MAXMASK]; depthmask_( int *maxlevel, /* MAXIMUM NUMBER OF LEVELS */ int *jj, /* HEADER RECORD NUMBER */ int *fn, /* FILE IDENTIFICATION NUMBERS FOR MASK FILES */ int *nmask, /* FIRST MASK NUMBER */ int *nmaskd, /* LAST MASK NUMBER */ float *temp, /* PARAMETER DATA */ int *ipn, /* PARAMETER CODE NUMBER FOR EACH MASK */ int *count, /* COUNTS NUMBER OF ALTERED DEPTHS */ int *count2, /* COUNTS NUMBER OF ALTERED PROFILES */ int *endall, /* NUMBER OF ENDS OF FILE MARKERS REACHED */ int *ireqpars, /* REQUESTED PARAMETERS */ int *ip2, /* REQUESTED PARAMETER CODES */ int *numdeps, /* NUMBER OF DEPTHS */ float *missing, /* MISSING VALUE MARKER */ int *paramcalc /* NUMBER OF CALCULATED PARAMETERS */ ) { /********************************************************** PARAMETERS: K - MASK NUMBER I2 - PROPER PARAMETER POSITION FOR ARRAY TEMP I3 - PROPERE PARAMETER POSITION FOR ARRAY COUNT I0 - PARAMETER COUNTER I - PARAMETER CODE IJ - DEPTH COUNTER ***********************************************************/ int k,i2,i3,i0,i,ij,gp,numextra,i2x,ifull=0; int i2max= *maxlevel * *(ip2+ *maxlevel); /*********************************************************** SET ALL ALTERED PROFILE COUNTS TO THEIR NEGATIVE WHEN THEY ARE AGAIN POSITIVE, THE PROFILE HAS BEEN ALTERED FOR THIS PARAMETER ************************************************************/ for ( i0 = 1; i0 <= *ireqpars; i0++) *(count2+*(ip2+i0)) = 0 - *(count2+*(ip2+i0)); /********************************************************** EXAMINE EACH MASK TO SEE ITS PRESENT RECORD NUMBER (JPRESENT) AND IF THIS NUMBER NEEDS TO BE UPDATED (IF IT IS LESS THAN PRESENT RECORD NUMBER). ***********************************************************/ for ( k = *nmask; k < *nmaskd; k++ ) { /********************************************************** EXAMINE A MASK ONLY IF IT HAS NOT YET BEEN ENTIRELY READ IN. ***********************************************************/ if ( !feof( fp[*(fn+k)] ) ) { /********************************************************** READ IN VALUES FROM FILE UNTIL THE PRESENT MASK RECORD NUMBER IS EQUAL TO OR GREATER THAN THE PRESENT PROFILE RECORD NUMBER. ***********************************************************/ while ( jpresent[k] < *jj && !feof( fp[*(fn+k)] ) ) { /*********************************************************** READ IN PROFILE RECORD NUMBER AND DEPTH NUMBER TO BE MASKED ************************************************************/ fread( &tworead, sizeof( struct write2 ), 1, fp[*(fn+k)] ); /*********************************************************** SET PRESENT RECORD NUMBER (JPRESENT) AND DEPTH NUMBER (GPRESENT) TO LAST VALUES READ IN. SUBTRACT ONE FROM DEPTH NUMBER SO IT REFLECTS CORRECT LEVEL. ************************************************************/ jpresent[k] = tworead.num; gpresent[k] = tworead.rec; if ( gpresent[k] != 0 ) gpresent[k] -=1; else gpresent[k] = -999; } /*********************************************************** IF END OF FILE HAS NOT BEEN REACHED, CONTINUE ************************************************************/ if ( !feof( fp[*(fn+k)] )) { /*********************************************************** SET I2 ACCORDING TO THE PARAMETER REPRESENTED BY THE MASK ************************************************************/ i2 = *maxlevel * ( *(ipn+k) - 1 ); i3 = *maxlevel * *(ipn+k); /*********************************************************** IF THE PRESENT RECORD NUMBER EQUALS THE PRESENT MASK RECORD NUMBER AND THE END OF FILE HAS NOT BEEN REACHED, MASK OUT ALL DEPTHS WHICH ARE IN THE MASK FILE FOR THIS PROFILE. THEN READ IN THE NEXT STRUCTURE FROM THE MASK FILE. ************************************************************/ while ( jpresent[k] == *jj && !feof( fp[*(fn+k)] ) ) { if ( gpresent[k] > -999 ) { if ( gpresent[k] < *maxlevel ) { i2x=0; gp= gpresent[k]; } else { numextra= (gpresent[k]/ *maxlevel) * *maxlevel; i2x= (*(ip2 + *maxlevel) + 2 + *paramcalc)*numextra; gp = gpresent[k] - numextra; } /********************************************************** COUNT + I2MAX IS THE TOTAL NUMBER OF HITS FOR THIS PROFILE ***********************************************************/ *(count+i2max) +=1; /*********************************************************** IF THIS MASK REPRESENTS A CERTAIN PARAMETER, ADD ONE TO THE COUNTER OF PROFILES MASKED FOR THIS PARAMETER. ************************************************************/ if ( *(ipn+k) > 0 && *(count2+*(ipn+k)) <= 0 ) { if ( gp <= -1 || *(temp+ i2x+i2+gp ) > *missing ) *(count2+*(ipn+k)) = 0 - *(count2+*(ipn+k)) + 1; } /*********************************************************** IF THIS MASK REPRESENTS ALL PARAMETERS, ADD ONE TO EACH COUNTER ************************************************************/ else if ( *(ipn+k) == 0 ) { for ( i0 = 1; i0 <= *ireqpars; i0++) { if ( *(count2+*(ip2+i0)) <= 0 ) { if ( *(ip2+i0) == 0 || gp <= -1 || *(temp+ i2x+i2+gp) > *missing ) *(count2+*(ip2+i0)) = 0 - *(count2+*(ip2+i0)) + 1; } } } /*********************************************************** THE LAST ALTERNATIVE MASK REPRESENTING BOTH TEMPERATURE AND SALINITY (VALUE OF IPN IS -1). IN THIS CASE ADD ONE TO BOTH TEMPERATURE AND SALINITY COUNTERS. ************************************************************/ else if ( *(ipn + k) < 0 ) { if ( gp <= -1 || *(temp+ i2x + gp) > *missing ) if ( *(count2+1) <=0 ) *(count2+1) = 0 - *(count2+1) + 1; if ( gp <= -1 || *(temp+ *maxlevel + i2x + gp) > *missing ) if ( *(count2+2) <=0) *(count2+2) = 0 - *(count2+2) + 1; } /***************************************************** IF THIS IS A SINGLE PARAMETER MASK, MASK OUT ONLY THE PRESCRIBED VALUES FOR THIS ONE PARAMETER. ******************************************************/ if ( *(ipn+k) > 0 ) { /***************************************************** A VALUE OF -1 OR LESS FOR DEPTH NUMBER MEANS TO MASK THE ENTIRE PROFILE. MASK OUT THE PARAMETER FOR EACH DEPTH AND ADD ONE TO THE INDIVIDUAL DEPTH COUNTER AT EACH DEPTH. ******************************************************/ if ( gp <= -1 ) { ifull = 1; for ( ij = 0; ij < *numdeps; ij++ ) { if ( ij < *maxlevel ) { i2x=0; gp = ij; } else { numextra= (ij/ *maxlevel) * *maxlevel; i2x= (*(ip2 + *maxlevel) + 2 + *paramcalc)*numextra; gp = ij - numextra; } *(temp + ij + i2 +i2x) = *missing; (*(count+ ij + i3 + i2x)) +=1; } } /******************************************************* OTHERWISE MASK OUT ONLY THE VALUE PRESCRIBED IN GPRESENT ********************************************************/ else { *( temp + gp + i2 + i2x) = *missing; (*(count+ gp + i3 + i2x)) +=1; } } /***************************************************** IF THE MASK REPRESENTS ALL PARAMETERS (IPN = 0) MASK OUT EACH PARAMETER. ******************************************************/ else if ( *(ipn+k) == 0 ) { /***************************************************** RUN THROUGH EACH REQUESTED PARAMETER ******************************************************/ for ( i0 = 1; i0 <= *ireqpars; i0++ ) { /***************************************************** SET PROPER PARAMETER CODE AND POSITION MARKER ******************************************************/ i = *(ip2+i0); i2 = *maxlevel * ( i - 1 ); i3 = *maxlevel * i; /***************************************************** MASK OUT PRESCRIBED LEVEL AND ADD ONE TO PROPER COUNTER ******************************************************/ if ( i == 0 ||*( temp + gp + i2 +i2x) > *missing ) { if ( i != 0 ) *( temp + gp + i2 +i2x ) = *missing; *( count+ gp + i2x + i3 ) +=1; } } } /***************************************************** IF IPN IS LESS THAN ZERO, MASK OUT THE PRESCRIBED LEVEL FOR TEMPERATURE AND SALINITY, AND ADD ONE TO EACH COUNTER. *******************************************************/ else { *( temp + gp + i2x + *maxlevel ) = *missing; *( temp + gp + i2x ) = *missing; (*( count + gp + i2x + *maxlevel )) +=1; (*( count + gp + i2x + 2* *maxlevel )) +=1; } } /************************************************************* READ IN THE NEXT RECORD AND DEPTH NUMBER FROM FILE. **************************************************************/ fread( &tworead, sizeof ( struct write2 ), 1, fp[*(fn+k)] ); jpresent[k] = tworead.num; gpresent[k] = tworead.rec; if ( gpresent[k] != 0 ) gpresent[k] -=1; else gpresent[k] = -999; } /************************************************************* IF THIS IS THE END OF FILE, ADD ONE TO END OF FILE COUNTER. **************************************************************/ } if ( feof( fp[*(fn+k)] )) *endall += 1; } } /*********************************************************** RESET COUNTER IF A FULL PARAMETER MASK WAS SET ************************************************************/ if ( ifull == 1 ) { *(count + i2max) *= -1; ifull=0; } /*********************************************************** RESET ALL ALTERED PROFILE COUNTS TO THE POSITIVE ************************************************************/ for ( i0 = 1; i0 <= *ireqpars; i0++) { if ( *(count2+*(ip2+i0)) < 0 ) *(count2+*(ip2+i0)) = 0 - *(count2+*(ip2+i0)); } } /*************************************************************** SUBROUTINE DJSORT DJSORT SORTS A FILE NUMERICALLY. FIRST THE CONTENTS OF THE FILE ARE READ INTO AN ARRAY. THEN THEY ARE SORTED USING THE QSORT FACILITY. THEN THE CONTENTS ARE READ BACK OUT TO THE ORIGINAL FILE. DJSORT IS ONLY FOR FILES CONTAINING TWO INTEGER STRUCTURES (PREP). ****************************************************************/ djsort_( int *fn /* FILE IDENTIFICATION NUMBER */ ) { /**************************************************************** PARAMETERS: I - COUNTER NUMPROS - NUMBER OF VALUES TO BE SORTED *****************************************************************/ int i; int numpros = 0; /**************************************************************** READ IN ALL THE VALUES FROM FILE. *****************************************************************/ while ( !feof(fp[*fn]) ) { numpros++; prep[numpros].num= 0; prep[numpros].rec= 0; fread( &prep[numpros], sizeof( struct write2 ) , 1, fp[*fn]); } /*************************************************************** SUBTRACT ONE FROM THE VALUE COUNTER SINCE THE LAST ADDITION WAS FOR THE END OF FILE MARKER. ****************************************************************/ numpros--; /*************************************************************** REWIND THE FILE ****************************************************************/ fseek( fp[*fn], 0L, SEEK_SET ); /*************************************************************** SORT FILES USING QSORT: PREP[1] - STARTING POINT FOR SORT NUMPROS - NUMBER OF VALUES TO SORT SIZEOF() - SIZE OF VALUES BEING SORTED UNCOMPAREM - SORTING SUBROUTINE ****************************************************************/ qsort( &prep[1], numpros, sizeof( struct write2 ), comparem2 ); /*************************************************************** PLACE SORTED VALUES BACK IN FILE. ****************************************************************/ for ( i = 1; i <= numpros; i++ ) fwrite( &prep[i], sizeof( struct write2 ), 1, fp[*fn] ); } /****************************************************************** SUBROUTINE EXTRANAME EXTRANAME CONSTRUCTS A FILE NAME WHICH POINTS TO A DIRECTORY WHICH IS NOT PART OF THE MAIN DATA BASE FUNCTIONALITY (SUCH AS THE INFORMATION DIRECTORY). IT IS CONSTRUCTED AS FOLLOWS: /MAINBRANCH/EXTRA/XNAME MAINBRANCH IS THE MAIN DIRECTORY PATH TO THE DATA BASE EXTRA IS THE SUBDIRECTORY NAME XNAME IS THE NAME OF THE FILE *******************************************************************/ extraname_( char *extra, /* SUBDIRECTORY NAME */ char *xname, /* FILE NAME */ char *filename /* CONSTRUCTED FILE NAME */ ) { sprintf( filename, "%s%s/%s\0",MAINBRANCH,extra,xname); /* printf(" subdirectory: %s\n",extra); printf(" file name: %s\n",xname); printf(" constructed file name: %s\n",filename); */ } /*************************************************************** SUBROUTINE FILEASSIGN FILEASSIGN ASSIGNS AN UNUSED FILE IDENTIFICATION NUMBER TO A USER VARIABLE ***************************************************************/ fileassign( int *filenumber ) { int minassign = 302, maxassign = 490; int ifound=0; int i = minassign; while ( i < maxassign && ftrack[i] != 0 ) i++; if ( i < maxassign ) { ifound = 1; *filenumber = i; } else printf("Cannot assign file number, all values between %d", " and %d are in use.\n",minassign,maxassign); return ifound; } /************************************************************** SUBROUTINE FILECLOSEX FILECLOSE CLOSES AN ENTIRE FILE SET. THIS INCLUDES ALL PARAMETER FILES, DEPTH AND HEADER FILES, AND ANY MASK FILES ASSOCIATED WITH THE FILE SET. ***************************************************************/ fileclose_( int *fn, /* FILE IDENTIFICATION NUMBERS FOR MASKS */ int *nmasks, /* NUMBER OF MASKS */ int *ireqpars, /* NUMBER OF PARAMETERS */ int *isoor, /* STANDARD (1) OR OBSERVED (0) LEVELS */ int *isecond, /* SECOND HEADER CLOSING INFORMATION: 0 - DON'T CLOSE 1 - CLOSE */ int *set /* FILE SET NUMBER */ ) { /*************************************************************** PARAMETERS: I - COUNTER I2 - FILE IDENTIFICATION NUMBER FOR PARAMETERS S - FILE CLOSING INSTRUCTION FSELECT - FILE SET BASE FILE IDENTIFICATION NUMBER, BASED ON NUMBER OF PARAMETERS AND FILE SET NUMBER. *****************************************************************/ int i,i2,s; int fselect = 2 * (*ireqpars * (*set-1)) + 3 * (*set-1); /********************************************************* CLOSE ALL MASKS. REASSIGN TRACKING NUMBER TO ZERO INSTEAD OF -1 FOR REUSE BY OTHER SET MASKS **********************************************************/ for ( i = 0; i < *nmasks; i++ ) { if ( ftrack[*(fn+i)] == 1 ) { s = fclose( fp[*(fn+i)] ); ftrack[*(fn+i)]=0; } else printf("Attempt to close unopened file: %d\n",*(fn+i)); } /********************************************************* CLOSE ALL PARAMETER FILES **********************************************************/ for ( i = 1; i <= *ireqpars; i++ ) { i2 = *ireqpars * *isoor + i + 1; if ( ftrack[fselect+i2] == 1 ) { s = fclose( fp[fselect+i2] ); ftrack[fselect+i2]=0; } else { i2 = *ireqpars + i + 1; if ( ftrack[fselect+i2] == 1 ) { s = fclose( fp[fselect+i2] ); ftrack[fselect+i2]=0; } else printf("Attempt to close unopened file: %d\n",fselect+i2); } } /********************************************************* CLOSE HEADER FILE IF THERE ARE ANY PARAMETERS, AND CLOSE DEPTH FILE IF THIS IS OBSERVED LEVEL DATA. **********************************************************/ if (*ireqpars > 0 ) { if ( ftrack[fselect+1] == 1 ) { s=fclose( fp[fselect+1] ); ftrack[fselect+1]=0; } else printf("Attempt to close unopened file: %d\n",fselect+1); if (*isoor == 0) { if ( ftrack[fselect+0] == 1 ) { s=fclose( fp[fselect+0] ); ftrack[fselect+0]=0; } else printf("Attempt to close unopened file: %d\n",fselect+0); } } /********************************************************* CLOSE SECOND HEADER IF FILE IS OPEN **********************************************************/ if ( *isecond > 0 ) { if ( ftrack[fselect+ 2 * (*ireqpars) + 2] == 1 ) { s = fclose( fp[fselect+ 2 * (*ireqpars) + 2] ); ftrack[fselect+ 2 * (*ireqpars) + 2] = 0; } else printf("Attempt to close unopened file: %d\n", fselect+2 * (*ireqpars) + 2); } } /***************************************************************** SUBROUTINE FILEEND FILEEND MOVES A FILE POINTER TO THE END OF A FILE. ******************************************************************/ fileend_( int *filenumber /* FILE IDENTIFICATION NUMBER */ ) { int s; if ( (s=fseeko( fp[*filenumber], 0, SEEK_END )) != 0) printf("end of file not reachable: %d\n",*filenumber) ; } /****************************************************************** SUBROUTINE FILEOPEN FILEOPEN OPENS FILES FOR ACCESS FROM C SUBROUTINES. IF FILEOPEN CANNOT OPEN A FILE WITH THE TYPE SPECIFIED, IT WILL TRY TO OPEN IT AS A REGULAR FILE, FAILING THIS IT WILL OPEN A NEW FILE. FAILING THIS IT WILL WRITE TO SCREEN THAT THE FILE CANNOT BE OPENED. IF A NEW FILE IS OPENED WHEN THIS WAS NOT THE INPUT FILETYPE, A MESSAGE WILL ALSO BE SENT TO SCREEN. WHEN A FILE IS OPENED NORMALLY A MESSAGE CONTAINING FILENUMBER AND NAME IS SENT TO SCREEN. SUBROUTINE STEPS: 1. OPEN FILE ACCORDING TO SPECIFICATIONS, SEND MESSAGE TO SCREEN IF SUCCESSFUL. 2. FAILING THIS, TRY TO OPEN A REGULAR ACCESS FILE, ASSUMING THAT A BAD FILETYPE HAS BEEN SENT. 3. FAILING THIS OPEN A NEW FILE, SEND APPROPRIATE MESSAGE. 4. FAILING THIS SEND APPROPRIATE MESSAGE. 5. IF A NEW FILE IS OPENED, BY DESIGN OR OTHERWISE, THE FILE IS IMMEDIATELY CLOSED AND REOPENED. THIS WAY THERE IS AN END OF FILE MARKER PLACED IN THE FILE. *******************************************************************/ /***************************************************************** *fp is a C FILE structure array which can hold a maximum of MAXFILE files ftrack is set to one or zero for each file identification number associated with *fp. one means file identification number is associated with an open file, zero means file identification number is not in use at present ******************************************************************/ FILE *fp[MAXFILE]; int ftrack[MAXFILE]; fileopen_( char *filename, /* FILE NAME CONSTRUCTED FROM /MAIN BRANCH DIRECTORY, WHICH IS HARDWIRED INTO NAMING PROGRAMS, /PROBE TYPE/, /OBSERVED OR /STANDARD, AND /PARAMETER TYPE/, OR /MAIN BRANCH/, /PROBE TYPE/ /HEADER, /DEPTH OR /MASK/ AND FOR MASK, /PARAMETER TYPE/ AND /MASKNAME/ THESE NAMES ARE CONSTRUCTED IN NAMING PROGRAMS, NAMEOTHER FOR /DEPTH AND /HEADER FILES, NAMEFILE FOR PARAMETERS, AND MASKNAME FOR MASKS. */ char filetypein[], /* TYPE OF FILE TO BE OPENED, POSSIBLE TYPES ARE: r - TEXT FILE w - NEW TEXT FILE a - APPENDABLE TEXT FILE r+ - BINARY FILE w+ - NEW BINARY FILE a+ - APPEND TO BINARY FILE rb+ - READ AND WRITE BINARY FILE x - open as rb+ ONLY */ int *filenumber /* NUMBER ASSIGNED TO FILE TO BE OPENED, 0 FOR DEPTH FILE 1 FOR HEADER FILE CALCULATED DEPENDING ON FILE SET AND PARAMETER ORDER FOR PARAMETER FILE 70 + ORDER FOR MASK FILES */ ) { /*********************************************** S IS FOR CLOSING NEW FILES TO BE REOPENED ONLYOLD IS SET TO ONE IF ONLY AN OLD FILE SHOULD BE OPENED ORIGNUMBER IS ORIGINAL FILE NUMBER FILETYPE IS THE TYPE OF FILE TO BE OPENED ************************************************/ int s,ix,onlyold=0,orignumber; int nowrite=0; char filetype[5]; /*********************************************** IF FILE NUMBER IS LESS THAN ZERO, USER IS REQUESTING A COMPUTER GENERATED FILE IDENTIFICATION NUMBER ASSIGN FILE IDENTIFICATION NUMBER IN THIS CASE ************************************************/ if ( *filenumber == -2 ) { nowrite=1; *filenumber = -1; } /* printf("probename %s\n",probename_[1]);*/ orignumber = *filenumber; if ( *filenumber < 0 ) if ( (s = fileassign(filenumber)) == 0 ) return; /* printf("probename %s\n",probename_[1]);*/ /*********************************************** CHECK IF FILE IDENTIFICATION NUMBER IS ALREADY IN USE ************************************************/ if ( *filenumber >= 0 && ftrack[*filenumber] > 0 ) { printf(" CAUTION: FILENUMBER %d IS ALREADY IN USE.\n", *filenumber); printf(" FILE %s WILL NOT BE OPENED\n",filename); return; } /*********************************************** PRINT FILENUMBER AND FILENAME TO SCREEN SET FILETRACK TO 1 FOR THIS FILE NUMBER TO INDICATE FILE WILL BE OPENED ************************************************/ if ( nowrite == 0 ) printf(" %d %s\n", *filenumber, filename); /*printf("probename %s\n",probename_[1]);*/ ftrack[*filenumber] = 1; /********************************************** IF FILETYPE IS GIVEN AS 'x', RESET TO 'rb+', BUT ONLY OPEN IF FILE ALREADY EXISTS ***********************************************/ if ( filetypein[0] == 'x' ) { filetype[0]='r'; filetype[1]='b'; filetype[2]='+'; filetype[3]='\0'; onlyold = 1; } else { ix=0; while ((filetype[ix] = filetypein[ix]) != '\0' ) ix++; } /*********************************************** OPEN FILE ************************************************/ if ( nowrite == 0 ) printf("file mode: %s\n",filetype,filenumber); if ((fp[*filenumber] = fopen(filename,filetype)) == NULL) { printf("inside\n"); if ( onlyold == 0 ) { /*********************************************** IF THIS FAILS OPEN FILE AS READABLE TEXT FILE ************************************************/ if ((fp[*filenumber] = fopen(filename,"r")) ==NULL) { /*********************************************** IF THIS FAILS, OPEN A NEW FILE. ALTHOUGH THIS IS OPENED AS A TEXT FILE, IT CAN BE USED AS A BINARY FILE. PRINT TO SCREEN THAT THE FILE COULD NOT BE OPENED IF THIS FAILS. OTHERWISE CLOSE AND REOPEN THE FILE TO INSERT AN END OF FILE MARKER. PRINT TO SCREEN THAT A NEW FILE HAS BEEN OPENED. ************************************************/ if ((fp[*filenumber] = fopen(filename,"w")) ==NULL) { printf(" unable to open %s\n ", filename); ftrack[*filenumber] = 0; if ( orignumber == -1 ) *filenumber = -1; } else { s = fclose( fp[*filenumber] ); fp[*filenumber] = fopen(filename,"rb+"); printf(" %s is a new file\n ",filename); } } /************************************************************* INDICATE THAT THIS FILE HAS BEEN OPENED AS READ-ONLY *************************************************************/ else { printf("WARNING: FILE CAN ONLY BE OPENED AS READ-ONLY\n"); } } /************************************************************ INDICATE THAT FILE DOES NOT EXIST *************************************************************/ else { printf("FILE DOES NOT EXIST AND WILL NOT BE OPENED AS"); printf(" A NEW FILE\n"); ftrack[*filenumber] = 0; if ( orignumber == -1 ) *filenumber = -1; } } } /***************************************************************** SUBROUTINE FILEPOS FILEPOS FINDS THE PRESENT FILE POINTER POSITION, IN USER DESIGNATED UNITS, FROM THE BEGINNING OF THE FILE. THE UNIT FOR A HEADER FILE IS THE SIZE OF STRUCTURE HEADERDATA + THE SIZE OF AN INTEGER MULTIPLIED BY THE NUMBER OF PARAMETERS A PROBE MEASURES PLUS ONE FOR THE SECOND HEADER AND ONE FOR THE DEPTH FOR PROBES WHICH MEASURE MORE THAN ONE PARAMETER. DATA FILES HAVE A UNIT OF SIZE OF INTEGER. MASK FILES VARY BY THE SIZE OF THE STRUCTURE WHICH THEY STORE. NOTE: THIS SUBROUTINE IS NOT PORTABLE TO MACHINES WHERE INTEGER AND REAL STORAGE SIZES ARE DIFFERENT. ON SUCH MACHINES, THIS SUBROUTINE CAN ONLY BE USED FOR INTEGER VARIABLES. ******************************************************************/ filepos_( int *fn, /* FILE IDENTIFICATION NUMBER */ int *head, /* TYPE OF FILE BEING INVESTIGATED: 0 - MASK FILE 1 - HEADER FILE 2 - NORMAL PARAMETER FILE 3 - SPECIAL PARAMETER FILE 4 - .C MASK */ int *mult, /* SIZE MULTIPLIER (SEE ABOVE) */ int *recnum /* THE RETURNED VALUE, THE PRESENT FILE POINTER POSITION */ ) { /**************************************************************** CALCULATE SIZE OF ONE UNIT (AS DESCRIBED ABOVE). *****************************************************************/ off_t size,x; if ( *head <= 1 ) size= *head * sizeof( struct headerdata ) + *mult * sizeof( int); else if ( *head == 2 ) size= sizeof( struct write2fs ); else if ( *head == 3 ) size= sizeof(struct write3fs ); else if ( *head == 4 ) size= sizeof(struct write2c); /**************************************************************** CALCULATE FILE POINTER POSITION IN BYTES BY USING FTELL UTILITY. DIVIDE BY SIZE TO GET IN PROPER UNITS. *****************************************************************/ x=ftello(fp[*fn])/size; *recnum = ftello( fp[*fn] )/size; } /************************************************************** SUBROUTINE FILEREWIND FILEREWIND SETS A FILE POINTER TO THE BEGINNING OF A FILE. ***************************************************************/ filerewind_( int *filenumber /* FILE INDETIFICATION NUMBER */ ) { fseeko( fp[*filenumber], 0, SEEK_SET ); } /***************************************************************** SUBROUTINE FINDCRUISE FINDCRUISE PLACES ALL THE RECORD NUMBERS FOR A USER INPUT CRUISE INTO AN ARRAY FOR USE IN THE MAIN PROGRAM. ******************************************************************/ /***************************************************************** MAKE INC A WRITE2 STRUCTURE (TWO INTEGERS). THE FIRST INTEGER IS THE NUMBER OF PROFILES IN A CRUISE, THE SECOND IS THE LOCATION OF THE RECORD NUMBER FOR THE FIRST PROFILE IN A CRUISE, IN THE PRIMARY FILE. ******************************************************************/ struct write2 inc; findcruise_( int *choice, /* USER INPUT CRUISE NUMBER */ int *nproc, /* NUMBER OF PROFILES FOR THIS CRUISE */ int *icgrid, /* RECORD NUMBERS OF PROFILES FOR THIS CRUISE */ int *fn, /* FILE IDENTIFICATION NUMBER FOR FILE CONTAINING CRUISE NUMBER AND POSITION OF INFORMATION ON CRUISE IN SECONDARY FILE */ int *fn1, /* FILE IDENTIFICATION NUMBER FOR FILE CONTAINING RECORD NUMBERS SORTED BY CRUISE (PRIMARY FILE) */ int *fn2 /* FILE IDENTIFICATION NUMBER FOR FILE CONTAINING NUMBER OF PROFILES FOR A CRUISE AND LOCATION IN PRIMARY FILE OF RECORD NUMBER OF FIRST PROFILE (SECONDARY FILE) */ ) { /**************************************************************** INTERNAL VARIABLES: CNUM - CRUISE NUMBER READ IN FROM INDEX FILE INDEX - ORDER OF CRUISE IN INDEX FILE (ALSO POSITION OF CRUISE INFORMATION IN SECONDARY FILE) ******************************************************************/ int cnum = 0; int index = 0; /***************************************************************** READ THROUGH INDEX FILE UNTIL REQUESTED CRUISE NUMBER IS FOUND ADD ONE TO INDEX FOR EACH CRUISE NUMBER READ IN. ******************************************************************/ fseek( fp[*fn], 0L, SEEK_SET ); while ( cnum != *choice && !feof( fp[*fn] ) ) { fread( &cnum, sizeof( int ), 1, fp[*fn] ); index +=1; } /**************************************************************** IF THE CRUISE NUMBER WAS NOT FOUND, SET NUMBER OF PROFILES TO -1 AND RETURN TO MAIN PROGRAM. *****************************************************************/ if ( feof( fp[*fn] ) ) { *nproc = -1; fseek( fp[*fn], 0L, SEEK_SET ); return; } /**************************************************************** USE INDEX TO GO TO THE CORRECT POSITION IN THE SECONDARY FILE TO READ IN INFORMATION ON THE CRUISE READ IN THE NUMBER OF PROFILES IN THIS CRUISE (INC.NUM) AND THE STARTING POSITION OF PROFILE RECORD NUMBERS (INC.REC). *****************************************************************/ fseek( fp[*fn2], (index-1) * sizeof( struct write2 ), SEEK_SET ); fread( &inc, sizeof( struct write2 ), 1, fp[*fn2] ); /**************************************************************** USE THIS INFORMATION TO SCROLL TO THE PROPER POSITION IN THE PRIMARY FILE AND TO SET THE NUMBER OF PROFILES. *****************************************************************/ fseek( fp[*fn1], inc.rec * sizeof( int ), SEEK_SET ); *nproc = inc.num; /**************************************************************** READ IN THE PROFILE NUMBERS TO ARRAY ICGRID *****************************************************************/ fread( icgrid, sizeof( int ), *nproc, fp[*fn1] ); /*************************************************************** REWIND FILES ****************************************************************/ fseek( fp[*fn], 0L, SEEK_SET ); fseek( fp[*fn1], 0L, SEEK_SET ); fseek( fp[*fn2], 0L, SEEK_SET ); } /*********************************************************** SUBROUTINE GEOREADTOMASK GEOREAD READS ALL RECORD NUMBERS OF PROFILES IN A USER SPECIFIED GRID BOX. IT DOES THIS BY FIRST GETTING INFORMATION ON THE SPECIFIED GRID BOX ( NUMBER OF PROFILES IN GRID BOX AND LOCATION OF FIRST RECORD NUMBER FOR GRID BOX IN PRIMARY MASK) FROM A SECONDARY MASK FILE. USING THIS INFORMATION, THE ACTUAL PROFILE NUMBERS ARE READ INTO A MASK **************************************************************/ /************************************************************* DEFINE IN AS A TWO INTEGER STRUCTURE. THE FIRST INTEGER, IN.NUM IS THE NUMBER OF PROFILES IN A GRID BOX. THE SECOND INTEGER, IN.REC, IS THE LOCATION IN THE PRIMARY FILE OF THE FIRST PROFILE RECORD NUMBER IN THE SPECIFIED GRID BOX. **************************************************************/ struct write2 in; georeadtomask_( int *lon, /* CHOSEN LONGITUDE */ int *lat, /* CHOSEN LATITUDE */ int *numpros, /* NUMBER OF PROFILES AT A GRID POINT */ int *idim, /* NUMBER OF LONGITUDE SPACINGS */ int *fn1, /* FILE NUMBER OF PRIMARY FILE */ int *fn2, /* FILE NUMBER OF SECONDARY FILE */ int *fnout /* OUTPUT FILE NUMBER */ ) { /********************************************************* PARAMETERS: SEEKNUM - POSITION OF DESIRED INFORMATION IN SECONDARY FILE. THIS NUMBER IS DETERMINED FROM THE INPUT LATITUDE MINUS ONE MULTIPLIED BY THE LONGITUDE SPACING, PLUS THE INPUT LONGITUDE MINUS ONE. IGRIDPOS - STATION POSITIONS READ IN ***********************************************************/ int seeknum,i,igridpos; /********************************************************** CALCULATE SECONDARY MASK POSITION ***********************************************************/ seeknum = *idim * ( *lat - 1 ) + *lon - 1; /********************************************************** MOVE FILE POINTER TO CORRECT POSITION IN SECONDARY FILE. ***********************************************************/ fseek( fp[*fn2], seeknum * sizeof( struct write2 ), SEEK_SET ); /********************************************************** READ NUMBER OF PROFILES IN GRID BOX ( IN.NUM ) AND LOCATION OF FIRST PROFILE ( IN.REC ). ***********************************************************/ fread( &in, sizeof( struct write2 ), 1, fp[*fn2] ); /********************************************************** SET NUMPROS TO THE NUMBER OF PROFILES. ***********************************************************/ *numpros = in.num; /*********************************************************** USE LOCATION OF FIRST PROFILE TO MOVE FILE POINTER TO CORRECT POSITION IN PRIMARY FILE. ************************************************************/ fseek( fp[*fn1], in.rec * sizeof( int ), SEEK_SET ); /*********************************************************** READ IN PROFILE RECORD NUMBERS WRITE OUT TO FILE ************************************************************/ for ( i = 1; i <= in.num; i++ ) { fread( &igridpos, sizeof( int ), 1, fp[*fn1] ); fwrite( &igridpos, sizeof(int ), 1, fp[*fnout]); } } /****************************************************************** SUBROUTINE GETFORSURF GETFORSURF RETRIEVES PARAMETER CODES FOR 1. LATITUDE, 2. LONGITUDE AND 3. JULIAN DAY ******************************************************************/ getforsurf_( int *i, /* TYPE OF PARAMETER CODE 1. LATITUDE 2. LONGITUDE 3. JULIAN DAY */ int *ival /* CODE NUMBER FOR GIVEN PARAMETER */ ) { *ival= surfhead[*i-1]; } /***************************************************************** SUBROUTINE GETGPRESENT GETGPRESENT RETRIEVES A VALUE FROM GPRESENT. GPRESENT IS THE PRESENT SEQUENTIAL DEPTH NUMBER FOR A GIVEN MASK ******************************************************************/ getgpresent_( int *masknumber, /* NUMERICAL ORDER OF MASK BEING SE */ int *fromgpresent /* VALUE TO ENTER FOR GPRESENT */ ) { /***************************************************************** GET THE PRESENT PROFILE NUMBER ******************************************************************/ *fromgpresent = gpresent[*masknumber -1]; } /***************************************************************** SUBROUTINE GETJPRESENT GETJPRESENT RETRIEVES A VALUE FROM JPRESENT. JPRESENT IS THE PRESENT SEQUENTIAL STATION NUMBER FOR A GIVEN MASK ******************************************************************/ getjpresent_( int *masknumber, /* NUMERICAL ORDER OF MASK BEING SE */ int *fromjpresent /* VALUE TO ENTER FOR JPRESENT */ ) { /***************************************************************** GET THE PRESENT PROFILE NUMBER ******************************************************************/ *fromjpresent = jpresent[*masknumber -1]; } /**************************************************** FUNCTION GETPROBENAME GETPROBENAME RETURNS THE CHARACTER STRING PROBENAME FOR THE REQUESTED PROBE CODE NUMBER *****************************************************/ getprobename_( int *n, char *proben ) { strcpy(proben,probename_[*n]); } /****************************************************************** SUBROUTINE GETSURFPROBE GETSURFPROBE CHECKS IF A PROBE IS MARKED AS SURFACE-ONLY 1= SURFACE ONLY 0= PROFILE OR BIOLOGICAL DATA ******************************************************************/ getsurfprobe_( int *i, /* PROBE CODE */ int *ival /* SURFACE-ONLY MARKER */ ) { *ival= surfprobe[*i]; } /***************************************************** FUNCTION GETUSER GETUSER GETS USER NAME FROM COMPUTER *******************************************************/ getuser_( char *WHOami /* USER NAME */ ) { FILE *fone; char *p = WHOami; system("whoami > .OCLdb_getuser"); fone=fopen(".OCLdb_getuser\0","rb+\0"); fscanf(fone,"%s",WHOami); fclose(fone); while ( *p++ != '\0' ); *p--; *p = ' '; } /* FUNCTION ISITNAN ISITNAN RETURNS A NON-ZERO DIGIT IF INPUT NUMBER IS NAN (NOT A NUMBER) ZERO OTHERWISE */ int isitnan_( float *inval /* INPUT NUMBER */ ) { return isnan(*inval); } /* FUNCTION ISITRETURN ISITRETURNS RETURNS A 0 IF INPUT CHARACTER IS NOT A RETURN, ONE OTHERWISE */ int isitreturn_( char *inchar /* INPUT CHARACTER */ ) { if ( !isprint(*inchar) ) return 1; else return 0; } /*************************************************************** SUBROUTINE JSORT JSORT SORTS A FILE NUMERICALLY. FIRST THE CONTENTS OF THE FILE ARE READ INTO AN ARRAY. THEN THEY ARE SORTED USING THE QSORT FACILITY. THEN THE CONTENTS ARE READ BACK OUT TO THE ORIGINAL FILE. JSORT IS ONLY FOR FILES CONTAINING ONE INTEGER STRUCTURES (PREPI). ****************************************************************/ jsort_( int *fn /* FILE IDENTIFICATION NUMBER */ ) { /**************************************************************** PARAMETERS: I - COUNTER NUMPROS - NUMBER OF VALUES TO BE SORTED *****************************************************************/ int i; int numpros = 0; /**************************************************************** READ IN ALL THE VALUES FROM FILE. *****************************************************************/ while ( !feof(fp[*fn]) ) { numpros++; fread( &prepi[numpros], sizeof( int ) , 1, fp[*fn]); } /*************************************************************** SUBTRACT ONE FROM THE VALUE COUNTER SINCE THE LAST ADDITION WAS FOR THE END OF FILE MARKER. ****************************************************************/ numpros--; /*************************************************************** REWIND THE FILE ****************************************************************/ fseek( fp[*fn], 0L, SEEK_SET ); /*************************************************************** SORT FILES USING QSORT: PREPI[1] - STARTING POINT FOR SORT NUMPROS - NUMBER OF VALUES TO SORT SIZEOF() - SIZE OF VALUES BEING SORTED UNCOMPAREM - SORTING SUBROUTINE ****************************************************************/ qsort( &prepi[1], numpros, sizeof( int ), comparem ); /*************************************************************** PLACE SORTED VALUES BACK IN FILE. ****************************************************************/ for ( i = 1; i <= numpros; i++ ) fwrite( &prepi[i], sizeof( int ), 1, fp[*fn] ); } /****************************************************************** SUBROUTINE LOOPREAD LOOPREAD READS IN THE STARTING AND ENDING PROFILE NUMBERS FOR A SPECIFIC YEAR AND MONTH (OR JUST FOR A YEAR). THE VALUES ARE CONTAINED IN A .L FILE IN A TWO INTEGER STRUCTURE ********************************************************************/ /******************************************************************* DEFINE LOOP AS A WRITE2 (TWO INTEGER) STRUCTURE TO READ IN THE STARTING AND ENDING LOOP VALUES. ********************************************************************/ struct write2 loop; loopread_( int *jstart, /* STARTING PROFILE NUMBER FOR YEAR (AND MONTH) */ int *jend, /* ENDING PROFILE NUMBER FOR YEAR (AND MONTH) */ int *fn, /* FILE IDENTIFICATION NUMBER FOR FILE WITH LOOP INFORMATION */ int *iyear, /* REQUESTED YEAR */ int *month, /* REQUESTED MONTH (13 IS ALL MONTHS) */ int *leof /* SET TO ONE IF END OF FILE HAS BEEN REACHED */ ) { /********************************************************** PARAMETERS: YEAR - INPUT YEAR MINUS 1800, USED TO FIND PROPER POSITION IN FILE PSIZE - PROPER POSITION IN FILE. THIS IS FOURTEEN TIMES THE CALCULATED YEAR ( ONE FOR EACH MONTH, ONE FOR NO MONTH (0), AND ONE FOR ALL MONTHS (13)) PLUS DESIRED MONTH ************************************************************/ int year = *iyear - 1800; int psize; /************************************************* ALL YEARS PRIOR TO 1801 ARE PLACED TOGETHER ***************************************************/ if ( year < 0 ) year = 0; /************************************************** CALCULATE PROPER POSITION OF DESIRED INFORMATION ***************************************************/ psize = year * 14 + *month; /*************************************************** MOVE TO PROPER POSITION IN FILE (FSEEK) READ STRUCTURE CONTAINING BEGINNING AND ENDING PROFILE VALUES FOR DESIRED YEAR (AND MONTH) ****************************************************/ fseek( fp[*fn], psize * sizeof( struct write2 ), SEEK_SET ); fread( &loop, sizeof( struct write2 ), 1, fp[*fn] ); /*************************************************** IF DESIRED DATE IS PAST END OF FILE, SET *LEOF TO ONE AND EXIT SUBROUTINE. *****************************************************/ if ( feof( fp[*fn] ) ) { *leof = 1; return; } /***************************************************** SET STARTING VALUE AND ENDING VALUE TO BE SENT TO MAIN PROGRAM. ******************************************************/ *jstart = loop.num; *jend = loop.rec; } /***************************************************************** SUBROUTINE MASKINIT MASKINIT INITIALIZES JPRESENT AND ALLEND. JPRESENT HOLDS THE PRESENT PROFILE NUMBER FOR EACH MASK. ALLEND IS SET TO ONE WHEN ALL SEQUENTIAL MASK FILES HAVE REACHED THE END OF FILE. ******************************************************************/ /**************************************************************** MAKE JPRESENT AN INTEGER ARRAY OF MAXMASK ITEMS. MAXMASK IS THE MAXIMUM NUMBER OF MASKS ALLOWED IN THE OCL SYSTEM. *****************************************************************/ int jpresent[MAXMASK]; maskinit_( int *nmask, /* NUMBER OF MASKS BEING INITIALIZED */ int *allend /* END OF FILES MARKER. THIS IS SET TO ONE WHEN ALL SEQUENTIAL MASK FILES HAVE BEEN COMPLETELY READ */ ) { int j; /* COUNTER */ /***************************************************************** SET *ALLEND TO ZERO TO REFLECT THAT MASKS HAVE NOT BEEN READ YET. ******************************************************************/ *allend = 0; /***************************************************************** FOR EACH MASK, SET THE PRESENT PROFILE NUMBER TO -1 TO SIGNIFY THAT NO PROFILE HAS YET BEEN READ. ******************************************************************/ for ( j = 0; j < *nmask; j++) jpresent[j]= -1; } /********************************************************************* SUBROUTINE MASKNAME MASKNAME CONSTRUCTS A FULL FILENAME FOR A MASK. THE FILE NAME IS CONSTRUCTED AS FOLLOWS: /MAIN BRANCH DIRECTORY/PROBE TYPE/'MASKS'/PARAMETER TYPE/ FILENAME MAIN BRANCH DIRECTORY IS A GLOBAL CONSTANT. PROBE TYPE IS A GLOBAL C CHARACTER ARRAY TAKEN FROM PROBEFILE.D PARAMETER TYPE IS ALSO A GLOBAL C ARRAY FROM PROBEFILE.D FILE NAME IS USER INPUT FILE NAME *********************************************************************/ maskname_( char *type, /* REQUESTED FILE NAME */ int *partype, /* PARAMETER CODE NUMBER */ char *filename, /* CONSTRUCTED FILE NAME */ int *ptype /* PROBE CODE NUMBER */ ) { sprintf( filename,"%sdata/%s/masks/%s/%s\0",MAINBRANCH, probename_[*ptype],pname[*partype],type); } /********************************************************************** SUBROUTINE NAMEFILE NAMEFILE CONSTRUCTS A FILE NAME FOR PARAMETER DATA. THE FILE NAME IS CONSTRUCTED AS FOLLOWS: /MAIN BRANCH DIRECTORY/PROBETYPE/OBSERVED OR STANDARD/PARAMETER NAME MAIN BRANCH DIRECTORY IS A GLOBAL CONSTANT. IT IS THE PATHNAME TO THE DATA DIRECTORIES. PROBETYPE IS A GLOBAL C CHARACTER ARRAY INPUT FROM PROBEFILE.D OBSERVED OR STANDARD DEPENDS ON ISOOR, 0 FOR OBSERVED, 1 FOR STANDARD PARAMETER NAME IS ANOTHER GLOBAL C CHARACTER ARRAY FROM PROBEFILE.D PROBE TYPE AND PARAMETER NAME CORRESPOND TO RESPECTIVE CODES. THIS SUBROUTINE ALSO CALCULATES A FILE NUMBER TO CORRESPOND TO THE FILE NAME. THIS NUMBER IS DEPENDENT ON WHETHER OBSERVED OR STANDARD LEVELS ARE BEING INVESTIGATED, THE ORDER IN WHICH A PARAMETER WAS CHOSEN FOR INVESTIGATION AND THE NUMBER OF PARAMETERS BEING INVESTIGATED. SUBROUTINE STEPS: 1. SET OBSERVED AND STANDARD CHARACTER ARRAYS 2. CONSTRUCT FILE NAME 3. CALCULATE FILE NUMBER ********************************************************************/ /************************************************************* FTYPE IS THE OBSERVED OR STANDARD CHARACTER STRING **************************************************************/ char *ftype[1]; namefile_( int *soor, /* OBSERVED (0) OR STANDARD (1) LEVELS ARE TO BE INVESTIGATED */ int *i, /* PARAMETER CODE FOR PRESENT PARAMETER */ int *i0, /* PARAMETER ORDER */ int *type, /* PROBE TYPE CODE */ int *fn, /* CALCULATED FILE NUMBER */ int *parnum, /* NUMBER OF INVESTIGATED PARAMETERS */ char *filename /* CONSTRUCTED FILE NAME */ ) { /**************************************************************** CONSTRUCT FILE NAME *****************************************************************/ if ( *soor == 0 ) sprintf( filename, "%sdata/%s/observed/%s\0", MAINBRANCH, probename_[*type], pname[*i] ); else sprintf( filename, "%sdata/%s/standard/%s\0", MAINBRANCH, probename_[*type], pname[*i] ); /**************************************************************** COMPUTE FILE NUMBER ******************************************************************/ *fn = *parnum * *soor + *i0 + 1; } /************************************************************** SUBROUTINE NAMEOTHER NAMEOTHER CONSTRUCTS FILE NAMES FOR HEADER AND DEPTH FILES. THE FILE NAME IS CONSTRUCTED AS FOLLOWS: /MAIN BRANCH DIRECTORY/PROBE TYPE/HEADER OR DEPTH MAIN BRANCH IS A GLOBAL CONSTANT, PROBE TYPE IS A GLOBAL C CHARACTER ARRAY TAKEN FROM PROBEFILE.D. IT CORRESPONDS TO THE INPUT PROBE CODE. ****************************************************************/ nameother_( char *head, /* EITHER 'HEADER' OR 'DEPTH' */ int *type, /* REQUESTED PROBE CODE */ char *filename /* CONSTRUCTED FILE NAME */ ) { sprintf( filename,"%sdata/%s/%s\0",MAINBRANCH, probename_[*type], head); } /************************************************************ SUBROUTINE NEWCMASK NEWCMASK TAKES THE CONTENTS OF A TEMPORARY FILE, CREATED IN TEMPCMASK, AND TRANSFERS IT TO A NEWLY CREATED MASK. BOTH FILES CONTAIN C STRUCTURES, ONE INTEGER AND ONE FIFTEEN CHARACTER ARRAY. **************************************************************/ struct write2c cinfoc; newcmask_( int *numpro, /* NUMBER OF STRUCTURES TO BE TRANSFERED */ int *fn, /* FILE IDENTIFICATION NUMBER FOR NEW MASK */ int *fn2 /* FILE IDENTIFICATION NUMBER FOR TEMPORARY MASK */ ) { int i; /**************************************************************** ALLOCATE SPACE FOR SORTING STRUCTURES *****************************************************************/ /* if ( (prep = calloc( *numpro+1, 2 * sizeof( int ) )) == NULL ) printf(" SPACE ALLOCATION FAILED\n"); */ /**************************************************************** READ PROPER ARRAY POSITION INTO PREP FOR SORTING *****************************************************************/ for ( i = 1; i <= *numpro; i++ ) { fread( &cinfoc, sizeof( struct write2c ), 1, fp[*fn2]); prep[i].num = i; prep[i].rec = cinfoc.num; } /*********************************************************** SORT PREP BY THE SECOND NUMBER (REC). ************************************************************/ qsort( &prep[1], *numpro, sizeof( struct write2 ), compare); /*********************************************************** PUT SORTED VALUES INTO NEW MASK FILE. POSITION IN TEMPORARY FILE OF SORTED VALUES IS HELD IN PREP.NUM. ************************************************************/ for ( i = 1; i <= *numpro; i++ ) { fseek( fp[*fn2], (prep[i].num - 1) * sizeof( struct write2c ), SEEK_SET); fread( &cinfoc, sizeof( struct write2c ), 1, fp[*fn2]); fwrite( &cinfoc, sizeof( struct write2c ), 1, fp[*fn]); } /************************************************************ FREE UP SPACE USED FOR SORTING *************************************************************/ /* free( prep ); */ } /*************************************************** SUBROUTINE ONEFILECLOSE ONEFILECLOSE CLOSES A SINGLE FILE. ****************************************************/ onefileclose_( int *fn /* FILE IDENTIFICATION NUMBER */ ) { int s; if ( ftrack[*fn] == 1 ) { s = fclose( fp[*fn] ); printf("%d was closed \n ",*fn); ftrack[*fn] = -1; } else printf("attempt to close unopened file: %d\n",*fn); } /*************************************************** SUBROUTINE ONEFILECLOSEFT ONEFILECLOSE CLOSES A SINGLE FILE. THIS VERSION RESETS THE TRACKING TO 0 FOR REUSE, INSTEAD OF -1, FOR NO REUSE ****************************************************/ onefilecloseft_( int *fn /* FILE IDENTIFICATION NUMBER */ ) { int s; if ( ftrack[*fn] == 1 ) { s = fclose( fp[*fn] ); printf("%d was closed \n ",*fn); ftrack[*fn] = 0; } else printf("attempt to close unopened file: %d\n",*fn); } /*************************************************** SUBROUTINE ONEFILECLOSEFTS ONEFILECLOSE CLOSES A SINGLE FILE. THIS VERSION RESETS THE TRACKING TO 0 FOR REUSE, INSTEAD OF -1, FOR NO REUSE THIS VERSION IS SILENT ****************************************************/ onefileclosefts_( int *fn /* FILE IDENTIFICATION NUMBER */ ) { int s; if ( ftrack[*fn] == 1 ) { s = fclose( fp[*fn] ); /* printf("%d was closed \n ",*fn); */ ftrack[*fn] = 0; } else printf("attempt to close unopened file: %d\n",*fn); } /************************************************************ SUBROUTINE POS2FILE POS2FILE POSITIONS A TWO INTEGER STRUCTURE FILE TO THE DESIRED POSITION. *************************************************************/ pos2file_( int *jj, /* DESIRED POSITION */ int *ifn /* FILE IDENTIFICATION NUMBER */ ) { fseek( fp[*ifn],( *jj -1 ) * sizeof( struct write2 ), SEEK_SET ); } /************************************************************ SUBROUTINE POSFILE POS2FILE POSITIONS AN INTEGER FILE TO THE DESIRED POSITION. *************************************************************/ posfile_( int *jj, /* DESIRED POSITION */ int *ifn /* FILE IDENTIFICATION NUMBER */ ) { fseek( fp[*ifn],( *jj -1 ) * sizeof( int ), SEEK_SET ); } /***************************************************************** SUBROUTINE PUTGPRESENT PUTGPRESENT SETS A VALUE FOR GPRESENT. GPRESENT IS THE PRESENT SEQUENTIAL STATION NUMBER FOR A GIVEN MASK ******************************************************************/ putgpresent_( int *masknumber, /* NUMERICAL ORDER OF MASK BEING SE */ int *forgpresent /* VALUE TO ENTER FOR JPRESENT */ ) { /***************************************************************** SET THE PRESENT PROFILE NUMBER ******************************************************************/ gpresent[*masknumber -1]= *forgpresent; } /***************************************************************** SUBROUTINE PUTJPRESENT PUTJPRESENT SETS A VALUE FOR JPRESENT. JPRESENT IS THE PRESENT SEQUENTIAL STATION NUMBER FOR A GIVEN MASK ******************************************************************/ putjpresent_( int *masknumber, /* NUMERICAL ORDER OF MASK BEING SE */ int *forjpresent /* VALUE TO ENTER FOR JPRESENT */ ) { /***************************************************************** SET THE PRESENT PROFILE NUMBER ******************************************************************/ jpresent[*masknumber -1]= *forjpresent; } /*********************************************************** SUBROUTINE READC2MASK READC2MASK READS A STRUCTURE OUT TO FILE. THE STRUCTURE CONTAINS TWO CHARACTER ARRAYS OF 5 AND 80 CHARACTERS RESPECTIVELY. ************************************************************/ /*********************************************************** DEFINE CINFO2 AS A WRITE2C2 STRUCTURE WITH TWO CHARACTER VARIABLES OF 5 AND 80 CHARACTERS. ************************************************************/ struct write2c2 cinfo2; readc2mask_( char *carray1, /* FIRST CHARACTER ARRAY TO BE READ IN */ char *carray2, /* SECOND CHARACTER ARRAY TO BE READ IN */ int *ifn, /* FILE IDENTIFICATION NUMBER */ int *iend /* SET TO ONE IF END OF FILE IS ENCOUNTERED */ ) { fread(&cinfo2, sizeof( struct write2c2 ), 1, fp[*ifn]); /* printf("read1\n");*/ if ( !feof( fp[*ifn] ) ) { strcpy( carray1, cinfo2.carr1 ); /* printf("carr %s\n",carray1);*/ strcpy( carray2, cinfo2.carr2 ); /* printf("carr %s\n",carray2);*/ } else *iend = 1; } /*********************************************************** SUBROUTINE READCMASK READCMASK READS A STRUCTURE OUT TO FILE. THE STRUCTURE CONTAINS AN INTEGER AND A CHARACTER ARRAY (15 LETTERS MAX). ************************************************************/ /*********************************************************** DEFINE CINFO AS A STRUCTURE WITH AN INTEGER AND A 15 LETTER CHARACTER. ************************************************************/ struct write2c cinfo; readcmask_( int *jj, /* PROFILE NUMBER */ char *carray, /* CHARACTER ARRAY TO BE WRITTEN OUT */ int *ifn, /* FILE IDENTIFICATION NUMBER */ int *iend /* SET TO ONE IF END OF FILE ENCOUNTERED */ ) { fread(&cinfo, sizeof( struct write2c ), 1, fp[*ifn]); if ( !feof( fp[*ifn] ) ) { *jj = cinfo.num; strcpy( carray, cinfo.carr ); } else *iend = 1; } /***************************************************************** SUBROUTINE READDATA READDATA READS IN PROFILE INFORMATION FROM DIRECT ACCESS C FILES. THERE IS ONE FILE FOR THE HEADER INFORMATION, ONE FILE FOR OBSERVED DEPTHS, AND TWO FILES FOR EACH PARAMETER MEASURED BY THE PROBE TYPE BEING INVESTIGATED, ONE FOR OBSERVED LEVEL DATA AND ONE FOR STANDARD LEVEL DATA. READDATA CAN READ IN ALL PARAMETERS FOR A PROFILE OR A SUBSET OF THE TOTAL NUMBER OF PARAMETERS FOR A PROFILE (WITHOUT READING THE REMAINING PARAMETERS). READDATA CAN READ IN ANY PROFILE NUMBER IN A FILE IMMEDIATELY WITHOUT READING ANY OTHER PROFILES. SUBROUTINE STEPS: 1. SET PRELIMARY VARIABLES 2. READ IN MAIN HEADER INFORMATION, DATE, TIME, AND POSITION OF PROFILE ALONG WITH COUNTRY AND CRUISE CODES IF AVAILABLE. 3. RUN THROUGH ALL REQUESTED PARAMETERS, IF A REQUESTED PARAMETER EXISTS FOR THIS PROBE, READ IN THE DATA FROM THE PROPER FILE. IF THIS IS THE FIRST PARAMETER READ IN AND OBSERVED LEVELS ARE BEING INVESTIGATED, ALSO READ IN DEPTH DATA. 4. ALTER *OLDRECORD TO REFLECT THE PRESENT FILE POINTER POSITION *******************************************************************/ /****************************************************************** MAKE THREEDATA A WRITE3FS STRUCTURE. THIS IS A STRUCTURE WITH TWO INTEGERS (NUM,GEO) AND ONE REAL (REC). THREEDATA IS FOR RECORDING BIOLOGICAL DATA AND SECOND HEADER INFORMATION. NUM IS PARAMETER CODE, GEO IS NUMBER OF SIGNIFICANT FIGURES. THE REAL IS PARAMETER VALUE. GEO IS A SHORT INTEGER. MAKE TWODATA A WRITE2FS STRUCTURE. THIS IS A STRUCTURE WITH ONE SHORT INTEGER (NUM) AND ONE REAL (REC). TWODATA IS FOR RECORDING ALL PARAMETERS EXCEPT BIOLOGICAL AND SECOND HEADER. NUM IS NUMBER OF SIGNIFICANT FIGURES. REC IS THE PARAMETER VALUE *******************************************************************/ struct write2fs twodata2[maxlev]; readdata_( char ccx[], /* HEADER INFORMATION: NODC COUNTRY CODE, CONSISTS OF TWO CHARACTERS. SEE APPENDIX IN OCL DATA SYSTEMS INSTRUCTION MANUAL FOR CODE DESCRIPTIONS. */ float *tempptr, /* PARAMETER DATA: IN FORTRAN THIS IS A TWO DIMENSIONAL ARRAY ARRANGED AS TEMP(MAXLEVELS,MAXPARMS), RECORDING OBSERVATIONS AT EACH DEPTH LEVEL FOR EACH PARAMETER. */ int *ndeps, /* HEADER INFORMATION : NUMBER OF DEPTHS; *NDEPS IS NUMBER OF OBSERVED DEPTHS, *(NDEPS+1) IS NUMBER OF STANDARD DEPTHS FOR A PROFILE */ int *jj, /* HEADER INFORMATION: PROFILE NUMBER; THIS NUMBER IS USED TO FIND THE POSITION IN THE HEADER FILE TO STORE INFORMATION ABOUT THE PROFILE IN QUESTION */ int *year, /* HEADER INFORMATION: YEAR OF PROFILE (FOUR DIGITS; I.E. 1955 ) */ int *month, /* HEADER INFORMATION: MONTH OF PROFILE (ONE OR TWO DIGITS; I.E. 2 IS FEBRUARY ) */ int *day, /* HEADER INFORMATION: DAY OF PROFILE (ONE OR TWO DIGITS) */ float *time, /* HEADER INFORMATION: GREENWICH MEAN TIME OF PROFILE IN HOURS TO THOUSANDTHS */ int *cruise, /* HEADER INFORMATION: NODC CRUISE NUMBER (ONLY FOR NODC ARCHIVE DATA */ float *lat, /* HEADER INFORMATION: LATITUDE OF PROFILE DEGREES TO THOUSANDTHS, NEGATIVE VALUES ARE SOUTHERN LATITUDES */ float *lon, /* HEADER INFORMATION: LONGITUDE OF PROFILE IN DEGREES TO THOUSANDTHS, NEGATIVE VALUES ARE WESTERN LONGITUDES */ int *startpoint, /* PROFILE NUMBER CORRESPONDING TO PRESENT HEADER FILE POINTER POSITION. THIS NUMBER IS INITIALLY SET TO ONE */ float *depthptr, /* DEPTH DATA: ARRAY OF OBSERVED LEVEL DEPTHS */ int *parnum, /* NUMBER OF PARAMETERS MEASURED BY PRESENT PROBE. THIS NUMBER GOVERNS HOW MANY PARAMETER RECORD NUMBERS ARE WRITTEN TO A HEADER */ int *oldrecord, /* ARRAY OF POSITIONS OF PARAMETER FILE POINTERS (ALSO CALLED PRESENT RECORD NUMBERS) */ int *params, /* NUMBER OF USER REQUESTED PARAMETERS. ONLY REQUESTED PARAMETERS ARE WRITTEN (OR REWRITTEN) TO FILE. THIS NUMBER INCLUDES CALCULATED AS WELL AS MEASURED PARAMETERS */ int *p2, /* PARAMETER CODES OF REQUESTED PARAMETERS */ int *soor, /* STANDARD (1) OR OBSERVED (0) LEVELS */ int *maxlevel, /* MAXIMUM NUMBER OF DEPTH LEVELS. THIS NUMBER IS NEEDED TO SET THE CORRECT POSITION FOR THE ARRAY POINTER *TEMPPTR */ int *record, /* HEADER INFORMATION: DESIRED FILE POSITION FOR THE READING IN OF PARAMETER DATA (AN ARRAY). THIS CONTAINS THE RECORD NUMBER (NUMBER OF RECORDS FROM THE BEGINNING OF THE FILE) FOR WRITING THE FIRST LEVEL OF PARAMETER DATA OUT TO FILE. IF THE PARAMETER IS NOT PRESENT, THIS NUMBER IS SET TO -1. *RECORD IS RECORDED IN THE HEADER FILE AND IS THE KEY TO READING THE PROPER DATA FOR THE PROPER PROFILE. */ int *maxcal, /* MAXIMUM NUMBER OF PARAMETERS USEABLE IN SYSTEM. THIS IS NECESSARY TO SET THE CORRECT VALUE OF NREC ( DEFINED BELOW ) */ int *jp, /* PROBE TYPE CODE FOR PROBE BEING INVESTIGATED. ALSO NECESSARY TO SET THE CORRECT VALUE OF NREC (DEFINED BELOW). */ int *nprec, /* ORDER OF RECORDING OF PARAMETER BY PROBE. USED TO SET PROPER POSITION IN THE *RECORD VARIABLE, SINCE *RECORD NUMBER ONE MAY NOT CORRESPOND TO PARAMETER CODE (FOR EXAMPLE, IF ONLY SALINITY IS RECORDED BY A PROBE, *RECORD VALUE NUMBER ONE CORRESPONDS TO PARAMETER NUMBER TWO) */ int *itwo, /* ITWO IS SET TO TWO FOR BIOLOGICAL PARAMETER, ONE FOR SECOND HEADER, AND ZERO FOR ALL OTHER PARAMETER TYPES. */ float *bmiss, /* MISSING VALUE MARKER. THIS IS ONLY USED EXPLICITLY HERE FOR BIOLOGICAL DATA. */ int *second, /* SET TO ONE IF SECOND HEADER IS TO BE READ IN, ZERO OTHERWISE */ int *fnum, /* FILE SET NUMBER. IF MORE THAN ONE SET OF FILES IS BEING INVESTIGATED IN A MAIN PROGRAM, THAT IS, MORE THAN ONE PROBE TYPE BEING LOOKED AT SIMULTANEOUSLY, THE FILE NUMBERING IS OFFSET BY A NUMBER CALCULATED FROM THIS FILE SET NUMBER AND THE NUMBER OF PARAMETERS THE CORRESPONDING PROBE MEASURES. */ int *endpoint, /* END OF FILE MARKER. THIS IS SET TO ONE IF THE END OF THE FILE HAS BEEN REACHED, IT IS ZERO OTHERWISE. */ int *paramcalc, /* NUMBER OF CALCULATED PARAMETERS */ int *signif /* NUMBER OF SIGNIFICANT FIGURES IN A VALUE */ ) { /**************************************************************** PARAMETERS: I - PARAMETER CODE NUMBER I2 - POSITION OF CORRECT PARAMETER DATA IN *TEMPPTR I3 - FILE NUMBER I4 - POSITION OF CORRECT FILE POINTER PLACEMENT NUMBER IN *RECORD. J,J0,I0,IB,ICOUNT - COUNTERS ISO - HOLDS OBSERVED (0) OR STANDARD LEVEL (1) VALUE FOR CALCULATIONS OF PROPER POSITION IN *RECORD NTWO - NUMBER OF SPECIFIC SPECIAL PARAMETERS (INTEGER VALUE) MARKER - SET TO ONE WHEN DEPTH HAS BEEN WRITTEN OUT SIZE - SIZE, IN BYTES OF ONE HEADER RECORD PMARK - SET TO ZERO IF THERE IS ONLY ONE PARAMETER RECORDED PMARKI - SET TO ONE IF THERE IS ONLY ONE PARAMETER RECORDED PSIZE - TOTAL NUMBER OF PARAMETERS *2 (STANDARD AND OBSERVED) + ONE FOR DEPTH (IF THERE IS MORE THAN ONE RECORDED PARAMETER) NUMDEP -NUMBER OF DEPTH LEVELS FSELECT - BASE NUMBER FOR FILE NUMBER DEPENDENT ON WHICH FILE SET IS BEING INVESTIGATED AND THE NUMBER OF PARAMETERS THE PROBE BEING RECORDED MEASURES. TOTPARM - NUMBER OF PARAMETERS REQUESTED. (SAME AS *PARAMS UNLESS DEPTH IS THE ONLY REQUESTED PARAMETER) ICOUNT2 - COUNT OF NUMBER OF TAXA RECORDS NSET - NUMBER OF RECORD SETS NUMDEPA - HOLDER FOR NUMBER OF DEPTHS NUMDEP2 - NUMBER OF DEPTHS DEEPER THAN MAXLEVEL NUMEXTRA - NUMBER OF MULTIPLES OF MAXIMUM DEPTH LEVEL FOUND IN PROFILE ******************************************************************/ struct write3fs threedata; off_t size; int i, j, i2, i3, i4, i5, j0, i0, ntwo, iso, icount, ib=0, n; int marker=0, pmark=1; int numdep; int psize, pmarki=0; int fselect = 2 * (*params * (*fnum-1)) + 3 * (*fnum-1); int totparm = *params; int icount2 = 0, nset, i2x=0, numdepa=0,numdep2=0; int numextra=0,numextra2=0; int pcalc= *paramcalc; off_t xnum; /*************************************************************** IF NUMBER OF CALCULATED PARAMETERS IS NEGATIVE, RESET PCALC ****************************************************************/ if ( *paramcalc < 0 ) pcalc= 0- *paramcalc; /*************************************************************** SET THE TWO ONE PARAMETER MARKERS. IF THERE IS ONLY ONE PARAMETER RECORDED BY A PROBE, THE HEADER STRUCTURE IS SLIGHTLY DIFFERENT THAN IT WOULD BE OTHERWISE, SINCE IT IS NOT NECESSARY TO RECORD A DEPTH FILE POSITION IN THIS CASE, BECAUSE THIS NUMBER IS THE SAME AS THE OBSERVED LEVEL FILE PARAMETER POSITION NUMBER. PMARK AND PMARKI ARE POSITION HOLDERS SET DEPENDING ON THIS CONTINGENCY. ****************************************************************/ if ( *parnum == 1) { pmarki = 1; pmark = 0; } /**************************************************************** IF THE FIRST PARAMETER CODE IS -1, ONLY DEPTH IS REQUESTED, SO SET PNUM TO ONE. *****************************************************************/ if ( *(p2+1) == -1 ) totparm=1; /**************************************************************** COMPUTE RECORD SIZE: SIZE IS THE NUMBER OF BYTES IN AN INTEGER * THE SIZE OF THE HEADER STRUCTURE * (2 TIMES THE NUMBER OF PARAMETERS + ONE IF THERE IS MORE THAN ONE PARAMETER) PSIZE IS 2 TIMES THE NUMBER OF PARAMETERS PLUS ONE IF THERE IS MORE THAN ONE PARAMETER. ****************************************************************/ psize = 2 * *parnum + pmark + 1; size= sizeof( struct headerdata ) + (2 * (*parnum) + pmark + 1) * sizeof( int ); /**************************************************************** POSITION HEADER FILE TO PROPER RECORD. THIS IS ACCOMPLISHED BY MOVING THE FILE POINTER (PRESENT PROFILE NUMBER MINUS LAST INPUT FILE NUMBER) TIMES SIZE (AS CALCULATED ABOVE) UNITS. ****************************************************************/ fseeko( fp[(fselect+1)],( *jj - *startpoint ) * size , SEEK_CUR ); /**************************************************************** ADJUST PRESENT HEADER FILE PROFILE NUMBER (ADD ONE) ****************************************************************/ *startpoint = *jj + 1; /**************************************************************** READ HEADER INFORMATION INTO STRUCTURE HEADER. ****************************************************************/ fread(&header, sizeof( struct headerdata ), 1, fp[fselect+1]); /*************************************************************** IF THIS IS NOT THE END OF THE FILE, SET VARIABLES FOR THE MAIN PROGRAM. ****************************************************************/ if ( !feof(fp[fselect+1]) ) { *lat=header.lat; *lon=header.lon; *year=header.year; *month=header.month; *day=header.day; *time=header.time; *cruise=header.cruise; strncpy(ccx,header.cc,2); *ndeps=header.numdepo; *(ndeps+1)=header.numdeps; numdep = *(ndeps + *soor ); /* printf("%f %f %d %d %d %f %d %s %d %d\n",*lat,*lon, *year,*month,*day,*time,*cruise,ccx,*ndeps,*(ndeps+1));*/ /**************************************************** FIND NUMBER OF SETS OF DEPTH DATA THERE ARE, THAT IS THE NUMBER OF MULTIPLES OF MAXLEVEL ARE IN THE NUMBER OF DEPTHS *****************************************************/ numdepa = numdep; numextra=0; if ( numdep >= *maxlevel ) { numextra= numdep/ (*maxlevel); numdep2= numdep - (numextra * (*maxlevel)); numdepa= *maxlevel; } /**************************************************************** READ OBSERVED AND STANDARD LEVEL PARAMETER RECORD STARTING POSITIONS FROM THE HEADER FILE. ****************************************************************/ fread( (record+pmarki), sizeof( int ), psize, fp[fselect+1]); /************************************************************** START LOOP TO READ IN PARAMETER FROM FILE. IF *RECORD FOR A PARAMETER CONTAINS A -1, THIS PARAMETER IS NOT READ IN. OTHERWISE, THE PARAMETER IS READ FROM THE APPROPRIATE FILE STARTING AT THE FILE POSITION CONTAINED IN *RECORD. THIS LOOP IS RUN THROUGH FOR EACH REQUESTED PARAMETER AND ONCE FOR THE SECOND HEADER (IF REQUESTED) **************************************************************/ for ( i0=1; i0<= totparm + *second; i0++) { /************************************************************* IF ONLY ONE PARAMETER IS RECORDED BY A PROBE, THE DEPTH FILE POINTER AND THE OBSERVED LEVEL PARAMETER FILE POINTER WILL BE THE SAME. *************************************************************/ if ( *soor == 0 && *parnum == 1 && i0 <= totparm ) { *record = *(record+i0); } /************************************************************** ADJUST STORAGE NUMBERS FOR THIS PARAMETER: I IS THE PARAMETER CODE I2 SIMULATES A FORTRAN SECOND DIMENSION TO SET THE ARRAY POINTER TO THE CORRECT POSITION. I3 SETS THE CORRECT FILE NUMBER (I3 +FSELECT IS THE ACTUAL FILE NUMBER, FSELECT BEING DEPENDENT ON WHICH SET OF FILES IS BEING LOOKED AT) I4 IS THE CORRECT ARRAY POINTER POSITION FOR THE FILE POINTER POSITON FOR THE PARAMETER. IF DEPTH IS THE ONLY DESIRED PARAMETER ( I = -1 ) SET I4 TO ZERO SO AS TO SKIP ALL PARAMETER DATA. IF THIS IS A SECIAL PARAMETER ( BIOLOGICAL OR SECOND HEADER ), THERE IS ONLY STANDARD LEVEL DATA, SINCE DEPTH IS NOT A FACTOR FOR THESE PARAMETERS *************************************************************/ i= *(p2+i0); if ( i != -1 ) { if ( i0 > totparm ) i = *(p2 + *maxlevel); if ( *(itwo+i) > 0 ) iso = 1; else iso = *soor; i2 = *maxlevel * (i-1); if ( *(itwo+i) != 1 ) i3 = *params * iso + i0 + 1; else if ( *(p2 + 1) != -1 ) i3 = 2* totparm + 2; else i3 = (2* *parnum) + 2; i4 = *parnum * iso + *(nprec+ (((*jp)-1) * *maxcal ) + i-1 ); i5 = i4; if ( i0 > *params - pcalc ) i5 = 2* *parnum + 1 + (*soor * pcalc) + ( i0 - *params+ pcalc ); } else { i3 = 0; i4 = 0; i5 = 0; } /************************************************************* CHECK IF THIS PARAMETER IS PRESENT IN THIS PROFILE. (IF *RECORD FOR THIS PARAMETER IS A -1, THE PARAMETER WAS NOT RECORDED IN THIS PROBE. *************************************************************/ if ( *(record+i4) > -1 ) { /************************************************************* SPECIAL DATA IS READ SLIGHTLY DIFFERENTLY THAN PHYSICAL AND CHEMICAL DATA. CHECK IF THIS IS A SPECIAL DATA TYPE, THAT IS IF THE PARAMETERS ITWO VALUE IS GREATER THAN ZERO. IF NOT, READ AS NORMAL DATA. NORMAL DATA IS SIMPLY NUMDEPS REAL VALUES STORED IN *TEMPPTR, THE OUTER DIMENSION BEING PARAMETER CODE, THE INNER DIMENSION BEING DEPTH LEVEL. **************************************************************/ if ( i < 0 || *(itwo+i) < 1 ) { /************************************************************* IF OBSERVED LEVELS ARE BEING WRITTEN OUT (*SOOR IS ZERO) DEPTH MUST ALSO BE WRITTEN OUT. *************************************************************/ if ( *soor == 0 ) { /************************************************************* IF DEPTH HAS NOT YET BEEN WRITTEN OUT TO FILE MARKER IS SET TO ZERO. IF THIS IS THE FIRST PARAMETER TO BE WRITTEN OUT, SET MARKER TO ONE AND ALSO READ IN DEPTHS FOR OBSERVED LEVELS **************************************************************/ if ( marker == 0 ) { marker = 1; /************************************************************** MOVE DEPTH FILE POINTER TO PROPER POSITION, WHICH IS THE MOVEMENT OF THE POINTER (DESIRED POSITION MINUS PRESENT POSITION) UNITS. **************************************************************/ xnum= *record - *oldrecord; fseeko( fp[fselect+0], xnum * sizeof(float),SEEK_CUR); /************************************************************** READ DEPTHS IN FROM FILE **************************************************************/ fread( depthptr, sizeof(float), numdepa, fp[fselect+0]); for ( j=1; j< numextra; j++ ) { i2x= ( (*(p2 + *maxlevel)+ pcalc + 2) * j ) * *maxlevel; i2x -= *maxlevel; fread( (tempptr+ i2x), sizeof(float), *maxlevel, fp[fselect+0]); } if ( numdep2 > 0 ) { i2x= ( (*(p2 + *maxlevel)+ pcalc +2) * numextra ) * *maxlevel; i2x -= *maxlevel; fread( (tempptr+ i2x), sizeof(float), numdep2, fp[fselect+0]); } } } /*************************************************************** READ IN PARAMETER DATA IF DEPTH WAS NOT THE ONLY REQUESTED PARAMETER (I4 = 0). ****************************************************************/ if ( i > 0 ) { /*************************************************************** MOVE PARAMETER FILE POINTER TO PROPER POSITION, WHICH IS THE MOVEMENT OF THE POINTER (DESIRED POSITION MINUS PRESENT POSITION) UNITS. ***************************************************************/ xnum= *(record+i4) - *(oldrecord+i5); fseeko( fp[fselect+i3], xnum * sizeof(struct write2fs), SEEK_CUR); /*************************************************************** READ ENTIRE PARAMETER FIELD FROM FILE ***************************************************************/ fread( &twodata2[1], sizeof(struct write2fs), numdepa, fp[fselect+i3]); /*************************************************************** TRANSFER DATA FROM TWODATA TO TEMP ARRAY FOR PARAMETER DATA AND SIGNIF ARRAY FOR NUMBER OF SIGNIFICANT FIGURES ****************************************************************/ for ( n = 0; n < numdepa; n++ ) { *(tempptr +i2 + n) = twodata2[n+1].rec; *(signif + i2 + n) = twodata2[n+1].num; } for ( j=1; j< numextra; j++ ) { fread( &twodata2[1], sizeof(struct write2fs),*maxlevel, fp[fselect+i3]); i2x= (((*(p2+ *maxlevel)+ pcalc +2) * j ) * *maxlevel) + i2; for ( n = 0; n < *maxlevel; n++ ) { *(tempptr +i2x + n) = twodata2[n+1].rec; *(signif + i2x + n) = twodata2[n+1].num; } } if ( numdep2 > 0 ) { fread( &twodata2[1], sizeof(struct write2fs),numdep2, fp[fselect+i3]); i2x= (((*(p2+ *maxlevel)+ pcalc+2) * numextra ) * *maxlevel) + i2; for ( n = 0; n < numdep2; n++ ) { *(tempptr +i2x + n) = twodata2[n+1].rec; *(signif + i2x + n) = twodata2[n+1].num; } } /************************************************************** IF THIS IS A CALCULATED PARAMETER, RESET OLDRECORD TO NEW POSITION ***************************************************************/ if ( i4 != i5 ) *(oldrecord + i5) = *(record+i4) + numdep; } } /************************************************************** IF THIS IS A SPECIAL PARAMETER, READ DATA ACCORDINGLY. THE FORM IS A TWO DIGIT STRUCTURE, THE FIRST IS AN INTEGER CARRYING THE APPROPRIATE PARAMETER CODE, AS LISTED IN PROBEFILE.D, THE SECOND IS THE ACTUAL REAL VALUE OF THE PARAMETER. SPECIAL DATA IS STORED DIFFERENTLY IN THE PARAMETER ARRAY *TEMPPTR. THE PARAMETER CODE PART OF *TEMPPTR IS ALWAYS THE OVERALL SPECIAL CODE WHICH IS THE SAME AS A PARAMETER CODE. THE OTHER DIMENSION, WHICH IS DEPTH LEVEL FOR OTHER DATA, IS THE ACTUAL SPECIFIC PARAMETER CODE. SO FOR INSTANCE, THE VALUE OF BIOLOGICAL PARAMETER NUMBER 27 WOULD BE AT TEMP(27,I) IN FORTRAN, *(TEMPPTR+(I - 1) * *MAXLEVEL + 27) IN C. THE FIRST SPECIFIC PARAMETER IS ALWAYS THE NUMBER OF SPECIFIC PARAMETERS RECORDED IN THIS PROFILE. ****************************************************************/ else { /*************************************************************** MOVE SPECIAL PARAMETER FILE POINTER TO PROPER POSITION, WHICH IS THE MOVEMENT OF THE POINTER (DESIRED POSITION MINUS PRESENT POSITION) UNITS. ***************************************************************/ xnum= *(record+i4) - *(oldrecord+i4); fseeko( fp[fselect+i3], xnum * sizeof(struct write3fs), SEEK_CUR); /*************************************************************** READ NUMBER OF PARAMETERS INTO THE FIRST RECORDS. NOTE THAT THE NUMBER OF SPECIFIC SPECIAL PARAMETERS IS STORED IN NTWO SO IT IS REPRESENTED AS AN INTEGER INSTEAD OF A REAL. ****************************************************************/ fread( &threedata, sizeof(struct write3fs), 1, fp[fselect+i3]); ntwo = threedata.num; *(tempptr+i2) = ntwo; fread( &threedata, sizeof(struct write3fs), 1, fp[fselect+i3]); nset = threedata.num; *(tempptr+i2+1) = nset; /*************************************************************** READ SPECIAL PARAMETER DATA. ****************************************************************/ for ( ib = 1; ib <= ntwo; ib++ ) { fread( &threedata, sizeof(struct write3fs), 1, fp[fselect+i3]); *(tempptr+i2+threedata.num) = threedata.rec; *(signif+i2+threedata.num) = threedata.geo; } /**************************************************************** READ IN SPECIAL PARAMETER SET INFORMATION *****************************************************************/ icount2 = 1; if ( nset > 0 ) { threedata.num = 0; while ( threedata.num != 3 ) { fread( &threedata, sizeof(struct write3fs), 1, fp[fselect+i3]); if ( threedata.num < *maxlevel ) { ib= threedata.num; i2x= i2; } else { numextra2= (threedata.num)/ *maxlevel; ib = threedata.num - ( *maxlevel * numextra2 ); i2x= (((*(p2+ *maxlevel)+ pcalc + 2) * numextra2 ) * *maxlevel) + i2; } *(tempptr+i2x+ib) = threedata.rec; *(signif+i2x+ib) = threedata.geo; icount2 +=1; } } /**************************************************************** SET *OLDRECORD TO PRESENT FILE POINTER POSITION. *****************************************************************/ *(oldrecord+i4) = *(record+i4) + ntwo + icount2 + 1; icount2 = 0; } } } /*************************************************************** SET *OLDRECORD TO POSITION OF FILE POINTER AFTER READING DATA, WHICH WILL BE DESIRED FILE POSITION + NUMBER OF DEPTHS SET STARTING POSITION TO POSITION OF THE FILE POINTER DO THIS FOR OBSERVED AND STANDARD LEVEL RECORDS. DO NOT DO THIS FOR THE SPECIAL PARAMETERS, SINCE THIS HAS ALREADY BEEN DONE. ****************************************************************/ if ( marker == 1 ) { *oldrecord = *record + numdep; } if ( *paramcalc < 0 ) pcalc=0; for ( i0=1; i0<= (*params-pcalc); i0++) { i = *(p2+i0); if ( *(itwo+i) < 1 ) { i4 = *parnum * *soor + *(nprec+ (((*jp)-1) * *maxcal ) + i-1 ); if ( *(record+i4) > -1 ) *(oldrecord+i4)= *(record+i4) + numdep; } } } /****************************************************************** SIGNAL TO THE MAIN PROGRAM THAT THE FILE HAS REACHED IT'S END. *******************************************************************/ else *endpoint = 1; } /********************************************************* SUBROUTINE READLEVEL READLEVEL READS REAL DATA FROM A STANDARD GRID FILE IN BULK FORM. THE STANDARD GRID FILE IS A THREE DIMENSIONAL GRID, I,J,K WITH I DENOTING LONGITUDINAL, J DENOTING LATITUDINAL, AND K DENOTING DEPTH. WRITELEVEL CAN TAKE AN ARRAY OF ANY SIZE AND WRITE IT TO A FILE SET UP FOR THE SAME GRID SIZE OR ANOTHER GRID SIZE. **********************************************************/ readlevel_( int *iadim, /* STARTING LONGITUDE FOR ARRAY */ int *jadim, /* STARTING LATITUDE FOR ARRAY */ int *k1, /* FIRST DEPTH FOR ARRAY */ int *idims, /* STARTING LONGITUDE GRID */ int *jdims, /* STARTING LATITUDE GRID */ int *idime, /* ENDING LONGITUDE GRID */ int *jdime, /* ENDING LATITUDE GRID */ int *idim, /* MAXIMUM LONGITUDE SPACING FOR FILE */ int *jdim, /* MAXIMUM LATITUDE SPACING FOR FILE */ int *iparm, /* MAXIMUM LONGITUDE SPACING FOR DATA ARRAY */ int *jparm, /* MAXIMUM LATITUDE SPACING FOR DATA ARRAY */ int *ks, /* STARTING DEPTH LEVEL */ int *ke, /* ENDING DEPTH LEVEL */ int *fn, /* FILE IDENTIFICATION NUMBER */ float *temp /* DATA */ ) { /*********************************************************** LEVELSIZE - SIZE OF ONE GRID LEVEL FOR FILE RECORD - POINTER TO CORRECT LEVEL FOR FILE LATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR FILE ARRAYSIZE - SIZE OF ONE ARRAY LEVEL ARECORD - POINTER TO CORRECT LEVEL FOR ARRAY ALATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR ARRAY K - CURRENT DEPTH POINT FOR FILE J - CURRENT LATITUDE POINT FOR FILE I - CURRENT LONGITUDE POINT FOR FILE KA - CURRENT DEPTH POINT FOR ARRAY JA - CURRENT LATITUDE POINT FOR ARRAY IA - CURRENT LONGITUDE POINT FOR ARRAY *************************************************************/ int levelsize, record, latitude, ll, l, j, k, i; int arraysize, arecord, alatitude, ja, ka, ia; int ist, ied; /************************************************************* CALCULATE LEVEL SIZE AND ARRAY SIZE SET BASE DEPTH FOR ARRAY **************************************************************/ levelsize = *idim * *jdim; arraysize = *iparm * *jparm; ka = *k1-1; if ( *idims > *idime ) ll = 2; else ll=1; /************************************************************* RUN THROUGH K (DEPTH) LEVELS **************************************************************/ for ( k = *ks; k <= *ke; k++ ) { /************************************************************* CALCULATE DEPTH POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LATITUDE **************************************************************/ ka +=1; record = ( k-1 ) * levelsize; arecord = ( ka-1 ) * arraysize; ja = *jadim-1; /************************************************************* RUN THROUGH J ( LATITUDE ) POINTS **************************************************************/ for ( j = *jdims; j <= *jdime; j++ ) { /************************************************************* ADJUST LONGITUDE GRID STARTING, ENDING POINTS DEPENDENT ON WHETHER THE GREENWICH MERIDIAN HAS BEEN CROSSED OR NOT **************************************************************/ for ( l = 1; l <= ll; l++ ) { if ( ll == 2 ) { if ( l == 1 ) { ist= *idims; ied= *idim; } else { ist= 1; ied= *idime; } } else { ist= *idims; ied= *idime; } /************************************************************* CALCULATE LATITUDE POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LONGITUDE **************************************************************/ if ( l == 1 ) { ja +=1; ia = *iadim-2; } latitude = *idim * (j-1) + ( ist-1 ); alatitude = *iparm * (ja-1); /************************************************************* GO TO CORRECT POINT IN FILE **************************************************************/ fseek( fp[*fn],(record+latitude)*sizeof(float),SEEK_SET); /************************************************************* RUN THROUGH I (LONGITUDE) POINTS **************************************************************/ for ( i = ist -1; i < ied; i++ ) { ia +=1; /************************************************************* READ DATA FROM FILE **************************************************************/ fread( (temp+arecord+alatitude+ia), sizeof(float),1,fp[(*fn)]); } } } } } /********************************************************* SUBROUTINE READLEVELI READLEVELI READS INTEGER DATA FROM A STANDARD GRID FILE IN BULK FORM. THE STANDARD GRID FILE IS A THREE DIMENSIONAL GRID, I,J,K WITH I DENOTING LONGITUDINAL, J DENOTING LATITUDINAL, AND K DENOTING DEPTH. WRITELEVEL CAN TAKE AN ARRAY OF ANY SIZE AND WRITE IT TO A FILE SET UP FOR THE SAME GRID SIZE OR ANOTHER GRID SIZE. **********************************************************/ readleveli_( int *iadim, /* STARTING LONGITUDE FOR ARRAY */ int *jadim, /* STARTING LATITUDE FOR ARRAY */ int *k1, /* FIRST DEPTH FOR ARRAY */ int *idims, /* STARTING LONGITUDE GRID */ int *jdims, /* STARTING LATITUDE GRID */ int *idime, /* ENDING LONGITUDE GRID */ int *jdime, /* ENDING LATITUDE GRID */ int *idim, /* MAXIMUM LONGITUDE SPACING FOR FILE */ int *jdim, /* MAXIMUM LATITUDE SPACING FOR FILE */ int *iparm, /* MAXIMUM LONGITUDE SPACING FOR DATA ARRAY */ int *jparm, /* MAXIMUM LATITUDE SPACING FOR DATA ARRAY */ int *ks, /* STARTING DEPTH LEVEL */ int *ke, /* ENDING DEPTH LEVEL */ int *fn, /* FILE IDENTIFICATION NUMBER */ int *temp /* DATA */ ) { /*********************************************************** LEVELSIZE - SIZE OF ONE GRID LEVEL FOR FILE RECORD - POINTER TO CORRECT LEVEL FOR FILE LATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR FILE ARRAYSIZE - SIZE OF ONE ARRAY LEVEL ARECORD - POINTER TO CORRECT LEVEL FOR ARRAY ALATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR ARRAY K - CURRENT DEPTH POINT FOR FILE J - CURRENT LATITUDE POINT FOR FILE I - CURRENT LONGITUDE POINT FOR FILE KA - CURRENT DEPTH POINT FOR ARRAY JA - CURRENT LATITUDE POINT FOR ARRAY IA - CURRENT LONGITUDE POINT FOR ARRAY *************************************************************/ int levelsize, record, latitude, ll, l, j, k, i; int arraysize, arecord, alatitude, ja, ka, ia; int ist, ied; /************************************************************* CALCULATE LEVEL SIZE AND ARRAY SIZE SET BASE DEPTH FOR ARRAY **************************************************************/ levelsize = *idim * *jdim; arraysize = *iparm * *jparm; ka = *k1-1; if ( *idims > *idime ) ll = 2; else ll=1; /************************************************************* RUN THROUGH K (DEPTH) LEVELS **************************************************************/ for ( k = *ks; k <= *ke; k++ ) { /************************************************************* CALCULATE DEPTH POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LATITUDE **************************************************************/ ka +=1; record = ( k-1 ) * levelsize; arecord = ( ka-1 ) * arraysize; ja = *jadim-1; /************************************************************* RUN THROUGH J ( LATITUDE ) POINTS **************************************************************/ for ( j = *jdims; j <= *jdime; j++ ) { /************************************************************* ADJUST LONGITUDE GRID STARTING, ENDING POINTS DEPENDENT ON WHETHER THE GREENWICH MERIDIAN HAS BEEN CROSSED OR NOT **************************************************************/ for ( l = 1; l <= ll; l++ ) { if ( ll == 2 ) { if ( l == 1 ) { ist= *idims; ied= *idim; } else { ist= 1; ied= *idime; } } else { ist= *idims; ied= *idime; } /************************************************************* CALCULATE LATITUDE POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LONGITUDE **************************************************************/ if ( l == 1 ) { ja +=1; ia = *iadim-2; } latitude = *idim * (j-1) + ( ist-1 ); alatitude = *iparm * (ja-1); /************************************************************* GO TO CORRECT POINT IN FILE **************************************************************/ fseek( fp[*fn],(record+latitude)*sizeof(int),SEEK_SET); /************************************************************* RUN THROUGH I (LONGITUDE) POINTS **************************************************************/ for ( i = ist -1; i < ied; i++ ) { ia +=1; /************************************************************* READ DATA FROM FILE **************************************************************/ fread( (temp+arecord+alatitude+ia), sizeof(int),1,fp[(*fn)]); } } } } } /***************************************************************** SUBROUTINE READMASK READMASK READS A PROFILE RECORD NUMBER FROM A MASK FILE. ******************************************************************/ readmask_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *fn, /* MASK FILE IDENTIFICATION NUMBER */ int *iend /* SET TO ONE IF END OF FILE IS REACHED */ ) { /* if ( !feof(fp[*fn])) fread( jj, sizeof( int ), 1, fp[*fn] ); if ( feof(fp[*fn])) *iend = 1; */ int k; if ( fread( (void *) &k, sizeof( k ), 1, fp[*fn] ) == 1 ) *jj = k; else *iend = 1; } /***************************************************************** SUBROUTINE READMASK2 READMASK2 READS A TWO INTEGER STRUCTURE FROM A FILE. ******************************************************************/ /***************************************************************** MAKE IR2 A WRITE2 STRUCTURE (TWO INTEGERS). THE FIRST INTEGER IS IR2.NUM, THE SECOND IS IR2.REC ******************************************************************/ struct write2 ir2; readmask2_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *fn, /* MASK FILE IDENTIFICATION NUMBER */ int *iend, /* SET TO ONE IF END OF FILE IS REACHED */ int *isecond /* SECOND INTEGER READ IN */ ) { /* if ( !feof(fp[*fn])) { fread( &ir2, sizeof( struct write2 ), 1, fp[*fn] ); *jj = ir2.num; *isecond = ir2.rec; } if ( feof(fp[*fn])) *iend = 1; */ if ( fread( (void *) &ir2, sizeof( struct write2 ), 1, fp[*fn] ) == 1 ) { *jj = ir2.num; *isecond = ir2.rec; } else *iend = 1; } /***************************************************************** SUBROUTINE READMASK3 READMASK3 READS A THREE INTEGER STRUCTURE FROM A FILE. ******************************************************************/ /***************************************************************** MAKE IR3 A WRITE3 STRUCTURE (THREE INTEGERS). THE FIRST INTEGER IS IR3.NUM, THE SECOND IS IR3.REC, THE THIRD IS IR3.GEO ******************************************************************/ struct write3 ir3; readmask3_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *fn, /* MASK FILE IDENTIFICATION NUMBER */ int *iend, /* SET TO ONE IF END OF FILE IS REACHED */ int *isecond, /* SECOND INTEGER READ IN */ int *ithird /* THIRD INTEGER READ IN */ ) { if ( !feof(fp[*fn])) { fread( &ir3, sizeof( struct write3 ), 1, fp[*fn] ); *jj = ir3.num; *isecond = ir3.rec; *ithird = ir3.geo; } if ( feof(fp[*fn])) *iend = 1; } /***************************************************************** SUBROUTINE READMASK4 READMASK4 READS A FOUR INTEGER STRUCTURE FROM A FILE. ******************************************************************/ /***************************************************************** MAKE IR4 A WRITE4 STRUCTURE (FOUR INTEGERS). THE FIRST INTEGER IS IR3.NUM, THE SECOND IS IR3.NUM2, THE THIRD IS IR3.REC, THE FOURTH IS IR3.GEO ******************************************************************/ struct write4 ir04; readmask4_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *fn, /* MASK FILE IDENTIFICATION NUMBER */ int *iend, /* SET TO ONE IF END OF FILE IS REACHED */ int *isecond, /* SECOND INTEGER READ IN */ int *ithird, /* THIRD INTEGER READ IN */ int *ifour /* FOURTH INTEGER READ IN */ ) { if ( !feof(fp[*fn])) { fread( &ir04, sizeof( struct write4 ), 1, fp[*fn] ); *jj = ir04.num; *isecond = ir04.num2; *ithird = ir04.rec; *ifour = ir04.geo; } if ( feof(fp[*fn])) *iend = 1; } /************************************************************** FUNCTION READSURFACES READSURFACES READS VARIABLES ON DENSITY SURFACES FROM FILE ***************************************************************/ readsurfaces_( int *denseparms, /* NUMBER OF STORED DENSITY SURFACE VARIABLES, INCLUDING PRESSURE ON SURFACE */ int *jj, /* SEQUENTIAL STATION NUMBER */ int *startpoint, /* PRESENT POSITION FILE POSITION */ int *fposfile, /* POSITION FILE ID NUMBER */ int *ireqpars, /* NUMBER OF REQUESTED VARIABLES */ int *ip2, /* VARIABLE CODES */ int *denserecord, /* DESIRED FILE POSITON FOR VARIABLES */ int *olddenserecord, /* PRESENT FILE POSITION FOR VARIABLES */ int *ioutfile, /* FILE IDS FOR VARIABLE FILES */ int *npot, /* SEQUENTIAL ORDER FOR PRESENT REFERENCE LEVEL */ int *maxpot, /* MAXIMUM NUMBER OF REFERENCE LEVELS */ float *densevar, /* VARIABLES ON DENSITY SURFACES */ int *maxsurf, /* MAXIMUM NUMBER OF DENSITY SURFACES */ int *maxparm, /* MAXIMUM NUMBER OF VARIABLES */ int *maxcal, /* MAXIMUM NUMBER OF MEASURED/CALCULATED VARIABLES */ int *jp, /* PROBE CODE */ int *nprec, /* RECORD POSITION FOR EACH VARIABLE */ int *ishallow, /* INDEX OF FIRST DENSITY SURFACE RECORD */ int *ideep, /* INDEX OF LAST DENSITY SURFACE RECORD */ int *numdense, /* TOTAL POSSIBLE DENSITY SURFACES */ float *missing, /* MISSING VALUE MARKER */ float *tooshallow, /* MARKER FOR DENSITY SURFACE TOO SHALLOW */ float *toodeep, /* MARKER FOR DENSITY SURFACE TOO DEEP */ int *ieof /* END OF FILE MARKER */ ) { int i,i0,i2,j,ivarfile,ivarpos,nlevels=0; float submissing, submissing2; long int size; /************************************************************* COMPUTE RECORD SIZE (NUMBER OF DENSITY SURFACE VARIABLES) DENSEPARMS INCLUDES PRESSURE ON DENSITY SURFACE VARIABLE **************************************************************/ size = (*denseparms +2) * sizeof(int); /************************************************************* POSITION POSITIONS FILE **************************************************************/ fseek( fp[*fposfile],( *jj - *startpoint ) * size , SEEK_CUR ); /**************************************************************** ADJUST PRESENT POSITIONS FILE PROFILE NUMBER (ADD ONE) ****************************************************************/ *startpoint = *jj + 1; /*************************************************************** WRITE OUT NUMBER OF DENSITY SURFACES WITH VALUES AND FIRST SURFACE WITH VALUE ****************************************************************/ fread( &nlevels, sizeof(int), 1, fp[*fposfile]); fread( ishallow, sizeof(int), 1, fp[*fposfile]); if ( *ishallow > 0 ) *ideep= (*ishallow + nlevels) -1; else *ideep=0; if ( feof(fp[*fposfile]) ) { *ieof = 1; return; } /*************************************************************** READ POSITIONS FOR EACH VARIABLE FROM POSITIONS FILE ****************************************************************/ fread( (denserecord+1), sizeof(int), *denseparms, fp[*fposfile]); /*************************************************************** START LOOP TO READ IN VARIABLES A -1 IN DENSERECORD MEANS NO DATA FOR VARIABLE ****************************************************************/ for ( i0=1; i0<= *ireqpars; i0++) { i = *(ip2+i0); i2 = *( nprec + (((*jp)-1) * *maxcal) + (i-1)); printf("i2 %d %d %d\n",i,i2, *(denserecord + i2)); if ( *(denserecord + i2) > -1 ) { /*************************************************************** GO TO DESIGNATED POSITION IN VARIABLE FILE ****************************************************************/ ivarfile= *(ioutfile+((*npot-1) * (*maxparm + 1)) + i); fseek( fp[ivarfile], (*(denserecord+i2) - *(olddenserecord+i2)) * sizeof(float), SEEK_CUR); /**************************************************************** READ VARIABLE DATA INTO ARRAY *****************************************************************/ ivarpos= ((i-1) * *maxsurf) + (*ishallow-1); fread( (densevar + ivarpos), sizeof(float), nlevels,fp[ivarfile]); *(olddenserecord+i2) = *(denserecord+i2)+ nlevels; *(denserecord+i2) = *(olddenserecord+i2); /**************************************************************** ENTER MISSING VALUES INTO NONUSED DENSITY SURFACES *****************************************************************/ submissing= *missing; submissing2= *missing; if ( *(densevar + ivarpos) > *toodeep && *(densevar + ivarpos) <= *tooshallow+1. ) submissing= *tooshallow; if ( *(densevar + ivarpos + (nlevels-1)) <= *toodeep +1. && *(densevar + ivarpos + (nlevels-1)) > *missing ) submissing2= *toodeep; ivarpos -= (*ishallow-1); for ( j = ivarpos; j < ivarpos + (*ishallow-1); j++ ) *(densevar + j) = submissing; ivarpos += (*ideep-1); for ( j = ivarpos+1; j < ivarpos + *numdense; j++) *(densevar + j) = submissing2; } } } /************************************************************************ SUBROUTINE REALLOCATOR ALLOCATOR REALLOCATES THE PROPER AMOUNT OF STORAGE FOR AN ARRAY *************************************************************************/ /************************************************************** DEFINE *PREP AS A TWO INTEGER STRUCTURE. DEFINE *PREP2 AS A TWO INTEGER STRUCTURE. DEFINE *PREPF AS AN INTEGER, REAL STRUCTURE. DEFINE *PREP0 AS A REAL. DEFINE *PREPI AS AN INTEGER DEFINE *PREPSI AS A SHORT INTEGER DEFINE *PREP3 AS A THREE INTEGER STRUCTURE DEFINE *PREP4 AS A FOUR INTEGER STRUCTURE DEFINE *PREP5 AS A FIVE INTEGER STRUCTURE DEFINE *PREPFS AS A ONE REAL, ONE SHORT INTEGER STRUCTURE DEFINE *PREPIFS AS A ONE REAL, ONE INTEGER, ONE SHORT INTEGER STRUCTURE DEFINE *PREP2IF AS TWO INTEGERS, ONE REAL ***************************************************************/ struct write2 *prep,*prep2; struct write2f *prepf; struct write3 *prep3; struct write4 *prep4; struct write5 *prep5; struct write2if *prep2if; float *prep0; int *prepi; short int *prepsi; struct write2fs *prepfs; struct write3fs *prepifs; reallocator_( int *indicator, /* WHICH TYPE OF STRUCTURE TO ALLOCATE SPACE FOR: 0 - PREP0 (ONE REAL) 1 - WRITE2 (TWO INTEGERS) 2 - WRITE2F ( INTEGER,REAL) 3 - PREPI (ONE INTEGER) 4 - WRITE3 (THREE INTEGERS) 5 - PREP2 (TWO INTEGERS), SECOND WRITE2 STRUCTURE 6 - WRITE2FS - (ONE REAL, ONE SHORT INTEGER) 7 - WRITE3FS - (ONE REAL, ONE INTEGER, ONE SHORT INTEGER) 8 - PREPSI - (ONE SHORT INTEGER) 9 - PREP2IF - (TWO INTEGERS,ONE REAL) 10 - PREP4 (FOUR INTEGERS) 11 - PREP5 (FIVE INTEGERS) */ int *numpros /* NUMBER OF STRUCTURES FOR WHICH SPACE WILL BE ALLOCATED */ ) { int npros= *numpros+1; if ( *indicator == 0 ) { if ( (prep0 = realloc( prep0,npros * sizeof (float) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 1 ) { if ( (prep = realloc( prep,npros* 2 * sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 2 ) { if ( (prepf = realloc( prepf,npros* sizeof( float )+ sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 3 ) { if ( (prepi = realloc( prepi,npros * sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 4 ) { if ( (prep3 = realloc( prep3,npros * 3*sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 5 ) { if ( (prep2 = realloc( prep2,npros* 2 * sizeof( int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 6 ) { if ( (prepfs = realloc( prepfs,npros* sizeof( struct write2fs ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 7 ) { if ( (prepifs = realloc(prepifs, npros* sizeof( struct write3fs ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 8 ) { if ( (prepsi = realloc( prepsi,npros* sizeof( short int ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 9 ) { if ( (prep2if = realloc( prep2if,npros* sizeof( struct write2if ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 10 ) { if ( (prep4 = realloc( prep4,npros* sizeof( struct write4 ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } else if ( *indicator == 11 ) { if ( (prep5 = realloc( prep5,npros* sizeof( struct write5 ) )) == NULL ) printf( " Not enough space in memory for %d profiles to be sorted\n", *numpros); } } /************************************************************** SUBROUTINE SEQREAD SEQREAD READS ALL SEQUENTIAL MASKS TO FIND THE NEXT PROFILE TO BE EXAMINED. A SEQUENTIAL MASK IS A MASK WHICH CONTAINS ONLY PROFILE NUMBERS. THERE ARE TWO TYPES OF SEQUENTIAL MASKS; THE FIRST IS INCLUSIVE MASKS. INCLUSIVE MASKS CONTAIN THE PROFILE NUMBERS OF THOSE PROFILES WHICH ARE TO BE EXAMINED IN THE MAIN PROGRAM. THE SECOND TYPE IS EXCLUSIVE MASKS. THESE MASKS CONTAIN NUMBERS OF PROFILES WHICH ARE EXPRESSLY NOT TO BE EXAMINED IN THE MAIN PROGRAM. SEQREAD READS EACH MASK UNTIL THE NEXT PROFILE NUMBER WHICH IS IN AN INCLUSIVE MASK AND NOT IN AN EXCLUSIVE MASK IS FOUND. THE PRESENT PROFILE NUMBER FOR EACH MASK IS STORED IN JPRESENT. *****************************************************************/ seqread_( int *jj, /* PRESENT PROFILE RECORD NUMBER */ int *nmask, /* TOTAL NUMBER OF SEQUENTIAL MASKS */ int *nmask1, /* NUMBER OF INCLUSION MASKS */ int *eof, /* END OF SEARCH MARKER. SET TO ONE WHEN ALL FILES HAVE REACHED THEIR END OF FILE */ int *allend, /* NUMBER OF FILES WHICH HAVE REACHED THEIR END OF FILE */ int *fn /* FILE IDENTIFICATION NUMBERS FOR EACH MASK FILE */ ) { /************************************************************* I - COUNTER FOUND - DENOTES WHETHER A PROFILE RECORD NUMBER HAS BEEN FOUND JJIN - PROFILE RECORD NUMBER WHICH IS RETURNED TO THE MAIN PROGRAM. IT IS INITIALLY SET TO A VERY LARGE NUMBER SINCE THE SMALLEST OF ALL PROFILE RECORD NUMBERS CULLED FROM THE VARIOUS MASKS IS THE PROFILE RECORD NUMBER RETURNED. HENCE JJIN MUST FIRST BE SET TO A NUMBER WHICH IS LARGER THAN ANY PROFILE RECORD NUMBER. ***************************************************************/ int i; int found = 0; int jjin = 300000000; /*************************************************************** IF THERE ARE NO INCLUSIVE MASKS, SET THE OUTPUT RECORD NUMBER TO THE PRESENT RECORD NUMBER. IN THIS WAY, THE PRESENT RECORD NUMBER (PLUS ONE) WILL BE CHECKED AGAINST EXCLUSIVE MASKS. IF ALL MASKS ARE INCLUSIVE, SET FOUND TO -1. THIS IS THE ONLY WAY TO CHECK THE NEXT VALUE IN INCLUSIVE MASKS, SINCE MASKS ARE ONLY CHECKED IF FOUND IS LESS THAN THE NUMBER OF EXCLUSIVE MASKS. ****************************************************************/ if ( *nmask1 == 0 ) jjin = *jj; if ( *nmask - *nmask1 == 0 ) found = -1; /**************************************************************** IF FOUND IS LESS THAN THE NUMBER OF EXCLUSIVE MASKS, CHECK EACH MASK FILE. *****************************************************************/ while ( found < ( *nmask - *nmask1 ) ) { /**************************************************************** IF THERE ARE NO INCLUSIVE MASKS, CHECK THE NEXT SUCCESSIVE PROFILE AGAINST THE EXCLUSIVE MASKS. *****************************************************************/ if ( *nmask1 == 0 ) jjin += 1; /**************************************************************** IF THERE ARE NO EXCLUSIVE MASKS, SET FOUND TO ONE, SINCE THE NEXT VALUE READ FROM THE INCLUSIVE MASKS IS AUTOMATICALLY THE OUTPUT VALUE. OTHERWISE RESET FOUND. ****************************************************************/ if ( *nmask - *nmask1 == 0 ) found = 1; else found = 0; /*************************************************************** CHECK EACH INCLUSIVE MASK. ****************************************************************/ for ( i = 0; i < *nmask1; i++ ) { /*************************************************************** IF A MASK HAS ALREADY REACHED THE END OF ITS FILE, SUBTRACT ONE FROM *ALLEND, SINCE ONE WILL AGAIN BE ADDED AFTER AN ATTEMPT TO READ THE FILE. ****************************************************************/ if (feof(fp[*(fn+i)])) *allend -=1; /*************************************************************** WHILE THE PRESENT PROFILE RECORD NUMBER IN THE MASK IS LESS OR EQUAL TO THE LAST INVESTIGATED PROFILE RECORD NUMBER, READ THE NEXT PROFILE RECORD NUMBER FROM FILE (UNLESS THE FILE HAS BEEN COMPLETELY READ IN. ****************************************************************/ while ( jpresent[ i ] <= *jj && !feof( fp[ *(fn + i) ] )) { fread( &jpresent[i], sizeof( int ) , 1, fp[*(fn+i)]); } /*************************************************************** IF THE END OF FILE HAS BEEN REACHED, ADD ONE TO THE END OF FILE COUNTER. ****************************************************************/ if (feof(fp[*(fn+i)])) *allend +=1; } /*************************************************************** IF NOT ALL FILES HAVE REACHED THEIR END OF FILE, FIND THE LOWEST PROFILE NUMBER FROM ALL THE MASKS AND SET THIS AS THE NEXT PROFILE TO BE INVESTIGATED. *****************************************************************/ if ( *allend < *nmask1 ) { jjin = 300000000; for ( i = 0; i < *nmask1; i++ ) { if ( !feof(fp[*(fn+i)]) && jpresent[i] < jjin ) jjin = jpresent[i]; } } /********************************************************** IF ALL MASK FILES HAVE BEEN COMPLETELY READ, SET EOF TO ONE TO ALERT THE MAIN PROGRAM. ***********************************************************/ else if ( *nmask1 > 0 ) { *eof = 1; return; } /************************************************************ SET THE PROFILE RECORD NUMBER TO BE INVESTIGATED AS THE PRESENT PROFILE. **************************************************************/ *jj = jjin; /************************************************************* READ IN THE NEXT PROFILE RECORD NUMBERS FROM THE EXCLUSIVE MASKS. **************************************************************/ for ( i = *nmask1; i < *nmask; i++ ) { while ( jpresent[ i ] < jjin && !feof( fp[ *(fn + i) ] )) { fread( &jpresent[i], sizeof( int ) , 1, fp[*(fn+i)]); } /************************************************************* IF THE VALUE IN THE EXCLUSIVE MASK IS NOT EQUAL TO THE PRESENT PROFILE NUMBER OR THE EXCLUSIVE MASK HAS BEEN COMPLETELY READ, ADD ONE TO FOUND. WHEN FOUND EQUALS THE NUMBER OF EXCLUSIVE MASKS, THE PRESENT PROFILE RECORD NUMBER IS OUTPUT TO THE MAIN PROGRAM AS THE NEXT PROFILE TO BE INVESTIGATED. **************************************************************/ if ( feof(fp[*(fn+i)]) || jpresent[i] != jjin ) found +=1; } } } /*********************************************************** SUBROUTINE SETDEL SETDEL SETS THE INSIDE AND OUTSIDE LIMITS FOR DISTANCE FROM A STANDARD LEVEL WHICH AN OBSERVED MEASUREMENT MAY BE USED FOR INTERPOLATION. INTERPOLATION IS DONE USING A MODIFIED REINIGER- ROSS SCHEME WHICH USES FOUR OBSERVATIONS SURROUNDING A STANDARD LEVEL. HENCE, TWO DISTANCE LIMITS ARE USED, ONE, THE MORE STRINGENT CRITERIA, IS FOR THE CLOSESTS DEEPER AND CLOSEST SHALLOWER MEASUREMENT WITH RESPECTS TO THE STANDARD LEVEL. THE SECOND, LOOSER CRITERIA IS FOR THE FURTHEST SHALLOWER AND FURTHEST DEEPER MEASUREMENT. THE CRITERIA ARE AS FOLLOWS: STANDARD LEVELS INSIDE OUTSIDE 1-10 50. M 200. M 11-13 100. M 200. M 14-17 100. M 400. M 18-21 200. M 400. M 22-25 200. M 1000. M 26-40 1000. M 1000. M SUBROUTINE STEPS: 1. SET INSIDE LIMITS 2. SET OUTSIDE LIMITS **********************************************************************/ setdel_( int *nlevels, /* NUMBER OF LEVELS */ int *dz, /* STANDARD DEPTHS */ float *del, /* INSIDE DISTANCE LIMITS */ float *del2 /* OUTSIDE DISTANCE LIMITS */ ) { int j; /* COUNTER */ /******************************************************* SET INSIDE LIMITS old way: by standard depth level for ( j=1; j<= 10; j++) *(del+j-1) = 50.; for ( j=11; j<= 17; j++) *(del+j-1) = 100.; for ( j=18; j<= 25; j++) *(del+j-1) = 200.; for ( j=26; j<= 40; j++) *(del+j-1) = 1000.; new way: by depth ********************************************************/ /******************************************************* SET OUTSIDE LIMITS old way: by standard depth level for ( j=1; j<= 13; j++) *(del2+j-1) = 200.; for ( j=14; j<= 21; j++)*(del2+j-1) = 400.; for ( j=22; j<= 40; j++)*(del2+j-1) = 1000.; new way: by depth *********************************************************/ for ( j=0; j< *nlevels; j++ ) { if ( *(dz + j) <= 200. ) *(del+j) = 50.; else if ( *(dz + j) <= 800. ) *(del+j) = 100.; else if ( *(dz + j) <= 1750. ) *(del+j) = 200.; else *(del+j) = 1000.; if ( *(dz + j) <= 400. ) *(del2+j) = 200.; else if ( *(dz + j) <= 1200. ) *(del2+j) = 400.; else *(del2+j) = 1000.; } } /****************************************************************** SUBROUTINE SETFORSURF SETFORSURF STORES PARAMETER CODES FOR 1. LATITUDE, 2. LONGITUDE AND 3. JULIAN DAY ******************************************************************/ int surfhead[3]; setforsurf_( int *i, /* TYPE OF PARAMETER CODE 1. LATITUDE 2. LONGITUDE 3. JULIAN DAY */ int *ival /* CODE NUMBER FOR GIVEN PARAMETER */ ) { surfhead[*i-1]= *ival; } /************************************************************** SUBROUTINE SETSTANDEPS SETSTANDEPS SETS THE DEPTH WHICH CORRESPONDS TO THE STANDARD LEVEL NUMBERS THEY ARE AS FOLLOWS: STANDARD LEVEL DEPTH IN METERS 1. 0. 2. 10. 3. 20. 4. 30. 5. 50. 6. 75. 7. 100. 8. 125. 9. 150. 10. 200. 11. 250. 12. 300. 13. 400. 14. 500. 15. 600. 16. 700. 17. 800. 18. 900. 19. 1000. 20. 1100. 21. 1200. 22. 1300. 23. 1400. 24. 1500. 25. 1750. 26. 2000. 27. 2500. 28. 3000. 29. 3500. 30. 4000. 31. 4500. 32. 5000. 33. 5500. 34. 6000. 35. 6500. 36. 7000. 37. 7500. 38. 8000. 39. 8500. 40. 9000. A STANDARD DEPTH IS SIMPLY AN AGREED UPON LEVEL AT WHICH STUDIES ARE MADE. THEY ARE NECESSARY SINCE DATA COMES IN AT SO MANY DIFFERENT DEPTHS AND THE ONLY WAY TO MAKE SENSE OF IT IS TO TRY TO EXAMINE A FEW DISCRETE LEVELS TO WHICH THE INCOMING DATA MAY BE INTERPOLATED. THESE STANDARD LEVELS ARE THOSE USED BY LEVITUS IN HIS CLIMATOLOGICAL ATLAS (1982) AND ARE THE SAME AS THOSE USED AT NODC WITH THE ADDITION OF A FEW DEPTHS. *******************************************************************/ setstandeps_( float *standeps /* STANDARD DEPTH LEVELS */ ) { *standeps = 0.; *(standeps+1) = 10.; *(standeps+2) = 20.; *(standeps+3) = 30.; *(standeps+4) = 50.; *(standeps+5) = 75.; *(standeps+6) = 100.; *(standeps+7) = 125.; *(standeps+8) = 150.; *(standeps+9) = 200.; *(standeps+10) = 250.; *(standeps+11) = 300.; *(standeps+12) = 400.; *(standeps+13) = 500.; *(standeps+14) = 600.; *(standeps+15) = 700.; *(standeps+16) = 800.; *(standeps+17) = 900.; *(standeps+18) = 1000.; *(standeps+19) = 1100.; *(standeps+20) = 1200.; *(standeps+21) = 1300.; *(standeps+22) = 1400.; *(standeps+23) = 1500.; *(standeps+24) = 1750.; *(standeps+25) = 2000.; *(standeps+26) = 2500.; *(standeps+27) = 3000.; *(standeps+28) = 3500.; *(standeps+29) = 4000.; *(standeps+30) = 4500.; *(standeps+31) = 5000.; *(standeps+32) = 5500.; *(standeps+33) = 6000.; *(standeps+34) = 6500.; *(standeps+35) = 7000.; *(standeps+36) = 7500.; *(standeps+37) = 8000.; *(standeps+38) = 8500.; *(standeps+39) = 9000.; } /************************************************************** SUBROUTINE SETSTANDEPSFROMFILE SETSTANDEPS SETS THE DEPTH WHICH CORRESPONDS TO THE STANDARD LEVEL NUMBERS AS GIVEN IN DESIGNATED FILE *******************************************************************/ setstandepsfromfile_( int *ndeps, /* NUMBER OF DEPTHS */ float *standeps /* STANDARD DEPTH LEVELS */ ) { FILE *fpcheck, *fpdepth; int in_num; float xdum1,xdum2; char filename[80], fileextend[5]; *ndeps = 0; /* GET INFORMATION ON WHICH SET OF STANDARD DEPTHS */ if ( (fpcheck = fopen("whichdepthset.inf\0","r")) ==NULL ) { sprintf(filename,"%ssys.inf/whichdepthset.inf\0",MAINBRANCH); if ( (fpcheck = fopen(filename,"r")) ==NULL ) { printf(" unable to open %s\n",filename); return; } } fscanf(fpcheck,"%s",fileextend); in_num= fclose(fpcheck); sprintf(filename,"%ssys.inf/standard_depths_%s.dat\0",MAINBRANCH,fileextend); if ( (fpdepth = fopen(filename,"r")) ==NULL ) printf(" unable to open %s\n",filename); else { while ( !feof(fpdepth) ) { fscanf(fpdepth,"%d %f %f %f\n",&in_num,(standeps+ *ndeps),&xdum1,&xdum2); *ndeps +=1; } } in_num= fclose(fpdepth); } /****************************************************************** SUBROUTINE SETSURFPROBE SETSURFPROBE STORES SURFACE PROBE MARKER: 1 - SURFACE ONLY DATE 0 - PROFILE OR BIOLOGICAL DATA ******************************************************************/ int surfprobe[nprobe]; setsurfprobe_( int *i, /* PROBE CODE */ int *ival /* SURFACE PROBE MARKER */ ) { surfprobe[*i]= *ival; } /****************************************************************** SUBROUTINE ARRAYSORT ARRAYSORT SORTS AN INTEGER ARRAY BY ASCENDING NUMERICAL VALUE *******************************************************************/ sortarray_( int *iarray, /* ARRAY TO BE SORTED */ int *nsort /* NUMBER OF VALUES TO SORT */ ) { qsort( iarray, *nsort, sizeof( int ), comparem ); } /*************************************************************** SUBROUTINE TEMPFILE TEMPFILE WILL OPEN A TEMPORARY FILE. WHEN THE MAIN PROGRAM IS DONE RUNNING, THE TEMPORARY FILE DISAPEARS. ****************************************************************/ tempfile_( int *filenumber /* FILE NUMBER TO BE ASSIGNED TO THE TEMPORARY FILE. */ ) { int s; if ( *filenumber < 0 ) { if ( ( s = fileassign(filenumber)) == 0 ) { printf("No more available file numbers\n"); return; } } if ( ftrack[*filenumber] <= 0 ) { if ((fp[*filenumber] = tmpfile()) == NULL) printf(" unable to open %d\n ", *filenumber); else { printf(" Temporary file %d opened\n",*filenumber); ftrack[*filenumber] = 1; } } else { printf(" TEMPORARY FILE %d WILL NOT BE OPENED, AS",*filenumber); printf(" THIS FILE NUMBER IS ALREADY IN USE\n"); } } /*************************************************************** SUBROUTINE TEMPFILES TEMPFILE WILL OPEN A TEMPORARY FILE. WHEN THE MAIN PROGRAM IS DONE RUNNING, THE TEMPORARY FILE DISAPEARS. THIS VERSION DOES NOT PRINT TO SCREEN WHEN A FILE IS OPENED ****************************************************************/ tempfiles_( int *filenumber /* FILE NUMBER TO BE ASSIGNED TO THE TEMPORARY FILE. */ ) { int s; if ( *filenumber < 0 ) { if ( ( s = fileassign(filenumber)) == 0 ) { printf("No more available file numbers\n"); return; } } if ( ftrack[*filenumber] <= 0 ) { if ((fp[*filenumber] = tmpfile()) == NULL) printf(" unable to open %d\n ", *filenumber); else { ftrack[*filenumber] = 1; } } else { printf(" TEMPORARY FILE %d WILL NOT BE OPENED, AS",*filenumber); printf(" THIS FILE NUMBER IS ALREADY IN USE\n"); } } /*************************************************************** SUBROUTINE THREEJSORT THREEJSORT SORTS A FILE NUMERICALLY. FIRST THE CONTENTS OF THE FILE ARE READ INTO AN ARRAY. THEN THEY ARE SORTED USING THE QSORT FACILITY. THEN THE CONTENTS ARE READ BACK OUT TO THE ORIGINAL FILE. THREEJSORT IS ONLY FOR FILES CONTAINING THTEE INTEGER STRUCTURES (PREP). ****************************************************************/ threejsort_( int *fn /* FILE IDENTIFICATION NUMBER */ ) { /**************************************************************** PARAMETERS: I - COUNTER NUMPROS - NUMBER OF VALUES TO BE SORTED *****************************************************************/ int i; int numpros = 0; /**************************************************************** READ IN ALL THE VALUES FROM FILE. *****************************************************************/ while ( !feof(fp[*fn]) ) { numpros++; fread( &prep3[numpros], sizeof( struct write3 ) , 1, fp[*fn]); } /*************************************************************** SUBTRACT ONE FROM THE VALUE COUNTER SINCE THE LAST ADDITION WAS FOR THE END OF FILE MARKER. ****************************************************************/ numpros--; /*************************************************************** REWIND THE FILE ****************************************************************/ fseek( fp[*fn], 0L, SEEK_SET ); /*************************************************************** SORT FILES USING QSORT: PREP3[1] - STARTING POINT FOR SORT NUMPROS - NUMBER OF VALUES TO SORT SIZEOF() - SIZE OF VALUES BEING SORTED UNCOMPAREM - SORTING SUBROUTINE ****************************************************************/ qsort( &prep3[1], numpros, sizeof( struct write3 ), comparem3); /*************************************************************** PLACE SORTED VALUES BACK IN FILE. ****************************************************************/ for ( i = 1; i <= numpros; i++ ) fwrite( &prep3[i], sizeof( struct write3 ), 1, fp[*fn] ); } /*********************************************************** SUBROUTINE WRITECMASK WRITECMASK WRITES A STRUCTURE OUT TO FILE. THE STRUCTURE CONTAINS AN INTEGER AND A CHARACTER ARRAY (15 LETTERS MAX). ************************************************************/ /*********************************************************** DEFINE CINFO AS A STRUCTURE WITH AN INTEGER AND A 15 LETTER CHARACTER. ************************************************************/ struct write2c cinfo; writecmask_( int *jj, /* PROFILE NUMBER */ char *carray, /* CHARACTER ARRAY TO BE WRITTEN OUT */ int *ifn /* FILE IDENTIFICATION NUMBER */ ) { cinfo.num = *jj; strcpy( cinfo.carr, carray ); fwrite(&cinfo, sizeof( struct write2c ), 1, fp[*ifn]); } /********************************************************* SUBROUTINE WRITELEVEL WRITELEVEL WRITES OUT REAL DATA TO A STANDARD GRID FILE IN BULK FORM. THE STANDARD GRID FILE IS A THREE DIMENSIONAL GRID, I,J,K WITH I DENOTING LONGITUDINAL, J DENOTING LATITUDINAL, AND K DENOTING DEPTH. WRITELEVEL CAN TAKE AN ARRAY OF ANY SIZE AND WRITE IT TO A FILE SET UP FOR THE SAME GRID SIZE OR ANOTHER GRID SIZE. **********************************************************/ writelevel_( int *iadim, /* STARTING LONGITUDE FOR ARRAY */ int *jadim, /* STARTING LATITUDE FOR ARRAY */ int *k1, /* FIRST DEPTH FOR ARRAY */ int *idims, /* STARTING LONGITUDE GRID */ int *jdims, /* STARTING LATITUDE GRID */ int *idime, /* ENDING LONGITUDE GRID */ int *jdime, /* ENDING LATITUDE GRID */ int *idim, /* MAXIMUM LONGITUDE SPACING FOR FILE */ int *jdim, /* MAXIMUM LATITUDE SPACING FOR FILE */ int *iparm, /* MAXIMUM LONGITUDE SPACING FOR DATA ARRAY */ int *jparm, /* MAXIMUM LATITUDE SPACING FOR DATA ARRAY */ int *ks, /* STARTING DEPTH LEVEL */ int *ke, /* ENDING DEPTH LEVEL */ int *fn, /* FILE IDENTIFICATION NUMBER */ float *temp /* DATA */ ) { /*********************************************************** LEVELSIZE - SIZE OF ONE GRID LEVEL FOR FILE RECORD - POINTER TO CORRECT LEVEL FOR FILE LATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR FILE ARRAYSIZE - SIZE OF ONE ARRAY LEVEL ARECORD - POINTER TO CORRECT LEVEL FOR ARRAY ALATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR ARRAY K - CURRENT DEPTH POINT FOR FILE J - CURRENT LATITUDE POINT FOR FILE I - CURRENT LONGITUDE POINT FOR FILE KA - CURRENT DEPTH POINT FOR ARRAY JA - CURRENT LATITUDE POINT FOR ARRAY IA - CURRENT LONGITUDE POINT FOR ARRAY *************************************************************/ int levelsize, record, latitude, j, k, i; int arraysize, arecord, alatitude, ja, ka, ia; /************************************************************* CALCULATE LEVEL SIZE AND ARRAY SIZE SET BASE DEPTH FOR ARRAY **************************************************************/ levelsize = *idim * *jdim; arraysize = *iparm * *jparm; ka = *k1-1; /************************************************************* RUN THROUGH K (DEPTH) LEVELS **************************************************************/ for ( k = *ks; k <= *ke; k++ ) { /************************************************************* CALCULATE DEPTH POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LATITUDE **************************************************************/ ka +=1; record = ( k-1 ) * levelsize; arecord = ( ka-1 ) * arraysize; ja = *jadim-1; /************************************************************* RUN THROUGH J ( LATITUDE ) POINTS **************************************************************/ for ( j = *jdims; j <= *jdime; j++ ) { /************************************************************* CALCULATE LATITUDE POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LONGITUDE **************************************************************/ ja +=1; latitude = *idim * (j-1) + ( *idims-1 ); alatitude = *iparm * (ja-1); ia = *iadim-2; /************************************************************* GO TO CORRECT POINT IN FILE **************************************************************/ fseek( fp[*fn],(record+latitude)*sizeof(float),SEEK_SET); /************************************************************* RUN THROUGH I (LONGITUDE) POINTS **************************************************************/ for ( i = *idims -1; i < *idime; i++ ) { ia +=1; /************************************************************* WRITE DATA OUT TO FILE **************************************************************/ fwrite( (temp+arecord+alatitude+ia), sizeof(float),1,fp[(*fn)]); } } } } /********************************************************* SUBROUTINE WRITELEVELD WRITELEVELD WRITES OUT REAL DATA TO A STANDARD GRID FILE IN BULK FORM. THE STANDARD GRID FILE IS A THREE DIMENSIONAL GRID, I,J,K WITH I DENOTING LONGITUDINAL, J DENOTING LATITUDINAL, AND K DENOTING DEPTH. WRITELEVEL CAN TAKE AN ARRAY OF ANY SIZE AND WRITE IT TO A FILE SET UP FOR THE SAME GRID SIZE OR ANOTHER GRID SIZE. THIS VERSION TAKES A DOUBLE PRECISION REAL VALUE AND CONVERTS IT TO A SINGLE PRECISION VALUE BEFORE WRITING OUT **********************************************************/ writeleveld_( int *iadim, /* STARTING LONGITUDE FOR ARRAY */ int *jadim, /* STARTING LATITUDE FOR ARRAY */ int *k1, /* FIRST DEPTH FOR ARRAY */ int *idims, /* STARTING LONGITUDE GRID */ int *jdims, /* STARTING LATITUDE GRID */ int *idime, /* ENDING LONGITUDE GRID */ int *jdime, /* ENDING LATITUDE GRID */ int *idim, /* MAXIMUM LONGITUDE SPACING FOR FILE */ int *jdim, /* MAXIMUM LATITUDE SPACING FOR FILE */ int *iparm, /* MAXIMUM LONGITUDE SPACING FOR DATA ARRAY */ int *jparm, /* MAXIMUM LATITUDE SPACING FOR DATA ARRAY */ int *ks, /* STARTING DEPTH LEVEL */ int *ke, /* ENDING DEPTH LEVEL */ int *fn, /* FILE IDENTIFICATION NUMBER */ double *temp /* DATA */ ) { /*********************************************************** LEVELSIZE - SIZE OF ONE GRID LEVEL FOR FILE RECORD - POINTER TO CORRECT LEVEL FOR FILE LATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR FILE ARRAYSIZE - SIZE OF ONE ARRAY LEVEL ARECORD - POINTER TO CORRECT LEVEL FOR ARRAY ALATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR ARRAY K - CURRENT DEPTH POINT FOR FILE J - CURRENT LATITUDE POINT FOR FILE I - CURRENT LONGITUDE POINT FOR FILE KA - CURRENT DEPTH POINT FOR ARRAY JA - CURRENT LATITUDE POINT FOR ARRAY IA - CURRENT LONGITUDE POINT FOR ARRAY *************************************************************/ float stemp; int levelsize, record, latitude, j, k, i; int arraysize, arecord, alatitude, ja, ka, ia; /************************************************************* CALCULATE LEVEL SIZE AND ARRAY SIZE SET BASE DEPTH FOR ARRAY **************************************************************/ levelsize = *idim * *jdim; arraysize = *iparm * *jparm; ka = *k1-1; /************************************************************* RUN THROUGH K (DEPTH) LEVELS **************************************************************/ for ( k = *ks; k <= *ke; k++ ) { /************************************************************* CALCULATE DEPTH POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LATITUDE **************************************************************/ ka +=1; record = ( k-1 ) * levelsize; arecord = ( ka-1 ) * arraysize; ja = *jadim-1; /************************************************************* RUN THROUGH J ( LATITUDE ) POINTS **************************************************************/ for ( j = *jdims; j <= *jdime; j++ ) { /************************************************************* CALCULATE LATITUDE POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LONGITUDE **************************************************************/ ja +=1; latitude = *idim * (j-1) + ( *idims - 1 ); alatitude = *iparm * (ja-1); ia = *iadim-2; /************************************************************* GO TO CORRECT POINT IN FILE **************************************************************/ fseek( fp[*fn],(record+latitude)*sizeof(float),SEEK_SET); /************************************************************* RUN THROUGH I (LONGITUDE) POINTS **************************************************************/ for ( i = *idims -1; i < *idime; i++ ) { ia +=1; /************************************************************* WRITE DATA OUT TO FILE **************************************************************/ stemp = *(temp+arecord+alatitude+ia); fwrite( &stemp, sizeof(float),1,fp[(*fn)]); } } } } /********************************************************* SUBROUTINE WRITELEVELI WRITELEVELI WRITES OUT INTEGER DATA TO A STANDARD GRID FILE IN BULK FORM. THE STANDARD GRID FILE IS A THREE DIMENSIONAL GRID, I,J,K WITH I DENOTING LONGITUDINAL, J DENOTING LATITUDINAL, AND K DENOTING DEPTH. WRITELEVEL CAN TAKE AN ARRAY OF ANY SIZE AND WRITE IT TO A FILE SET UP FOR THE SAME GRID SIZE OR ANOTHER GRID SIZE. **********************************************************/ writeleveli_( int *iadim, /* STARTING LONGITUDE FOR ARRAY */ int *jadim, /* STARTING LATITUDE FOR ARRAY */ int *k1, /* FIRST DEPTH FOR ARRAY */ int *idims, /* STARTING LONGITUDE GRID */ int *jdims, /* STARTING LATITUDE GRID */ int *idime, /* ENDING LONGITUDE GRID */ int *jdime, /* ENDING LATITUDE GRID */ int *idim, /* MAXIMUM LONGITUDE SPACING FOR FILE */ int *jdim, /* MAXIMUM LATITUDE SPACING FOR FILE */ int *iparm, /* MAXIMUM LONGITUDE SPACING FOR DATA ARRAY */ int *jparm, /* MAXIMUM LATITUDE SPACING FOR DATA ARRAY */ int *ks, /* STARTING DEPTH LEVEL */ int *ke, /* ENDING DEPTH LEVEL */ int *fn, /* FILE IDENTIFICATION NUMBER */ int *temp /* DATA */ ) { /*********************************************************** LEVELSIZE - SIZE OF ONE GRID LEVEL FOR FILE RECORD - POINTER TO CORRECT LEVEL FOR FILE LATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR FILE ARRAYSIZE - SIZE OF ONE ARRAY LEVEL ARECORD - POINTER TO CORRECT LEVEL FOR ARRAY ALATITUDE - POINTER TO CORRECT LATITUDE COORDINATE FOR ARRAY K - CURRENT DEPTH POINT FOR FILE J - CURRENT LATITUDE POINT FOR FILE I - CURRENT LONGITUDE POINT FOR FILE KA - CURRENT DEPTH POINT FOR ARRAY JA - CURRENT LATITUDE POINT FOR ARRAY IA - CURRENT LONGITUDE POINT FOR ARRAY *************************************************************/ int levelsize, record, latitude, j, k, i; int arraysize, arecord, alatitude, ja, ka, ia; /************************************************************* CALCULATE LEVEL SIZE AND ARRAY SIZE SET BASE DEPTH FOR ARRAY **************************************************************/ levelsize = *idim * *jdim; arraysize = *iparm * *jparm; ka = *k1-1; /************************************************************* RUN THROUGH K (DEPTH) LEVELS **************************************************************/ for ( k = *ks; k <= *ke; k++ ) { /************************************************************* CALCULATE DEPTH POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LATITUDE **************************************************************/ ka +=1; record = ( k-1 ) * levelsize; arecord = ( ka-1 ) * arraysize; ja = *jadim-1; /************************************************************* RUN THROUGH J ( LATITUDE ) POINTS **************************************************************/ for ( j = *jdims; j <= *jdime; j++ ) { /************************************************************* CALCULATE LATITUDE POINTER FOR FILE AND ARRAY SET BASE VALUE FOR ARRAY LONGITUDE **************************************************************/ ja +=1; latitude = *idim * (j-1) + ( *idims -1 ); alatitude = *iparm * (ja-1); ia = *iadim-2; /************************************************************* GO TO CORRECT POINT IN FILE **************************************************************/ fseek( fp[*fn],(record+latitude)*sizeof(int),SEEK_SET); /************************************************************* RUN THROUGH I (LONGITUDE) POINTS **************************************************************/ for ( i = *idims -1; i < *idime; i++ ) { ia +=1; /************************************************************* WRITE DATA OUT TO FILE **************************************************************/ fwrite( (temp+arecord+alatitude+ia), sizeof(int),1,fp[(*fn)]); } } } } /***************************************************************** SUBROUTINE WRITETOMASK WRITETOMASK WRITES A PROFILE RECORD NUMBER OUT TO A MASK FILE. ******************************************************************/ writetomask_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *counter, /* COUNTS NUMBER OF PROFILES ADDED TO MASK */ int *fn /* MASK FILE IDENTIFICATION NUMBER */ ) { fwrite( jj, sizeof( int ), 1, fp[*fn] ); *counter +=1; /* printf(" %d %d %d %d\n",*jj,*counter,*fn,ftell(fp[*fn])/sizeof(int)); */ } /******************************************************** SUBROUTINE WRITETOMASK2 WRITETOMASK2 WRITES A TWO INTEGER STRUCTURE OUT TO A MASK FILE. *********************************************************/ writetomask2_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *counter, /* COUNTS NUMBER OF PROFILES ADDED TO MASK */ int *fn, /* MASK FILE IDENTIFICATION NUMBER */ int *isecond /* SECOND PARAMETER TO WRITE OUT */ ) { /********************************************************** MAKE INP A WRITE2 STRUCTURE, WHICH IS A STRUCTURE OF TWO INTEGERS. NUM WILL BE THE FIRST INTEGER, REC THE SECOND. ***********************************************************/ struct write2 inp; /********************************************************** SET THE SECOND INTERGER TO *ISECOND, THE FIRST TO *JJ ***********************************************************/ inp.rec = *isecond; inp.num = *jj; /********************************************************** WRITE THE STRUCTURE OUT TO FILE. ADD ONE TO COUNTER. ***********************************************************/ fwrite( &inp, sizeof( struct write2 ), 1, fp[*fn] ); *counter +=1; } /******************************************************** SUBROUTINE WRITETOMASK3 WRITETOMASK3 WRITES A THREE INTEGER STRUCTURE OUT TO A MASK FILE. *********************************************************/ writetomask3_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *counter, /* COUNTS NUMBER OF PROFILES ADDED TO MASK */ int *fn, /* MASK FILE IDENTIFICATION NUMBER */ int *isecond, /* SECOND PARAMETER TO WRITE OUT */ int *ithird /* THIRD PARAMETER TO WRITE OUT */ ) { /********************************************************** MAKE INP3 A WRITE3 STRUCTURE, WHICH IS A STRUCTURE OF TWO INTEGERS. NUM WILL BE THE FIRST INTEGER, REC THE SECOND, GEO THE THIRD. ***********************************************************/ struct write3 inp3; /********************************************************** SET THE SECOND INTERGER TO *ISECOND, THE FIRST TO *JJ, THE THIRD TO *ITHIRD. ***********************************************************/ inp3.rec = *isecond; inp3.num = *jj; inp3.geo = *ithird; /********************************************************** WRITE THE STRUCTURE OUT TO FILE. ADD ONE TO COUNTER. ***********************************************************/ fwrite( &inp3, sizeof( struct write3 ), 1, fp[*fn] ); *counter +=1; } /******************************************************** SUBROUTINE WRITETOMASK4 WRITETOMASK4 WRITES A THREE INTEGER STRUCTURE OUT TO A MASK FILE. *********************************************************/ writetomask4_( int *jj, /* PROFILE HEADER RECORD NUMBER */ int *counter, /* COUNTS NUMBER OF PROFILES ADDED TO MASK */ int *fn, /* MASK FILE IDENTIFICATION NUMBER */ int *jj2, /* SECOND PARAMETER TO WRITE OUT */ int *isecond, /* THIRD PARAMETER TO WRITE OUT */ int *ithird /* FOURTH PARAMETER TO WRITE OUT */ ) { /********************************************************** MAKE INP4I A WRITE4 STRUCTURE, WHICH IS A STRUCTURE OF TWO INTEGERS. NUM WILL BE THE FIRST INTEGER, REC THE SECOND, GEO THE THIRD. ***********************************************************/ struct write4 inp4i; /********************************************************** SET THE SECOND INTERGER TO *ISECOND, THE FIRST TO *JJ, THE THIRD TO *ITHIRD. ***********************************************************/ inp4i.num = *jj; inp4i.num2 = *jj2; inp4i.rec = *isecond; inp4i.geo = *ithird; /********************************************************** WRITE THE STRUCTURE OUT TO FILE. ADD ONE TO COUNTER. ***********************************************************/ fwrite( &inp4i, sizeof( struct write4 ), 1, fp[*fn] ); *counter +=1; } /*************************************************************** SUBROUTINE ZEROFTRACK ZEROFTRACK INITIALIZES FTRACK, THE FILE TRACKING ARRAY ****************************************************************/ zeroftrack_( int *iok /* SET TO MAX NUMBER OF FILES */ ) { int i; for ( i = 0; i < MAXFILE; i++ ) ftrack[i] = 0; *iok = MAXFILE; }