Previous: Python API   Up: Madrigal developer's guide   Next: Fortran API

Madrigal C API

 

The madrec library (libmadrec.a) contains a comprehensive set of C-language procedures for working with Cedar Database files (the madrec module), and recently has been upgraded to work at a higher data level with both measured and derived data (the maddata module).

The madrec library (libmadrec.a) contains a comprehensive set of C-language procedures for working with Cedar Database files. Five version of CEDAR file are supported - Madrigal, Blocked Binary, Cbf, Unblocked binary and Ascii. In addition, an entire file may be read into memory for rapid random record access. When opening a file for reading, the madrec package is able to determine the file version automatically. Data, header and catalog records are all supported. The Cedar format itself is big-endian, but Madrec is endian-neutral and works on little endian as well as big endian computers.

The maddata module allows an application writer to ignore the difference between measured and derived parameters - from the maddata level, any file can be assumed to contain its measured data and all possible derived data. The maddata module is also designed to be easily extended to derive new parameters.

The following are suggested lines to add to your Makefile when using the Madrigal C API:

  # Library directory  LIBDIR = $(MADROOT)/lib    # Include directory  INCLUDEDIRS = -I. -I$(MADROOT)/source/madc/include    LDLIBS = -L$(LIBDIR) -lmadrec -lgeo -lm -lnsl        if solaris:    LDFLAGS = -R$(LIBDIR)        if gnu:    LDFLAGS = -Xlinker -R$(LIBDIR)  

madrec and maddata procedures

The madrec library (libmadrec.a) contains a comprehensive set of C-language procedures for working with Cedar Database files (the madrec module), and at a higher data level with both measured and derived data (the maddata module). As of release 2.2, all Madrigal software is built on the madrec C library.

Overview of file-level madrec API

As detailed in the synopsis of madrecOpen, five version of CEDAR file are supported - Madrigal, Blocked Binary, Cbf, Unblocked binary and Ascii. In addition, and entire file may be read into memory for rapid random record access. When opening a file for reading, the madrec package is able to determine the file version automatically. Data, header and catalog records are all supported. The Cedar format itself is big-endian, but Madrec is endian-neutral and works on little endian as well as big endian computers.

All methods in madc that return an array of any sort (char, int, or double) allocate the returned array from the heap. The user of this library is responsible for freeing these arrays when done. Some methods, such as cedarGetGeodetic, also allocate arrays for pointers passed in as arguments. This is the case when the method is designed to return more than one array, as is the case with cedarGetGeodetic. See the documentation of the individual methods for details.

Overview of data level maddata API

The maddata level exposes Madrigal in such a way that the user does not need to worry about whether data is measured in a file or derived. The user needs only deal with the abstact maddata data structure.The struct maddata is intented to provide easy access to madrigal data from a single cedar file that has been combined with derived parameters and has been filtered. The maddata module can also be used without files by passing in data directly needed to calculate other parameters.

The data is organized as follows:


           Maddata           MadparmList
         |         |
         v         v
      Madcycle   Madfilter
         |
         v
      Madrecord

All data in this structure corresponds to Madrigal parameters, and so is referenced by its unique mnemonic, not by Cedar parameter codes. All data is stored as doubles, with special values as defined in cedar.h.

While this module is written in C and not C++; its methods and design are as close as I could get to object-oriented. Every data structure should be instantiated via a create* method and released via destroy*. All other methods take the respective data structure pointer as the first argument. See usage in simpleMaddata.c.

The Madrecord structure defined in this file differs from the Madrec structure defined in madrec.h in that the Madrecord struct does not care about the Cedar file format, or indeed in what way the data is stored. It's basic unit of data is a double, not the 16 bit Int as in the Cedar format.

The derivation engine behind this interface is defined in the private modules madDeriveEngine and madDeriveMethods. Extending maddata simply involves adding new methods (and possibly parameters), as fully explained in madDeriveMethods.h.

See the files simpleMaddata.c and simpleNonfileMaddata.c for example usage, or the online examples.


The madrec module

madrecCreate madrecDestroy madrecOpen madrecClose madrecGetNextRec
madrecPutNextRec madrecRewind madrecGetPreviousRec madrecGetRecByRecno madrecGetRecByKey
madrecGenKeys madrecDeleteKeys madrecPrintKeys madrecCheckFile madrecCopy
madrecGetFileType madrecSetError madrecGetError madrecGetMissing madrecGetNumParms
madrecGetParmsList madrecGetParmLoc madrecGetParmMin madrecGetParmMax madrecHasCatalog
madrecHasHeader madrecGetSortedRecnoList compareCedarIndices cedarGetMadroot cedarGetLtot
cedarGetKrec isDataRecord cedarGetKinst cedarGetKindat cedarGetIbyr
cedarGetIbdt cedarGetIbhm cedarGetIbcs cedarGetIeyr cedarGetIedt
cedarGetIehm cedarGetIecs cedarGetLprol cedarGetJpar cedarGetMpar
cedarGetNrow cedarGetKpar cedarGetWord cedarGetStartTime cedarGetEndTime
cedarGetStartJday cedarGetEndJday cedarGetStartIndex cedarGetEndIndex cedarGet1dParcodes
cedarGet2dParcodes cedarHas1DParcode cedarHas2DParcode cedarGet1dParm cedarGet2dParm
cedarGet2dParmValue cedarGetFlatParm hasData cedarGetParmCodeArray cedarGetParmArray
cedarGetGeodetic cedarGet1dInt cedarGet2dInt cedarGet2dIntValue cedarCreateRecord
cedarCreateCatalogRecord cedarAppendCatalogRecord cedarCreateHeaderRecord cedarAppendHeaderRecord cedarSetKrec
cedarSetKinst cedarSetKindat cedarSetStartTime cedarSetEndTime cedarSet1dParm
cedarSetNorm1dParm cedarSet2dParm cedarSetNorm2dParm cedarSet1dInt cedarSet2dInt
cedarPrintRecord cedarGetInformation cedarPrintProlog cedarReadParCodes cedarGetNumParCodes
cedarGetParCode cedarGetParCodeIndex madGetParMnemIndex isMadparmError getStdMnem
cedarGetParCodeType madGetParMnemType madGetCategoryIndex cedarGetParDescription madGetParDescription
cedarGetParInt16Description madGetParInt16Description cedarGetParScaleFactor madGetParScaleFactor cedarGetNormScaleFactor
madGetNormScaleFactor cedarGetParUnits madGetParUnits cedarGetParMnemonic cedarGetParCodeFromMnemonic
cedarGetParFormat madGetParFormat cedarGetParWidth madGetParWidth cedarHasHtmlDesc
madHasHtmlDesc cedarCheckRecord cedarHexPrintRecord cedarDecimalPrintRecord cedarSetError
cedarGetError cedarTabInt cedarUpdateParmsList cedarGetStationPos cedarGetStationName
searchFilesByDate loadExpFileTable goodDataExists sprod vadd
vsub csconv vctcnv point look
convrt rpcart gdv los2geodetic solarzen_az
solardist shadowheight sunrise_set jday jdater
idmyck dmadptr getKey dinvmadptr madGetDayno

/***********************************************************************
*
* madrecCreate     creates a madrec object
*
*   arguments:
*       None
*
*   returns:
*       pointer to the new madrec object
*
*/

Madrec *
madrecCreate ()
 
 

/***********************************************************************
*
* madrecDestroy    destroys a madrec object
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns
*       0
*
*/

int
madrecDestroy (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecOpen     opens a madrec data file
*
*   arguments:
*       madrecp - pointer to the madrec object
*       iotype  - file type as described below
*       filnam  - file name
*
*   The following file types (iotype) are supported:
*
*       Open Cedar file for sequential reading:
*             1 - Determine file type automatically
*            10 - Madrigal file
*            11 - Blocked Binary file
*            12 - Cbf file
*            13 - Unblocked Binary file
*            14 - Ascii file
*
*       Create Cedar file for update; discard previous contents if any:
*             2 - Madrigal file
*            20 - Madrigal file
*            21 - Blocked Binary file
*            22 - Cbf file
*            23 - Unblocked Binary file
*            24 - Ascii file
*
*       Create Cedar file in memory for sequential and random read and write. 
*            30 - Determine file type automatically
*            40 - Madrigal file
*            41 - Blocked Binary file
*            42 - Cbf file
*            43 - Unblocked Binary file
*            44 - Ascii file 
*
*       Fast create Cedar file in memory for sequential and random read and write.
*          Does not calculate min and and max parameter values 
*            50 - Determine file type automatically
*            60 - Madrigal file
*            61 - Blocked Binary file
*            62 - Cbf file
*            63 - Unblocked Binary file
*            64 - Ascii file
*
*   returns:
*       0 - File opened successfully
*       1 - Invalid file type (iotype)
*       2 - unable to open data file
*       3 - data file already open
*       4 - input file name too long
*       5 - error writing file to memory
*
*/

int
madrecOpen (Madrec *madrecp, int iotype, char *filnam)
 
 

/***********************************************************************
*
* madrecClose    closes a madrec data file
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - File closed successfully
*       1 - error closing file
*       2 - file not open
*       3 - error flushing file
*
*/

int
madrecClose (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetNextRec   reads a cedar record and fills a Madrec structure
*                    with the information in the record.
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - Record read successfully
*       1 - Illegal file type (bad iotype in madrec)
*      -n - Error in CedarIO package
*
*/

int
madrecGetNextRec (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecPutNextRec   writes a cedar record.
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - 
*       1 - Illegal file type (bad iotype in madrec)
*      -n - Error in CedarIO package
*
*/

int
madrecPutNextRec (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecRewind   rewinds a cedar record.
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - 
*       1 - Illegal file type (bad iotype in madrec)
*      -n - Error in CedarIO package
*
*/

int
madrecRewind (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetPreviousRec   reads an madrigal record and fills a Mad 
*                        structure with the information in the record.
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - 
*
*/

int
madrecGetPreviousRec(Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetRecByRecno   reads a madrigal record and fills a Mad 
*                          structure with the information in the record.
*                          The record number is specified by the second
*                          argument. The first record is recno=0.
*
*   arguments:
*       madrecp - pointer to the madrec object
*       recno   - the record number to get. The first record is recno=0.
*
*   returns:
*       0 - Record read successfully
*      -1 - Specified record not in file
*
*/

int
madrecGetRecByRecno(Madrec *madrecp, int recno)
 
 

/***********************************************************************
*
* madrecGetRecordByKey   reads an madrigal record and fills a Mad 
*                        structure with the information in the record.
*                        The record is the first data record for which key is
*                        greater than or equal to the start key of the
*                        record, and less than the start time of the
*                        following record. Thus, if the specified key
*                        corresponds to a time within a record, the
*                        first such record is returned. Header or catalog
*                        records are never returned.
*                    
*
*   arguments:
*       madrecp - pointer to the madrec object
*       key - time in seconds since 1/1/1950
*
*   returns:
*       0 - if record found
*      -1 - if record not found
*
*/

int
madrecGetRecByKey(Madrec *madrecp, double key)
 
 

/***********************************************************************
*
* madrecGenKeys   Generates madrec key array. All information needed to
*                 access records randomly by key or record number is
*                 saved.
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - 
*
*/


int
madrecGenKeys (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecDeleteKeys   Deletes madrec key array.
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - 
*
*/


int
madrecDeleteKeys (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecPrintKeys   Prints madrec file key table
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - 
*
*/


int
madrecPrintKeys (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecCheckFile    checks the structure of a madrec data file
*
  Block (Physical record) structure:
  
  6720 16bit words (Int16)
  
  word[0]       = Total number of significant words in the block
		  record (all blocks are 13440 bytes long)
    
  word[1]       = Pointer to the first word of the first logical
		  record contained in the block.
  
		  (set to zero if the block doesn't contain
		   any complete logical records i.e. it just
		   contains the last part of a logical record.)
  
  word[2]       = Pointer to the first word of the last logical
		  record contained in block.
  
  word[word[0]-1] = Checksum.
  
  Logical Records:
  
  word[0 - 15]  = Same as NCAR binary logical records.
  word[16]      = Pointer to word 1 of previous logical record.
		   -could be contained in previous block.
		   -Set to zero in the first logical record of the file.
*/

int
madrecCheckFile(Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecCopy   Copies logical record from one madrec object to another
*
*   arguments:
*       madrec1p - pointer to the source madrec object
*       madrec2p - pointer to the destination madrec object
*
*   returns:
*       0 - Record copied successfully
*       1 - Empty source record
*
*/

int
madrecCopy (Madrec *madrec1p, Madrec *madrec2p)
 
 

/***********************************************************************
*
* madrecGetFileType   Gets file type
*
*   arguments:
*       madrecp - pointer to madrec object
*
*/
int
madrecGetFileType (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecSetError   sets madrec error
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       0 - 
*
*/


int
madrecSetError (Madrec *madrecp, const char *error)
 
 

/***********************************************************************
*
* madrecGetError   gets last madrec error
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       error string 
*
*/

char *
madrecGetError (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetMissing   gets missing data value
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       double precision missing value 
*
*/

double
madrecGetMissing (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetNumParms   gets number of different parameters in file
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       number of distint parameters
*
*/

int
madrecGetNumParms (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetParmsList   gets list (int array) of different parameters
*                      codes in file
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       codes of distinct parameter 
*
*  This returned array is a pointer to an internal structure in Madrec;
*  it does not need to be freed by the user.
*
*/

int *
madrecGetParmsList (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetParmLoc   gets location of parameter
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns:
*       parameter location:
*           1 - 1D array
*           2 - 2D array
*           3 - Derived
*
*/

int *
madrecGetParmLoc (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetParmMin   gets minimum value of parameter
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns - Minimum value of parameter in entire file
*
*/

double *
madrecGetParmMin (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetParmMax   gets maximum value of parameter
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns - Maximum value of parameter in entire file
*
*/

double *
madrecGetParmMax (Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecHasCatalog   returns 1 if file has catalog record, 0 otherwise
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns - 1 if file has catalog record, 0 otherwise
*
*/

int madrecHasCatalog(Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecHasHeader   returns 1 if file has header record, 0 otherwise
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns - 1 if file has header record, 0 otherwise
*
*/

int madrecHasHeader(Madrec *madrecp)
 
 

/***********************************************************************
*
* madrecGetSortedRecnoList   gets int array of recno's sorted by start time key
*
*   arguments:
*       madrecp - pointer to the madrec object
*
*   returns - int array of recno's sorted by start time key, length = nrecords
*
*/

int * madrecGetSortedRecnoList (Madrec *madrecp)
 
 

/***********************************************************************
*
* compareCedarIndices   a private method to compare one CedarIndex to another
*
*   arguments:
*       void * cedarIndex1 - void pointer to the first CedarIndex
*       void * cedarIndex2 - void pointer to the second CedarIndex
*
*   returns - if cedarIndex1 before cedarIndex2, return -1
*             if cedarIndex1 same as cedarIndex2, return 0
*             if cedarIndex1 after cedarIndex2, return 1
*
*/
int compareCedarIndices(const void * index1, const void * index2)
 
 

/***********************************************************************
*
* cedarGetMadroot   copies Madroot path into user-supplied character
*                   buffer.
*
*   Simply calls getenv, if not found, uses #define __MAD_ROOT__
*
*   Returns  void
*/
void cedarGetMadroot(char * buf)
 
 

/***********************************************************************
*
* cedarGetLtot   gets length of record
*
*/

int cedarGetLtot (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetKrec   gets Kind of record
*
*/

int cedarGetKrec (Int16 *cedarp)
 
 

/***********************************************************************
*
* isDataRecord   returns 1 if data record, 0 if catalog or header
*
*/

int isDataRecord(Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetKinst   gets instrument code for these data
*
*/

int cedarGetKinst (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetKindat   gets kind-of-data code
*
*/

int cedarGetKindat (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIbyr   gets beginning year
*
*/

int cedarGetIbyr (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIbdt   gets beginning date (100*month+day)
*
*/

int cedarGetIbdt (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIbhm   gets beginning hour and minute (100*hour + minute)
*
*/

int cedarGetIbhm (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIbcs   gets beginning centisecond
*
*/

int cedarGetIbcs (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIeyr   gets ending year
*
*/

int cedarGetIeyr (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIedt   gets ending date (100*month+day)
*
*/

int cedarGetIedt (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIehm   gets ending hour and minute (100*hour + minute)
*
*/

int cedarGetIehm (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetIecs   gets ending centisecond
*
*/

int cedarGetIecs (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetLprol   gets prolog length
*
*/

int cedarGetLprol (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetJpar   gets number of single-valued parameters
*
*/

int cedarGetJpar (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetMpar  gets number of multiple-valued parameters
*
*/

int cedarGetMpar (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetNrow   gets number of entries for each multiple-valued parameter
*
*/

int cedarGetNrow (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetKpar  gets number of derived parameters
*
*  Deprecated - use Maddata module for all derived data
*
*/

int cedarGetKpar (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetWord   gets specified word from cedar record
*
*/

int cedarGetWord (Int16 *cedarp, int word)
 
 

/***********************************************************************
*
* cedarGetStartTime   gets start time of record
*
*/

int cedarGetStartTime (Int16 *cedarp, int *year, int *month, int *day,
                   int *hour, int *minute, int *second, int *centisecond)
 
 

/***********************************************************************
*
* cedarGetEndTime   gets end time of record
*
*/

int cedarGetEndTime (Int16 *cedarp, int *year, int *month, int *day,
                   int *hour, int *minute, int *second, int *centisecond)
 
 

/***********************************************************************
*
* cedarGetStartJday   gets start Julian Day plus fractioanl day
*
*/

double cedarGetStartJday (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetEndJday   gets end Julian Day plus fractioanl day
*
*/

double cedarGetEndJday (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetStartIndex   gets start index time of record
*
*/

double cedarGetStartIndex (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetEndIndex   gets end index time of record
*
*/

double cedarGetEndIndex (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGet1dParcodes  gets 1D parameter codes from a madrigal record
*
*  This methods allocates dynamic memory for the array of ints
*  returned.  The caller of this method is responsible for
*  calling free to release this memory when finished with it.
*
*  If no 1D parameter codes, returns NULL pointer.
*
*/

int * cedarGet1dParcodes(Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGet2dParcodes  gets 2D parameter codes from a madrigal record
*
*  This methods allocates dynamic memory for the array of ints
*  returned.  The caller of this method is responsible for
*  calling free to release this memory when finished with it.
*
*  If no 2D parameter codes, returns NULL pointer.
*/

int * cedarGet2dParcodes(Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarHas1DParcode  returns 1 if cedarp has particular 1D parcode, 0 otherwise.
*
*/
int cedarHas1DParcode(Int16 *cedarp, int parcode)
 
 

/***********************************************************************
*
* cedarHas2DParcode  returns 1 if cedarp has particular 2D parcode, 0 otherwise.
*
*/
int cedarHas2DParcode(Int16 *cedarp, int parcode)
 
 

/***********************************************************************
*
* cedarGet1dParm   gets a scaled 1D parameter from a madrigal record
*
*  If 1D parm does not exist, returns double "missing"
*  If 1D parm = -32767 (missing), returns double "missing"
*  If 1D parm is an error code, and = -32766 (assumed), returns double "assumed"
*  If 1D parm is an error code, and = +32767 (known bad), returns double "knownbad"
*
*  Otherwise, scales value and includes additional increment values
*  if they exist
*
*  If cedarp is a header or catalog record; warning is printed to std err
*  and returns "missing"
*
*/

double cedarGet1dParm(Int16 *cedarp, int parcode)
 
 

/***********************************************************************
*
* cedarGet2dParm   gets a scaled 2D parameter from a madrigal record
*
*  If 2D parm does not exist, returns array of double "missing"
*  If 2D parm = -32767 (missing), returns double "missing"
*  If 2D parm is an error code, and = -32766 (assumed), returns double "assumed"
*  If 2D parm is an error code, and = +32767 (known bad), returns double "knownbad"
*
*  Otherwise, scales value and includes additional increment values
*  if they exist
*
*  This methods allocates dynamic memory for the array of doubles
*  returned.  The caller of this method is responsible for
*  calling free to release this memory when finished with it.
*
*  If nrow = 0, returns NULL pointer.
*
*  If parcode not found, returns array of missing
*
*  If cedarp is a header or catalog record; warning is printed to std err
*  and returns NULL
*/

double * cedarGet2dParm(Int16 *cedarp, int parcode)
 
 

/***********************************************************************
*
* cedarGet2dParmValue   gets a single scaled 2D parameter from a madrigal record
*
*  If 2D parm does not exist, returns double "missing"
*  If 2D parm = -32767 (missing), returns double "missing"
*  If 2D parm is an error code, and = -32766 (assumed), returns double "assumed"
*  If 2D parm is an error code, and = +32767 (known bad), returns double "knownbad"
*  If row is greater than number of 2d rows, returns double "missing"
*
*  Otherwise, scales value and includes additional increment values
*  if they exist
*
*  This method differs from cedarGet2dParm in that it only returns a
*  single double from a single row, so no malloc/free is required.
*
*
*  If cedarp is a header or catalog record; warning is printed to std err
*  and returns missing
*/

double cedarGet2dParmValue(Int16 *cedarp, int parcode, int row)
 
 

/***********************************************************************
*
* cedarGetFlatParm   creates a flattened 2D parameter
*
*  If 1D parmeter exists, copies array of double of length nrow with
*  every value set to the 1D value.  If not, uses cedarGet2dParm.  Note
*  cedarGet2dParm returns all "missing" is parm not found.
*
*  This methods allocates dynamic memory for the array of doubles
*  returned.  The caller of this method is responsible for
*  calling free to release this memory when finished with it.
*
*  If nrow = 0, returns NULL pointer.
*
*  If parcode not found, returns array of missing
*/

double * cedarGetFlatParm(Int16 *cedarp, int parcode)
 
 

/***********************************************************************
*
* hasData   determines whether any non-missing data in a double array
*
*  Returns 0 if all data in 2d array of length nrow is missing, 1
*  otherwise.
*/

int hasData(int nrow, double * parp)
 
 

/***********************************************************************
*
* cedarGetParmCodeArray   gets parameter codes of all parameters
*                         in specp->pparms which are actually available
*                         from the current record.
*
*  User is responsible for calling free to release the returned
*  array of ints when finished with them.
*
*  Deprecated - use Maddata module instead
*/

int * cedarGetParmCodeArray(Int16 *cedarp, Ffspec *specp, int *nlines) {
 
 

/***********************************************************************
*
* cedarGetParmArray   flattens a subset of a CEDAR file
*
*  If record is rejected, nlinesp will be set to 0; returned
*     double array will be set to random values.
*
*  User is responsible for calling free to release the returned
*  array of doubles when finished with them.
*
*  Deprecated - use Maddata module
*/

double * cedarGetParmArray(Int16 *cedarp, Ffspec *specp, int *nlinesp)
 
 

/***********************************************************************
*
* cedarGetGeodetic   gets geodetic coordinates from radar coordinates
*
*  cedarGetGeodetic modifies the three arrays of doubles to return
*  lat, long, and alt.  Length of each array is nrows.  Geodetic
*  coordinates will be calculated in any of the following ways:
*
*     1) az, el, and range - az from azm, az1, or az2, and
*        el from elm, el, or el2
*     2) (altb, alte, or gdalt), gdlat and glon
*     3) (altb, altav or altb, alte, or gdalt) alone - lat and long assumed
*        to be that of instrument
*
*     If all three methods fail, all three arrays populated with missing
*
*     All parameters can be either 1d or 2d.
*
*  This methods allocates dynamic memory for the array of doubles
*  modified.  The caller of this method is responsible for
*  calling free to release the memory from these 3 arrays when
*  finished with them.
*
*  If nrow = 0, returns -1.
*/

int cedarGetGeodetic(Int16 *cedarp, double **gdlatpp, double **glonpp, double **gdaltpp)
 
 

/***********************************************************************
*
* cedarGet1dInt   gets a 1D parameter (unscaled) from a madrigal record
*
*/

Int16 cedarGet1dInt(Int16 *cedarp, int parcode)
 
 

/***********************************************************************
*
* cedarGet2dInt   gets a 2D parameter (unscaled) from a madrigal record
*
*  This method allocates dynamic memory for the array of ints
*  returned.  The caller of this method is responsible for
*  calling free to release this memory when finished with it.
*
*  If nrow = 0, returns NULL pointer.
*
*  If parcode not found, returns array of missingData
*/

Int16 * cedarGet2dInt(Int16 *cedarp, int parcode)
 
 

/***********************************************************************
*
* cedarGet2dIntValue   gets a single 2D parameter (unscaled) from a madrigal record
*
*  This method differs from cedarGet2dInt in that it only returns
*  a single unscaled Int16 from a particular row.
*
*  If nrow = 0,  or row > number of 2d rows, returns missingData.
*
*  If parcode not found, returns missingData
*/

Int16 cedarGet2dIntValue(Int16 *cedarp, int parcode, int row)
 
 

/***********************************************************************
*
* cedarCreateRecord  creates a new Cedar record
*
*   User is responsible for freeing dynamically allocated array
*   when finished with it.
*
*   If two many rows passed in to fit in Cedar format, then prints error
*   to stderr and returns NULL pointer
*/

Int16 *cedarCreateRecord(int lprol, int jpar, int mpar, int nrow,
                         int krec, int kinst, int kindat,
                         int year1, int month1, int day1,
                         int hour1, int minute1, int second1, int centisecond1,
                         int year2, int month2, int day2,
                         int hour2, int minute2, int second2, int centisecond2)
 
 

/***********************************************************************
*
* cedarCreateCatalogRecord  creates a new Cedar Catalog record
*
*   This method creates a catalog record with or without the actual text.
*   Users can also append text to this record by calling cedarAppendCatalogRecord
*
*   Inputs:
*
*       kinst - instrument code from instTab.txt
*       modexp - code describing the mode of the experiment
*       year1, month1, day1, hour1, minute1, second1, centisecond1 - starting time
*           of experiment
*       year2, month2, day2, hour2, minute2, second2, centisecond2 - starting time
*           of experiment
*       text - text to append.  See Cedar database format for suggested layout.
*              Must be multiple of 80 characters in length - no line feeds.  May
*              be empty, if user is planning to use cedarAppendCatalogRecord.
*
*   Returns - pointer to Int16 holding newly allocated catalog record. User is
*   responsible for freeing dynamically allocated array
*   when finished with it.
*/

Int16 *cedarCreateCatalogRecord(int kinst, int modexp,
                                int year1, int month1, int day1,
                                int hour1, int minute1, int second1, int centisecond1,
                                int year2, int month2, int day2,
                                int hour2, int minute2, int second2, int centisecond2,
				char * text)
 
 

/***********************************************************************
*
* cedarAppendCatalogRecord  appends text to an existing Catalog Record
*
*   Users should first create a catalog record by calling cedarCreateCatalogRecord
*
*   Inputs:
*
*       Int16 *cedarp - pointer to existing catalog record
*       char * text - text to append.  See Cedar database format for suggested layout.
*                     Must be multiple of 80 characters in length - no line feeds.
*
*   Returns: 0 if success, -1 if failure
*
*/
int cedarAppendCatalogRecord(Int16 **cedarpp, char * text)
 
 

/***********************************************************************
*
* cedarCreateHeaderRecord  creates a new Cedar Header record
*
*   This method creates a header record with or without the actual text.
*   Users can also append text to this record by calling cedarAppendHeaderRecord
*
*   Inputs:
*
*       kinst - instrument code from instTab.txt
*       kindat - code describing the kind of data
*       year1, month1, day1, hour1, minute1, second1, centisecond1 - starting time
*           of experiment
*       year2, month2, day2, hour2, minute2, second2, centisecond2 - starting time
*           of experiment
*       jpar - number of single-valued parameters in accompanying data records
*       mpar - number of multiple-valued parameters in accompanying data records
*       text - text to append.  See Cedar database format for suggested layout.
*              Must be multiple of 80 characters in length - no line feeds.  May
*              be empty, if user is planning to use cedarAppendHeaderRecord.
*
*   Returns - pointer to Int16 holding newly allocated header record. User is
*   responsible for freeing dynamically allocated array
*   when finished with it.
*/

Int16 *cedarCreateHeaderRecord(int kinst, int kindat,
                                int year1, int month1, int day1,
                                int hour1, int minute1, int second1, int centisecond1,
                                int year2, int month2, int day2,
                                int hour2, int minute2, int second2, int centisecond2,
				int jpar, int mpar,
				char * text)
 
 

/***********************************************************************
*
* cedarAppendHeaderRecord  appends text to an existing Header Record
*
*   Users should first create a header record by calling cedarCreateHeaderRecord
*
*   Inputs:
*
*       Int16 *cedarp - pointer to existing header record
*       char * text - text to append.  See Cedar database format for suggested layout.
*                     Must be multiple of 80 characters in length - no line feeds.
*
*   Returns: 0 if success, -1 if failure
*
*/
int cedarAppendHeaderRecord(Int16 **cedarpp, char * text)
 
 

/***********************************************************************
*
* cedarSetKrec   sets Kind of record
*
*/

int cedarSetKrec (Int16 *cedarp, int krec)
 
 

/***********************************************************************
*
* cedarSetKinst   sets instrument code for these data
*
*/

int cedarSetKinst (Int16 *cedarp, int kinst)
 
 

/***********************************************************************
*
* cedarSetKindat   sets kind-of-data code
*
*/

int cedarSetKindat (Int16 *cedarp, int kindat)
 
 

/***********************************************************************
*
* cedarSetStartTime   sets start time of record
*
*/

int cedarSetStartTime (Int16 *cedarp, int year, int month, int day,
                       int hour, int minute, int second, int centisecond)
 
 

/***********************************************************************
*
* cedarSetEndTime   sets end time of record
*
*/

int cedarSetEndTime (Int16 *cedarp, int year, int month, int day,
                     int hour, int minute, int second, int centisecond)
 
 

/***********************************************************************
*
* cedarSet1dParm   sets a 1D parameter in a Cedar record
*
*   Inputs:
*       Int16 *cedarp - pointer to existing Cedar record
*       int parcode   - Cedar parmater code
*       double parm   - doubles containing value to set.Special values
*                       may be set by setting values to #defines
*                       missing, assumed, or knownbad
*       int index     - index of which 2d parameter to set
*
*   Returns 1 if failure, 0 if success.  If value out of Int16 range, will set
*   value to missing and return failure.
*/

int cedarSet1dParm(Int16 *cedarp, int parcode, double parm, int index)
 
 

/***********************************************************************
*
* cedarSetNorm1dParm   sets a 1D parameter in a Cedar record with the units
*                      of the standard parameter even if additional increment parameter
*
*   Inputs:
*       Int16 *cedarp - pointer to existing Cedar record
*       int parcode   - Cedar parmater code
*       double parm   - doubles containing value to set.Special values
*                       may be set by setting values to #defines
*                       missing, assumed, or knownbad
*       int index     - index of which 2d parameter to set
*
*   Returns 1 if failure, 0 if success.  If value out of Int16 range, will set
*   value to missing and return failure.
*/

int cedarSetNorm1dParm(Int16 *cedarp, int parcode, double parm, int index)
 
 

/***********************************************************************
*
* cedarSet2dParm   sets all values for a 2D parameter in a cedar record
*
*   Inputs:
*       Int16 *cedarp - pointer to existing Cedar record
*       int parcode   - Cedar parmater code
*       double *parmp - array of doubles containing values to set.  Length
*                       must be nrow.  Special values may be set by setting
*                       values to #defines missing, assumed, or knownbad
*       int index     - index of which 2d parameter to set
*
*   Returns 1 if failure, 0 if success. If any value out of Int16 range, will set
*   value to missing, but all valid values will still be set.  Returns 1 if any
*   out of range data found.
*
*/

int cedarSet2dParm(Int16 *cedarp, int parcode, double *parmp, int index)
 
 

/***********************************************************************
*
* cedarSetNorm2dParm   sets all values for a 2D parameter in a cedar record
*                      with the units as standard parameter even if
*                      additional increment parameter
*
*   Inputs:
*       Int16 *cedarp - pointer to existing Cedar record
*       int parcode   - Cedar parmater code
*       double *parmp - array of doubles containing values to set.  Length
*                       must be nrow.  Special values may be set by setting
*                       values to #defines missing, assumed, or knownbad
*       int index     - index of which 2d parameter to set
*
*   Returns 1 if failure, 0 if success. If any value out of Int16 range, will set
*   value to missing, but all valid values will still be set.  Returns 1 if any
*   out of range data found.
*
*/

int cedarSetNorm2dParm(Int16 *cedarp, int parcode, double *parmp, int index)
 
 

/***********************************************************************
*
* cedarSet1dInt   puts a 1D parameter (unscaled) into a madrigal record
*
*/

int cedarSet1dInt(Int16 *cedarp, int parcode, Int16 int1d, int index)
 
 

/***********************************************************************
*
* cedarSet2dInt   puts a 2D parameter (unscaled) into a madrigal record
*
*/

int cedarSet2dInt(Int16 *cedarp, int parcode, Int16 *int2dp, int index)
 
 

/***********************************************************************
*
* cedarPrintRecord   prints cedar record
*
*/

int cedarPrintRecord(Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarGetInformation   gets Ascii Information from Catalog or Header record
*
*   inputs:  Int16 * cedarp (pointer to cedar record)
*
*   outputs:  char * (pointer to dynamically allocated string holding
*             ASCII text in catalog or header record, or empty string
*             if no text available.  Will return empty string if called
*             with a data record instead of a header or catalog record).
*             The string will have 81 characters for each line of
*             information - the first 80 characters will be the 80
*             characters in the file with unprintable characters converted
*             to spaces, and the 81st character a newline. After the last
*             line a null character is added to make a valid c string.
*
*  The user is resposible for freeing the returned string when finished
*  with it.
*
*/

char * cedarGetInformation(Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarPrintProlog   prints cedar record prolog
*
*/

int cedarPrintProlog(Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarReadParCodes   reads the following metadata tables:
*
*  1. parcods.tab  (parameter information)
*  2. instTab.txt   (instrument location)
*  3. madCatTab.txt  (parameter category information)
*
*   For the moment hard-coded to the column layout of parcods.tab
*      0-7     Code
*      10-48   Description   Note: DESC_LEN   = 40
*      50-60   Int16Desc     Note: DESC16_LEN = 12
*      62-68   ScaleFactor
*      70-77   Units         Note: UNIT_LEN   =  9
*      81-100  Mnemonic      Note: MNEM_LEN   = 21
*      105-112 Format
*      114-115 Width
*      118-120 CatId
*      122-122 hasDesc  - does this mnemonic have an html description?
*      124-124 hasErrDesc - does this error mnemonic have an html description?
*
*   Returns 0 if successful, non-zero and error set if not successful
*/

int cedarReadParCodes ()
 
 

/***********************************************************************
*
* cedarGetNumParCodes   Gets number of Cedar parameter codes in parcods.tab
*/

int cedarGetNumParCodes ()
 
 

/***********************************************************************
*
* cedarGetParCode   Gets Cedar parameter code from table given its position
*                   in file parcods.tab
*
*
*/

int
cedarGetParCode (int position)
 
 

/***********************************************************************
*
* cedarGetParCodeIndex   Gets index of Cedar parameter code in table, given its code
*
*   For a pure Madrigal parameter with code 0, will return missing.  Use
*   madGetParMnemIndex instead.  For a negative parcode, will return negitive
*   of index found.  If not found, returns missingData.
*
*   No longer requires that parcods.tab be in order.
*/

int cedarGetParCodeIndex (int parcode)
 
 

/***********************************************************************
*
*  madGetParMnemIndex   Gets index of Madrigal parameter code in table, given its mnemonic
*
*   Returns the index of the specified mnemonic.  Matching is case-insensitive, and
*   ignores whitespace. If not found and begins with "D", will next search with "D"
*   removed, and return the negitive of the index found.  If still not found,
*   returns missingData.
*
*/
int madGetParMnemIndex (char * mnem)
 
 

/***********************************************************************
*
*  isMadparmError   returns 1 if this is an error parm, 0 if standard,
*                   -1 if neither
*
*
*/
int isMadparmError(const char * mnem)
 
 

/***********************************************************************
*
*  getStdMnem   converts a str to standard mnemonic form
*
*   Inputs: const char * mnem    - the string containing the mnemonic to be converted
*           char * stdMnem - a string to copy the standard form of the
*                            mnemonic to.  Allocated by the user.  At most
*                            MNEM_LEN - 1 characters will be copied.  Std form
*                            strips all whitespace and is upper case.
*
*/

void getStdMnem (const char * mnem, char * stdMnem)
 
 

/***********************************************************************
*
* cedarGetParCodeType   Gets type of Cedar parameter code from table, given its code.
*
*   For a pure Madrigal parameter with code 0, will return first found.  Use
*   madGetParMnemType instead.  If not in parcods.tab but in a standard range,
*   as defined by madCatTab.txt will return Cedar values.  If not in parcodes
*   and not in any standard range, will return "Unknown Parameter Type"
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.
*/

char * cedarGetParCodeType (int parcode)
 
 

/***********************************************************************
*
* madGetParMnemType   Gets type of Madrigal parameter from table, given its mnemonic.
*
*   If mnemonic not in parcods.tab, will return "Unknown Parameter Type"
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.
*/

char * madGetParMnemType (char * mnem)
 
 

/***********************************************************************
*
* madGetCategoryIndex   Gets the index of a given Category name.
*
*   If category string not found, returns missingData
*   Matching is case and whitespace sensitive
*
*/

int madGetCategoryIndex (char * category)
 
 

/***********************************************************************
*
* cedarGetParDescription   Gets Cedar parameter code description from
* table
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.
*
*
*/

char * cedarGetParDescription (int parcode)
 
 

/***********************************************************************
*
* madGetParDescription   Gets Madrigal parameter code description from
* table, given mnemonic
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.
*
*/

char * madGetParDescription (char * mnem)
 
 

/***********************************************************************
*
* cedarGetParInt16Description   Gets Cedar parameter code Int16
*                               description from table
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.
*/

char * cedarGetParInt16Description (int parcode)
 
 

/***********************************************************************
*
* madGetParInt16Description   Gets Madrigal parameter code Int16
*                               description from table, given mnemonic
*
*/

char * madGetParInt16Description (char * mnem)
 
 

/***********************************************************************
*
* cedarGetParScaleFactor   Gets Cedar parameter scale factor from table
*
*/

double cedarGetParScaleFactor (int parcode)
 
 

/***********************************************************************
*
* madGetParScaleFactor   Gets Madrigal parameter scale factor from table,
*                        given mnemonic
*
*/

double madGetParScaleFactor (char * mnem)
 
 

/***********************************************************************
*
* cedarGetNormScaleFactor   Gets Cedar parameter scale factor, where additional
*                           increment parameters use the same units as main
*                           parameter.  Differs from cedarGetParScaleFactor, which
*                           returns scale factors for additional increment parameters
*                           that may have different units than the main parameter.
*
*/

double cedarGetNormScaleFactor (int parcode)
 
 

/***********************************************************************
*
* madGetNormScaleFactor   Gets Madrigal parameter scale factor, where additional
*                           increment parameters use the same units as main
*                           parameter.  Differs from cedarGetParScaleFactor, which
*                           returns scale factors for additional increment parameters
*                           that may have different units than the main parameter.
*
*/

double madGetNormScaleFactor (char * mnem)
 
 

/***********************************************************************
*
* cedarGetParUnits   Gets Cedar parameter code units from table
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.
*/

char * cedarGetParUnits (int parcode)
 
 

/***********************************************************************
*
* madGetParUnits   Gets Madrigal parameter code units from table,
*                  given mnemonic
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.
*/

char * madGetParUnits (char * mnem)
 
 

/***********************************************************************
*
* cedarGetParMnemonic   Gets Cedar parameter code mnemonic from table
*
*   User is responsible for freeing dynamically allocated string
*   when finished with it.  If parcode 0 passed in, first Madrigal
*   parameter found will be returned.
*
*   If unknown parcode passed in, mnemonic is atoi(parcode)
*/

char * cedarGetParMnemonic (int parcode)
 
 

/***********************************************************************
*
* cedarGetParCodeFromMnemonic   Gets Cedar parameter code given mnemonic
*
*   If mnemonic is integer in form of string, returns that integer
*   If not found, returns missingData
*
*/

int cedarGetParCodeFromMnemonic (char * mnem)
 
 

/***********************************************************************
*
* cedarGetParFormat   Gets Cedar parameter code format from table.
*
*   If not found, returns NULL
*/

char * cedarGetParFormat (int parcode)
 
 

/***********************************************************************
*
* madGetParFormat   Gets Madrigal parameter format from table (given mnemonic)
*
*   If not found, returns NULL
*/

char * madGetParFormat (char * mnem)
 
 

/***********************************************************************
*
* cedarGetParWidth   Gets Cedar parameter field width from table
*
*    If unknown, returns default value of 11
*
*/

int cedarGetParWidth (int parcode)
 
 

/***********************************************************************
*
* madGetParWidth   Gets Madrigal parameter field width from table,
*                  given mnemonic
*
*    If unknown, returns default value of 11
*/

int madGetParWidth (char * mnem)
 
 

/***********************************************************************
*
* cedarHasHtmlDesc   Returns 1 if parameter has entry in Html description
*                    page, 0 if not.  Works also for error codes (< 0)
*
*    If unknown, returns default value of 0
*
*/

int cedarHasHtmlDesc(int parcode)
 
 

/***********************************************************************
*
* madHasHtmlDesc   Returns 1 if mnemonic has entry in Html description
*                    page, 0 if not.  Works also for error mnemonics.
*
*    If unknown, returns default value of 0
*/

int madHasHtmlDesc (char * mnem)
 
 

/***********************************************************************
*
* cedarCheckRecord   checks cedar record for consistency
*
*/

int cedarCheckRecord (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarHexPrintRecord   prints hex version of record
*
*/

int cedarHexPrintRecord (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarDecimalPrintRecord   prints hex version of record
*
*/

int cedarDecimalPrintRecord (Int16 *cedarp)
 
 

/***********************************************************************
*
* cedarSetError   sets cedar error
*
*/

int cedarSetError (const char *error)
 
 

/***********************************************************************
*
* cedarGetError   gets last cedar error
*
*/

char * cedarGetError ()
 
 

/***********************************************************************
*
* cedarTabInt   linear interpolation routine
*
* tabint interpolates linearly to calculate y(x) from a table
* containing nt independent variable values xt and dependent
* variable values yt. the xt are assumed to be in non-decreasing
* order.
*
*/

double cedarTabInt (int nt, double *xt, double *yt, double x, double badval)
 
 

/***********************************************************************
*
* cedarUpdateParmsList   Updates list of parameters and their minimum
*                        and maximum values
*
*   The first eleven parameters are effectively derived:
*   [0] 10: year, [1] 11: month,  [2] 12: day
*   [3] 13: hour, [4] 14: minute, [5] 15: second,
*   [6] 16: centisecond [7] 34: uth, [8] 160: gdlat,
*   [9] 170: glon, [10] 110: gdalt
*
*   All parameters actually in the file will be listed starting with
*   the 12th.  If any of the above parameters are actually in the file
*   itself, they will appear again.
*
*   Does not include data from 2D rows if all error parameters are
*   missing of knownbad
*
*   Also updates earliestStartTime, latestEndTime, and lists of
*   all kinsts and kindats found in file.
*
*   If header or catalog record, returns 0 immediately without making
*   any changes.
*
*/

int cedarUpdateParmsList(Int16 *cedarp, int *numParmsp,
                         int *parmsListpp[], int *parmLocpp[],
                         double *parmMinpp[], double *parmMaxpp[], int *parmMissing[],
                         int *startJday0,
                         double * earliestStartTime, double * latestEndTime,
                         int * numKinst, int * kinstArr,
                         int * numKindat, int * kindatArr)
 
 

/***********************************************************************
*
*  cedarGetStationPos  Gets instrument coordinates for a given kinst
*
*      Uses data from metadata/instTab.txt
*
*/

void cedarGetStationPos(int kinst, double * lat, double * lon, double * alt)
 
 

/***********************************************************************
*
*  cedarGetStationName  Gets instrument name for a given kinst
*
*      Uses data from metadata/instTab.txt
*
*/

char * cedarGetStationName(int kinst)
 
 

/***********************************************************************
*
* searchFilesByDate    searches the metadata for all files between
*                      starttime and endtime.
*
*   arguments:
*       double starttime: seconds since 1/1/1950.
*       double endtime: seconds since 1/1/1950.
*       int * numFilesFound: pointer to int, set to number of files found
*       char ** fileList: pointer to char pointer to be allocated and
*                         populated with a comma-delimited list of full
*                         paths to files found
*       double ** fileStarttime: pointer to double array to be allocated and
*                                populated with start times of each file found
*                                (number of seconds since 1/1/1950)
*       double ** fileEndtime: pointer to double array to be allocated and
*                              populated with end times of each file found
*                              (number of seconds since 1/1/1950)
*
*       To be found, the file must start after starttime and end before endtime.
*       File must also be a default file.
*
*       User must free fileList, fileStarttime, fileEndtime if numFilesFound > 0
*
*   returns: 0 if success, non-zero and error set if not successful
*
*/
int searchFilesByDate(double starttime,
                      double endtime,
                      int * numFilesFound,
                      char ** fileList,
                      double ** fileStarttime,
                      double ** fileEndtime)
 
 

/***********************************************************************
*
* loadExpFileTable    Loads data from expTab.txt and fileTab.txt into
*                     global data. Private method - do not call directly.
*
*   arguments: None
*
*   returns: 0 if success, non-zero and error set if not successful
*
*   Affects: loads global data that deals with expTab and fileTab
*
*/
int loadExpFileTable()
 
 

/***********************************************************************
*
* goodDataExists    Returns 1 if record contains valid data at 2d parameter
*                   index index2D.  Valid data is when the absolute value
*                   of any error parameter is not missing or knownbad.
*                   If no error parameters, always returns 1.
*                   0 otherwise.
*
*   arguments:
*       record pointer to Madrigal record
*       index into 2D parameter values
*
*   returns:
*       1 if 2d index contains valid data,
*       0 if not
*
*/
int goodDataExists(Int16 * recordp, int index2D)
 
 

/***********************************************************************
* 
* sprod calculates the scalar product of two vectors a and b,
* sprod = a .dot. b.
*/
double
sprod(double *a, double *b)
 
 

/***********************************************************************
*      
* vadd calculates the sum of two vectors a and b, c = a + b.
*/
int 
vadd(double *a, double *b, double *c)
 
 

/***********************************************************************
*
* vsub calculates the difference of two vectors a and b, c = a - b.
*/
int
vsub(double *a, double *b, double *c)
 
 

/***********************************************************************
*
* csconv converts between cartesian coordinates x,y,z and spherical
* coordinates r,theta,phi. if imode=1, (x,y,z) -> (r,theta,phi).
* if imode=2, (r,theta,phi) -> (x,y,z). theta and phi are in
* degrees.
*/
int
csconv(double *xp, double *yp, double *zp,
       double *rp, double *thetap, double *phip,
       int imode)
 
 

/***********************************************************************
*
* vctcnv converts between the cartesian and spherical coordinate
* representations of a vector field f. (fx,fy,fz) are the
* components of the field at (x,y,z). (fr,ft,fp) are the
* components of the field at (r,theta,phi) in the directions of
* increasing r, increasing theta and increasing phi. if imode=1,
* (fx,fy,fz,x,y,z) -> (fr,ft,fp,r,theta,phi). if imode=2,
* (fr,ft,fp,r,theta,phi) -> (fx,fy,fz,x,y,z). theta and phi are
* in degrees.
*/
int
vctcnv(double *fxp, double *fyp, double *fzp,
       double *xp, double *yp, double *zp,
       double *frp, double *ftp, double *fpp,
       double *rp, double *thetap, double *phip,
       int imode)
 
 

/***********************************************************************
*
* point calculates the position of a point defined by the radar
* line-of sight vector to that point.
* 
* input parameters
*    sr    - distance of station from center of earth (km)
*    slat  - geocentric latitude of station (deg)
*    slon  - longitude of station (deg)
*    az    - radar azimuth (deg)
*    el    - radar elevation (deg)
*    range - radar range (km)
* 
* output parameters
*    pr    - distance from center of earth of observation point (km)
*   glat  - observation point geocentric latitude (deg)
*    glon  - observation point longitude (deg)
*/
int
point(double *srp, double *slatp, double *slonp,
      double *azp, double *elp, double *rangep,
      double *prp, double *glatp, double *glonp)
 
 

/***********************************************************************
*
* look calculates the azimuth, elevation and range from a radar
* of a specified point.
* 
* input parameters
*    sr    - distance of station from center of earth (km)
*    slat  - geocentric latitude of station (deg)
*    slon  - longitude of station (deg)
*    pr    - distance from center of earth of observation point (km)
*    glat  - observation point geocentric latitude (deg)
*    glon  - observation point longitude (deg)
* 
* output parameters
*    az    - radar azimuth (deg)
*    el    - radar elevation (deg)
*    range - radar range (km)
*/
int
look(double *srp, double *slatp, double *slonp,
     double *prp, double *glatp, double *glonp,
     double *azp, double *elp, double *rangep)
 
 

/***********************************************************************
*
* convrt converts between geodetic and geocentric coordinates. the
* reference geoid is that adopted by the iau in 1964. a=6378.16,
* b=6356.7746, f=1/298.25. the equations for conversion from
* geocentric to geodetic are from astron. j., vol 66, 1961, p. 15.
*      i=1   geodetic to geocentric
*      i=2   geocentric to geodetic
*    gdlat   geodetic latitude (degrees)
*    gdalt   altitude above geoid (km)
*    gclat   geocentric latitude (degrees)
*      rkm   geocentric radial distance (km)
*/
int
convrt(int i, double *gdlatp, double *gdaltp,
       double *gclatp, double *rkmp)

 
 

/***********************************************************************
*
* rpcart computes the components (rfx,rfy,rfz) relative to an earth
* centered cartesian coordinate system of the radar line of sight
* vector from a radar with coordinates sr (distance from center
* of earth), slat (geocentric latitude) and slon (longitude). the
* observation point is specified by az (azimuth), el (elevation) and
* range (range). the cartesian coordinates of the observation
* point are returned in (pfx,pfy,pfz).
*    input - sr,slat,slon,az,el,range
*    output - rfx,rfy,rfz,pfx,pfy,pfz
*/
int
rpcart (double *srp,  double *slatp, double *slonp,
        double *azp,  double *elp,   double *rangep,
        double *rfxp, double *rfyp,  double *rfzp,
        double *pfxp, double *pfyp,  double *pfzp)
 
 

/***********************************************************************
*
* gdv converts a vector field f at geodetic latitude gdlat and
* geocentric latitude gclat from a geocentric based representation
* to a geodetic based representation. the geocentric components
* are fr (radial outward), ft (increasing geocentric colatitude,
* e.g. southward) and fp (increasing east longitude). the
* geodetic components are fx (northward, parallel to surface of
* earth), fy (eastward, parallel to surface of earth) and fz
* (downward, perpendicular to surface of earth). fr,ft,fp thus
* correspond to spherical coordinates r,theta,phi, with their
* origin at the center of the earth. x,y,z are the coordinates
* customarily used to describe the three components of the
* geomagnetic field. fp and fy are the same.
*/
int
gdv(double *gdlatp, double *gclatp,
    double *frp, double *ftp, double *fpp,
    double *fxp, double *fyp, double *fzp)
 
 

/***********************************************************************
*
* los2geodetic calculates the position of a point defined by an instrument
* line-of sight vector to that point. This is a convenience routine in
* which the instrument location is specified by its CEDAR instrument code
* and which returns the geodetic coordinates of the point.
* 
* 
* input parameters
*    kinst - instrument code in metadata
*    az    - radar azimuth (deg)
*    el    - radar elevation (deg)
*    range - radar range (km)
* 
* output parameters
*    gdlat - observation point geodetic latitude (deg)
*    glon  - observation point longitude (deg)
*    gdalt - altitude above geoid (km)
*/

int los2geodetic(int kinst, double az, double el, double range,
             double *gdlatp, double *glonp, double *gdaltp)
 
 

/***********************************************************************
*
* solarzen_az calculates the solar zenith and az angles for a given time, gdlat,
*          and glon.
* 
* 
* input parameters
*    double ut    - Universal time in seconds since 1950
*    double gdlat - geodetic latitude in degrees
*    double glon  - geodetic longitude in degrees
* 
* output parameters
*    szen - solar zenith angle (deg, 0=directly overhead)
*    saz  - solar azimuth angle (deg, N=0, E=90)
*    
*
*    Solar zenith angle is calculated at 0 alt, although this changes
*    very little with altitute.  No atmospheric correction is applied.
*    This method uses solpos.c, written by National Renewable Energy
*    Laboratory.
*
*    This method is a modified version of  stest.c found at 
*    http://rredc.nrel.gov/solar/codes_algs/solpos/
*/
void solarzen_az(double ut, double gdlat, double glon, double * szen, double * saz)
 
 

/***********************************************************************
*
* solardist calculates the distance in km from the center of the earth
*          to the center of the sun at time ut.
* 
* 
* input parameters
*    double ut    - Universal time in seconds since 1950
* 
* returns double - distance in km from the center of the earth
*          to the center of the sun at time ut
*
*    This method is taken from "Practical Astronomy with Your
*    Calculator" 2nd edition, Peter Duffett-Smith, p. 80-87.
*/
double solardist(double ut)
 
 

/***********************************************************************
*
* shadowheight calculates the distance directly above any gdlat and glon
*              for a given UT in km at which the earth's shadow terminates.
*              Will be 0.0 on dayside of earth.
* 
* 
* input parameters
*    double ut    - Universal time in seconds since 1950
*    double gdlat - geodetic latitude in degrees
*    double glon  - geodetic longitude in degrees
* 
* returns double - distance directly above any gdlat and glon
*              for a given UT in km at which the earth's shadow terminates.
*              Will be 0.0 on dayside of earth.
*
*    This method uses the results of solarzen and solardist to create a simple
*    cone on a sphere model of the earth's shadow.  Shadow height is defined as
*    the lowest elevation at which any part of the sun can be seen.  No atmospheric
*    bending of light is included. The radius of the earth is calculated at the 
*    tan point of the sun's rays.
*
*    Algorithm:
*
*    Solar Zenith Angle = Z
*    Solar Azimuth      =Az (0 = North, 90 = East)
*
*    Get latitude of tangent point of sun's rays:
*
*      = gdlat + cos(Az)*(Z-90.0)
*
*    Get earthRadius at that point using convrt at gdlat = 0 (sea level)
*
*    ConeHalfAngle = C = atan((sunRadius - earthRadius)/soldist)
*
*
*                               (cos Z tan C + 1 - sin Z)
*    Shadowheight = earthRadius -------------------------
*                                  (sin Z - cos Z tan C)
*
*    Daytime (Shadowheight = 0) if numerator negitive or if
*    Z <= 91.0.
*/
double shadowheight(double ut, double gdlat, double glon)
 
 

/***********************************************************************
*
* sunrise_set calculates the time UT  of ionospheric sunrise
*             and sunset.
* 
* 
* input parameters
*    double ut    - Universal time in seconds since 1950
*    double gdlat - geodetic latitude in degrees
*    double glon  - longitude in degrees
*    double gdalt - geodetic altitude in km
*    double * sunrise - pointer to double allocated by user to be
*                       set to sunrise time UT 
*    double * sunset - pointer to double allocated by user to be
*                       set to sunset time UT 
* 
* returns void
*
*    If either sunrise or sunset not found, set to missing.
*    All times in seconds since 1/1/1950
*
*  Algorithm:
*
*    Depends on shadowheight calculation, so limitations discussed
*    there apply (atmospheric bending of light ignored).
*
*    If glon < 0:
*      solar midnight = UT - glon*24/360
*      solar noon     = UT + 12 - glon*24/360
*
*    If sun is not set at solar midnight (defined by shadowheight > gdalt),
*    or sun not up at solar noon, check if any difference between 0 and 24 UT.
*    If so, find only one of sunrise and sunset as described below, and set
*    the other to missing.  If not, return missing for both, because that point
*    is either in the sun or in the shadow all day.  The user must determine
*    which by comparing shadowheight and gdalt.  Otherwise, seek sunrise
*    between solar midnight and solar noon, slice remaining time in half each
*    guess.  Stop when time step less than 1 minute.
*    
*            If sun is up at 0 UT that day:  Seek sunset between 0.0 and
*    solar midnight as above.
*            Else: Seek sunset between solar noon and 24.0 as above.
*    
*    Else if glon > 0:
*        solar midnight = UT + 24 - glon*24/360
*        solar noon     = UT + 12 - glon*24/360
*    
*    If sun is not set at solar midnight (defined by shadowheight > gdalt),
*    or sun not up at solar noon, check if any difference between 0 and 24 UT.
*    If so, find only one of sunrise and sunset as described below, and set
*    the other to missing.  If not, return missing for both, because that point
*    is either in the sun or in the shadow all day.  The user must determine
*    which by comparing shadowheight and gdalt.  Otherwise, seek sunset
*    between solar noon and solar midnight, slice remaining time in half each
*    guess.  Stop when time step less than 1 minute.
*    
*            If sun is up at 0 UT that day:  Seek sunrise between solar
*    midnight and 24.0 as above.
*    
*            Else: Seek sunrise between 0.0 and solar noon as above.
*
*   Note: day is divided 11 times to ensure greater than one minute resolution.
*/
void sunrise_set(double ut,
                 double gdlat, 
                 double glon,
                 double gdalt,
                 double * sunrise,
                 double * sunset)
 
 

/***********************************************************************
*  jday  - returns Julian day number given day, month, and year
*  
*    Julian day 0 is Nov. 24, -4713
*
*    Returns -1 if illegal year, month, day passed in
*/
int jday(int day, int month, int year)
 
 

/***********************************************************************
*  jdater - sets day, month and year given jdayno
* 
*    Inverse of jday method
*/
    int jdater (int jdayno, int *day, int *month, int *year)
 
 

/***********************************************************************
*
*  idmyck - returns 0 if valid day, month, and year
*
*/
int idmyck(int day, int month, int year)
 
 

/***********************************************************************
*
* dmadptr - returns number of seconds since 1/1/1950 for iyr, imd, ihm, ics
*           as double
*
*    Can retain fractions of a second
*
*    Inputs: iyr - year
*            imd - month/day as integer mmdd
*            ihm - hour/min as integer hhmm
*            ics - centiseconds since last minute
*
*/
double dmadptr(int iyr, int imd, int ihm, int ics)
 
 

/***********************************************************************
*
* getKey - returns number of seconds since 1/1/1950 for year,
*          month, day, hour, minute, second
*
*/
double getKey(int year, int month, int day,
           int hour, int minute, int second)
 
 

/***********************************************************************
*
* dinvmadptr - sets iyr, imd, ihm, ics given dmadptr (number of seconds 
*              as a double since 1/1/1950)
*
*    inverse of dmadptr.  
*
*    Returns 0 if success, 1 if failure (out of range time)
*    Uses time.h, and constant to shift from 1/1/1970 to 1/1/1950
*/
int dinvmadptr(double dmadptr, int * iyr, int * imd, int * ihm, int * ics)
 
 

/***********************************************************************
*
* madGetDayno - gets day number (1-366) given year, month, and day
*
*
*    Returns -1 if illegal year, month, day passed in
*/
int madGetDayno(int year, int month, int day)

 


The maddata module

createMadparmList copyMadparmList destroyMadparmList appendMadparm hasParm
isErrorParm getIndex getMinParm getMaxParm analyzeFileParms
getDerivedParms createMadfilterList destroyMadfilterList appendMadfilter copyMadfilterList
getMadfilterListFromStr createMaddata createNonfileMaddata destroyMaddata appendMadrecParmType
appendMadcycle createMadcycle destroyMadcycle createMadrecord destroyMadrecord
simpleMadrecordPrint simpleMadfilterPrint simpleMaddataPrint classicIsprint printIsprintHeader
getIsprintHeader printIsprintLabel getIsprintLabel classicMadrecordPrint getClassicMadrecordStrings
lookerMadrecordPrint populate1DDataFromStr populate2DDataFromStr

/***********************************************************************
*
* createMadparmList   initializes a new MadparmList
*
*   arguments: None
*
*   returns - pointer to newly created MadparmList.  Use 
*             destroyMadparmList when done
*/
MadparmList * createMadparmList()
 
 

/***********************************************************************
*
* copyMadparmList   copies an existing MadparmList
*
*   arguments: Pointer to existing MadparmList
*
*   returns - pointer to newly copied MadparmList, newly allocated
*             on the heap.  Use destroyMadparmList when done
*             Returns NULL if NULL passed in
*/
MadparmList * copyMadparmList(MadparmList * madparmList)
 
 

/***********************************************************************
*
* destroyMadparmList   releases an existing MadparmList
*
*   arguments: pointer to existing MadparmList
*
*   returns - void
*/
void destroyMadparmList(MadparmList * madParmList)
 
 

/***********************************************************************
*
* appendMadparm   adds a new parameter to the MadparmList
*
*   arguments: MadparmList * madparmList - pointer to existing MadparmList
*              const char * mnem - string containing name
*
*      mnem is copied into newly allocated memory, so user is free to
*      release mnem after this method.  mnem converted to standard form.
*
*   returns - 0 if success, -1 if failure (if mnem too long or unknown)
*/
int appendMadparm(MadparmList * madparmList, const char * mnem)
 
 

/***********************************************************************
*
*  hasParm   returns 1 if madparmList has parameter, 0 otherwise
*
*   arguments: MadparmList * madparmList - pointer to existing MadparmList
*              const char * mnem - string containing name
*
*      comparision is done after coverting mnem to standard form
*
*   returns - 0 if success, -1 if failure (if mnem too long)
*/
int hasParm(MadparmList * madparmList, const char * mnem)
 
 

/***********************************************************************
*
*  isErrorParm   returns 1 parameter at index is error, 0 if standard
*
*   arguments: MadparmList * madparmList - pointer to existing MadparmList
*              int index - index into madparmList
*
*   returns - 1 parameter at index is error, 0 if standard, -1 if
*             index out of bounds
*/
int isErrorParm(MadparmList * madparmList, int index)
 
 

/***********************************************************************
*
*  getIndex   returns index of parameter if found, -1 otherwise
*
*   arguments: MadparmList * madparmList - pointer to existing MadparmList
*              const char * mnem - string containing name
*
*      comparision is done after coverting mnem to standard form
*
*   returns - index of parameter if found, -1 otherwise
*/
int getIndex(MadparmList * madparmList, const char * mnem)
 
 

/***********************************************************************
*
*  getMinParm   returns minimum value of mnem, or missing if unknown
*
*   arguments: MadparmList * madparmList - pointer to existing MadparmList
*              char * mnem - string containing name of parameter
*
*   returns - minimum value of mnem, or missing if unknown or not in list
*/
double getMinParm(MadparmList * madparmList, char * mnem)
 
 

/***********************************************************************
*
*  getMaxParm   returns maximum value of mnem, or missing if unknown
*
*   arguments: MadparmList * madparmList - pointer to existing MadparmList
*              char * mnem - string containing name of parameter
*
*   returns - maximum value of mnem, or missing if unknown or not in list
*/
double getMaxParm(MadparmList * madparmList, char * mnem)
 
 

/***********************************************************************
*
* analyzeFileParms   get 4 lists of parameters from file:
*                     1) all 1D measured parameters
*                     1) all 2D measured parameters
*                     1) all 1D derivable parameters
*                     1) all 2D derivable parameters
*
*   arguments: char * filename - full path to file
*              MadparmList * list1DMeasParms - pointer to MadparmList to be
*                  populated with all 1D measured parameters found in file 
*              MadparmList * list2DMeasParms - pointer to MadparmList to be
*                  populated with all 2D measured parameters found in file 
*              MadparmList * list1DDervParms - pointer to MadparmList to be
*                  populated with all 1D parameters that could be derived
*              MadparmList * list2DDervParms - pointer to MadparmList to be
*                  populated with all 2D parameters that could be derived
*              FILE * errFile   - errFile to write an error messages to
*
*   returns - 0 if success, -1 otherwise
*
*   affects - populates the four input lists.  All four pointers should point
*   to NULL when passed in.  When done with these four lists, user should call
*   destroyMadparmList for each to free memory.
*
*   Note: Since a file may contain more than one type of record, these lists contain
*   parameters from any record that fits into each list.  For example, a certain 1D 
*   parameter is measured in one type of record, but can be derived from another type
*   where its not measured, that parameter would appear in both list1DMeasParms and
*   list1DDervParms.  
*
*   See also method getDerivableParms, which accepts two lists of measured 1D and 
*   measured 2D parameters, and returns two lists of derivable 1D and 
*   derivable 2D parameters.  Since this other method does not analyze a file, it does not
*   have the ambiguities of analyzeFileParms discussed above.
*/
int analyzeFileParms(char * filename, 
                     MadparmList ** list1DMeasParms,
                     MadparmList ** list2DMeasParms,
                     MadparmList ** list1DDervParms,
                     MadparmList ** list2DDervParms,
                     FILE * errFile)
 
 

/***********************************************************************
*
* getDerivedParms   gets a list of derivable parameters given a list of
*                   measured parameters
*
*   arguments: MadparmList * listMeasParms - pointer to MadparmList 
*                  containing measured parameters
*
*   returns - MadparmList * listDervParms - pointer to MadparmList 
*                  containing all parameters that could be derived.
*                  User is responsible for calling destroyMadparmList
*                  when done with this list
*
*/
MadparmList * getDerivedParms(MadparmList * listMeasParms)
 
 

/***********************************************************************
*
* createMadfilterList   initializes a new MadfilterList
*
*   arguments: None
*
*   returns - pointer to newly created MadfilterList.  Use 
*             destroyMadfilterList when done
*/
MadfilterList * createMadfilterList()
 
 

/***********************************************************************
*
* destroyMadfilterList   releases an existing MadfilterList
*
*   arguments: pointer to existing MadfilterList
*
*   returns - void
*/
void destroyMadfilterList(MadfilterList * madFiltList)
 
 

/***********************************************************************
*
* appendMadfilter   adds a new Madfilter to the MadfilterList
*
*   arguments: MadfilterList * madfilt_list - pointer to existing MadfilterList
*              Filter_type filtType - enum used to identify filter types
*              int numRange - number of ranges included - must be greater than 0
*              double * lower - array of lower limits of range - if "missing", no 
*                               lower limit for that range
*              double * upper - array of upper limits of range - if "missing", no 
*                               upper limit for that range
*              char * - madParm1 - Mnemonic of first parameter - cannot be 0 length
*              char * - madParm2 - Mnemonic of second parameter - can be 0 length if SINGLE_FILT
*
*      lower, upper, madParm1 and madParm2 are copied into newly allocated memory, so user is free to
*      release them after this method.  madParm1 and madParm2 converted to standard mnemonic form.
*
*   returns - 0 if success, -1 if failure (if either mnemonic too long, if madfilt_list NULL,
*             or numRange < 1)
*/
int appendMadfilter(MadfilterList * madFiltList,
                    Filter_type filtType, 
                    int numRange,
                    double * lower, 
                    double * upper, 
                    char * madParm1,
                    char * madParm2)
 
 

/***********************************************************************
*
* copyMadfilterList   copies an existing MadfilterList
*
*   arguments: Pointer to existing MadfilterList
*
*   returns - pointer to newly copied MadfilterList, newly allocated
*             on the heap.  Use destroyMadfilterList when done
*             Returns NULL if NULL passed in
*/
MadfilterList * copyMadfilterList(MadfilterList * madfilterList)
 
 

/***********************************************************************
*
* getMadfilterListFromStr   creates a MadfilterList based on an isprint-like command string
*
*   arguments: str - an isprint-like command string
*
*      lower, upper, madParm1 and madParm2 are copied into newly allocated memory, so user is free to
*      release them after this method.  madParm1 and madParm2 converted to standard mnemonic form.
*
*      The filter string is the same string that is used in the new isprint
*      command line.  Filters are separated by spaces.  The allowed filters
*      are:  
*  
*         date1=mm/dd/yyyy  (starting date to be examined. If time1 not given, defaults to 0 UT.)
*            Example: date1=01/20/1998 
* 
*         time1=hh:mm:ss (starting UT time to be examined. If date1 given, is applied to date1.
*                         If not, applies on the first day of the experiment.)
*            Example: time1=13:30:00
* 
*         date2=mm/dd/yyyy (ending date to be examined.  If time2 not given, defaults to 0 UT.)
*            Example: date2=01/21/1998
*
*         time2=hh:mm:ss (ending UT time to be examined - If date2 not given, ignored.)
*            Example: time2=15:45:00
* 
*         In the follow arguments ranges are used.  If any range value is not given, it may be used to 
*         indicate no lower or upper limit (but the comma is always required). Ranges are inclusive
*         of the end points:
* 
*         z=lower alt limit1, upper alt limit1 [or lower alt limit2 , upper alt limit2 ...] (km)
*            Example 1: z=100,500  (This would limit the geodetic altitude to 100 to 500 km.)
*            Example 2: z=100,200or300,400  (This would limit the geodetic altitude to 100 to 200 km
*                                            or 300 to 400 km.)
*            Example 3: z=,200or300,400   (Since the lower limit of the first range is missing, this 
*                                          would limit the geodetic altitude to anything below 200 km 
*                                          or from 300 to 400 km.)
* 
*         az=lower az limit1, upper az limit1 [or lower az limit2 , upper az limit2 ...] (from -180 to 180 degrees)
*            Example 1: az=100,120  (This would limit the azimuth to 100 to 120 degrees.)
*            Example 2: z=-180,-90or90,180  (This would limit the azimuth to between -180 and -90 degrees or
*                                            to between 90 and 180 degrees.  Note this allows a filter to go
*                                            through 180 degrees.)
*  
*         el=lower el limit1, upper el limit1 [or lower el limit2 , upper el limit2 ...] (from 0 to 90) 
*            Example 1: z=0,45  (This would limit the elevation from 0 to 45 degrees.) 
* 
*         plen=lower pl limit1, upper pl limit1 [or lower pl limit2 , upper pl limit2 ...] (pulse len in sec)
*            Example 1: z=,5e-4  (This would limit the pulse length to 5e-4 seconds or less.)
*   
*   
*         Free form filters using any mnemonic, or two mnemonics added, subtracted, multiplied, or divided.
*         Any number of filters may be added: 
*  
*         filter=[mnemonic] or [mnemonic1,[+*-/]mnemonic2] , lower limit1 , upper limit1 [or lower limit2 , upper limit2 ...] 
*            Example 1: filter=ti,500,1000or2000,3000   (Limits the data to points where Ti is between 500 and 1000 degrees
*                                                      or between 2000 and 3000 degrees.  Note that the units are always
*                                                      those of the Cedar standard.)
*            Example 2: filter=gdalt,-,sdwht,0,    (This filter implies "gdalt - sdwht" must be greater than 0.0.  Since
*                                                   sdwht is shadow height - the distance above any point on the earth 
*                                                   where the sun is first visible - this filter implies that only data 
*                                                   in direct sunlight will be displayed.)
*            Example 3: filter=ti,/,Dti,100,   (Limits the data to points where the ratio Ti/dTi is more than 100.)
*   
*         So an full FLTSTR argument might be:
*      
*            "date1=01/20/1998 time1=13:30:00 z=,200or300,400 filter=gdalt,-,sdwht,0, filter=ti,/,Dti,100,"
*
*   returns - MadfilterList if success, NULL if failure
*/
MadfilterList * getMadfilterListFromStr(char * str)
 
 

/***********************************************************************
*
* createMaddata   creates a new Maddata
*
*   arguments:
*
*     char * filename - full path to the file which was basis of data 
*     char * infoStr  - Information string (may be used in outputing formatted data)
*     MadparmList *   madparmList - list of Madrigal parameters desired
*     MadfilterList * madFiltList - list of Madfilters to apply
*     FILE * errFile   - errFile to write an error messages to
*
*
*   returns - pointer to newly created Maddata.  Use 
*             destroyMaddata when done
*
*   Allocates memory to store all data, so all input may be released or changed
*   after this method is called.  Maddata is the main data structure, and is meant 
*   to be the main way to expose Madrigal data from a single cedar file that 
*   applies filtering and calculates derived data.
*
*   Returns NULL if failure.
*/
Maddata * createMaddata(char * filename,
                        char * infoStr,
                        MadparmList * requestParmList,
                        MadfilterList * madfilterList,
                        FILE * errFile)
 
 

/***********************************************************************
*
* createNonfileMaddata   creates a new Maddata using user-supplied data
*                        rather than data from a file
*
*   arguments:
*
*     MadparmList * madparmList - list of Madrigal parameters desired
*     double ut1                - start time of integration period
*     double ut2                - end time of integration period 
*     int kinst                 - kinst id - needed since its in the prolog
*     MadparmList * oneDParms,  - list of 1D parameters for which you plan 
*                                 to provide data - may be 0 length
*     MadparmList * twoDParms,  - list of 2D parameters for which you plan 
*                                  to provide data - may be 0 length
*     int num2Drows             - number of 2D rows - may be zero
*     double * oneDdata         - array of 1D data in order of oneDParms
*     double ** twoDdata        - array of num2Drows double * to 2D data 
*                                 Each double * points to array of doubles of
*                                 length = length of twoDParms
*     FILE * errFile   - errFile to write an error messages to
*
*
*   returns - pointer to newly created Maddata.  Use 
*             destroyMaddata when done.  Will contain only one Madrecord.
*
*   Allocates memory to store all data, so all input may be released or changed
*   after this method is called.  Use this method to calculate Maddata when
*   you want to directly provide measured data, rather than get it from a file.  
*/
Maddata * createNonfileMaddata(MadparmList * requestedParms,
                               double ut1,
                               double ut2,
                               int kinst,
                               MadparmList * oneDParms,
                               MadparmList * twoDParms,
                               int num2Drows,
                               double * oneDdata,
                               double ** twoDdata,
                               FILE * errFile)
 
 

/***********************************************************************
*
* destroyMaddata   releases an existing Maddata
*
*   arguments: pointer to existing Maddata
*
*   returns - void
*/
void destroyMaddata(Maddata * maddata)
 
 

/***********************************************************************
*
* appendMadrecParmType   appends a new MadrecParmType onto maddata
*
*   arguments: 
*
*     Maddata * maddata - pointer to Maddata to append new cycle to
*     MadparmList * parm1DList - the list of 1D parameters in that type
*     MadparmList * parm1DList - the list of 2D parameters in that type
*
*
*   returns - index of new type.  Starts at 0.  If failure,
*             returns -1
*
*   Allocates memory to store all data, so all input may be released or changed
*   after this method is called.
*/
int appendMadrecParmType(Maddata * maddata,
                         MadparmList * parm1DList,
                         MadparmList * parm2DList)
 
 

/***********************************************************************
*
* appendMadcycle   appends a new Madcycle onto maddata
*
*   arguments: 
*
*     Maddata * maddata - pointer to Maddata to append new cycle to
*     int   cycleId     - cycle id (identifies cycle type)
*     char *   cycleDesc - Additional cycle description (may be empty string)
*
*
*   returns - cycle index of new cycle.  Starts at 0.  If failure,
*             returns -1
*
*   Allocates memory to store all data, so all input may be released or changed
*   after this method is called.
*/
int appendMadcycle(Maddata * maddata,
                   int cycleId,
                   char * cycleDesc)
 
 

/***********************************************************************
*
* createMadcycle   creates a new Madcycle
*
*   arguments:
*
*     int   cyclenum  - cycle number 
*     int   cycleId   - cycle id (identifies cycle type)
*     char *   cycleDesc - Additional cycle description (may be empty string)
*
*
*   returns - pointer to newly created Madcycle.  Use 
*             destroyMadcycle when done
*
*   Allocates memory to store all data, so all input may be released or changed
*   after this method is called.  Use appendMadrecord to append a new Madrecord
*/
Madcycle * createMadcycle(int cyclenum,
                          int cycleId,
                          char * cycleDesc)
 
 

/***********************************************************************
*
* destroyMadcycle   releases an existing Madcycle
*
*   will also free all Madrecords in this cycle
*
*   arguments: pointer to existing Madcycle
*
*   returns - void
*/
void destroyMadcycle(Madcycle * madcycle)
 
 

/***********************************************************************
*
* createMadrecord   creates a new Madrecord
*
*   arguments:
*
*   Rec_type  rectype - Record type: HEADER_REC, CATALOG_REC, or DATA_REC.  If DATA_REC,
*                       text will be empty string, no matter what passed in. If not, 
*                       data1Dparms will be null.
*   int numType       - index into maddata.madrecParmTypeList that defines the parm type of 
*                       record (that is, its list of 1D and 2D parameters)
*   char   *  text    - Text of header or catalog record. Empty string if data rec.
*   int num1DParms    - Number of 1D parameters to copy
*   double *  data1Dparms - pointer to array of doubles containing 1D data
*   int  kinst  - instrument id
*   double starttime - start time of record in seconds since 1/1/1950
*   double endtime - end time of record in seconds since 1/1/1950
*
*     Number of 1D parameters and order must correspond to
*     maddata.parm1DList
*
*   returns - pointer to newly created Madrecord.  Use 
*             destroyMadrecord when done
*
*   Allocates memory to store all data, so all input arrays may be released or changed
*   after this method is called.  Use createMadrecord to create a record with just the
*   1D data; then append each 2D row using append2DRow
*/
Madrecord * createMadrecord(Rec_type rectype,
                            int numType,
                            char * text,
                            int num1DParms,
                            double * data1Dparms,
                            int kinst,
                            double starttime,
                            double endtime)
 
 

/***********************************************************************
*
* destroyMadrecord   releases an existing Madrecord
*
*   arguments: pointer to existing Madrecord
*
*   returns - void
*/
void destroyMadrecord(Madrecord * madrecord)
 
 

/***********************************************************************
*
* simpleMadrecordPrint - a simple method that prints all data from one Madrecord
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int cycId - cycle number of Madrecord
*         int recId - record number in cycle of Madrecord to print
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*    Prints simple version of Madrecord to FILE
*/
void simpleMadrecordPrint(Maddata * maddata,
                          int cycId,
                          int recId,
                          FILE * fp)
 
 

/***********************************************************************
*
* simpleMadfilterPrint - a simple method that prints all data from Maddata
*                        a single Madfilter
*
*   arguments: 
*         Madfilter * madfilter - pointer to Madfilter
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*    Prints simple version of Madfilter to FILE
*/
void simpleMadfilterPrint(Madfilter * madfilter, int filterNum, FILE * fp)
 
 

/***********************************************************************
*
* simpleMaddataPrint - a simple method that prints all data from Maddata
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*    Prints simple version of Maddata to FILE
*/
void simpleMaddataPrint(Maddata * maddata, FILE * fp)
 
 

/***********************************************************************
*
* classicIsprint - a method that prints all data in standard isprint format
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int displayHeaders - if 1, display headers, if 0, don't
*         int displaySummary - if 1, display summary at top,
*                              if 0, don't
*         int maxCharsPerLine - if 0, no limit, if < ISPRINT_MIN_CHARS_PER_LINE, 
*                               limit line to ISPRINT_MIN_CHARS_PER_LINE, else
*                               limit line to maxCharsPerLine
*         char * missingStr - string to use when data missing
*         char * assumedStr - string to use when error data assumed
*         char * knownBadStr - string to use when error data knownBad
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*    Prints Maddata in standard isprint format to FILE.  Isprint format
*    does not differentiate between 1 and 2D data; everything is treated
*    as 2D data.  Cycle ignored.  If both displayHeaders and displaySummary == 0,
*    only data will be printed without any labels.
*/
void classicIsprint(Maddata * maddata,
                    int displayHeaders,
                    int displaySummary,
                    int maxCharsPerLine,
                    char * missingStr,
                    char * assumedStr,
                    char * knownBadStr,
                    FILE * fp)
 
 

/***********************************************************************
*
* printIsprintHeader - prints isprint header (time and instrument)
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int cycleNum - cycle number
*         int recNum - record in that cycle
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*    Prints isprint header line.
*/
void printIsprintHeader(Maddata * maddata, 
                        int cycleNum,
                        int recNum, 
                        FILE * fp)
 
 

/***********************************************************************
*
* getIsprintHeader - returns malloced string containing isprint header (time and instrument)
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int cycleNum - cycle number
*         int recNum - record in that cycle
*
*   returns - char * to malloced string containing isprint header (time and instrument)
*
*    Similiar to printIsprintHeader except returns string instead of printing it.
*    User must free returned string when done with it.
*/
char * getIsprintHeader(Maddata * maddata, 
                        int cycleNum,
                        int recNum)
 
 

/***********************************************************************
*
* printIsprintLabel - prints isprint header
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int maxCharsPerLine - limit line to maxCharsPerLine
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*    Prints isprint header line.
*/
void printIsprintLabel(Maddata * maddata, 
                        int maxCharsPerLine, 
                        FILE * fp)
 
 

/***********************************************************************
*
* getIsprintLabel - creates malloced strings containing isprint label
*                   and comma-separated mnemonics
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int maxCharsPerLine - limit line to maxCharsPerLine
*         char ** mnemStr - string containing comma-separated requested mnemonics
*         char ** labelStr - string containing mnemonics labels as formatted for isprint
*
*   returns - void
*
*    User must free malloced strings mnemStr and labelStr when done with them.
*/
void getIsprintLabel(Maddata * maddata, 
                     int maxCharsPerLine,
                     char ** mnemStr,
                     char ** labelStr)
 
 

/***********************************************************************
*
* classicMadrecordPrint - prints a single Madrecord in isprint format
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int cycleNum - cycle number
*         int recNum - record in that cycle
*         int displayHeaders - if 1, display headers, if 0, don't
*         int maxCharsPerLine - limit line to maxCharsPerLine
*         char * missingStr - string to use when data missing
*         char * assumedStr - string to use when error data assumed
*         char * knownBadStr - string to use when error data knownBad
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*    Prints isprint header line.
*/
void classicMadrecordPrint(Maddata * maddata, 
                          int cycleNum, 
                          int recNum, 
                          int displayHeaders,
                          int maxCharsPerLine,
                          char * missingStr,
                          char * assumedStr,
                          char * knownBadStr,
                          FILE * fp)
 
 

/***********************************************************************
*
* getClassicMadrecordStrings - returns strings describing a single Madrecord 
*                              in isprint format
*
*   similar to classicMadrecordPrint except returns data as strings instead
*   of directly fprintf'ing output
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata
*         int cycleNum - cycle number
*         int recNum - record in that cycle
*         int maxCharsPerLine - limit line to maxCharsPerLine
*         char * missingStr - string to use when data missing
*         char * assumedStr - string to use when error data assumed
*         char * knownBadStr - string to use when error data knownBad
*         char ** headerStr - string containing header as formatted for isprint
*         char ** mnemStr - string containing comma-separated requested mnemonics
*         char ** labelStr - string containing mnemonics labels as formatted for isprint
*         char ** dataStr - string containing data as formatted for isprint, except
*                          rows separated by commas instead of carriage return.
*
*   The strings mnemStr, headerStr, and dataStr are allocated on the heap, and are
*   the resposiblity of the caller to free when no longer needed.
*
*   returns - void
*/
void getClassicMadrecordStrings(Maddata * maddata, 
                                int cycleNum, 
                                int recNum, 
                                int maxCharsPerLine,
                                char * missingStr,
                                char * assumedStr,
                                char * knownBadStr,
                                char ** headerStr,
                                char ** mnemStr,
                                char ** labelStr,
                                char ** dataStr)
 
 

/***********************************************************************
*
* lookerMadrecordPrint - prints a single Madrecord in looker format
*
*
*   arguments: 
*         Maddata * maddata - pointer to Maddata (assumed to have one record only)
*         char * missingStr - string to use when data missing
*         char * assumedStr - string to use when error data assumed
*         char * knownBadStr - string to use when error data knownBad
*         int printHeaderFlag - if zero, surpress printing header line
*         FILE * fp - file to print to (may be stdout)
*
*   returns - void
*
*/
void lookerMadrecordPrint(Maddata * maddata, 
                          char * missingStr,
                          char * assumedStr,
                          char * knownBadStr,
			  int printHeaderFlag,
                          FILE * fp)
 
 

/***********************************************************************
*
* populate1DDataFromStr - uses a command string to populate a MadparmList
*                         and an array of doubles
*
*   For example, if onedString = "gdalt=100.0 glon=45.0 gdlat=-20.0",
*   oneDParms would have gdalt, glon, and gdlat, and oneDdata = {100.0, 45.0, -20.0}
*
*   arguments: 
*         char * onedString - string that describes 1D data
*         MadparmList ** oneDParms - created list of 1D parameters
*         double ** oneDdata - pointer to array of doubles.  Memory malloc'ed here
*         and must be free'd by the user when done
*
*   returns - 0 if success, -1 if problem
*
*/
int populate1DDataFromStr(char * onedString, 
                          MadparmList ** oneDParms, 
                          double ** oneDdata)
 
 

/***********************************************************************
*
* populate2DDataFromStr - uses a command string to populate a MadparmList
*                         and an array of doubles
*
*   For example, if twodString is:
*
*      "gdlat=45,45,45,45,50,50,50,50 glon=20,20,30,30,20,20,30,30 gdalt=500,600,500,600,500,600,500,600"
*
*   (Note that each parameters must have same number of values or an error is thrown)
*
*   twoDParms would have gdalt, glon, and gdlat, and 
*   twoDdata = { {45.0,45.0,45.0,45.0,50.0,50.0,50.0,50.0},
*                {20.0,20.0,30.0,30.0,20.0,20.0,30.0,30.0},
*                {500.0,600.0,500.0,600.0,500.0,600.0,500.0,600.0}}
*
*   arguments: 
*         char * twodString - string that describes 2D data
*         MadparmList ** twoDParms - created list of 2D parameters
*         double *** twoDdata - pointer to array of arrays of doubles.  Memory malloc'ed here
*         and must be free'd by the user when done
*         int * num2Drows - number of rows found in each 2D parameter
*
*   returns - number of 2D values per parameter if success, -1 if problem
*
*/
int populate2DDataFromStr(char * twodString, 
                          MadparmList ** twoDParms, 
                          double *** twoDdata, 
                          int * num2Drows)
 
 

Private madrec and maddata methods

These methods are private to the madc library, and should not need to be used by application developers. They are documented here for maintenance. They involve low-level routines to access various Cedar files, and also the details of how the madDeriveEngine module works


getNextMadrigalRecord putNextMadrigalRecord getNextCedarAsciiRecord putNextCedarAsciiRecord getNextCedarCbfRecord
getNextCosRecord putNextCedarCbfRecord putNextCosRecord flushCedarCbfRecord endFileCedarCbfRecord
endDataCedarCbfRecord writeCbfControlWord getNextCedarBlockedRecord putNextCedarBlockedRecord flushCedarBlockedRecord
getNextCedarUnblockedRecord putNextCedarUnblockedRecord getMemNextCedarUnblockedRecord putMemNextCedarUnblockedRecord putMemFastNextCedarUnblockedRecord
editMemNextCedarUnblockedRecord cedarFileType isProlog madptr jday1
idmyk1 setCheckSum int encodeBits int
setbit dumpCedarRecord fread16 fwrite16 reorderBytes
createInfoMethod destroyInfoMethod createInfoMultiRowMethod destroyInfoMultiRowMethod createInfoDervFile
destroyInfoDervFile getRecType load1DMeasData load2DMeasData load1DMultiRowData
load1DMultiRowDataNonfile load2DMultiRowData load2DMultiRowDataNonfile evaluateFilter appendMadrecord
updateMadrecordWithMultiRow append2DRow createInfoDerived destroyInfoDerived dispatchMethod
dispatchMultiRowMethod checkIf1DMethodNeeded checkIf2DMethodNeeded make1DMethodNeeded make2DMethodNeeded
checkIfMultiRowMethodNeeded hasOutput

/***********************************************************************
*
* getNextMadrigalRecord  reads a madrigal record
*
* The file should be positioned at the beginning of a record before
* calling this function, and on the first call, the Cedar record
* pointer, *cedarRecord, should be NULL. The pointers at the beginning
* of each block (words 1 and 2) and the checksum (word(blockSize-1) are
* ignored.
*
* Madrec completely ignores the 5 extra control words, words 17-21, in the
* Madrigal format prolog. They are removed when a Madrigal record is read 
* and added when a Madrigal record is written.
* These extra words are fully compliant with the CEDAR binary format in
* the case of data records, since the prolog length is specified in the
* data record.  They are not fully compliant with the CEDAR standard in
* the case of binary catalog and header records, which have fixed prolog
* lengths of 40, of which only the first 12 and 15 respectively are
* significant. The standard requires that the remaining words in the
* prolog must be zero. However, in practice this has often been ignored,
* even at NCAR, and it is unlikely that any CEDAR software actually
* chokes at non-zero words beyond 12 and 15 in catalog and header
* records.
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*    blockSize   - Madrigal file block size. Normally 6720 16-bit integers.
*    sigWords    - Number of signifcant words in the current block
*
*/

int
getNextMadrigalRecord (FILE *fp, Int16 **cedarRecordpp,
                       int blockSize,
                       int *sigWordsp)
 
 

/***********************************************************************
*
* putNextMadrigalRecord   adds madrigal record to a Madrigal file
*
* Madrigal files written by the Fortran library have an extra 0 after
* the last record. This may serve as an EOF indicator (zero-length record).
* This is not in the specification and is not added by this routine. 
* getNextMadrigalRecord handles the extra zero correctly.
*
* Cedar data records may have a shorter or longer prolog than data records
* in a Madrigal file, which always have a 21-word prolog. So, this routine
* transfers data from the input Cedar record to a Madrigal record,
* modifying the prolog as required, and then outputs the Madrigal
* record.
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*    blockSize   - 
*    blockIndex  - Madrigal file block size. Normally 6720 16-bit integers.
*    block       - The Madrigal block - normally 2*6720=13440 bytes.
*    prevRec     - Position of previous record in its block
*    thisRec     - Position of current record in its block.
*  
*/

int
putNextMadrigalRecord (FILE *fp, Int16 **cedarRecordpp,
                       int blockSize,
                       int *blockIndexp,
                       Int16 **blockpp,
                       int *prevRecp,
                       int *thisRecp)
 
 

/***********************************************************************
*
* getNextCedarAsciiRecord   reads record in CEDAR ASCII format
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*
*/

int
getNextCedarAsciiRecord (FILE *fp, Int16 **cedarRecordpp)
 
 

/***********************************************************************
*
* putNextCedarAsciiRecord   writes record in CEDAR ASCII format
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*
*/

int
putNextCedarAsciiRecord (FILE *fp, Int16 **cedarRecordpp)
 
 

/***********************************************************************
*
* getNextCedarCbfRecord   Gets the next CEDAR record from a CBF file
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*    blockSize   -
*    lCosBlock   -
*    pos         - position within Cos record, which contains multiple
*                    Cedar records
*    fwi         -
*    cosRecord   -
*
*/
int
getNextCedarCbfRecord(FILE *fp, Int16 **cedarRecordpp,
                      int forceCosRead,
                      int blockSize,
                      int *initPos8p,
                      int *initFwip,
                      int *initPosp,
                      int *initLCosBlockp,
                      int *lCosBlockp,
                      int *posp,
                      int *fwip,
                      Int16 **cosRecordpp)
 
 

/***********************************************************************
*
* getNextCosRecord   Gets the next CEDAR record from a CBF file
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*    fwi         -
*
*/
int
getNextCosRecord(FILE *fp, Int16 **cosRecordpp, int *fwip)
 
 

/***********************************************************************
*
* putNextCedarCbfRecord   Puts the next CEDAR record into a CBF file
*
*    fp                  - File pointer to the Madrigal file
*    cedarRecord         - The Cedar record
*    blockSize           - Cos Blocksize (normally 4096)
*    lbuf                -
*    pos                 -
*    cosRecord           -
*    blockNumber         -
*    previousFileIndex   -
*    previousRecordIndex -
*    lastControlWord     -
*
*/
int
putNextCedarCbfRecord(FILE *fp, Int16 **cedarRecordpp,
                      int blockSize,
                      int *lbufp,
                      int *posp,
                      Int16 **cosRecordpp,
                      int *blockNumberp,
                      int *previousFileIndexp,
                      int *previousRecordIndexp,
                      long *lastControlWordp)
 
 

/***********************************************************************
*
* putNextCosRecord   Writes the next Cos record to a CBF file
*
*    fp                  - File pointer to the Madrigal file
*    cedarRecord         - The Cedar record
*    blockSize           -
*    lbuf                -
*    blockNumber         -
*    previousFileIndex   -
*    previousRecordIndex - 
*    lastControlWord     -
*
*/
int
putNextCosRecord(FILE *fp, Int16 **cosRecordpp,
                 int blockSize,
                 int *lbufp,
                 int *blockNumberp,
                 int *previousFileIndexp,
                 int *previousRecordIndexp,
                 long *lastControlWordp)
 
 

/***********************************************************************
*
* flushCedarCbfRecord   Flushes the last CEDAR record into a CBF file
*
*    fp                  - File pointer to the Madrigal file
*    cedarRecord         - The Cedar record
*    blockSize           -
*    lbuf                -
*    blockNumber         -
*    previousFileIndex   -
*    previousRecordIndex - 
*    lastControlWord     -
*
*/
int
flushCedarCbfRecord(FILE *fp, Int16 **cedarRecordpp,
                    int blockSize,
                    int *lbufp,
                    int *posp,
                    Int16 **cosRecordpp,
                    int *blockNumberp,
                    int *previousFileIndexp,
                    int *previousRecordIndexp,
                    long *lastControlWordp)
 
 

/***********************************************************************
*
* endFileCedarCbfRecord   Writes end-of-file to a CBF file
*
*    fp                  - File pointer to the Madrigal file
*    cedarRecord         - The Cedar record
*    blockSize           -
*    previousFileIndex   -
*    lastControlWord     -
*
*/
int
endFileCedarCbfRecord(FILE *fp, Int16 **cedarRecordpp,
                                int blockSize,
                                int *previousFileIndexp,
                                long *lastControlWordp)
 
 

/***********************************************************************
*
* endDataCedarCbfRecord   Writes end-of-data CBF file
*
*    fp                  - File pointer to the Madrigal file
*    cedarRecord         - The Cedar record
*    blockSize           -
*    lastControlWord     -
*
*/
int
endDataCedarCbfRecord(FILE *fp, Int16 **cedarRecordpp,
                                int blockSize,
                                long *lastControlWordp)
 
 

/***********************************************************************
*
* writeCbfControlWord   Gets the next CEDAR record from a CBF file
*
*    fp           - File pointer to the Madrigal file
*    cedarRecord  - The Cedar record
*    m            -
*    bdf          -
*    bn           -
*    fwi          -
*    ubc          -
*    pfi          -
*    pri          -
*/
int
writeCbfControlWord(FILE *fp,
                    int m,
                    int bdf,
                    int bn,
                    int ubc,
                    int pfi,
                    int pri,
                    long *lastControlWordp)
 
 

/***********************************************************************
*
* getNextCedarBlockedRecord   Gets the next CEDAR record from a file
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*    lBlockp     - pointer to the length of the current block
*    posp        - pointer to the position within the current block
*
*/
int
getNextCedarBlockedRecord(FILE *fp, Int16 **cedarRecordpp,
                          Int16 *lBlockp,
                          int *posp)
 
 

/***********************************************************************
*
* putNextCedarBlockedRecord   Puts the next CEDAR record into a file
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*    maxBlock    -
*    lbuf        -
*    posp        -
*    block       -
*/
int
putNextCedarBlockedRecord(FILE *fp, Int16 **cedarRecordpp,
                          int *maxBlock,
                          int *lbufp,
                          int *posp,
                          Int16 **blockpp)
 
 

/***********************************************************************
*
* flushCedarBlockedRecord   Flushes the last CEDAR record into a CBF file
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*    maxBlock    -
*    lbuf        -
*    posp        -
*    block       -
*
*/
int
flushCedarBlockedRecord(FILE *fp, Int16 **cedarRecordpp,
                        int *maxBlock,
                        int *lbufp,
                        int *posp,
                        Int16 **blockpp)
 
 

/***********************************************************************
*
* getNextCedarUnblockedRecord   Gets the next CEDAR record from a file
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*
*/
int
getNextCedarUnblockedRecord(FILE *fp, Int16 **cedarRecordpp)
 
 

/***********************************************************************
*
* putNextCedarUnblockedRecord   Puts the next CEDAR record into a file
*
*    fp          - File pointer to the Madrigal file
*    cedarRecord - The Cedar record
*
*/
int
putNextCedarUnblockedRecord(FILE *fp, Int16 **cedarRecordpp)
 
 

/***********************************************************************
*
* getMemNextCedarUnblockedRecord   Gets the next CEDAR record from memory
*
*    cedarFilepp   - The block of memory holding a list of Cedar records
*    cedarRecordpp - The Cedar record to be populated from cedarFilepp
*    posp          - The present number of Int16's already read from cedarFilepp
*    recordpInMem  - Determines whether cedarRecordpp is pointing into cedarFilepp
*                    or separate block of memory on the heap
*
*/
int getMemNextCedarUnblockedRecord(Int16 **cedarFilepp, 
                                   Int16 **cedarRecordpp,
                                   int *posp,
                                   int *recordpInMem)
 
 

/***********************************************************************
*
* putMemNextCedarUnblockedRecord   Puts the next CEDAR record into memory
*
*    cedarFilepp   - The block of memory being filled with a list of Cedar records
*    cedarRecordpp - The Cedar record to be appended to cedarFilepp
*    fileSizep     - The present number of bytes in cedarFilepp
*    posp          - The present number of Int16's in cedarFilepp, not
*                    including trailing 0 (see below)
*
*    To indicate this is last record, append Int16 = 0 at end,
*    so ltot will be zero (last record indicator)
*/
int
putMemNextCedarUnblockedRecord(Int16 **cedarFilepp, Int16 **cedarRecordpp,
                               int *fileSizep, int *posp)
 
 

/***********************************************************************
*
* putMemFastNextCedarUnblockedRecord   Puts the next CEDAR record into memory with
*                                      fewer realloc calls.  Allocates more memory
*                                      than needed to increase speed.  Is meant to be
*                                      a private method only called from madrecOpen.
*                                      Requires that cedarFilepp be realloc'ed to right
*                                      size after file is fully loaded into memory
*
*    cedarFilepp   - The block of memory being filled with a list of Cedar records
*    cedarRecordpp - The Cedar record to be appended to cedarFilepp
*    fileSizep     - The present number of bytes in cedarFilepp
*    posp          - The present location of Int16 pointer in file
*    memPos        - The present location of Int16 pointer in memory
*
*    To indicate this is last record, append Int16 = 0 at end,
*    so ltot will be zero (last record indicator)
*/
int putMemFastNextCedarUnblockedRecord(Int16 **cedarFilepp, 
                                       Int16 **cedarRecordpp,
                                       int *fileSizep, 
                                       int *posp,
                                       int *memPos)
 
 

/***********************************************************************
*
* editMemNextCedarUnblockedRecord   Gets pointer to the next CEDAR record
*
*    cedarFilepp   - The block of memory holding a list of Cedar records
*    cedarRecordpp - The Cedar record to be editted - will point to somewhere in
*                    cedarFilepp
*    posp          - The record in cedarFilepp for cedarRecordpp to point at
*    recordpInMem  - Determines whether cedarRecordpp is pointing into cedarFilepp
*                    or separate block of memory on the heap
*
*/
int
editMemNextCedarUnblockedRecord(Int16 **cedarFilepp, 
                                Int16 **cedarRecordpp,
                                int *posp,
                                int *recordpInMem)
 
 

/***********************************************************************
*
* cedarFileType   Gets Cedar File Type
*
*    Supported formats:
*        0 - Madrigal
*        1 - Blocked Binary
*        2 - Cbf
*        3 - Unblocked Binary
*        4 - Ascii
*
*    Supported record types:
*        0 - Catalog
*        1 - Header
*        2 - Data
*
*/

int
cedarFileType(char *fileName, int madrigalBlockSize, int cbfBlockSize)
 
 

/***********************************************************************
*
* isProlog - Checks for consistent Cedar prolog
*   prolog - Pointer to the prolog
*
*/
int
isProlog(Int16 *prolog)
 
 

/***********************************************************************
*
*/
int
madptr(Int16 *time)
 
 

/***********************************************************************
*
* 
*
*/
int
jday1(int day, int month, int year)
 
 

/***********************************************************************
*
* 
*
*/
int
idmyk1(int day, int month, int year)
 
 

/***********************************************************************
*
* setCheckSum   sets block checksum
*
*/

int
setCheckSum (int blockSize, Int16 **blockpp)
 
 

/***********************************************************************
*
* decodeBits    Returns bits b1 to b2 of buf as an unsigned integer
*
*/

unsigned int
decodeBits(unsigned char *buf, unsigned int b1, unsigned int b2)
 
 

/***********************************************************************
*
* encodeBits    Encodes unsigned integer val in bits b1 to b2 of buf
*
*/

void
encodeBits(unsigned char *buf, unsigned int b1, unsigned int b2, unsigned int val)
 
 

/***********************************************************************
*
* getbit    returns 1 if bit b in array buf is 1, else 0.
*
*/

unsigned int
getbit(unsigned char *buf, unsigned int b)
 
 

/***********************************************************************
*
* setbit    Sets bit b in array buf to last bit in bv.
*           Thus, if bv=0, bit b in buf will be set to 0,
*            else if bv=1, bit b in buf will be set to 1.
*           No other bit in buf will be changed.
*
*/

void
setbit(unsigned char *buf, unsigned int b, unsigned int bv)
 
 

/***********************************************************************
*
* dumpCedarRecord    Dumps beginning and end of Cedar record
*
*/

void
dumpCedarRecord(Int16 **recordpp, char *title)
 
 

/***********************************************************************
*
* fread16   Reads big-endian 16-bit integers
*
*    ptr           - Pointer to array of 16-bit integers
*    size_t size   - Must be 2
*    size_t nitems - Number of 16-bit integers to be read
*    stream        - Pointer to input file. The file should be
*                    positioned at the beginning of an sequence of at
*                    least nitems big-endian 16-bit integers.
*
*    The CEDAR format represents data stored on tape or disk as 16-bit big
*    endian integers. fread16 is endian-neutral. It works on both big endian
*    and little endian computers. However, this flexibility imposes a
*    performance penalty on big endian computers. This penalty can be
*    reduced by changing the BIGENDIAN constant to 1.
*
*/

size_t
fread16(void *ptr, size_t size, size_t nitems, FILE *stream)
 
 

/***********************************************************************
*
* fwrite16   Writes big-endian 16-bit integers   
*
*    ptr           - Pointer to array of 16-bit integers
*    size_t size   - Must be 2
*    size_t nitems - Number of 16-bit integers to write
*    stream        - Pointer to input file. Nitems 16-bit integers will
*                    be written to stream in big-endian order.
*
*    The CEDAR format represents data stored on tape or disk as 16-bit big
*    endian integers. fread16 is endian-neutral. It works on both big endian
*    and little endian computers. However, this flexibility imposes a
*    performance penalty on big endian computers. This penalty can be
*    reduced by changing the BIGENDIAN constant to 1.
*
*/

size_t
fwrite16(void *ptr, size_t size, size_t nitems, FILE *stream)
 
 

/***********************************************************************
*
* reorderBytes   returns byte order of original file
*
*    ptr           - Pointer to Int16 array 
*    numInt16s     - Size of ptr Int16 array 
*
*    orderBytes undoes the effect of using fread16, and returns an array of
*    chars read via fread16 to its original order as found in the file.  This is
*    used in reading header and catalog records, where the data is read as chars
*    and not as Int16's.  For big-endian machines it does nothing, for little-endian
*    machines it switches adjacent bytes.
*
*/
void reorderBytes(Int16 * ptr, int numInt16s)
 
 

/***********************************************************************
*
* createInfoMethod - sets up a InfoMethod struct that describes one
*                    particular method used to derive parameters
*
*   arguments:
*      int numInputs - the number of inputs required
*      int numOutputs - the number of outputs required
*
*   Number of inputs and outputs defined in gCompExtList.
*
*   returns - pointer to newly created InfoMethod struct; destroy
*             using destroyInfoMethod
*/
InfoMethod * createInfoMethod(int numInputs, int numOutputs)
 
 

/***********************************************************************
*
* destroyInfoMethod - frees all memory for given InfoMethod struct
*
*   arguments:
*      InfoMethod * infoMethod - pointer to struct to free
*
*   returns - void
*/
void destroyInfoMethod(InfoMethod * infoMethod)
 
 

/***********************************************************************
*
* createInfoMultiRowMethod - sets up a InfoMultiRowMethod struct that describes one
*                    particular MultiRow method used to derive parameters
*
*   arguments:
*      int numInputs - the number of inputs required
*      int * inputType - an array of ints = 1 or 2, depending in 1 or 2D input,
*                        len =  numInputs
*      int numOutputs - the number of outputs required
*      int * outputType - an array of ints = 1 or 2, depending in 1 or 2D output,
*                        len =  numOutputs
*
*   Number of inputs and outputs and types defined in gCompExtMultiRowList.
*
*   Creates inputArr and outputArr.  For now they are arrays of pointers to
*   arrays of doubles of length 1 double.  If this method actually turns out to
*   be needed, the 2D arrays will be reallocated to MAX_2D_ROWS
*
*   returns - pointer to newly created InfoMultiRowMethod struct; destroy
*             using destroyInfoMultiRowMethod
*/

InfoMultiRowMethod * createInfoMultiRowMethod(int numInputs,
                                              const int * inputType,
                                              int numOutputs,
                                              const int * outputType)
 
 

/***********************************************************************
*
* destroyInfoMultiRowMethod - frees all memory for given InfoMultiRowMethod struct
*
*   arguments:
*      InfoMultiRowMethod * infoMultiRowMethod - pointer to struct to free
*
*   returns - void
*/
void destroyInfoMultiRowMethod(InfoMultiRowMethod * infoMultiRowMethod)
 
 

/***********************************************************************
*
* createInfoDervFile - sets up a InfoDervFile struct in preparation for
*                     calculating all derived parameters for a file
*
*   arguments:
*      madrec * madrecp - pointer to madrec struct that has an in-memory file
*      MadparmList * requestParm - list of parameters requested
*      MadfilterList * filtList - list of Madfilters to apply
*      FILE * errFile   - errFile to write an error messages to
*
*   Examines each record in the in-memory file to get measured 1d and 2d parameters.
*   If first time that unique record type found, calls createInfoDerived
*   to create an analysis plan.  For each record, records its type and
*   location in returned struct InfoDervFile.  Call destroyInfoDervFile
*   when done with this struct.
*
*   returns - pointer to created InfoDervFile struct; if failure,
*             returns NULL and writes error to errFile
*/
InfoDervFile * createInfoDervFile(Madrec * madrecp,
                                  MadparmList * requestParm,
                                  MadfilterList * filtList,
                                  FILE * errFile)
 
 

/***********************************************************************
*
* destroyInfoDervFile - frees all memory for given InfoDervFile struct
*
*   arguments:
*      InfoDervFile * info - pointer to struct to free
*
*   returns - void
*/
void destroyInfoDervFile(InfoDervFile * infoDervFile)
 
 

/***********************************************************************
*
* getRecType - returns record type index in InfoDervFile for recno
*
*   arguments:
*      InfoDervFile * infoDervFile - pointer to InfoDervFile containing analysis
*      int recno - record number in file (starting at 0)
*
*   returns - record type index in InfoDervFile for recno.  If not
*             found, returns -1
*/
int getRecType(InfoDervFile * infoDervFile, int recno)
 
 

/***********************************************************************
*
* load1DMeasData - copies 1D measured data into infoDervFile's memory
*
*   arguments:
*      InfoDervFile * infoDervFile - pointer to InfoDervFile containing analysis
*      Madrec * madrecp - pointer to Madrec holding data from file
*      int recType - record type of present record
*      double first_ibyr - year of first record (faster than rewinding to get these four)
*      double first_ibdt - date of first record
*      double first_ibhm - hm*100+min of first record
*      double first_ibcs - centisecs of first record
*
*   returns - void
*
*   affects - copies measured 1D data into appropriate place in
*             infoDervFile->infoDervList[recType]->all1DParm
*/
void load1DMeasData(InfoDervFile * infoDervFile,
                    Madrec * madrecp,
                    int recType,
                    double first_ibyr,
                    double first_ibdt,
                    double first_ibhm,
                    double first_ibcs)
 
 

/***********************************************************************
*
* load2DMeasData - copies 2D measured data into infoDervFile's memory
*
*   arguments:
*      InfoDervFile * infoDervFile - pointer to InfoDervFile containing analysis
*      Madrec * madrecp - pointer to Madrec holding data from file
*      int recType - record type of present record
*      int row - 2D row to load (starts at 0)
*
*   returns - void
*
*   affects - copies measured 2D data into appropriate place in
*             infoDervFile->infoDervList[recType]->all2DParm
*/
void load2DMeasData(InfoDervFile * infoDervFile,
                    Madrec * madrecp,
                    int recType,
                    int row)
 
 

/***********************************************************************
*
* load1DMultiRowData - copies 1D data from infoDervFile into
*                      InfoMultiRowMethod->inputArr for all needed
*                      multi-row methods
*
*   arguments:
*      InfoDervFile * infoDervFile - pointer to InfoDervFile containing analysis
*      int recType - record type of present record
*
*   returns - void
*
*   affects - copies 1D data from infoDervFile into
*             InfoMultiRowMethod->inputArr
*/
void load1DMultiRowData(InfoDervFile * infoDervFile,
                        int recType)
 
 

/***********************************************************************
*
* load1DMultiRowDataNonfile - copies 1D data from infoDerv into
*                             InfoMultiRowMethod->inputArr for all needed
*                             multi-row methods - used when no file used
*
*   arguments:
*      InfoDerived * infoDerv - pointer to InfoDerived containing analysis
*
*   returns - void
*
*   affects - copies 1D data from infoDerv into
*             InfoMultiRowMethod->inputArr
*/
void load1DMultiRowDataNonfile(InfoDerived * infoDerived)
 
 

/***********************************************************************
*
* load2DMultiRowData - copies 2D data from infoDervFile into
*                      InfoMultiRowMethod->inputArr for all needed
*                      multi-row methods
*
*   arguments:
*      InfoDervFile * infoDervFile - pointer to InfoDervFile containing analysis
*      int recType - record type of present record
*      int count2D - index into 2D record being added
*
*   returns - void
*
*   affects - copies 2D data from infoDervFile into
*             InfoMultiRowMethod->inputArr
*/
void load2DMultiRowData(InfoDervFile * infoDervFile,
                        int recType,
                        int count2D)
 
 

/***********************************************************************
*
* load2DMultiRowDataNonfile - copies 2D data from infoDerived into
*                             InfoMultiRowMethod->inputArr for all needed
*                             multi-row methods - used when no file used
*
*   arguments:
*      InfoDerived * infoDerived - pointer to InfoDerived containing analysis
*      int count2D - index into 2D record being added
*
*   returns - void
*
*   affects - copies 2D data from infoDerive into
*             InfoMultiRowMethod->inputArr
*/
void load2DMultiRowDataNonfile(InfoDerived * infoDerived,
                               int count2D)
 
 

/***********************************************************************
*
* evaluateFilter - returns 1 if filter accepts, 0 if fails
*
*   arguments:
*      InfoDervFile * infoDervFile - pointer to InfoDervFile containing analysis
*      int recType - record type of present record
*      int dim - 1 for 1D filter, 2 for 2D filter
*      int filtIndex - index into filter list filt1DList or filt2DList, which
*                      determines which filter to apply
*
*   returns - 1 if filter accepts, 0 if fails
*
*   notes - if any filter parameter is missing, filter fails
*/
int evaluateFilter(InfoDervFile * infoDervFile,
                   int recType,
                   int dim,
                   int filtIndex)
 
 

/***********************************************************************
*
* appendMadrecord   appends a new Madrecord to Maddata
*
*   arguments:
*
*      Maddata * maddata - pointer to Maddata to append to
*      InfoDerived * infoDeriv - pointer to InfoDerived that contains the data
*      int cycIndex      - index of cycle to add Madrecord to
*      int typeIndex     - index of type of record. Refers to maddata.madrecParmTypeList
*      Rec_type  rectype - Record type: HEADER_REC, CATALOG_REC, or DATA_REC.  If DATA_REC,
*                          text will be empty string, no matter what passed in. If not,
*                          data1Dparms will be null.
*      char   *  text    - Text of header or catalog record. Empty string if data rec.
*      int  kinst        - instrument id
*      double starttime  - start time of record in seconds since 1/1/1950
*      double endtime    - end time of record in seconds since 1/1/1950
*
*   returns - index of MadRecord added if successful, starting at 0, -1 if error
*/
int appendMadrecord(Maddata * maddata,
                    InfoDerived * infoDerv,
                    int cycIndex,
                    int typeIndex,
                    Rec_type rectype,
                    char * text,
                    int kinst,
                    double starttime,
                    double endtime)
 
 

/***********************************************************************
*
* updateMadrecordWithMultiRow   modifies an existing Madrecord with data from a multi-row method
*
*   arguments:
*
*      Maddata * maddata - pointer to Maddata to append to
*      InfoMultiRowMethod * infoMultiRowMeth - pointer to InfoMultiRowMethod containing new data
*      int methIndex     - index into which multi-row method this is
*      int cycIndex      - index of cycle that Madrecord is in
*      int recIndex      - index into which record in cycle is being modified
*      int typeIndex     - index of type of record. Refers to maddata.madrecParmTypeList
*      int numRows       - number of 2D rows being updated
*
*   returns - 0 if successful, -1 if error
*/
int updateMadrecordWithMultiRow(Maddata * maddata,
                                InfoMultiRowMethod * infoMultiRowMeth,
                                int methIndex,
                                int cycIndex,
                                int recIndex,
                                int typeIndex,
                                int numRows)
 
 

/***********************************************************************
*
* append2DRow   appends a row of 2D data to a Maddata->Madcycle->Madrecord
*
*   arguments:
*
*      Maddata * maddata - pointer to Maddata to append to
*      InfoDerived * infoDeriv - pointer to InfoDerived that contains the data
*      int cycIndex      - index of cycle to add Madrecord to
*      int recIndex      - index of Madrecord in cycle to append 2D
*      int typeIndex     - index of type of record. Refers to maddata.madrecParmTypeList
*
*   returns - index of 2D row added if successful, starting at 0, -1 if error
*/
int append2DRow(Maddata * maddata,
                InfoDerived * infoDerv,
                int cycIndex,
                int typeIndex,
                int recIndex)
 
 

/***********************************************************************
*
* createInfoDerived - sets up a InfoDerived struct in preparation for
*                     calculating all derived parameters for a given
*                     record type
*
*   A record type is a unique ordered combination of 1d measured parameters and
*   2d measured parameters
*
*   arguments:
*      MadparmList * meas1DParmList - list of measured 1D parameters
*      MadparmList * meas2DParmList - list of measured 2D parameters
*      MadparmList * requestedParmList - list of parameters requested
*      MadfilterList * filtList - list of filters requested
*
*   Searchs through the information in gCompExtList to determine which
*   methods need to be called for 1D and 2D cases.  Determines which
*   requested parameters can not be derived.  Sets up allocated memory
*   to hold all measured and derived parameters. Sets up inputMap and
*   outputMap to rapidly move data into input and output arrays required
*   for each method.  Free using destroyInfoDerived.
*
*   returns - pointer to created InfoDerived struct; if failure,
*             returns NULL
*/
InfoDerived * createInfoDerived(MadparmList * meas1DParmList,
                                MadparmList * meas2DParmList,
                                MadparmList * requestedParmList,
                                MadfilterList * filtList)
 
 

/***********************************************************************
*
* destroyInfoDerived - frees all memory for given InfoDerived struct
*
*   arguments:
*      InfoDerived * info - pointer to struct to free
*
*   returns - void
*/
void destroyInfoDerived(InfoDerived * info)
 
 

/***********************************************************************
*
* dispatchMethod - calls the derived method set by methIndex
*
*   arguments:
*      InfoDerived * infoDeriv - pointer to struct to update by
*                                calling method
*      int methIndex - index of method being run
*      FILE * errFile - error file for methods to write to
*
*   writes error message to errFile if error occurs
*
*   returns - 0 if no error thrown by underlying method
*/
int dispatchMethod(InfoDerived * infoDeriv, int methIndex, FILE * errFile)
 
 

/***********************************************************************
*
* dispatchMultiRowMethod - calls the derived multi-row method set by methIndex
*
*   arguments:
*      InfoDerived * infoDeriv - pointer to struct to update by
*                                calling method
*      int methIndex - index of method being run
*      FILE * errFile - error file for methods to write to
*
*   writes error message to errFile if error occurs
*
*   returns - 0 if no error thrown by underlying method
*/
int dispatchMultiRowMethod(InfoDerived * infoDeriv,
                           int methIndex,
                           int numRows,
                           FILE * errFile)
 
 

/***********************************************************************
*
* checkIf1DMethodNeeded - if 1D method is needed, calls make1DMethodNeeded
*
*   arguments:
*      InfoDerived * infoDeriv - pointer to struct to update if
*                                method is needed
*      int methIndex - index of method being checked
*      MadparmList filtParmsNotRequestedList - additional parameters needed
*
*     Method being checked has already been found to be one
*     that can be used successfully given measured 1D parameter
*     and outputs of earlier derived methods.
*
*   returns - void
*/
void checkIf1DMethodNeeded(InfoDerived * infoDeriv,
                           int methIndex,
                           MadparmList * filtParmsNotRequestedList)
 
 

/***********************************************************************
*
* checkIf2DMethodNeeded - if 2D method is needed, calls make2DMethodNeeded
*
*   arguments:
*      InfoDerived * infoDeriv - pointer to struct to update if
*                                method is needed
*      int methIndex - index of method being checked
*      MadparmList filtParmsNotRequestedList - additional parameters needed
*
*     Method being checked has already been found to be one
*     that can be used successfully given measured 1 and 2D parameters
*     and outputs of earlier derived methods.
*
*   returns - void
*/
void checkIf2DMethodNeeded(InfoDerived * infoDeriv,
                           int methIndex,
                           MadparmList * filtParmsNotRequestedList)
 
 

/***********************************************************************
*
* make1DMethodNeeded - sets this method and all it depends on as needed
*
*   arguments:
*      InfoDerived * infoDeriv - pointer to struct to update
*      int methIndex - index of method need
*
*     This is a recursive method that returns only after all dependent
*     methods have been set as needed.  It adds all input and output
*     parameters to allUsed1DParmList if not there already.
*
*   returns - void
*/
void make1DMethodNeeded(InfoDerived * infoDeriv, int methIndex)
 
 

/***********************************************************************
*
* make2DMethodNeeded - sets this method and all it depends on as needed
*
*   arguments:
*      InfoDerived * infoDeriv - pointer to struct to update
*      int methIndex - index of method need
*
*     This is a recursive method that returns only after all dependent
*     methods have been set as needed.  It adds all input and output
*     parameters to allUsed2DParmList or allUsed2DParmList if not there already.
*
*   returns - void
*/
void make2DMethodNeeded(InfoDerived * infoDeriv, int methIndex)
 
 

/***********************************************************************
*
* checkIfMultiRowMethodNeeded - makes multi-row method needed if required
*
*   arguments:
*      InfoDerived * infoDeriv - pointer to struct to update if
*                                multi-row method is needed
*      int methIndex - index of multi-row method being checked
*
*     Multi-row method being checked has already been found to be one
*     that can be used successfully given measured 1 and 2D parameters
*     and outputs of earlier derived methods. Reallocates InfoMultiRowMethod->
*     inputArr and outputArr if needed, and sets up inputMap.
*
*   returns - void
*/
void checkIfMultiRowMethodNeeded(InfoDerived * infoDeriv,
                                 int methIndex)
 
 

/***********************************************************************
*
* hasOutput - returns 1 if CompiledExt outputs given mnem, 0 otherwise
*
*   arguments:
*      const CompiledExt * ext - pointer to compiled extension being analyzed
*      const char *  mnem - pointer to mnemonic
*
*   returns  1 if CompiledExt outputs given mnem, 0 otherwise
*/
int hasOutput(const CompiledExt * exten, const char * mnem)
 
 

Methods to derive Madrigal parameters

These methods are used to derive Madrigal parameters from other Madrigal parameters. They are documented here to fully describe the derivation algorithms.


checkErrorData getDebyeFactor getElecDensity getTsyganenkoField traceTsyganenkoField
getTsyganenkoG1Index getTsyganenkoG2Index traceMagneticField run_iri faraday_rotation
getByear getTime getBmd getBMonthDay getMd
getUtUnix getDayno getBhm getBhhmmss getEhhmmss
getHm getUth getUts getBUth getInttms
getInttmm getDatntd getUt getBegUt getJdayno
getJulian_date getUt1 getUt2 getDut21 getFyear
getStation getAltInc getAveAlt getAveDAlt getResl
getAzmDaz getDAzmDDaz getElmDel getDElmDDel getGeod
getDGeod getGeodGdalt getGeodAlt getAzElRange getSZen
getSltmut getSlt getSdwHt getSuntime getTecGdalt
getGcdist getMag getGeocgm getTsygan getAacgm
fromAacgm getMlt getEregion getAspect getSltc
getAplt getSZenc getConjSun getGeo getDst
getFof2 getPopl getPop getNel getNe
getDNel getDNe getNemaxl getNemax getTr
getTe getTi getDteCctitr getDte getCol
getCo getNeNel getDNeDNel getVisrNe getVisrTe
getVisrTi getVisrVo getVisrHNMax getVisrNeDiff getVisrNelDiff
getVisrTeDiff getVisrTiDiff getVisrVoDiff getSn getSnp3
getChip31 getWchsq1 getChisq1 getChip32 getWchsq2
getChisq2 getVi1Vi1f getVi2Vi2f getVipeVipe1 getVipeVipe2
getVipnVipn1 getVipnVipn2 getVi6Vipu getViGeom getViGeod
getVn1Vn1p2 getVn2Vn2p2 getVnGeom getVnGeod getEFGeom
getEFGeod getJGeom getJGeod getNeut getTn
getTnNoPhp getDTn getCond getDCond getImf
getIri getTestAveAlt

/***********************************************************************
*
* checkErrorData - a helper method that looks at input data for methods
*                  that calculate error parameters to find assumed or
*                  knownbad special values.  If found, all outputs
*                  set to missing and return 1.  If not, return 0.
*
*   arguments:
*      inCount - num inputs
*      inputArr - double array
*      outCount - num outputs
*      outputArr - double array
*
*
*   returns - 1 if any input assumed or knownbad, 0 otherwise
*/
int checkErrorData(int inCount,
                   double * inputArr,
                   int outCount,
                   double * outputArr)
 
 

/***********************************************************************
*
* getDebyeFactor - a helper method that finds the debye length g given
*                  Tr and Pfac.
*
*   arguments:
*      double Tr - temperature ratio Te/Ti
*      double Pfac - a factor determined from the uncorrected electron density
*
*   Returns:
*      double g which is a solution to g(1+Tr+g)(1+g)-Pfac=0
*
*      if fails to converge, returns 0.0
*/
double getDebyeFactor(double Tr, double Pfac)
 
 

/***********************************************************************
*
* getElecDensity - a helper method that finds the corrected electron density
*                  given Ti, Tr, the log10 of the uncorrected electron
*                  density Popl in lg(m^-3), and the aspect angle.
*
*   Algorithm from Fortran method NELCAL in madlib, modified with
*   aspect angle dependence using algorithm from F.S. Rodrigues and
*   Dave Hysell.  Rodriques/Hysell used if beam within 6 degrees of
*   perpendicular to magnetic field line (84 < aspect < 96).  Fails
*   if within 1 degree of perpendicular.
*
*   arguments:
*      double Ti - ion temperature
*      double Tr - temperature ratio Te/Ti
*      double Popl - the uncorrected electron density Popl in lg(m^-3)
*      double aspect - magnetic field line
*
*   Returns:
*      double - the log10 of the corrected electron density in lg(m^-3)
*      if fails, returns missing
*/
double getElecDensity(double Ti, double Tr, double Popl, double aspect)
 
 

/***********************************************************************
*
* getTsyganenkoField - a helper method that finds the XGSM and YGSM point
*     on the equatorial plane for the field line determined by the given
*     point in space and time using the Tsyganenko model.
*
*    Note that the 2001 Tsyganenko model uses IMF and solar wind
*    speed measurements taken every 5 minutes for a hour.  Since
*    Madrigal presently only has hourly measurements, we'll just average
*    two measurements instead of 12.
*
*    Since Tsyganenko uses globals, this code is not thread safe.
*
*
*   arguments:
*      double time - time in seconds since 1/1/1950
*      double gdlat - geodetic latitude
*      double glon - geodetic longitude
*      double gdalt - geodetic altitude in km
*      double swspd_now - solar wind speed now in m/s
*      double swspd_1hour - solar wind speed 1 hour earlier in m/s
*      double imf_ygsm_now - imf in y gsm direction in nTesla measured now
*      double imf_ygsm_1hour - imf in y gsm direction in nTesla measured 1 hour ago
*      double imf_zgsm_now - imf in z gsm direction in nTesla measured now
*      double imf_zgsm_1hour - imf in z gsm direction in nTesla measured 1 hour ago
*      double swden - solar wind density in m^-3
*      double dst - dst in  nTesla
*           (the following are output parameters)
*      double * eq_xgsm - x point in equatorial plane where field line crosses (in GSM)
*      double * eq_ygsm - y point in equatorial plane where field line crosses (in GSM)
*      double * eq_xgse - x point in equatorial plane where field line crosses (in GSE)
*      double * eq_ygse - y point in equatorial plane where field line crosses (in GSE)
*
*      If failure, all b* parameters will be set to missing
*
*
*   Returns:
*      double - 0 if success, -1 if failure
*/
int getTsyganenkoField(double time,
                       double gdlat,
		       double glon,
		       double gdalt,
		       double swspd_now,
		       double swspd_1hour,
		       double imf_ygsm_now,
		       double imf_ygsm_1hour,
		       double imf_zgsm_now,
		       double imf_zgsm_1hour,
		       double swden,
		       double dst,
		       double * eq_xgsm,
		       double * eq_ygsm,
		       double * eq_xgse,
		       double * eq_ygse)
 
 

/***********************************************************************
*
* traceTsyganenkoField - a helper method that finds the point on the
*     magnetic field line determined by  the qualifiers: conjugate, north_alt,
*     south_alt, apex, or GSM XY plane for the field line determined by the given
*     point in space and time using the Tsyganenko model.
*
*    Note that the 2001 Tsyganenko model uses IMF and solar wind
*    speed measurements taken every 5 minutes for a hour.  Since
*    Madrigal presently only has hourly measurements, we'll just average
*    two measurements instead of 12.
*
*    Since Tsyganenko uses globals, this code is not thread safe.
*
*   arguments:
*      double time - time in seconds since 1/1/1950
*      double gdlat - input geodetic latitude
*      double glon - input geodetic longitude
*      double gdalt - input geodetic altitude in km
*      double swspd_now - solar wind speed now in m/s
*      double swspd_1hour - solar wind speed 1 hour earlier in m/s
*      double imf_ygsm_now - imf in y gsm direction in nTesla measured now
*      double imf_ygsm_1hour - imf in y gsm direction in nTesla measured 1 hour ago
*      double imf_zgsm_now - imf in z gsm direction in nTesla measured now
*      double imf_zgsm_1hour - imf in z gsm direction in nTesla measured 1 hour ago
*      double swden - solar wind density in m^-3
*      double dst - dst in  nTesla
*      int qualifier - 0 for conjugate, 1 for north_alt, 2 for south_alt, 3 for apex, 4 for GSM XY plane
*      double * stopAlt - altitude to stop trace at, if qualifier is north_alt or south_alt.
*                         If other qualifier, this parameter is ignored
*           (the following are output parameters)
*      double * end_gdlat (if qualifier == 4 (GSM XY plane), this will be XGSM instead)
*      double * end_glon (if qualifier == 4 (GSM XY plane), this will be YGSM  instead)
*      double * end_gdalt (if qualifier == 4 (GSM XY plane), this will be ZGSM = 0 instead)
*
*      If failure, all end* parameters will be set to missing
*
*
*   Returns:
*      double - 0 if success, -1 if failure
*/
int traceTsyganenkoField(double time,
                         double gdlat,
		         double glon,
		         double gdalt,
		         double swspd_now,
		         double swspd_1hour,
		         double imf_ygsm_now,
		         double imf_ygsm_1hour,
		         double imf_zgsm_now,
		         double imf_zgsm_1hour,
		         double swden,
		         double dst,
			 int    qualifier,
			 double stopAlt,
		         double * end_gdlat,
		         double * end_glon,
		         double * end_gdalt)
 
 

/***********************************************************************
*
* getTsyganenkoG1Index - a helper method that calculates the Tsyganenko G1 Index
*    as defined in ftp://nssdcftp.gsfc.nasa.gov/models/magnetospheric/tsyganenko/
*                        2001paper/Paper2/2001ja000220.pdf.
*
*    Note that the 2001 Tsyganenko G1 index uses IMF and solar wind
*    speed measurements taken every 5 minutes for a hour.  Since
*    Madrigal presently only has hourly measurements, we'll just average
*    two measurements instead of 12.
*
*
*   arguments:
*      double swspd_now - solar wind speed now in m/s
*      double swspd_1hour - solar wind speed 1 hour earlier in m/s
*      double imf_ygsm_now - imf in y gsm direction in nTesla measured now
*      double imf_ygsm_1hour - imf in y gsm direction in nTesla measured 1 hour ago
*      double imf_zgsm_now - imf in z gsm direction in nTesla measured now
*      double imf_zgsm_1hour - imf in z gsm direction in nTesla measured 1 hour ago
*
*
*   Returns:
*      double - G1 index.  If problem, returns missing.
*/
double getTsyganenkoG1Index(double swspd_now,
                            double swspd_1hour,
			    double imf_ygsm_now,
			    double imf_ygsm_1hour,
			    double imf_zgsm_now,
			    double imf_zgsm_1hour)
 
 

/***********************************************************************
*
* getTsyganenkoG2Index - a helper method that calculates the Tsyganenko G2 Index
*    as defined in ftp://nssdcftp.gsfc.nasa.gov/models/magnetospheric/tsyganenko/
*                        2001paper/Paper2/2001ja000220.pdf.
*
*    Note that the 2001 Tsyganenko G2 index uses IMF and solar wind
*    speed measurements taken every 5 minutes for a hour.  Since
*    Madrigal presently only has hourly measurements, we'll just average
*    two measurements instead of 12.
*
*
*   arguments:
*      double swspd_now - solar wind speed now in m/s
*      double swspd_1hour - solar wind speed 1 hour earlier in m/s
*      double imf_zgsm_now - imf in z gsm direction in nTesla measured now
*      double imf_zgsm_1hour - imf in z gsm direction in nTesla measured 1 hour ago
*
*
*   Returns:
*      double - G1 index.  If problem, returns missing.
*/
double getTsyganenkoG2Index(double swspd_now,
                            double swspd_1hour,
			    double imf_zgsm_now,
			    double imf_zgsm_1hour)
 
 

/***********************************************************************
*
* traceMagneticField - a public method used to support the Magnetic field
*                      line trace web service.
*
*
*
*   arguments:
*      int year
*      int month
*      int day
*      int hour
*      int min
*      int sec
*      double gdlat - geodetic latitude of starting point
*      double glon - longitude of starting point
*      double gdalt - geodetic altitude of starting point
*      int model - 0 for Tsyganenko, 1 for IGRF
*      int qualifier - 0 for conjugate, 1 for north_alt, 2 for south_alt, 3 for apex, 4 for GSM XY plane
*            If qualifier == 4, model must be Tsyganenko.
*      double * stopAlt - altitude to stop trace at, if qualifier is north_alt or south_alt.
*                         If other qualifier, this parameter is ignored
*           (the following are output parameters)
*      double * end_gdlat (if qualifier == 4 (GSM XY plane), this will be XGSM instead)
*      double * end_glon (if qualifier == 4 (GSM XY plane), this will be YGSM  instead)
*      double * end_gdalt (if qualifier == 4 (GSM XY plane), this will be ZGSM = 0 instead)
*
*
*   Returns:
*      double - 0 if success, -1 if failure
*/
int traceMagneticField(int year,
                       int month,
		       int day,
		       int hour,
		       int min,
		       int sec,
                       double gdlat,
		       double glon,
		       double gdalt,
		       int model,
		       int qualifier,
		       double stopAlt,
		       double * end_gdlat,
		       double * end_glon,
		       double * end_gdalt)
 
 

/***********************************************************************
*
* run_iri - a public method used to simplify calling the iri model
*
*
*
*   input arguments: *      int year
*      int month
*      int day
*      int hour
*      int min
*      int sec
*      double gdlat - geodetic latitude of starting point
*      double glon - longitude of starting point
*      double gdalt - geodetic altitude of starting point
*      double * iri - array of 11 doubles containing returned data -
*                   allocated by user.  Contains :
*            NE_IRI     Electron density in #/meter3.    units: m-3
*            NEL_IRI    Log of electron density in #/meter3.   units:log10(m-3)
*            TN_IRI  IRI Neutral temperature
*            TI_IRI   IRI Ion temperature
*            TE_IRI   IRI Electron temperature
*            PO+_IRI   IRI Composition - [O+]/Ne
*            PNO+_IRI   IRI Composition - [NO+]/Ne
*            PO2+_IRI   IRI Composition - [O2+]/Ne
*            PHE+_IRI   IRI Composition - [HE+]/Ne
*            PH+_IRI   IRI Composition - [H+]/Ne
*            PN+_IRI   IRI Composition - [N+]/Ne
*   Returns:
*      double - 0 if success, -1 if failure
*
*   Calls IRI method iri_sub, for only one altitude.  Updated for IRI 2007 release.
*/
int run_iri(int year,
            int month,
            int day,
            int hour,
            int min,
            int sec,
            double gdlat,
            double glon,
            double gdalt,
            double * iri)
 
 

/***********************************************************************
 *
 *  faraday_rotation    calculates total phase shift due to a single pass of an
 *                      electromagnetic wave from a ground instrument to a point
 *                      in space.
 *
 *   Uses quasi-longitudinal approximation, so not appropriate if perp
 *   to magnetic field.
 *   Uses coord and IRI from geolib
 *
 *   Inputs: year month day hour min sec sgdlat slon sgdalt gdlat glon gdalt freq
 *           double * tec, double * total_tec
 *
 *   where sgdlat slon sgdalt are geodetic station location,
 *   gdlat glon gdalt are geodetic point locations, and freq is
 *   wave frequency in Hz.
 *   double * tec is a pointer to a double, which is set to total tec from
 *          station to point in electons/m^2, or missing if error.
 *   double * total_tec is a pointer to a double, which is set to total tec from
 *          station to GPS satellite height (22000 km) in electons/m^2 through line containing
 *          point, or missing if error.
 *
 *   Returns: one way faraday rotation in radians, missing if error
 */
double faraday_rotation(int year, int month, int day, int hour, int min, int sec,
		                double sgdlat, double slon, double sgdalt,
		                double gdlat, double glon, double gdalt, double freq,
		                double * tec, double * total_tec)
 
 

/***********************************************************************
*
* getByear   derives Byear from IBYR
*
*   arguments:
*      inCount (num inputs) = 1 (IBYR)
*      inputArr - double array holding:
*                 IBYR - year of beginning of record
*      outCount (num outputs) = 1 (BYEAR)
*      outputArr - double array holding:
*                 BYEAR - year of beginning of record
*
*   Algorithm: BYEAR =  IBYR directly from prolog
*
*   returns - 0 (successful)
*/
int getByear(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getTime   derives basic time parameters from all prolog time information.
*
*    All outputs set at average time between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 7 (YEAR, MONTH, DAY, HOUR, MIN, SEC, CSEC)
*      outputArr - double array holding:
*                  YEAR - year at avg time in record
*                  MONTH - month at avg time in record
*                  DAY - day at avg time in record
*                  HOUR - hour at avg time in record
*                  MIN - min at avg time in record
*                  SEC - sec at avg time in record
*                  CSEC - centisec at avg time in record
*
*   Algorithm: Determine average time in record, determine time
*
*   returns - 0 (successful)
*/
int getTime(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getBmd   derives Bmd from IBDT
*
*   arguments:
*      inCount (num inputs) = 1 (IBDT)
*      inputArr - double array holding IBDT - mmdd of beginning of record
*      outCount (num outputs) = 1 (BMD)
*      outputArr - double array holding BMD - mmdd of beginning of record
*
*   Algorithm: BMD =  IBDT directly from prolog
*
*   returns - 0 (successful)
*/
int getBmd(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getBMonthDay   derives BMONTH and BDAY from IBDT
*
*   arguments:
*      inCount (num inputs) = 1 (IBDT)
*      inputArr - double array holding IBDT - mmdd of beginning of record
*      outCount (num outputs) = 2 (BMONTH and BDAY)
*      outputArr - double array holding BMONTH and BDAY - month and day of beginning of record
*
*   Algorithm: BMonth =  IBDT directly from prolog / 100
*              BDay = IBDT - 100*BMonth
*
*   returns - 0 (successful)
*/
int getBMonthDay(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getMd   derives mmdd from all prolog time information.
*
*    Mmdd is set as mmdd at average time between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (MD)
*      outputArr - double array holding: MD - mmdd at avg time in record
*
*   Algorithm: Determine average time in record, determine its mmdd
*
*   returns - 0 (successful)
*/
int getMd(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getUtUnix   derives ut1_unix and ut2_unix from all prolog time information.
*
*    ut1_unix is the unix timestamp (referenced to midnight UT 1/1/1970)
*    of the beginning of the record (seconds)
*    ut2_unix is the unix timestamp (referenced to midnight UT 1/1/1970)
*    of the end of the record (seconds)
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 2 (UT1_UNIX, UT2_UNIX)
*      outputArr - double array holding: UT1_UNIX - Unix seconds (1/1/1970) at start
*                                        UT2_UNIX - Unix seconds (1/1/1970) at end
*
*   Algorithm: Determine average time in record, determine its mmdd
*
*   returns - 0 (successful)
*/
int getUtUnix(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getDayno   derives day number from all prolog time information.
*
*    dayno is set as the day number (1-366) at average time between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (DAYNO)
*      outputArr - double array holding: DAYNO - day number at avg time in record
*
*   Algorithm: Determine average time in record, determine its day number
*
*   returns - 0 (successful), -1 if error
*/
int getDayno(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getBhm   derives Bhm from IBHM
*
*   arguments:
*      inCount (num inputs) = 1 (IBHM)
*      inputArr - double array holding IBHM - hhmm of beginning of record
*      outCount (num outputs) = 1 (BHM)
*      outputArr - double array holding BHM - hhmm of beginning of record
*
*   Algorithm: BHM =  IBHM directly from prolog
*
*   returns - 0 (successful)
*/
int getBhm(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getBhhmmss   derives Bhhmmss from IBHM and IBCS
*
*   arguments:
*      inCount (num inputs) = 2 (IBHM, IBCS)
*      inputArr - double array holding IBHM - hhmm of beginning of record
*                                      IBCS - centiseconds at beginning of record
*      outCount (num outputs) = 1 (BHHMMSS)
*      outputArr - double array holding BHHMMSS - hhmmss of beginning of record
*
*   Algorithm: BHHMMSS from  IBHM*100 + IBCS/100
*
*   returns - 0 (successful)
*/
int getBhhmmss(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getEhhmmss   derives Ehhmmss from IEHM and IECS
*
*   arguments:
*      inCount (num inputs) = 2 (IEHM, IECS)
*      inputArr - double array holding IEHM - hhmm of ending of record
*                                      IECS - centiseconds at ending of record
*      outCount (num outputs) = 1 (EHHMMSS)
*      outputArr - double array holding EHHMMSS - hhmmss of ending of record
*
*   Algorithm: EHHMMSS from  IEHM*100 + IECS/100
*
*   returns - 0 (successful)
*/
int getEhhmmss(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getHm   derives hhmm from all prolog time information.
*
*    HM is set as hhmm at average time between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (HM)
*      outputArr - double array holding: HM - hhmm at avg time in record
*
*   Algorithm: Determine average time in record, determine its hhmm
*
*   returns - 0 (successful)
*/
int getHm(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getUth   derives UTH (hours since midnight UT of first day of experiment)
*          from all prolog time information.
*
*    UTH is set as the number of hours at average time between beginning
*    and end of record since midnight UT of first day of experiment.
*
*   arguments:
*      inCount (num inputs) = 12 (FIRST_IBYR, FIRST_IBDT, FIRST_IBHM, FIRST_IBCS,
*                                 IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (UTH)
*      outputArr - double array holding: UTH - number of hours at avg time in record
*                  since midnight UT of first day of experiment.
*
*   Algorithm: Determine average time in record, determine when midnight of first day
*              was using FIRST_*, get number of hours since then
*
*   returns - 0 (successful)
*/
int getUth(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getUts   derives UTS (seconds since midnight UT of first day of experiment)
*          from all prolog time information.
*
*    UTS is set as the number of seconds at average time between beginning
*    and end of record since midnight UT of first day of experiment.
*
*   arguments:
*      inCount (num inputs) = 12 (FIRST_IBYR, FIRST_IBDT, FIRST_IBHM, FIRST_IBCS,
*                                 IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (UTS)
*      outputArr - double array holding: UTS - number of seconds at avg time in record
*                  since midnight UT of first day of experiment.
*
*   Algorithm: Determine average time in record, determine when midnight of first day
*              was using FIRST_*, get number of seconds since then
*
*   returns - 0 (successful)
*/
int getUts(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getBUth   derives B_UTH (hours until start time since midnight UT of first day of experiment)
*           from all prolog time information.
*
*    B_UTH is set as the number of hours at beginning time
*    of record since midnight UT of first day of experiment.
*
*   arguments:
*      inCount (num inputs) = 8 (FIRST_IBYR, FIRST_IBDT, FIRST_IBHM, FIRST_IBCS,
*                                IBYR, IBDT, IBHM, IBCS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (B_UTH)
*      outputArr - double array holding: B_UTH - number of hours at record start time
*                  since midnight UT of first day of experiment.
*
*   Algorithm: Get start time in record, determine when midnight of first day
*              was using FIRST_*, get number of hours since then
*
*   returns - 0 (successful)
*/
int getBUth(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getInttms   derives integration time in seconds from all prolog time information.
*
*    INTTMS is set as the number of seconds between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (INTTMS)
*      outputArr - double array holding: INTTMS - number of seconds between beginning
*                                        and end of record
*
*   Algorithm: Determine beg and end time in record, determine difference in seconds
*
*   returns - 0 (successful)
*/
int getInttms(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getInttmm   derives integration time in minutes from all prolog time information.
*
*    INTTMM is set as the number of minutes between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (INTTMM)
*      outputArr - double array holding: INTTMM - number of minutes between beginning
*                                        and end of record
*
*   Algorithm: Determine beg and end time in record, determine difference in minutes
*
*   returns - 0 (successful)
*/
int getInttmm(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getDatntd   derives integration time in days from all prolog time information.
*
*    INTTMM is set as the number of days between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (DATNTD)
*      outputArr - double array holding: DATNTD - number of days between beginning
*                                        and end of record
*
*   Algorithm: Determine beg and end time in record, determine difference in days
*
*   returns - 0 (successful)
*/
int getDatntd(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getUt   derives UT  (Hours since midnight of exp beg, MOD 24).
*
*
*   arguments:
*      inCount (num inputs) = 1 (UTH)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (UT)
*      outputArr - double array holding: UT - Hours since midnight
*                                        of exp beg, MOD 24
*
*   Algorithm: UT = fmod(UTH, 24.0)
*
*   returns - 0 (successful)
*/
int getUt(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getBegUt   derives Beg_UT  (Hours since midnight of exp beg, MOD 24, using start time).
*
*
*   arguments:
*      inCount (num inputs) = 1 (B_UTH)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (BEG_UT)
*      outputArr - double array holding: BEG_UT - Hours since midnight
*                                        of exp beg, MOD 24, using start time
*
*   Algorithm: BEG_UT = fmod(B_UTH, 24.0)
*
*   returns - 0 (successful)
*/
int getBegUt(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getJdayno   derives Julian day number from all prolog time information.
*
*    Jdayno is set as day number at average time between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (JDAYNO)
*      outputArr - double array holding: JDAYNO (Julian day number)
*
*   Algorithm: Determine average time in record, determine its Julian Day number
*              via date method jday.
*
*   returns - 0 (successful), -1 if error
*/
int getJdayno(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getJulian_date   derives Julian day wich is a float number from all prolog time information.
*
*    Julian_date is set as Julian date at average time between beginning
*    and end of record.
*
*   arguments:
*      inCount (num inputs) = 9 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS, JDAYNO)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (Julian_date)
*      outputArr - double array holding: Julian_date (is a float)
*
*
*
*   returns - 0 (successful), -1 if error
*/
int getJulian_date(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getUt1   derives UT1 from prolog start time.
*
*    UT1 is the number of seconds from 1/1/1950 to record start time.
*
*   arguments:
*      inCount (num inputs) = 4 (IBYR, IBDT, IBHM, IBCS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (UT1)
*      outputArr - double array holding: UT1
*
*   Algorithm: Determine start time in record via dmadptr
*
*   returns - 0 (successful)
*/
int getUt1(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getUt2   derives UT2 from prolog end time.
*
*    UT2 is the number of seconds from 1/1/1950 to record end time.
*
*   arguments:
*      inCount (num inputs) = 4 (IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (UT2)
*      outputArr - double array holding: UT2
*
*   Algorithm: Determine end time in record via dmadptr
*
*   returns - 0 (successful)
*/
int getUt2(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getDut21   derives Integration time in secs from UT2 - UT1.
*
*
*   arguments:
*      inCount (num inputs) = 2 (UT1, UT2)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (DUT21)
*      outputArr - double array holding: DUT21 (record/integration
*                  time in seconds).
*
*   Algorithm: DUT21 = UT2 - UT1
*
*   returns - 0 (successful)
*/
int getDut21(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getFyear   derives average time as float year from all prolog time information.
*
*    Fyear is set at average time between beginning
*    and end of record in units of years.
*
*   arguments:
*      inCount (num inputs) = 8 (IBYR, IBDT, IBHM, IBCS, IEYR, IEDT, IEHM, IECS)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 1 (FYEAR)
*      outputArr - double array holding: FYEAR - ave time in years
*
*   Algorithm: Determine average time in record, determine its fyear
*
*   returns - 0 (successful)
*/
int getFyear(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getStation   gets instrument lat, lon, and alt given kinst.
*
*
*   arguments:
*      inCount (num inputs) = 1 (KINST)
*      inputArr - double array holding inputs from above
*      outCount (num outputs) = 3 (GDLATR, GDLONR, GALTR)
*      outputArr - double array holding:
*                         GDLATR - Inst geod latitude (N hemi=pos) - deg
*                         GDLONR - Inst geod longitute - deg
*                         GALTR  - Inst altitute above sea level (km)
*
*   Algorithm: Gets all data from instTab.txt via cedarGetStationPos
*
*   returns - 0 (successful)
*/
int getStation(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getAltInc   derives GDALT as  ALTB + (ROW*ALTAV)
*
*   arguments:
*      inCount (num inputs) = 3 (ROW, ATLB, ALTAV)
*      inputArr - double array holding:
*                 ROW - 2D row number (start at 0)
*                 ALTB - starting altitude
*                 ALTAV - altitude increment per row
*      outCount (num outputs) = 1 (GDALT in km)
*      outputArr - double array holding:
*                 GDALT - Geodetic altitude in km
*
*   Algorithm: GDALT = ALTB + (ROW*ALTAV)
*
*   returns - 0 (successful)
*/
int getAltInc(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getAveAlt   derives GDALT as average of ALTB and ALTE
*
*   arguments:
*      inCount (num inputs) = 2 (ATLB, ALTE)
*      inputArr - double array holding:
*                 ALTB - starting altitude
*                 ALTE - ending altitude
*      outCount (num outputs) = 1 (GDALT in km)
*      outputArr - double array holding:
*                 GDALT - Geodetic altitude in km
*
*   Algorithm: GDALT = (ATLB + ALTE)/2
*
*   returns - 0 (successful)
*/
int getAveAlt(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getAveDAlt   derives dGDALT given dALTB and dALTE
*
*   arguments:
*      inCount (num inputs) = 2 (DATLB, DALTE)
*      inputArr - double array holding:
*                 DALTB - error in starting altitude (km)
*                 DALTE - error in sending altitude km)
*      outCount (num outputs) = 1 (DGDALT in km)
*      outputArr - double array holding:
*                 DGDALT - error in Geodetic altitude in km
*
*   Algorithm: dGDALT = 1/2(DATLB^2 + DALTE^2)^1/2
*
*   returns - 0 (successful)
*/
int getAveDAlt(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getResl   derives resl from mresl
*
*   A trivial method that equates the Millstone range resolution with
*   the standard range resolution
*
*   arguments:
*      inCount (num inputs) = 1 (MRESL)
*      inputArr - double array holding:
*                 MRESL - Millstone specific range resolution in km
*      outCount (num outputs) = 1 (RESL in km)
*      outputArr - double array holding:
*                 RESL - range resolution in km
*
*   Algorithm: RESL = MRESL
*
*   returns - 0 (successful)
*/
int getResl(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getAzmDaz   derives AZM and DAZ from AZ1 and AZ2
*
*   arguments:
*      inCount (num inputs) = 2 (AZ1, AZ2)
*      inputArr - double array holding:
*                 AZ1 - starting azimuth
*                 AZ2 - ending azimuth
*      outCount (num outputs) = 2 (AZM and DAZ)
*      outputArr - double array holding:
*                 AZM - median azimuth from -180 to 180 deg
*                 DAZ - Degrees of rotation from AZ1 to AZ2
*
*   Algorithm: The assumption is made that a clockwise motion
*   of the antenna always increases AZ, and counterclockwise
*   decreases AZ.  In case this convention is not followed,
*   a warning is printed to errFile whenever abs(DAZ) is greater
*   than 180 degrees.
*
*   This warning surpressed per request SRI on 1/15/2004
*
*   returns - 0 (successful)
*/
int getAzmDaz(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getDAzmDDaz   derives DAZM and DDAZ from DAZ1 and DAZ2
*
*   arguments:
*      inCount (num inputs) = 2 (DAZ1, DAZ2)
*      inputArr - double array holding:
*                 DAZ1 - error in starting azimuth
*                 DAZ2 - error in ending azimuth
*      outCount (num outputs) = 2 (DAZM and DDAZ)
*      outputArr - double array holding:
*                 AZM - error in median azimuth from -180 to 180 deg
*                 DAZ - error in Degrees of rotation from AZ1 to AZ2
*
*   Algorithm: dAZM = 1/2(DDAZ1^2 + DDAZ2^2)^1/2
*              dDAZ = (DDAZ1^2 + DDAZ2^2)^1/2
*
*   returns - 0 (successful)
*/
int getDAzmDDaz(int inCount,
                double * inputArr,
                int outCount,
                double * outputArr,
                FILE * errFile)
 
 

/***********************************************************************
*
* getElmDel   derives ELM and DEL from EL1 and EL2
*
*   arguments:
*      inCount (num inputs) = 2 (EL1, EL2)
*      inputArr - double array holding:
*                 EL1 - starting elevation in deg
*                 EL2 - ending elevation in deg
*      outCount (num outputs) = 2 (ELM, DEL)
*      outputArr - double array holding:
*                 ELM - median elevation in deg
*                 DEL - degrees of rotation between EL1 and EL2
*
*   Algorithm: ELM = EL1+EL2 / 2; DEL = EL2 - EL1
*
*   returns - 0 (successful)
*/
int getElmDel(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getDElmDDel   derives DELM and DDEL from DEL1 and DEL2
*
*   arguments:
*      inCount (num inputs) = 2 (DEL1, DEL2)
*      inputArr - double array holding:
*                 DEL1 - error in starting elevation
*                 DEL2 - error in ending elevation
*      outCount (num outputs) = 2 (DELM and DDEL)
*      outputArr - double array holding:
*                 ELM - error in median elevation
*                 DEL - error in Degrees of rotation from EL1 to EL2
*
*   Algorithm: dELM = 1/2(DDEL1^2 + DDEL2^2)^1/2
*              dDEL = (DDEL1^2 + DDEL2^2)^1/2
*
*   returns - 0 (successful)
*/
int getDElmDDel(int inCount,
                double * inputArr,
                int outCount,
                double * outputArr,
                FILE * errFile)
 
 

/***********************************************************************
*
* getGeod   derives Geodetic lat, long and alt from kinst, azm, elm, and range
*
*   arguments:
*      inCount (num inputs) = 4 (KINST, AZM, ELM, RANGE)
*      inputArr - double array holding:
*                 KINST - instrument id
*                 AZM - mean azimuth in deg
*                 ELM - mean elevation in deg
*                 RANGE - range in km
*      outCount (num outputs) = 3 (GDLAT, GLON, GDALT)
*      outputArr - double array holding:
*                 GDLAT - geodetic latitude of measurement
*                 GLON - geodetic longitude of measurement
*                 GDALT - geodetic altitude of measurement
*
*   Algorithm: Calls los2geodetic from geometry.c
*
*   returns - 0 (successful)
*/
int getGeod(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getDGeod   derives error in Geodetic lat, long and alt
*            from azm, dazm, elm, delm, range, and drange
*
*   arguments:
*      inCount (num inputs) = 7 (KINST, AZM, DAZM, ELM, DELM, RANGE, DRANGE)
*      inputArr - double array holding:
*                 KINST - instrument id
*                 AZM - mean azimuth in deg
*                 DAZM - error in mean azimuth
*                 ELM - mean elevation in deg
*                 DELM - error in mean elevation
*                 RANGE - range in km
*                 DRANGE - error in range
*      outCount (num outputs) = 3 (DGDLAT, DGLON, DGDALT)
*      outputArr - double array holding:
*                 DGDLAT - error in geodetic latitude
*                 DGLON - error in geodetic longitude
*                 DGDALT - error in geodetic altitude
*
*   Algorithm: Calculate derivatives with respect to AZM, ELM, and
*              RANGE by simply finding the difference with them
*              incremented by 1 degree or 1 km.  These derivitives
*              are:
*                 dlatdaz, dlatdel, dlatdrange
*                 dlondaz, dlondel, dlondrange
*                 daltdaz, daltdel, daltdrange
*
*              then:
*
*     dgdlat = ((dlatdaz*dazm)^2 + (dlatdel*delm)^2 + (dlatdrange*drange)^2)^1/2
*     dgdlon = ((dlondaz*dazm)^2 + (dlondel*delm)^2 + (dlondrange*drange)^2)^1/2
*     dgdalt = ((daltdaz*dazm)^2 + (daltdel*delm)^2 + (daltdrange*drange)^2)^1/2
*
*   returns - 0 (successful)
*/
int getDGeod(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getGeodGdalt   derives Geodetic lat, long and alt from kinst, azm, elm, and gdalt
*
*   arguments:
*      inCount (num inputs) = 4 (KINST, AZM, ELM, GDALT)
*      inputArr - double array holding:
*                 KINST - instrument id
*                 AZM - mean azimuth in deg
*                 ELM - mean elevation in deg
*                 GDALT - alt in km
*      outCount (num outputs) = 3 (GDLAT, GLON)
*      outputArr - double array holding:
*                 GDLAT - geodetic latitude of measurement
*                 GLON - geodetic longitude of measurement
*
*   Algorithm: Calls los2geodetic from geometry.c after calculating range
*
*   returns - 0 (successful)
*/
int getGeodGdalt(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getGeodAlt   derives Geodetic lat, long  by assuming measured point is
*              directly above instrument
*
*    This method will be called only if GDLAT, GLON cannot be derived
*    any other way
*
*   arguments:
*      inCount (num inputs) = 2 (GDLATR, GDLONR)
*      inputArr - double array holding:
*                 GDLATR - Inst geod latitude (N hemi=pos) - deg
*                 GDLONR - Inst geod longitute - deg
*      outCount (num outputs) = 2 (GDLAT, GLON)
*      outputArr - double array holding:
*                 GDLAT - geodetic latitude of measurement
*                 GLON - longitude of measurement
*
*   Algorithm: Sets GDLAT, GLON to station values
*
*   returns - 0 (successful)
*/
int getGeodAlt(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getAzElRange   derives Azm, Elm, and Range given gdlat,glon,gdalt
*                (point position) and gdlatr,glonr,galtr (station position)
*
*    This method will be called only if Azm, Elm, and Range cannot be derived
*    any other way
*
*   arguments:
*      inCount (num inputs) = 6 (GDLAT, GLON, GDALT, GDLATR, GDLONR, GALTR)
*      inputArr - double array holding:
*                 GDLAT - geodetic latitude of measurement
*                 GLON - longitude of measurement
*                 GDALT - geodetic altitude of measurement in km
*                 GDLATR - Inst geod latitude (N hemi=pos) - deg
*                 GDLONR - Inst geod longitute - deg
*                 GALTR - geodetic altitude of station in km
*      outCount (num outputs) = 3 (AZM, ELM, RANGE)
*      outputArr - double array holding:
*                 AZM - mean azimuth in deg
*                 ELM - mean elevation in deg
*                 RANGE - range in km
*
*   Algorithm: See look in geometry.c
*
*   returns - 0 (successful)
*/
int getAzElRange(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getSZen   derives Solar zenith angle in deg (0 = overhead)
*
*   arguments:
*      inCount (num inputs) = 4 (UT1, UT2, GDLAT, GLON)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*      outCount (num outputs) = 1 (SZEN)
*      outputArr - double array holding:
*                 SZEN - Solar zenith angle in deg (0 = overhead)
*
*   Algorithm: See solarzen in geometry.c
*
*   returns - 0 (successful)
*/
int getSZen(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getSltmut   derives SLTMUT (local solar time diff)
*
*   arguments:
*      inCount (num inputs) = 3 (UT1, UT2, GLON)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GLON - geodetic longitude
*      outCount (num outputs) = 1 (SLTMUT)
*      outputArr - double array holding:
*                 SLTMUT - Local solar time diff (=SLT-UT) +E lon in hhmm
*
*   Algorithm: Add 3600*24*GLON/360 to average UT - convert to hhmm, where
*              GLON goes from -180 to 180
*
*   returns - 0 (successful)
*/
int getSltmut(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getSlt   derives SLT (local solar time  in hours)
*
*   arguments:
*      inCount (num inputs) = 3 (UT1, UT2, GLON)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GLON - geodetic longitude
*      outCount (num outputs) = 1 (SLT)
*      outputArr - double array holding:
*                 SLT - Local solar time in hours (0-24)
*
*   Algorithm: Add 3600*24*GLON/360 to average UT - convert to hours, where
*              GLON goes from -180 to 180
*
*   returns - 0 (successful)
*/
int getSlt(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getSdwHt   derives shadowheight - the distance directly above any gdlat and glon
*              for a given UT in km at which the earth's shadow terminates.
*              Will be 0.0 on dayside of earth.
*
*   arguments:
*      inCount (num inputs) = 4 (UT1, UT2, GDLAT, GLON)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*      outCount (num outputs) = 1 (SDWHT)
*      outputArr - double array holding:
*                 SDWHT - the distance in km above the given gdlat and glon
*                         at which any part of the sun is visible (may be 0.0)
*
*   Algorithm: See shadowheight in geometry.c
*
*   returns - 0 (successful)
*/
int getSdwHt(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getSuntime  derives sunset and sunrise for given point in space and time
*             for that day UT.
*
*   arguments:
*      inCount (num inputs) = 5 (UT1, UT2, GDLAT, GLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*                 GDALT - geodetic altitude in km
*      outCount (num outputs) = 4 (SUNRISE, SUNSET, SUNRISE_HOUR, SUNSET_HOUR)
*      outputArr - double array holding:
*                 SUNRISE - time (UT) that day of sunrise at that point in space
*                 SUNSET - time (UT) that day of sunset at that point in space
*                 SUNRISE_HOUR - time (in hours UT) that day of sunrise at that point in space
*                 SUNSET_HOUR - time (in hours UT) that day of sunset at that point in space
*
*   Algorithm: See sunrise_set in geometry.c
*
*   returns - 0 (successful)
*/
int getSuntime(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getTecGdalt  returns the altitude associated with a TEC measurement (350 km).
*
*   arguments:
*      inCount (num inputs) = 3 (TEC, GDLAT, GLON)
*      inputArr - double array holding:
*                 TEC - Total electron content
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*      outCount (num outputs) = 1 (GDALT)
*      outputArr - double array holding:
*                 GDALT - geodetic altitude in km
*
*   Algorithm: Hard-coded return of 350.0 km
*
*   returns - 0 (successful)
*/
int getTecGdalt(int inCount,
                double * inputArr,
                int outCount,
                double * outputArr,
                FILE * errFile)
 
 

/***********************************************************************
*
* getGcdist  returns the great circle distance from the instrument to a point in space.
*
*   arguments:
*      inCount (num inputs) = 4 (GDLATR, GDLONR, GDLAT, GLON)
*      inputArr - double array holding:
*                 GDLATR - radar geodetic latitude
*                 GDLONR - radar geodetic longitude
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*      outCount (num outputs) = 1 (GCDIST)
*      outputArr - double array holding:
*                 GCDIST - great circle distance from the instrument to a point in space
*                          relected onto the earth's surface (assumes spherical earth) in km.
*
*   Algorithm: See http://www.faqs.org/faqs/geography/infosystems-faq/ for great circle calculation
*
*   returns - 0 (successful)
*/
int getGcdist(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getMag   derives magnetic parameters given a point in space and time.
*
*   arguments:
*      inCount (num inputs) = 5 (UT1, UT2, GDLAT, GLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*                 GDALT - geodetic altitude
*      outCount (num outputs) = 16
*      outputArr - double array holding:
*                 BN - Northward comp of geomag field (1E-8 T)
*                 BE - Eastward comp of geomag field (1E-8 T)
*                 BD - Downward comp of geomag field (1E-8 T)
*                 BMAG - geomag field strength (1E-8 T)
*                 BDEC - Geomag Field East Declination (deg)
*                 BINC - Geomag Field Downward Inclination (deg)
*                 LSHELL - L value in measurement volume
*                 DIPLAT - Dip latitude in measurement volume (deg)
*                 INVLAT - Invariant latitude in measurement volume (deg)
*                 APLAT - Apex latitude (deg)
*                 APLON - Apex longitude (deg)
*                 MAGCONJLAT - Magnetic conjugate geodetic latitude (deg)
*                 MAGCONJLON - Magnetic conjugate longitude (deg)
*                 CXR - MBperp. Direction Cosine (South [Apex]) m/s
*                 CYR - MBperp. Direction Cosine (East [Apex]) m/s
*                 CZR - MBperp. Direction Cosine (Up field line [Apex]) m/s
*
*   Algorithm: See coord in coord.f
*
*   returns - 0 (successful)
*/
int getMag(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getGeocgm   derives magnetic parameters given a point in space and time using CGM code.
*
*    Uses the GEO-CGM code available at http://nssdc.gsfc.nasa.gov/space/cgm/cgm.html
*
*    Since slower that coord.f, used only to find cgm_lat, cgm_long, and mlt
*
*   arguments:
*      inCount (num inputs) = 5 (UT1, UT2, GDLAT, GLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*                 GDALT - geodetic altitude
*      outCount (num outputs) = 2
*      outputArr - double array holding:
*                 CGM_LAT - Corrected geomagnetic latitude
*                 CGM_LONG - Corrected geomagnetic longitude
*
*   Algorithm: See geocgm01 in geo-cgm.f
*
*   returns - 0 (successful)
*/
int getGeocgm(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getTsygan   derives field line crossing points using Tsyganenko model.
*
*    Finds the crossing point of any given field line determined by
*    the input time and point of either the dipole equatorial plane (that
*    is, the XY plane of the GSM coordinate system), or of the equatorial plane (that
*    is, the XY plane of the GSE coordinate system).  Returns the crossing point
*    of the GSM XY plane as TSYG_EQ_XGSM and TSYG_EQ_YGSM (ZGSM is by definition zero),
*    and of the GSE XY plane as TSYG_EQ_XGSE and TSYG_EQ_YGSE (ZGSE is by definition zero).
*
*   arguments:
*      inCount (num inputs) = 5 (UT1, UT2, GDLAT, GLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*                 GDALT - geodetic altitude
*      outCount (num outputs) = 4
*      outputArr - double array holding:
*                 TSYG_EQ_XGSM - X GSM value where field line crosses GSM XY plane
*                 TSYG_EQ_YGSM - Y GSM value where field line crosses GSM XY plane
*                 TSYG_EQ_XGSE - X GSE value where field line crosses GSE XY plane
*                 TSYG_EQ_YGSE - Y GSE value where field line crosses GSE XY plane
*
*   Algorithm: See Geopack_2003.f, T01_01.f
*
*   returns - 0 (successful)
*/
int getTsygan(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getAacgm   derives AACGM (adjusted altitude corrected geomagnetic) or PACE coordinates.
*
*    Finds AACGM (adjusted altitude corrected geomagnetic) or PACE lat and lon
*    given geodetic lat and lon.
*
*   arguments:
*      inCount (num inputs) = 3 (GDLAT, GLON, GDALT)
*      inputArr - double array holding:
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*                 GDALT - geodetic altitude
*      outCount (num outputs) = 2
*      outputArr - double array holding:
*                 AACGM (adjusted altitude corrected geomagnetic) or PACE latitude
*                 AACGM (adjusted altitude corrected geomagnetic) or PACE longitude
*
*   Algorithm: See sfc_convert_geo_coord.f
*
*   returns - 0 (successful)
*/
int getAacgm(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* fromAacgm   derives geodetic from AACGM (adjusted altitude corrected geomagnetic) or PACE coordinates.
*
*    Finds geodetic lat and lon given AACGM (adjusted altitude corrected geomagnetic) or PACE lat and lon.
*
*   arguments:
*      inCount (num inputs) = 3 (PACLAT, PACLON, GDALT)
*      inputArr - double array holding:
*                 PACLAT - AACGM or PACE latitude
*                 PACLON - AACGM or PACE longitude
*                 GDALT - geodetic altitude
*      outCount (num outputs) = 2
*      outputArr - double array holding:
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*
*   Algorithm: See sfc_convert_geo_coord.f
*
*   returns - 0 (successful)
*/
int fromAacgm(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getMlt   derives AACGM magnetic local time.
*
*    Finds AACGM MLT given time and PACLAT.
*
*   arguments:
*      inCount (num inputs) = 3 (UT1, UT2, PACLAT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 PACLAT - PACE magnetic latitude of meas volume
*      outCount (num outputs) = 1
*      outputArr - double array holding:
*                 MLT (Magnetic local time)
*
*   Algorithm: See mlt.f
*
*   returns - 0 (successful)
*/
int getMlt(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getEregion   derives parameters associated with field lines intercepting the E region.
*
*    Finds 6 parameters related to where the magnetic field line associated with a given
*      input point intersects the E region.
*
*   inCount (num inputs) = 5 (UT1, UT2, GDLAT, GLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*                 GDALT - geodetic altitude
*      outCount (num outputs) = 6
*      outputArr - double array holding:
*                      E_REG_S_LAT - The latitude of the southern point where the magnetic
*                                    field line defined by the input point hits the  E region (100 km)
*                      E_REG_S_LON - The longitude of the southern point where the magnetic
*                                    field line defined by the input point hits the E region (100 km)
*                      E_REG_S_SDWHT - The shadow height of the southern point where the magnetic field
*                                      line defined by the input point hits the E region (100 km).
*                                      Shadow height is the altitude of the lowest point on the line of
*                                      constant geodetic lat and lon in sunlight.
*                      E_REG_N_LAT - The latitude of the northern point where the magnetic
*                                    field line defined by the input point hits the  E region (100 km)
*                      E_REG_N_LON - The longitude of the northern point where the magnetic
*                                    field line defined by the input point hits the E region (100 km)
*                      E_REG_N_SDWHT - The shadow height of the northern point where the magnetic field
*                                      line defined by the input point hits the E region (100 km).
*                                      Shadow height is the altitude of the lowest point on the line of
*                                      constant geodetic lat and lon in sunlight.
*
*
*   Algorithm: Uses traceMagneticField
*
*   returns - 0 (successful)
*/
int getEregion(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getAspect   derives magnetic aspect angle of radar beam and magnetic field
*
*   inCount (num inputs) = 8 (UT1, UT2, GDLATR, GDLONR, GALTR,
                              AZM, ELM, RANGE)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLATR - radar geodetic latitude
*                 GDLONR - radar geodetic longitude
*                 GALTR - radar geodetic altitude
*                 AZM - median azimuth
*                 ELM - median elevation
*                 RANGE - range to point in km
*      outCount (num outputs) = 1
*      outputArr - double array holding:
*                      ASPECT - Magnetic aspect angle
*
*   returns - 0 (successful)
*/
int getAspect(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getSltc   derives SLTC (local solar time at magnetic conjugate point in hours)
*
*   arguments:
*      inCount (num inputs) = 3 (UT1, UT2, MAGCONJLON)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 MAGCONJLON - magnetic conjugate longitude
*      outCount (num outputs) = 1 (SLTC)
*      outputArr - double array holding:
*                 SLTC - Local solar time at magnetic conjugate in hours (0-24)
*
*   Algorithm: Add 3600*24*MAGCONJLON/360 to average UT - convert to hours, where
*              MAGCONJLON goes from -180 to 180
*
*   returns - 0 (successful)
*/
int getSltc(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getAplt   derives APLT (local solar time at magnetic apex point in hours)
*
*   arguments:
*      inCount (num inputs) = 3 (UT1, UT2, APLON)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 APLON - magnetic apex longitude
*      outCount (num outputs) = 1 (APLT)
*      outputArr - double array holding:
*                 APLT - Local solar time at magnetic apex in hours (0-24)
*
*   Algorithm: Add 3600*24*APLON/360 to average UT - convert to hours, where
*              MAGCONJLON goes from -180 to 180
*
*   returns - 0 (successful)
*/
int getAplt(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getSZenc   derives Solar zenith angle at magnetic conjugate in deg (0 = overhead)
*
*   arguments:
*      inCount (num inputs) = 4 (UT1, UT2, MAGCONJLAT, MAGCONJLON)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 MAGCONJLAT - magnetic conjugate geodetic latitude
*                 MAGCONJLON - magnetic conjugate longitude
*      outCount (num outputs) = 1 (SZENC)
*      outputArr - double array holding:
*                 SZEN - Solar zenith angle at magnetic conjugate in deg (0 = overhead)
*
*   Algorithm: See solarzen in geometry.c
*
*   returns - 0 (successful)
*/
int getSZenc(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getConjSun  derives sunset, sunrise, and shadow height for the magnetic conjugate
*             point in space and time for that day UT.
*
*   arguments:
*      inCount (num inputs) = 5 (UT1, UT2, MAGCONJLAT, MAGCONJLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 MAGCONJLAT - magnetic conjugate latitude
*                 MAGCONJLON - magnetic conjugate longitude
*                 GDALT - geodetic altitude in km
*      outCount (num outputs) = 5 (CONJ_SUNRISE, CONJ_SUNSET, CONJ_SUNRISE_H, CONJ_SUNSET_H, MAGCONJSDWHT)
*      outputArr - double array holding:
*                 CONJ_SUNRISE - time (UT) that day of sunrise at magnetic conjugate
*                 CONJ_SUNSET - time (UT) that day of sunset at magnetic conjugate
*                 CONJ_SUNRISE_H - time (in hours UT) that day of sunrise at magnetic conjugate
*                 CONJ_SUNSET_H - time (in hours UT) that day of sunset at magnetic conjugate
*                 MAGCONJSDWHT - shadow height at that time at magnetic conjugate
*
*   Algorithm: See sunrise_set, shadowheight in geometry.c
*
*   returns - 0 (successful)
*/
int getConjSun(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getGeo   derives geophysical parameter Kp, Ap3, Ap, f10.7, and fbar
*          given a time
*
*   arguments:
*      inCount (num inputs) = 2 (UT1, UT2)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*      outCount (num outputs) = 5 (KP, AP3, AP, F10.7, and FBAR)
*      outputArr - double array holding:
*                 KP - Kp Index
*                 AP3 - ap index (3-hourly)
*                 AP - AP index (daily)
*                 F10.7 - solar flux observed (Ottawa)
*                 FBAR - Multiday average observed (Ott)
*
*   Algorithm: Get data from geo500101g.002 at average UT.  Only
*              the first time any thread calls this method will the
*              data file be read into static variable geoDayArr.  Array
*              of GeoDay structs is used since it has a more compact
*              memory footprint than the madrec data structure, and
*              geo500101g.002 is a large file.  The old style file
*              geo500101g.001 will be used if geo500101g.002 is not found.
*
*   returns - 0 if successful, -1 if problem finding either file
*/
int getGeo(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getDst   derives geophysical parameter Dst given a time
*
*   arguments:
*      inCount (num inputs) = 2 (UT1, UT2)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*      outCount (num outputs) = 1 (DST)
*      outputArr - double array holding:
*                 DST - DST index in nT
*
*   Algorithm: Get data from dst570101g.002 at average UT.  Only
*              the first time any thread calls this method will the
*              data file be read into static variable dstDayArr. Array
*              of DstDay structs is used since it has a more compact
*              memory footprint than the madrec data structure, and
*              dst570101g.002 is a large file.  The old style file
*              dst570101g.001 will be used if dst570101g.002 is not found.
*
*   returns - 0 if successful, -1 if problem finding file
*/
int getDst(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getFof2   derives geophysical parameter Fof2 (above particular station) given a time
*
*   arguments:
*      inCount (num inputs) = 2 (UT1, UT2)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 KINST - station kinst above which Fof2 is measured
*      outCount (num outputs) = 1 (FOF@)
*      outputArr - double array holding:
*                 FOF2 - Fof2 in MHz above station
*
*   Algorithm: For now, only works for Millstone, but can be extended
*              to work for any instrument for which data is available. For
*              kinst = 30,31,32, get data from uld761203g.002 at average UT.  Only
*              the first time any thread calls this method will the
*              data file be read into static variable fof2DayArr. Array
*              of Fof2Day structs is used since it has a more compact
*              memory footprint than the madrec data structure, and
*              uld761203g.002 is a large file.  The old style file
*              uld761203g.001 will be used if uld761203g.002 is not found.
*
*   returns - 0 if successful, -1 if problem finding file
*/
int getFof2(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getPopl   derives Popl from log10(Pop).
*
*
*   arguments:
*      inCount (num inputs) = 1 (POP)
*      inputArr - double array holding:
*         POP - Uncorrected electron density (Te/Ti=1) (m-3)
*      outCount (num outputs) = 1 (POPL)
*      outputArr - double array holding:
*         POPL -  Log10(uncorrected electron density)  lg(m-3)
*
*   returns - 0 (successful)
*/
int getPopl(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getPop   derives Pop from 10^(Popl).
*
*
*   arguments:
*      inCount (num inputs) = 1 (POPL)
*      inputArr - double array holding:
*         POPL -  Log10(uncorrected electron density) lg(m-3)
*      outCount (num outputs) = 1 (POP)
*      outputArr - double array holding:
*         POP -  Uncorrected electron density (Te/Ti=1) (m-3)
*
*   returns - 0 (successful)
*/
int getPop(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getNel   derives Nel from log10(Ne).
*
*
*   arguments:
*      inCount (num inputs) = 1 (NE)
*      inputArr - double array holding:
*         NE - electron density (m-3)
*      outCount (num outputs) = 1 (NEL)
*      outputArr - double array holding:
*         NEL -  Log10(electron density) lg(m-3)
*
*   returns - 0 (successful)
*/
int getNel(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getNe   derives Ne from 10^(Nel).
*
*
*   arguments:
*      inCount (num inputs) = 1 (NEL)
*      inputArr - double array holding:
*         NEL -  Log10(electron density) lg(m-3)
*      outCount (num outputs) = 1 (NE)
*      outputArr - double array holding:
*         NE -  electron density (m-3)
*
*   returns - 0 (successful)
*/
int getNe(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getDNel   derives DNel from DNe.
*
*
*   arguments:
*      inCount (num inputs) = 1 (DNE)
*      inputArr - double array holding:
*         DNE - error in electron density (m-3)
*      outCount (num outputs) = 1 (DNEL)
*      outputArr - double array holding:
*         DNEL -  Log10(error in electron density) lg(m-3)
*
*   returns - 0 (successful)
*/
int getDNel(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getDNe   derives DNe from DNel.
*
*
*   arguments:
*      inCount (num inputs) = 1 (DNEL)
*      inputArr - double array holding:
*         DNEL -  Log10(error in electron density) lg(m-3)
*      outCount (num outputs) = 1 (DNE)
*      outputArr - double array holding:
*         DNE -  error in electron density (m-3)
*
*   returns - 0 (successful)
*/
int getDNe(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getNemaxl   derives Nemaxl from log10(Nemax).
*
*
*   arguments:
*      inCount (num inputs) = 1 (NEMAX)
*      inputArr - double array holding:
*         NEMAX - Maximum electron density (m-3)
*      outCount (num outputs) = 1 (NEMAXL)
*      outputArr - double array holding:
*         NEMAXL -  Log10(maximum electron density) lg(m-3)
*
*   returns - 0 (successful)
*/
int getNemaxl(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getNemax   derives Nemax from 10^(Nemaxl).
*
*
*   arguments:
*      inCount (num inputs) = 1 (NEMAXL)
*      inputArr - double array holding:
*         NEMAXL -  Log10(maximum electron density) lg(m-3)
*      outCount (num outputs) = 1 (NEMAX)
*      outputArr - double array holding:
*         NEMAX -  Maximum electron density (m-3)
*
*   returns - 0 (successful)
*/
int getNemax(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getTr   derives temperature ratio Te/Ti.
*
*
*   arguments:
*      inCount (num inputs) = 2 (TE, TI)
*      inputArr - double array holding:
*         TE -  Electron temperature - K
*         TI -  Ion temperature - K
*      outCount (num outputs) = 1 (TR)
*      outputArr - double array holding:
*         TR -  Temperature ratio (Te/Ti)
*
*   returns - 0 (successful)
*/
int getTr(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getTe   derives electron temperature Te from Tr*Ti.
*
*
*   arguments:
*      inCount (num inputs) = 2 (TR, TI)
*      inputArr - double array holding:
*         TR -  Temperature ratio (Te/Ti)
*         TI -  Ion temperature - K
*      outCount (num outputs) = 1 (TE)
*      outputArr - double array holding:
*         TE -  Electron temperature - K
*
*   returns - 0 (successful)
*/
int getTe(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getTi   derives ion temperature Ti from Te/Tr.
*
*
*   arguments:
*      inCount (num inputs) = 2 (TE, TR)
*      inputArr - double array holding:
*         TE -  Electron temperature - K
*         TR -  Temperature ratio (Te/Ti)
*      outCount (num outputs) = 1 (TI)
*      outputArr - double array holding:
*         TI -  Ion temperature - K
*
*   returns - 0 (successful)
*/
int getTi(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getDteCctitr   derives error in electron temperature given CCTITR, TI, TR, DTI, and DTR.
*
*
*   arguments:
*      inCount (num inputs) = 5 (CCTITR, TI, TR, DTI, DTR)
*      inputArr - double array holding:
*         CCTITR -  Ti, Tr correlation coefficient
*         TI -  Ion temperature - K
*         TR -  Temperature ratio (Te/Ti)
*         DTI -  Error in Ion temperature - K
*         DTR -  Error in Temperature ratio (Te/Ti)
*      outCount (num outputs) = 1 (DTE)
*      outputArr - double array holding:
*         DTE -  Error in Electron temperature - K
*
*   Algorithm: DTE = SQRT(TR**2*DTI**2 + TI**2*DTR**2 + 2.0D0*TR*TI*CVTITR),
*       where CVTITR = DTI*DTE*CCTITR.
*
*   Uses Ti, Tr correlation coefficient coefficient, unlike getDte, which uses TE
*
*   returns - 0 (successful)
*/
int getDteCctitr(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getDte   derives error in electron temperature given TE, TI, TR, DTI, and DTR.
*
*
*   arguments:
*      inCount (num inputs) = 5 (TE, TI, TR, DTI, DTR)
*      inputArr - double array holding:
*         TE -  Electron temperature - K
*         TI -  Ion temperature - K
*         TR -  Temperature ratio (Te/Ti)
*         DTI -  Error in Ion temperature - K
*         DTR -  Error in Temperature ratio (Te/Ti)
*      outCount (num outputs) = 1 (DTE)
*      outputArr - double array holding:
*         DTE -  Error in Electron temperature - K
*
*   Algorithm: DTE = TE * ((DTR/TR)**2 + (DTI/TI)**2)**1/2.
*
*   returns - 0 (successful)
*/
int getDte(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getCol   derives Col from log10(Co).
*
*
*   arguments:
*      inCount (num inputs) = 1 (CO)
*      inputArr - double array holding:
*         CO - Ion-neutral collision frequency - (s^-1)
*      outCount (num outputs) = 1 (COL)
*      outputArr - double array holding:
*         COL -  Log10(Ion-neutral collision frequency) - lg(s^-1)
*
*   returns - 0 (successful)
*/
int getCol(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getCo   derives Co from 10^(Col).
*
*
*   arguments:
*      inCount (num inputs) = 1 (COL)
*      inputArr - double array holding:
*         COL -  Log10(Ion-neutral collision frequency) - lg(s^-1)
*      outCount (num outputs) = 1 (CO)
*      outputArr - double array holding:
*         CO -  Ion-neutral collision frequency - (s^-1)
*
*   returns - 0 (successful)
*/
int getCo(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getNeNel   derives Ne and Nel from Ti, Tr, Popl, and aspect angle.
*
*
*   arguments:
*      inCount (num inputs) = 4 (TI, TR, POPL, ASPECT)
*      inputArr - double array holding:
*         TI -  Ion temperature - K
*         TR -  Temperature ratio (Te/Ti)
*         POPL -  Log10(uncorrected electron density) lg(m-3)
*         ASPECT - magnetic aspect angle (0 = up B)
*      outCount (num outputs) = 2 (NE, NEL)
*      outputArr - double array holding:
*         NE -  Corrected electron density (m^-3)
*         NEL -  log10 of Corrected electron density lg(m^-3)
*
*   Algorithm - see getElecDensity
*
*   returns - 0 (successful)
*/
int getNeNel(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getDNeDNel   derives DNe and DNel from Ti, Tr, Popl, and aspect angle and associated errors.
*
*
*   arguments:
*      inCount (num inputs) = 7 (TI, TR, POPL, ASPECT, DTI, DTR, DPOPL)
*      inputArr - double array holding:
*         TI -  Ion temperature - K
*         TR -  Temperature ratio (Te/Ti)
*         POPL -  Log10(uncorrected electron density) lg(m-3)
*         ASPECT - magnetic aspect angle (0 = up B)
*         DTI -  Error in Ion temperature - K
*         DTR -  Error in Temperature ratio (Te/Ti)
*         DPOPL -  Error in Log10(uncorrected electron density) lg(m-3)
*      outCount (num outputs) = 2 (DNE, DNEL)
*      outputArr - double array holding:
*         DNE -  Error in Corrected electron density (m^-3)
*         DNEL -  Error in log10 of Corrected electron density lg(m^-3)
*
*   Algorithm - see getElecDensity
*
*   returns - 0 (successful)
*/
int getDNeDNel(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getVisrNe   derives Model Ne, Nel using Shunrong's model
*
*
*   arguments:
*      inCount (num inputs) = 6 (UT1, KINST, SLT, GDALT, GDLAT, ELM)
*      inputArr - double array holding:
*         UT1 - UT at record start
*         KINST - instrument id
*         SLT - Local solar time in hours (0-24)
*         GDALT - geodetic altitude in km
*         GDLAT - geodetic latitude
*         ELM - mean elevation in degrees
*      outCount (num outputs) = 2 (NE_MODEL, NEL_MODEL)
*      outputArr - double array holding:
*         NE_MODEL -  Model electron density (m^-3)
*         NEL_MODEL -  log10 of Model electron density lg(m^-3)
*
*   Algorithm - see Shunrong's model at http://madrigal.haystack.mit.edu/models/
*
*   returns - 0 (successful)
*/
int getVisrNe(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVisrTe   derives Model Te using Shunrong's model
*
*
*   arguments:
*      inCount (num inputs) = 6 (UT1, KINST, SLT, GDALT, GDLAT, ELM)
*      inputArr - double array holding:
*         UT1 - UT at record start
*         KINST - instrument id
*         SLT - Local solar time in hours (0-24)
*         GDALT - geodetic altitude in km
*         GDLAT - geodetic latitude
*         ELM - mean elevation in degrees
*      outCount (num outputs) = 1 (TE_MODEL)
*      outputArr - double array holding:
*         TE_MODEL -  Model electron temperature (K)
*
*   Algorithm - see Shunrong's model at http://madrigal.haystack.mit.edu/models/
*
*   returns - 0 (successful)
*/
int getVisrTe(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVisrTi   derives Model Ti using Shunrong's model
*
*
*   arguments:
*      inCount (num inputs) = 6 (UT1, KINST, SLT, GDALT, GDLAT, ELM)
*      inputArr - double array holding:
*         UT1 - UT at record start
*         KINST - instrument id
*         SLT - Local solar time in hours (0-24)
*         GDALT - geodetic altitude in km
*         GDLAT - geodetic latitude
*         ELM - mean elevation in degrees
*      outCount (num outputs) = 1 (TI_MODEL)
*      outputArr - double array holding:
*         TI_MODEL -  Model ion temperature (K)
*
*   Algorithm - see Shunrong's model at http://madrigal.haystack.mit.edu/models/
*
*   returns - 0 (successful)
*/
int getVisrTi(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVisrVo   derives Model Vo using Shunrong's model
*
*
*   arguments:
*      inCount (num inputs) = 6 (UT1, KINST, SLT, GDALT, GDLAT, ELM)
*      inputArr - double array holding:
*         UT1 - UT at record start
*         KINST - instrument id
*         SLT - Local solar time in hours (0-24)
*         GDALT - geodetic altitude in km
*         GDLAT - geodetic latitude
*         ELM - mean elevation in degrees
*      outCount (num outputs) = 1 (VO_MODEL)
*      outputArr - double array holding:
*         VO_MODEL -  Model line-of sight velocity (up=+) (m/s)
*
*   Algorithm - see Shunrong's model at http://madrigal.haystack.mit.edu/models/
*
*   returns - 0 (successful)
*/
int getVisrVo(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVisrHNMax   derives Model HMax and NMax using Shunrong's model
*
*
*   arguments:
*      inCount (num inputs) = 6 (UT1, KINST, SLT, GDALT, GDLAT, ELM)
*      inputArr - double array holding:
*         UT1 - UT at record start
*         KINST - instrument id
*         SLT - Local solar time in hours (0-24)
*         GDALT - geodetic altitude in km
*         GDLAT - geodetic latitude
*         ELM - mean elevation in degrees
*      outCount (num outputs) = 2 (HMAX_MODEL, NMAX_MODEL)
*      outputArr - double array holding:
*         HMAX_MODEL -  ISR-based empirical model of HMAX
*         NMAX_MODEL -  ISR-based empirical model of NMAX
*
*   Algorithm - see Shunrong's model at http://madrigal.haystack.mit.edu/models/
*
*   returns - 0 (successful)
*/
int getVisrHNMax(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getVisrNeDiff   derives ne_modeldiff - the difference between measured and model ne
*
*
*   arguments:
*      inCount (num inputs) = 2 (NE, NE_MODEL)
*      inputArr - double array holding:
*         NE -  Measured electron density (m^-3)
*         NE_MODEL -  Model electron density (m^-3)
*      outCount (num outputs) = 1 (NE_MODELDIFF)
*      outputArr - double array holding:
*         NE_MODELDIFF -  Measured Ne - Model electron density (m^-3)
*
*   returns - 0 (successful)
*/
int getVisrNeDiff(int inCount,
                  double * inputArr,
                  int outCount,
                  double * outputArr,
                  FILE * errFile)
 
 

/***********************************************************************
*
* getVisrNelDiff   derives nel_modeldiff - the difference between measured and model nel
*
*
*   arguments:
*      inCount (num inputs) = 2 (NEL, NEL_MODEL)
*      inputArr - double array holding:
*         NEL -  Measured electron density log10(m^-3)
*         NEL_MODEL -  Model electron density log10(m^-3)
*      outCount (num outputs) = 1 (NEL_MODELDIFF)
*      outputArr - double array holding:
*         NEL_MODELDIFF -  Measured Nel - Model electron density log10(m^-3)
*
*   returns - 0 (successful)
*/
int getVisrNelDiff(int inCount,
                   double * inputArr,
                   int outCount,
                   double * outputArr,
                   FILE * errFile)
 
 

/***********************************************************************
*
* getVisrTeDiff   derives te_modeldiff - the difference between measured and model te
*
*
*   arguments:
*      inCount (num inputs) = 2 (TE, TE_MODEL)
*      inputArr - double array holding:
*         TE -  Measured electron temperature (K)
*         TE_MODEL -  Model electron temperature (K)
*      outCount (num outputs) = 1 (TE_MODELDIFF)
*      outputArr - double array holding:
*         TE_MODELDIFF -  Measured Te - Model electron temperature (K)
*
*   returns - 0 (successful)
*/
int getVisrTeDiff(int inCount,
                  double * inputArr,
                  int outCount,
                  double * outputArr,
                  FILE * errFile)
 
 

/***********************************************************************
*
* getVisrTiDiff   derives ti_modeldiff - the difference between measured and model ti
*
*
*   arguments:
*      inCount (num inputs) = 2 (TI, TI_MODEL)
*      inputArr - double array holding:
*         TI -  Measured ion temperature (K)
*         TI_MODEL -  Model ion temperature (K)
*      outCount (num outputs) = 1 (TI_MODELDIFF)
*      outputArr - double array holding:
*         TI_MODELDIFF -  Measured TI - Model ion temperature (K)
*
*   returns - 0 (successful)
*/
int getVisrTiDiff(int inCount,
                  double * inputArr,
                  int outCount,
                  double * outputArr,
                  FILE * errFile)
 
 

/***********************************************************************
*
* getVisrVoDiff   derives vo_modeldiff - the difference between measured and model vo
*
*
*   arguments:
*      inCount (num inputs) = 2 (VO, VO_MODEL)
*      inputArr - double array holding:
*         VO -  Measured line-of sight velocity (up=+) (m/s)
*         VO_MODEL -  Model line-of sight velocity (up=+) (m/s)
*      outCount (num outputs) = 1 (VO_MODELDIFF)
*      outputArr - double array holding:
*         VO_MODELDIFF -  Measured Vo - Model line-of sight velocity (up=+) (m/s)
*
*   returns - 0 (successful)
*/
int getVisrVoDiff(int inCount,
                  double * inputArr,
                  int outCount,
                  double * outputArr,
                  FILE * errFile)
 
 

/***********************************************************************
*
* getSn   derives Sn given Snp3
*
*
*   arguments:
*      inCount (num inputs) = 1 (SNP3)
*      inputArr - double array holding:
*         SNP3 - Signal to noise ratio
*      outCount (num outputs) = 1 (SN)
*      outputArr - double array holding:
*         SN - Signal to noise ratio
*
*   Algorithm - SN and SNP3 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getSn(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getSnp3   derives Snp3 given Sn
*
*
*   arguments:
*      inCount (num inputs) = 1 (SN)
*      inputArr - double array holding:
*         SN - Signal to noise ratio
*      outCount (num outputs) = 1 (SNP3)
*      outputArr - double array holding:
*         SNP3 - Signal to noise ratio
*
*   Algorithm - SN and SNP3 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getSnp3(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getChip31   derives Chip3 given Chisq
*
*
*   arguments:
*      inCount (num inputs) = 1 (CHISQ)
*      inputArr - double array holding:
*         CHISQ - Reduced-chi square of fit
*      outCount (num outputs) = 1 (CHIP3)
*      outputArr - double array holding:
*         CHIP3 - Reduced-chi square of fit
*
*   Algorithm - CHISQ and CHIP3 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getChip31(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getWchsq1   derives Wchsq given Chip3
*
*
*   arguments:
*      inCount (num inputs) = 1 (CHIP3)
*      inputArr - double array holding:
*         CHIP3 - Reduced-chi square of fit
*      outCount (num outputs) = 1 (WCHSQ)
*      outputArr - double array holding:
*         WCHSQ - Reduced-chi square of fit
*
*   Algorithm - WCHSQ and CHIP3 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getWchsq1(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getChisq1   derives Chisq given Wchsq
*
*
*   arguments:
*      inCount (num inputs) = 1 (WCHSQ)
*      inputArr - double array holding:
*         WCHSQ - Reduced-chi square of fit
*      outCount (num outputs) = 1 (CHISQ)
*      outputArr - double array holding:
*         CHISQ - Reduced-chi square of fit
*
*   Algorithm - CHISQ and WCHSQ differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getChisq1(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getChip32   derives Chip3 given Wchsq
*
*
*   arguments:
*      inCount (num inputs) = 1 (WCHSQ)
*      inputArr - double array holding:
*         WCHSQ - Reduced-chi square of fit
*      outCount (num outputs) = 1 (CHIP3)
*      outputArr - double array holding:
*         CHIP3 - Reduced-chi square of fit
*
*   Algorithm - WCHSQ and CHIP3 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getChip32(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getWchsq2   derives Wchsq given Chisq
*
*
*   arguments:
*      inCount (num inputs) = 1 (CHISQ)
*      inputArr - double array holding:
*         CHISQ - Reduced-chi square of fit
*      outCount (num outputs) = 1 (WCHSQ)
*      outputArr - double array holding:
*         WCHSQ - Reduced-chi square of fit
*
*   Algorithm - CHISQ and WCHSQ differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getWchsq2(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getChisq2   derives Chisq given Chip3
*
*
*   arguments:
*      inCount (num inputs) = 1 (CHIP3)
*      inputArr - double array holding:
*         CHIP3 - Reduced-chi square of fit
*      outCount (num outputs) = 1 (CHISQ)
*      outputArr - double array holding:
*         CHISQ - Reduced-chi square of fit
*
*   Algorithm - CHISQ and CHIP3 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getChisq2(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVi1Vi1f   derives Vi1 given Vi1f
*
*
*   arguments:
*      inCount (num inputs) = 1 (VI1F)
*      inputArr - double array holding:
*         VI1F - F-region ion velocity in dir 1 (east)
*      outCount (num outputs) = 1 (VI1)
*      outputArr - double array holding:
*         VI1 - Ion velocity in direction 1 (eastward)
*
*   Algorithm - VI1 is just a generalized version of VI1F, so equal
*
*   returns - 0 (successful)
*/
int getVi1Vi1f(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVi2Vi2f   derives Vi2 given Vi2f
*
*
*   arguments:
*      inCount (num inputs) = 1 (VI2F)
*      inputArr - double array holding:
*         VI2F - F-region ion velocity in dir 2 (north)
*      outCount (num outputs) = 1 (VI2)
*      outputArr - double array holding:
*         VI2 - Ion velocity in direction 2 (northward)
*
*   Algorithm - VI2 is just a generalized version of VI2F, so equal
*
*   returns - 0 (successful)
*/
int getVi2Vi2f(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVipeVipe1   derives Vipe given Vipe1
*
*
*   arguments:
*      inCount (num inputs) = 1 (VIPE1)
*      inputArr - double array holding:
*         VIPE1 - Ion velocity in direction 4 (perp east)
*      outCount (num outputs) = 1 (VIPE)
*      outputArr - double array holding:
*         VIPE - Ion velocity in direction 4 (perp east)
*
*   Algorithm - VIPE1 and VIPE differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getVipeVipe1(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getVipeVipe2   derives Vipe given Vipe2
*
*
*   arguments:
*      inCount (num inputs) = 1 (VIPE2)
*      inputArr - double array holding:
*         VIPE2 - Ion velocity in direction 4 (perp east)
*      outCount (num outputs) = 1 (VIPE)
*      outputArr - double array holding:
*         VIPE - Ion velocity in direction 4 (perp east)
*
*   Algorithm - VIPE2 and VIPE differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getVipeVipe2(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getVipnVipn1   derives Vipn given Vipn1
*
*
*   arguments:
*      inCount (num inputs) = 1 (VIPN1)
*      inputArr - double array holding:
*         VIPN1 - Ion velocity in direction 5 (perp north)
*      outCount (num outputs) = 1 (VIPN)
*      outputArr - double array holding:
*         VIPN - Ion velocity in direction 5 (perp north)
*
*   Algorithm - VIPN1 and VIPN differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getVipnVipn1(int inCount,
                 double * inputArr,
                 int outCount,
                 double * outputArr,
                 FILE * errFile)
 
 

/***********************************************************************
*
* getVipnVipn2   derives Vipn given Vipn2
*
*
*   arguments:
*      inCount (num inputs) = 1 (VIPN2)
*      inputArr - double array holding:
*         VIPN2 - Ion velocity in direction 5 (perp north)
*      outCount (num outputs) = 1 (VIPN)
*      outputArr - double array holding:
*         VIPN - Ion velocity in direction 5 (perp north)
*
*   Algorithm - VIPN2 and VIPN differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getVipnVipn2(int inCount,
                double * inputArr,
                int outCount,
                double * outputArr,
                FILE * errFile)
 
 

/***********************************************************************
*
* getVi6Vipu   derives Vipu given Vi6
*
*
*   arguments:
*      inCount (num inputs) = 1 (VI6)
*      inputArr - double array holding:
*         VI6 - Ion velocity in dir 6 (antiparallel)
*      outCount (num outputs) = 1 (VIPU)
*      outputArr - double array holding:
*         VIPU - Parallel ion velocity (+ upward)
*
*   Algorithm - VI6 and VIPU differ only in sign
*
*   returns - 0 (successful)
*/
int getVi6Vipu(int inCount,
               double * inputArr,
               int outCount,
               double * outputArr,
               FILE * errFile)
 
 

/***********************************************************************
*
* getViGeom   derives geomagnetic ion velocity given geodetic ion veleocity
*
*
*   arguments:
*      inCount (num inputs) = 7 (VI1, VI2, VI3, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         VI1 - Ion velocity in direction 1 (eastward)
*         VI2 - Ion velocity in direction 2 (northward)
*         VI3 - Ion velocity in direction 3 (up)
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (VIPE, VIPN, VIPU)
*      outputArr - double array holding:
*         VIPE - Ion velocity in direction 4 (perp east)
*         VIPN - Ion velocity in direction 5 (perp north)
*         VIPU - Parallel ion velocity (+ upward)
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getViGeom(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getViGeod   derives geodetic ion velocity given geomagnetic ion veleocity
*
*
*   arguments:
*      inCount (num inputs) = 7 (VIPE, VIPN, VIPU, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         VIPE - Ion velocity in direction 4 (perp east)
*         VIPN - Ion velocity in direction 5 (perp north)
*         VIPU - Parallel ion velocity (+ upward)
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (VI1, VI2, VI3)
*      outputArr - double array holding:
*         VI1 - Ion velocity in direction 1 (eastward)
*         VI2 - Ion velocity in direction 2 (northward)
*         VI3 - Ion velocity in direction 3 (up)
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getViGeod(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVn1Vn1p2   derives Vn1 given Vn1P2
*
*
*   arguments:
*      inCount (num inputs) = 1 (VN1P2)
*      inputArr - double array holding:
*         VN1P2 - Neutral wind in direction 1 (eastward)
*      outCount (num outputs) = 1 (VN1)
*      outputArr - double array holding:
*         VN1 - Neutral wind in direction 1 (eastward)
*
*   Algorithm - VN1 and VN1P2 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getVn1Vn1p2(int inCount,
                double * inputArr,
                int outCount,
                double * outputArr,
                FILE * errFile)
 
 

/***********************************************************************
*
* getVn2Vn2p2   derives Vn2 given Vn2P2
*
*
*   arguments:
*      inCount (num inputs) = 1 (VN2P2)
*      inputArr - double array holding:
*         VN2P2 - Neutral wind in direction 2 (northward)
*      outCount (num outputs) = 1 (VN2)
*      outputArr - double array holding:
*         VN2 - Neutral wind in direction 2 (northward)
*
*   Algorithm - VN2 and VN2P2 differ only in Cedar scaling factor, which
*               is handled at a lower level
*
*   returns - 0 (successful)
*/
int getVn2Vn2p2(int inCount,
                double * inputArr,
                int outCount,
                double * outputArr,
                FILE * errFile)
 
 

/***********************************************************************
*
* getVnGeom   derives geomagnetic neutral velocity given geodetic neutral velocity
*
*
*   arguments:
*      inCount (num inputs) = 7 (VN1, VN2, VN3, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         VN1 - Neutral wind in direction 1 (eastward)
*         VN2 - Neutral wind in direction 2 (northward)
*         VN3 - Neutral wind in direction 3 (up)
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (VN4, VN5, VN6)
*      outputArr - double array holding:
*         VN4 - Neutral wind in direction 4 (perp east)
*         VN5 - Neutral wind in direction 5 (perp north)
*         VN6 - Neutral wind in dir 6 (antiparallel)
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getVnGeom(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getVnGeod   derives geodetic neutral velocity given geomagnetic neutral velocity
*
*
*   arguments:
*      inCount (num inputs) = 7 (VN4, VN5, VN6, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         VN4 - Neutral wind in direction 4 (perp east)
*         VN5 - Neutral wind in direction 5 (perp north)
*         VN6 - Neutral wind in dir 6 (antiparallel)
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (VN1, VN2, VN3)
*      outputArr - double array holding:
*         VN1 - Neutral wind in direction 1 (eastward)
*         VN2 - Neutral wind in direction 2 (northward)
*         VN3 - Neutral wind in direction 3 (up)
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getVnGeod(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getEFGeom   derives geomagnetic electric field given geodetic electric field
*
*
*   arguments:
*      inCount (num inputs) = 7 (EE, EN, EU, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         EE - Electric field in direction 1 (eastward)
*         EN - Electric field in direction 2 (nrthward)
*         EU - Electric field in direction 3 (up)
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (EPE, EPN, EAP)
*      outputArr - double array holding:
*         EPE - Electric field in direction 4 (perp est)
*         EPN - Electric field in direction 5 (perp nth)
*         EAP - Electric field in direction 6 (antipara)
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getEFGeom(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getEFGeod   derives geodetic electric field given geomagnetic electric field
*
*
*   arguments:
*      inCount (num inputs) = 7 (EPE, EPN, EAP, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         EPE - Electric field in direction 4 (perp est)
*         EPN - Electric field in direction 5 (perp nth)
*         EAP - Electric field in direction 6 (antipara)
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (EE, EN, EU)
*      outputArr - double array holding:
*         EE - Electric field in direction 1 (eastward)
*         EN - Electric field in direction 2 (nrthward)
*         EU - Electric field in direction 3 (up)
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getEFGeod(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getJGeom   derives geomagnetic current density given geodetic current density
*
*
*   arguments:
*      inCount (num inputs) = 7 (J1, J2, J3, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         J1 - Electric current density eastward
*         J2 - Electric current density northward
*         J3 - Electric current density up
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (J4, J5, J6)
*      outputArr - double array holding:
*         J4 - Electric current density perp east
*         J5 - Electric current density perp north
*         J6 - Electric current density antiparallel
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getJGeom(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getJGeod   derives geodetic current density given geomagnetic current density
*
*
*   arguments:
*      inCount (num inputs) = 7 (J4, J5, J6, BN, BE, BD, BMAG)
*      inputArr - double array holding:
*         J4 - Electric current density perp east
*         J5 - Electric current density perp north
*         J6 - Electric current density antiparallel
*         BN - Northward component of geomagnetic fld
*         BE - Eastward component of geomagnetic field
*         BD - Downward component of geomagnetic field
*         BMAG - Geomagnetic field strength
*      outCount (num outputs) = 3 (J1, J2, J3)
*      outputArr - double array holding:
*         J1 - Electric current density eastward
*         J2 - Electric current density northward
*         J3 - Electric current density up
*
*   Algorithm - See http://www.openradar.org/pipermail/openradar-madrigal/2011-September/000086.html
*
*   returns - 0 (successful)
*/
int getJGeod(int inCount,
              double * inputArr,
              int outCount,
              double * outputArr,
              FILE * errFile)
 
 

/***********************************************************************
*
* getNeut  uses MSIS 2000 model to predict neutral atmosphere parameters based
*          on geophysical parameters.  Includes anomalous oxygen component,
*          and also uses array of historical and present AP values, rather than
*          simply present AP value.  For now, errors are all set to 20% of
*          output value
*
*   arguments:
*      inCount (num inputs) = 5 (UT1, UT2, GDLAT, GLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*                 GDLAT - geodetic latitude
*                 GLON - geodetic longitude
*                 GDALT - geodetic altitude
*      outCount (num outputs) = 26 (TNM, TINFM, MOL, NTOTL, NN2L,
*                                   NO2L, NOL, NARL, NHEL, NHL,
*                                   NN4SL, NPRESL, PSH, DTNM, DTINFM, DMOL, DNTOTL, DNN2L,
*                                   DNO2L, DNOL, DNARL, DNHEL, DNHL,
*                                   DNN4SL, DNPRESL, DPSH)
*      outputArr - double array holding:
*                 TNM - Model neutral atmosphere temperature
*                 TINFM - Model Exospheric temperature
*                 MOL - Log10 (nutrl atm mass density in kg/m3)
*                 NTOTL - Log10 (nutrl atm number density in m-3)
*                 NN2L - Nutrl atm compositn-log10([N2] in m-3)
*                 NO2L - Nutrl atm compositn-log10([O2] in m-3)
*                 NOL - Nutrl atm composition-log10([O] in m-3)
*                 NARL - Nutrl atm compositn-log10([AR] in m-3)
*                 NHEL - Nutrl atm compositn-log10([HE] in M-3)
*                 NHL - Nutrl atm composition-log10([H] in m-3)
*                 NN4SL - Nutrl atm compstn-log10([N(4S)] in m-3)
*                 NPRESL - Neutral atmospher log10(pressure in Pa)
*                 PSH - Pressure scale height (m)
*                 DTNM - Error in Model neutral atmosphere temperature
*                 DTINFM - Error in Model Exospheric temperature
*                 DMOL - Error in Log10 (nutrl atm mass density in kg/m3)
*                 DNTOTL - Error in Log10 (nutrl atm number density in m-3)
*                 DNN2L - Error in Nutrl atm compositn-log10([N2] in m-3)
*                 DNO2L - Error in Nutrl atm compositn-log10([O2] in m-3)
*                 DNOL - Error in Nutrl atm composition-log10([O] in m-3)
*                 DNARL - Error in Nutrl atm compositn-log10([AR] in m-3)
*                 DNHEL - Error in Nutrl atm compositn-log10([HE] in M-3)
*                 DNHL - Error in Nutrl atm composition-log10([H] in m-3)
*                 DNN4SL - Error in Nutrl atm compstn-log10([N(4S)] in m-3)
*                 DNPRESL - Error in Neutral atmospher log10(pressure in Pa)
*                 DPSH - Error in Pressure scale height (m)
*
*
*   Algorithm: Calls MSIS subroutine gtd7d after collecting geophysical data.
*              Includes AP data from present and up to 57 hours prior to
*              present.
*
*              Gets pressure via ideal gas law (p=nkT)
*              Gets scale height via kT/mg, where m is average mass
*
*   returns - 0 (successful)
*/
int getNeut(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getTn  uses MSIS model and ISR data to derive Tn.
*
*   arguments:
*      inCount (num inputs) = 9 (TI, TE, NE, PH+, NOL, NHL, NN4SL, NO2L, NHEL)
*      inputArr - double array holding:
*                 TI - Ion temperature (K)
*                 TE - Electron temperature (K)
*                 NE - Electron density (m^3)
*                 PHP - Composition - [HE+]/Ne
*                 NOL - Nutrl atm composition-log10([O] in m-3) (MSIS)
*                 NHL - Nutrl atm composition-log10([H] in m-3) (MSIS)
*                 NN4SL - Nutrl atm compstn-log10([N(4S)] in m-3) (MSIS)
*                 NO2L - Nutrl atm compositn-log10([O2] in m-3) (MSIS)
*                 NHEL - Nutrl atm compositn-log10([HE] in M-3) (MSIS)
*      outCount (num outputs) = 1 (TN )
*      outputArr - double array holding:
*                 TN - Neutral atmosphere temperature (K)
*
*   Algorithm: See tnf.f in madf/geolib
*
*   returns - 0 (successful)
*/
int getTn(int inCount,
          double * inputArr,
          int outCount,
          double * outputArr,
          FILE * errFile)
 
 

/***********************************************************************
*
* getTnNoPhp  uses MSIS model and ISR data to derive Tn - uses Php = 0.
*
*   Meant to be called to get Tn if Php not in measured data
*
*   arguments:
*      inCount (num inputs) = 8 (TI, TE, NE, NOL, NHL, NN4SL, NO2L, NHEL)
*      inputArr - double array holding:
*                 TI - Ion temperature (K)
*                 TE - Electron temperature (K)
*                 NE - Electron density (m^3)
*                 NOL - Nutrl atm composition-log10([O] in m-3) (MSIS)
*                 NHL - Nutrl atm composition-log10([H] in m-3) (MSIS)
*                 NN4SL - Nutrl atm compstn-log10([N(4S)] in m-3) (MSIS)
*                 NO2L - Nutrl atm compositn-log10([O2] in m-3) (MSIS)
*                 NHEL - Nutrl atm compositn-log10([HE] in M-3) (MSIS)
*      outCount (num outputs) = 1 (TN )
*      outputArr - double array holding:
*                 TN - Neutral atmosphere temperature (K)
*
*   Algorithm: See tnf.f in madf/geolib
*
*   returns - 0 (successful)
*/
int getTnNoPhp(int inCount,
               double * inputArr,
	       int outCount,
	       double * outputArr,
	       FILE * errFile)
 
 

/***********************************************************************
*
* getDTn  uses MSIS model and ISR data to derive error in Tn.
*
*   arguments:
*      inCount (num inputs) = 16 (TI, TE, NE, NOL, NHL, NN4SL, NO2L, NHEL,
*                                 DTI, DTE, DNE, DNOL, DNHL, DNN4SL, DNO2L, DNHEL)
*      inputArr - double array holding:
*                 TI - Ion temperature (K)
*                 TE - Electron temperature (K)
*                 NE - Electron density (m^3)
*                 NOL - Nutrl atm composition-log10([O] in m-3) (MSIS)
*                 NHL - Nutrl atm composition-log10([H] in m-3) (MSIS)
*                 NN4SL - Nutrl atm compstn-log10([N(4S)] in m-3) (MSIS)
*                 NO2L - Nutrl atm compositn-log10([O2] in m-3) (MSIS)
*                 NHEL - Nutrl atm compositn-log10([HE] in M-3) (MSIS)
*                 DTI - Error in Ion temperature (K)
*                 DTE - Error in Electron temperature (K)
*                 DNE - Error in Electron density (m^3)
*                 DNOL - Error in Nutrl atm composition-log10([O] in m-3) (MSIS)
*                 DNHL - Error in Nutrl atm composition-log10([H] in m-3) (MSIS)
*                 DNN4SL - Error in Nutrl atm compstn-log10([N(4S)] in m-3) (MSIS)
*                 DNO2L - Error in Nutrl atm compositn-log10([O2] in m-3) (MSIS)
*                 DNHEL - Error in Nutrl atm compositn-log10([HE] in M-3) (MSIS)
*      outCount (num outputs) = 1 (DTN )
*      outputArr - double array holding:
*                 DTN - Error in Neutral atmosphere temperature (K)
*
*   Algorithm: See tnf.f in madf/geolib
*
*   returns - 0 (successful)
*/
int getDTn(int inCount,
           double * inputArr,
	       int outCount,
	       double * outputArr,
	       FILE * errFile)
 
 

/***********************************************************************
*
* getCond  uses Shunrong's code from Schunk and Nagy to derive Pederson and Hall
*          local conductivities.
*
*   arguments:
*      inCount (num inputs) = 10 (TI, TE, NE, PH+_IRI, PO+_IRI, NOL, NN2L, NO2L, TNM, BMAG)
*      inputArr - double array holding:
*                 TI - Ion temperature (K)
*                 TE - Electron temperature (K)
*                 NE - Electron density (m^3)
*                 PH+_IRI - IRI Composition % = [H+]/Ne * 100
*                 PO+_IRI - IRI Composition % = [O+]/Ne * 100
*                 NOL - Nutrl atm composition-log10([O] in m-3) (MSIS)
*                 NN2L - Nutrl atm compositn-log10([N2] in m-3) (MSIS)
*                 NO2L - Nutrl atm compositn-log10([O2] in m-3) (MSIS)
*                 TNM - MSIS Neutral atmosphere temperature (K)
*                 BMAG - Geomagnetic field strength (Tesla)
*      outCount (num outputs) = 4 (PDCON, PDCONL, HLCON, HLCONL)
*      outputArr - double array holding:
*                 PDCON - Pedersen Conductivity in mho/m3
*                 PDCONL - Log10(Pedersen Conductivity in mho/m3)
*                 HLCON - Hall Conductivity in mho/m3
*                 HLCONL - Log10(Hall Conductivity in mho/m3)
*
*   Algorithm: See conduct.f in madf/geolib
*
*   returns - 0 (successful)
*/
int getCond(int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
            FILE * errFile)
 
 

/***********************************************************************
*
* getDCond  uses Shunrong's code from Schunk and Nagy to derive errors in Pederson and Hall
*          local conductivities.
*
*   arguments:
*      inCount (num inputs) = 16 (TI, TE, NE, PH+_IRI, PO+_IRI, NOL, NN2L, NO2L, TNM, BMAG,
*                                 DTI, DTE, DNE, DNOL, DNN2L, DNO2L)
*      inputArr - double array holding:
*                 TI - Ion temperature (K)
*                 TE - Electron temperature (K)
*                 NE - Electron density (m^3)
*                 PH+_IRI - IRI Composition % = [H+]/Ne * 100
*                 PO+_IRI - IRI Composition % = [O+]/Ne * 100
*                 NOL - Nutrl atm composition-log10([O] in m-3) (MSIS)
*                 NN2L - Nutrl atm compositn-log10([N2] in m-3) (MSIS)
*                 NO2L - Nutrl atm compositn-log10([O2] in m-3) (MSIS)
*                 TNM - MSIS Neutral atmosphere temperature (K)
*                 BMAG - Geomagnetic field strength (Tesla)
*                 DTI - Error in Ion temperature (K)
*                 DTE - Error in Electron temperature (K)
*                 DNE - Error in Electron density (m^3)
*                 DNOL - Error in Nutrl atm composition-log10([O] in m-3) (MSIS)
*                 DNN2L - Error in Nutrl atm compositn-log10([N2] in m-3) (MSIS)
*                 DNO2L - Error in Nutrl atm compositn-log10([O2] in m-3) (MSIS)
*      outCount (num outputs) = 4 (DPDCON, DPDCONL, DHLCON, DHLCONL)
*      outputArr - double array holding:
*                 PDCON - Error in Pedersen Conductivity in mho/m3
*                 PDCONL - Error in Log10(Pedersen Conductivity in mho/m3)
*                 HLCON - Error in Hall Conductivity in mho/m3
*                 HLCONL - Error in Log10(Hall Conductivity in mho/m3)
*
*   Algorithm: See conduct.f in madf/geolib
*
*   returns - 0 (successful)
*/
int getDCond(int inCount,
             double * inputArr,
             int outCount,
             double * outputArr,
             FILE * errFile)
 
 

/***********************************************************************
*
* getImf   gets interplanetary magnetic field data given a time
*
*   arguments:
*      inCount (num inputs) = 2 (UT1, UT2)
*      inputArr - double array holding:
*                 UT1 - UT at record start
*                 UT2 - UT at record end
*      outCount (num outputs) = 10 (BXGSM, BYGSM, BZGSM, BIMF,
*                                   BXGSE, BYGSE, BZGSE,
*                                   SWDEN, SWSPD, SWQ)
*      outputArr - double array holding:
*                 BXGSM - Interplanetary Mag Field (Bx GSM coord)
*                 BYGSM - Interplanetary Mag Field (By GSM coord)
*                 BYGSM - Interplanetary Mag Field (Bz GSM coord)
*                 BIMF - Interplanetary Mag Field strength
*                 BXGSE - Interplanetary Mag Field (Bx GSE coord)
*                 BYGSE - Interplanetary Mag Field (By GSE coord)
*                 BZGSE - Interplanetary Mag Field (Bz GSE coord)
*                 SWDEN - Solar Wind Plasma Density
*                 SWSPD - Solar Wind Plasma Speed
*                 SWQ - IMF/Solar Wind Qualifier
*
*
*   Algorithm: Get data from imf631127g.001 at average UT.  Only
*              the first time any thread calls this method will the
*              data file be read into static variable imfDayArr.  Array
*              of ImfDay structs is used since it has a more compact
*              memory footprint than the madrec data structure, and
*              imf631127g.002 is a large file.  The old style file
*              imf631127g.001 will be used if imf631127g.002 is not found. Note that
*              BXGSM and BXGSE are equal.
*
*   returns - 0 if successful, -1 if problem finding file
*/
int getImf(int inCount,
           double * inputArr,
           int outCount,
           double * outputArr,
           FILE * errFile)
 
 

/***********************************************************************
*
* getIri
*   arguments:
*      inCount (num inputs) = 5 (UT1, UT2, GDLAT, GDLON, GDALT)
*      inputArr - double array holding:
*                 UT1 - UT at record start
		  UT2 - UT at record end
		  GDLAT - geodetic latitude
		  GLON - geodetic longitude
		  GDALT - geodetic altitude


*      outCount (num outputs) = 11 (NE_IRI, NEL_IRI, TN_IRI, TI_IRI, TE_IRI,
*                                   PO+_IRI, PNO+_IRI, PO2+_IRI, PHE+_IRI, PH+_IRI, PN+_IRI)
*      outputArr - double array holding:
*                  NE_IRI - electron density
		   NEL_IRI - log of electron density
		   TN_IRI - IRI neutral temperature
		   TI_IRI - IRI ion temperature
		   TE_IRI - IRI electron temperature
		   PO+_IRI - IRI composition [O+]/Ne
		   PNO+_IRI - IRI compostion [NO+]/Ne
		   PO2_IRI - IRI composition [O2+]/Ne
		   PHE+_IRI - IRI composition [HE+]/Ne
		   PH+_IRI - IRI composition [H+]/Ne
		   PN+_IRI  - IRI composition [N+]/Ne

*     Written by Alicia Fernandez, May 2007
*
*
*   returns - 0 (successful)
*/
int getIri (int inCount,
            double * inputArr,
            int outCount,
            double * outputArr,
	    FILE * errFile)
 
 

/***********************************************************************
*
* getTestAveAlt   dummy method that prints UT, then gets lowest value
*                 of gdlat as 1d parameter and average value as 2D parameter
*
*   arguments:
*      numRows - number of rows of 2D data in record
*      inCount (num inputs) = 2 (UT1, GDALT)
*      inputArr - array of double arrays holding:
*                 UT - 1D parameter
*                 GDALT - 2D parameter
*      outCount (num outputs) = 2 (LOW_GDALT, AVE_GDALT)
*      outputArr - array of double arrays holding:
*                 LOW_GDALT (len = 1)
*                 AVE_GDALT (len = numRows)
*
*   Algorithm: Average all GDALT values and find lowest.  This
*              is only a dummy method
*
*   returns - 0
*/
int getTestAveAlt(int numRows,
                  int inCount,
                  double ** inputArr,
                  int outCount,
                  double ** outputArr,
                  FILE * errFile)
 
 
Previous: Python API   Up: Madrigal developer's guide   Next: Fortran API