ingest_datachunk.c

Go to the documentation of this file.
00001 /*******************************************************************************
00002 *
00003 *  COPYRIGHT (C) 2006 Battelle Memorial Institute.  All Rights Reserved.
00004 *
00005 ********************************************************************************
00006 *
00007 *  Author:
00008 *     name:  Brian Ermold
00009 *     phone: (509) 375-2277
00010 *     email: brian.ermold@pnl.gov
00011 *
00012 ********************************************************************************
00013 *
00014 *  RCS INFORMATION:
00015 *    $RCSfile: ingest_datachunk.c,v $
00016 *    $Revision: 1.38 $
00017 *    $Locker: ermold $
00018 *    $Date: 2006/09/05 19:05:23 $
00019 *    $State: ds-dsutil-ingest_lib-1.4-0 $
00020 *
00021 *******************************************************************************/
00022 
00023 
00024 #include <ctype.h>
00025 #include <errno.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <utime.h>
00029 #include <sys/stat.h>
00030 
00031 #include "dslibc/version.h"
00032 #include "ingest_lib/ingest_datachunk.h"
00033 #include "ingest_lib/ingest_util.h"
00034 #include "ingest_lib/ingest_stats.h"
00035 #include "ingest_lib/sds_util.h"
00036 #include "ingest_lib/sds_status.h"
00037 #include "ingest_lib/sds_log.h"
00038 #include "ingest_lib/sds_tdb.h"
00039 #include "ingest_lib/version.h"
00040 
00041 /*******************************************************************************
00042 *  Private Variables:
00043 */
00044 
00045 static DataChunk *prev_dc = NULL; /* Used to store the previous datachunk */
00046 
00047 static struct {
00048     char dsc_name[32];
00049     char dsc_level[8];
00050     char base_name[32];
00051 } gOutDirMap[16];
00052 
00053 static int gOutDirMapCount = 0;
00054 
00055 /* End Private Variables */
00056 
00057 /*******************************************************************************
00058 *
00059 * Description:
00060 *   The append_global function will append to a Global Attribute in the datachuck
00061 *   that is passed.
00062 *
00063 * Inputs:
00064 *   dc:       DataChunk with Global Attribute to append to.
00065 *
00066 *   attname:  Name of the Global Attribute.
00067 *
00068 *   attvalue: Value to be appended to Global Attribute.
00069 *
00070 * Outputs:
00071 *   dc:       DataChunk with changed Global Attribute.
00072 *
00073 * Returns:
00074 *   1 on success,
00075 *   or 0 on failure or no change.
00076 *
00077 *******************************************************************************/
00078 int append_global(DataChunk *dc, char *attname, char *attvalue)
00079 {
00080     char newvalue[MAXSTRLEN];
00081     char *oldvalue;
00082 
00083     if ((oldvalue = dc_GetGlobalAttr(dc, attname)) == NULL) {
00084         strcpy(newvalue, attvalue);
00085     }
00086     else {
00087         sprintf(newvalue, "%s%s", oldvalue, attvalue);
00088     }
00089     return(change_global(dc, attname, newvalue));
00090 }
00091 
00092 /*******************************************************************************
00093 *
00094 * Description:
00095 *   The get_dc_platform_ds_class function will extract the datastream name and
00096 *   level from the data chunk platform name.
00097 *
00098 * Inputs:
00099 *   dc:        The DataChunk containing the platform name to parse.
00100 *
00101 *   dsc_name:  A pointer to the datastream class name to set.
00102 *
00103 *   dsc_level: A pointer to the datastream class level to set.
00104 *
00105 * Outputs:
00106 *   dsc_name:  The datastream name extracted from the data chunk platform name.
00107 *
00108 *   dsc_level: The datastream level extracted from the data chunk platform name.
00109 *
00110 * Returns:
00111 *   None.
00112 *
00113 *******************************************************************************/
00114 int get_dc_platform_ds_class(
00115     DataChunk *dc,
00116     char      *dsc_name,
00117     char      *dsc_level)
00118 {
00119     const char *site;
00120     const char *facility;
00121     char        dc_platform[MAXPLATNAME];
00122     char       *chrp;
00123 
00124     site     = get_process_site();
00125     facility = get_process_facility();
00126 
00127     /* Get the data chunk platform name */
00128 
00129     sprintf(dc_platform, "%s", ds_PlatformName(dc->dc_Platform));
00130 
00131     /* Extract the datastream level */
00132 
00133     chrp = (char *)strrchr(dc_platform, '.');
00134     strcpy(dsc_level, ++chrp);
00135 
00136     /* Extract the datastream name */
00137 
00138     chrp = strstr(dc_platform, facility);
00139 
00140     if (chrp == NULL) {
00141         append_log_msg(__FILE__, __LINE__,
00142             "Could not find facility (%s) in platform name: %s\n",
00143             facility, dc_platform);
00144         current_status(STATUS_BADPLATNAME);
00145         return(FAILURE);
00146     }
00147 
00148     *chrp = '\0';
00149 
00150     sprintf(dsc_name, dc_platform + strlen(site));
00151 
00152     return(SUCCESS);
00153 }
00154 
00155 int get_tdb_plat_names(
00156     DataChunk *dc,
00157     char      *tdb_plat_base,
00158     char      *tdb_plat_name,
00159     char      *tdb_alias_base,
00160     char      *tdb_alias_name)
00161 {
00162     int   status;
00163     char  dsc_name[MAXPLATNAME];
00164     char  dsc_level[MAXPLATNAME];
00165     int   tdb_inst_num;
00166     char *alias;
00167 
00168     status = get_dc_platform_ds_class(dc, dsc_name, dsc_level);
00169     if (status == FAILURE) {
00170         return(FAILURE);
00171     }
00172 
00173     tdb_inst_num = get_tdb_inst_num();
00174 
00175     if (tdb_plat_base) {
00176         strcpy(tdb_plat_base, dsc_name);
00177     }
00178 
00179     if (tdb_plat_name) {
00180         sprintf(tdb_plat_name, "%s%d", dsc_name, tdb_inst_num);
00181     }
00182 
00183     if (tdb_alias_base || tdb_alias_name) {
00184         if ((alias = get_tdb_alias(tdb_plat_base)) != NULL) {
00185 
00186             if (tdb_alias_base) {
00187                 strcpy(tdb_alias_base, alias);
00188             }
00189 
00190             if (tdb_alias_name) {
00191                 sprintf(tdb_alias_name, "%s%d", alias, tdb_inst_num);
00192             }
00193         }
00194         else {
00195             if (tdb_alias_base) {
00196                 strcpy(tdb_alias_base, tdb_plat_base);
00197             }
00198 
00199             if (tdb_alias_name) {
00200                 strcpy(tdb_alias_name, tdb_plat_name);
00201             }
00202         }
00203     }
00204 
00205     return(SUCCESS);
00206 }
00207 
00208 /*******************************************************************************
00209 *
00210 * Description:
00211 *   The change_flattr function will change a Field Level ATTRibute in the
00212 *   datachuck that is passed.
00213 *
00214 * Inputs:
00215 *   dc:           DataChunk with Field Level Attribute to change.
00216 *
00217 *   field_name:   Name of the field which contains FLATTR.
00218 *
00219 *   flattr_name:  Name of FLATTR to change.
00220 *
00221 *   flattr_value: New value of FLATTR.
00222 *
00223 * Outputs:
00224 *   dc:           DataChunk with new Field Level Attribute.
00225 *
00226 * Returns:
00227 *   1 on success,
00228 *   or 0 on failure or no change.
00229 *
00230 *******************************************************************************/
00231 int change_flattr (DataChunk *dc, char *field_name, char *flattr_name, char *flattr_value)
00232 {
00233     char     message[MAXSTRLEN];
00234     FieldId  fid;
00235     char    *lastvalue;
00236 
00237   /*  If fid is less then 0, it has not been defined.
00238    */
00239     if ((fid = F_Declared(field_name)) < 0) {
00240         append_log_msg(__FILE__, __LINE__,
00241             "Field %s is not in the TDB Platform Dictionary!", field_name);
00242     }
00243     else {
00244 
00245       /*  Set the New Field Level Attribute
00246        */
00247         dc_SetFieldAttr(dc, fid, flattr_name, flattr_value);
00248 
00249       /*  Return 1 if changed (or created), 0 no change.
00250        */
00251         lastvalue = get_previous_flattr(dc, fid, flattr_name);
00252 
00253         if (strcmp(lastvalue, flattr_value) != 0) {
00254             append_log_msg(__FILE__, __LINE__,
00255                 "Field attribute changed: %s:%s\n\tfrom:%s\n\tto:  %s\n",
00256                 field_name, flattr_name, lastvalue, flattr_value);
00257             return (1);
00258         }
00259         else {
00260             print_debug(__FILE__, __LINE__,
00261                 "flatter %s for field %s has not changed\n",
00262                 flattr_name, field_name);
00263         }
00264     }
00265 
00266     return (0);
00267 }
00268 
00269 /*******************************************************************************
00270 *
00271 * Description:
00272 *   The change_global function will change a Global Attribute in the datachuck
00273 *   that is passed.
00274 *
00275 * Inputs:
00276 *   dc:           DataChunk with Global Attribute to change.
00277 *
00278 *   glattr_name:  Name of the Global Attribute.
00279 *
00280 *   glattr_value: New value of Global Attribute.
00281 *
00282 * Outputs:
00283 *   dc:           DataChunk with changed Global Attribute.
00284 *
00285 * Returns:
00286 *   1 on success,
00287 *   or 0 on failure or no change.
00288 *
00289 *******************************************************************************/
00290 int change_global(DataChunk *dc, char *glattr_name, char *glattr_value)
00291 {
00292     char message[MAXSTRLEN];
00293     char *lastvalue;
00294 
00295   /*  If the value is 0, global_name has not been defined.
00296    */
00297     if (!dc_GetGlobalAttr(dc, glattr_name)) {
00298         print_debug(__FILE__, __LINE__,
00299             "Metadata for %s was not previously defined.\n", glattr_name);
00300     }
00301 
00302   /*  Set the New Global Attribute
00303    */
00304     dc_SetGlobalAttr(dc, glattr_name, glattr_value);
00305 
00306   /*  Return 1 if changed (or created), 0 no change.
00307    */
00308     lastvalue = get_previous_glattr(dc, glattr_name);
00309 
00310     if (strcmp(lastvalue, glattr_value) != 0) {
00311         append_log_msg(__FILE__, __LINE__,
00312             "Global attribute changed: %s\n\tfrom:%s\n\tto:  %s\n",
00313             glattr_name, lastvalue, glattr_value);
00314         return (1);
00315     }
00316     else {
00317         print_debug(__FILE__, __LINE__,
00318             "glattr %s has not changed\n", glattr_name);
00319     }
00320 
00321     return (0);
00322 }
00323 
00324 /*******************************************************************************
00325 *
00326 * Description:
00327 *   The check_for_std_metadata_changes function checks for changes in standard
00328 *   metadata (global attributes) from one dc to the next. It checks that all
00329 *   metadata from the current datachunk matches the metadata in the previous
00330 *   datachunk.  If there has been a change in the metadata then newfile gets set
00331 *   to TRUE so that a new output file will be created when the current dc is
00332 *   stored by Zebra.
00333 *
00334 * Inputs:
00335 *   dc: The current datachunk.
00336 *
00337 * Outputs:
00338 *   newfile:  Indicates whether a new output file should be created
00339 *             when the current dc is stored by Zeb.
00340 *
00341 * Returns:
00342 *   1 if there was a change,
00343 *   or 0 if no change.
00344 *
00345 *******************************************************************************/
00346 int check_for_std_metadata_changes(DataChunk *dc, int *new_file)
00347 {
00348     char       message[MAXSTRLEN];
00349     char      *newvalue;
00350     char      *oldvalue;
00351     int        index;
00352     int        status;
00353     static char *std_glattrs[] = {
00354 
00355         "ingest_software",
00356         "proc_level"     ,
00357         "site_id"        ,
00358         "facility_id"    ,
00359         "sample_int"     ,
00360         "averaging_int"  ,
00361         "serial_number"  ,
00362         "comment"        ,
00363         "resolution_description",
00364         (char *)NULL
00365     };
00366 
00367     status = 0;
00368 
00369     prev_dc = get_previous_dc(dc);
00370 
00371     if (prev_dc != (DataChunk *)NULL) {
00372 
00373         for(index = 0; std_glattrs[index] != NULL; index ++) {
00374             newvalue = dc_GetGlobalAttr(dc, std_glattrs[index]);
00375             oldvalue = dc_GetGlobalAttr(prev_dc, std_glattrs[index]);
00376 
00377             if (strcmp(newvalue, oldvalue) != 0) {
00378                 append_log_msg(__FILE__, __LINE__,
00379                     "Global attribute changed: %s\n\tfrom:%s\n\tto:  %s\n",
00380                     std_glattrs[index], oldvalue, newvalue);
00381                 status = 1;
00382                 *new_file = 1;
00383             }
00384         }
00385     }
00386     return(status);
00387 }
00388 
00389 /*******************************************************************************
00390 *
00391 * Description:
00392 *   The check_for_plat_metadata_changes function checks for changes in platform
00393 *   specific global attributes from one datachunk to the next. It checks that
00394 *   all metadata from the current datachunk matches the metadata in the previous
00395 *   datachunk. If there has been a change in the metadata then newfile gets set
00396 *   to TRUE so that a new output file will be created when the current dc is
00397 *   stored by Zebra.
00398 *
00399 * Inputs:
00400 *   dc:      The current datachunk.
00401 *
00402 * Outputs:
00403 *   newfile: Indicates whether a new output file should be created
00404 *            when the current dc is stored by Zeb.
00405 *
00406 * Returns:
00407 *   1 if there was a change,
00408 *   or 0 if no change.
00409 *
00410 *******************************************************************************/
00411 int check_for_plat_metadata_changes(DataChunk *dc, int *newfile)
00412 {
00413     char       message[MAXSTRLEN];
00414     char       tdb_plat_base[SHORTSTRLEN];
00415     char       tdb_plat_name[SHORTSTRLEN];
00416     char       tdb_alias_base[SHORTSTRLEN];
00417     char       tdb_alias_name[SHORTSTRLEN];
00418     int        attnum;
00419     char      *attname;
00420     char      *newvalue;
00421     char      *oldvalue;
00422     int        ndiffs     = 0;
00423 
00424     prev_dc = get_previous_dc(dc);
00425 
00426     if (prev_dc != (DataChunk *)NULL) {
00427 
00428         if (!db_reconnect()) {
00429             return(0);
00430         }
00431 
00432         get_tdb_plat_names(
00433             dc,
00434             tdb_plat_base,
00435             tdb_plat_name,
00436             tdb_alias_base,
00437             tdb_alias_name);
00438 
00439         for(attnum = 1; attnum < MAX_METADATA; attnum++) {
00440 
00441             attname  = get_glattr_name(
00442                 attnum,
00443                 tdb_plat_name,
00444                 tdb_plat_base,
00445                 tdb_alias_name,
00446                 tdb_alias_base);
00447 
00448             if (attname == NULL) {
00449                 break;
00450             }
00451 
00452             if (strcmp(attname, "end_global_attributes") == NULL) {
00453                 shared_tdb_free(attname);
00454                 break;
00455             }
00456 
00457             newvalue = dc_GetGlobalAttr(dc, attname);
00458             oldvalue = dc_GetGlobalAttr(prev_dc, attname);
00459 
00460             if (oldvalue == (char *) NULL) {
00461                 append_log_msg(__FILE__, __LINE__,
00462                     "Global attribute added: %s\n", attname);
00463                 ndiffs++;
00464                 *newfile = 1;
00465             }
00466             else if (strcmp(newvalue, oldvalue) != 0) {
00467                 append_log_msg(__FILE__, __LINE__,
00468                     "Global attribute changed: %s\n\tfrom:%s\n\tto:  %s\n",
00469                     attname, oldvalue, newvalue);
00470                 ndiffs++;
00471                 *newfile = 1;
00472             }
00473             shared_tdb_free(attname);
00474         }
00475 
00476         db_disconnect();
00477     }
00478 
00479     return(ndiffs);
00480 }
00481 
00482 /*******************************************************************************
00483 *
00484 * Description:
00485 *   The check_for_location_changes function checks for changes in location from
00486 *   one datachunk to the next. It checks that all metadata from the current
00487 *   datachunk matches the metadata in the previous datachunk. If there has been
00488 *   a change in the metadata then newfile gets set to TRUE so that a new output
00489 *   file will be created when the current dc is stored by Zebra.
00490 *
00491 * Inputs:
00492 *   dc:      The current datachunk.
00493 *
00494 * Outputs:
00495 *   newfile: Indicates whether a new output file should be created
00496 *            when the current dc is stored by Zeb.
00497 *
00498 * Returns:
00499 *   1 if there was a change,
00500 *   or 0 if no change.
00501 *
00502 *******************************************************************************/
00503 int check_for_location_changes(DataChunk *dc, int *newfile)
00504 {
00505     char       message[MAXSTRLEN];
00506     Location   curr_loc;
00507     Location   prev_loc;
00508 
00509     prev_dc = get_previous_dc(dc);
00510 
00511     if (prev_dc != (DataChunk *)NULL) {
00512 
00513         dc_GetLoc(dc, 0, &curr_loc);
00514         dc_GetLoc(prev_dc, 0, &prev_loc);
00515 
00516         if ((curr_loc.l_alt != prev_loc.l_alt) ||
00517             (curr_loc.l_lat != prev_loc.l_lat) ||
00518             (curr_loc.l_lon != prev_loc.l_lon)) {
00519 
00520             append_log_msg(__FILE__, __LINE__,
00521                 "Location changed: %s\n", ds_PlatformName(dc->dc_Platform));
00522             *newfile = 1;
00523             return(1);
00524         }
00525     }
00526     return(0);
00527 }
00528 
00529 /*******************************************************************************
00530 *
00531 * Description:
00532 *   The check_for_metadata_changes function checks that all metadata from the
00533 *   current datachunk matches the metadata in the previous datachunk. If there
00534 *   has been a change in the metadata then newfile gets set to TRUE so that a
00535 *   new output file will be created when the current dc is stored by Zeb.
00536 *
00537 * Inputs:
00538 *   dc:      The current datachunk.
00539 *
00540 * Outputs:
00541 *   newfile: Indicates whether a new output file should be created
00542 *            when the current dc is stored by Zeb.
00543 *
00544 * Returns:
00545 *   None.
00546 *
00547 *******************************************************************************/
00548 void check_for_metadata_changes(DataChunk *dc, int *newfile)
00549 {
00550     check_for_std_metadata_changes(dc, newfile);
00551     check_for_plat_metadata_changes(dc, newfile);
00552     check_for_location_changes(dc, newfile);
00553 }
00554 
00555 /*******************************************************************************
00556 *
00557 *  Description:
00558 *   The define_dimsizes will define the dimension sizes PERMANENTLY by storing
00559 *   the dim_size array in the TDB. This is needed because some instruments, like
00560 *   the AERI, change dimension sizes often and tell us the sizes in the raw data.
00561 *
00562 *  Inputs:
00563 *   dc:       The data chunk which to change dim sizes for.
00564 *
00565 *   ndims:    The number of dimensions for this dc.
00566 *
00567 *   dimsizes: The size of the dimensions for this dc.
00568 *
00569 * Outputs:
00570 *   None.
00571 *
00572 * Returns:
00573 *   SUCCESS || FAILURE
00574 *
00575 *******************************************************************************/
00576 int define_dimsizes(DataChunk *dc, int ndims, int *dimsizes)
00577 {
00578     char  tdb_plat_name[SHORTSTRLEN];
00579     char  datalevel[8];
00580     int   dimnum;
00581     char *chrp;
00582     int   retval;
00583 
00584     get_tdb_plat_names(dc, NULL, tdb_plat_name, NULL, NULL);
00585 
00586     get_dc_platform_datalevel(dc, datalevel);
00587 
00588     /*  First, check the dimension size values */
00589 
00590     for (dimnum = 1; dimnum < ndims + 1; dimnum++) {
00591         if ((dimsizes[dimnum - 1] < 1) || (dimsizes[dimnum - 1] > MAX_DIMSIZE)) {
00592             append_log_msg(__FILE__, __LINE__,
00593                 "Dimension size (%d) is out of range for platform %s, dimnum %d.\n",
00594                 dimsizes[dimnum - 1], tdb_plat_name, dimnum);
00595             return(FAILURE);
00596         }
00597     }
00598 
00599     if (!db_reconnect()) {
00600         return(FAILURE);
00601     }
00602 
00603     retval = SUCCESS;
00604 
00605     for (dimnum = 1; dimnum < ndims + 1; dimnum++) {
00606         if (!set_dim_size(tdb_plat_name, datalevel, dimnum, dimsizes[dimnum - 1])) {
00607             retval = FAILURE;
00608             break;
00609         }
00610     }
00611 
00612     db_disconnect();
00613 
00614     return(retval);
00615 }
00616 
00617 /*******************************************************************************
00618 *
00619 * Description:
00620 *   The set_dc_platform function sets the zebra platform name in the data chunk.
00621 *
00622 * Inputs:
00623 *   dc:        The datachunk to store the platform name in.
00624 *
00625 *   platbase:  The base platform name (i.e. vceil25k).
00626 *
00627 *   datalevel: The data level.
00628 *
00629 * Outputs:
00630 *   dc:        The data chunk with the platform name defined.
00631 *
00632 * Returns:
00633 *   SUCCESS || FAILURE
00634 *
00635 *******************************************************************************/
00636 int set_dc_platform(DataChunk *dc, char *platbase, char *datalevel)
00637 {
00638     const char *site;
00639     const char *facility;
00640 
00641     char  platform[SHORTSTRLEN];
00642 
00643     site     = get_process_site();
00644     facility = get_process_facility();
00645 
00646     if (dc) {
00647         sprintf (platform, "%s%s%s.%s", site, platbase, facility, datalevel);
00648 
00649         print_debug(__FILE__, __LINE__,
00650             "Looking up zebra platform: %s\n", platform);
00651 
00652         if ((dc->dc_Platform = ds_LookupPlatform(platform)) == BadPlatform) {
00653             current_status(STATUS_INITDC);
00654             append_log_msg(__FILE__, __LINE__,
00655                 "ds_LookupPlatform failed for platform %s\n", platform);
00656             return(FAILURE);
00657         }
00658     }
00659     else {
00660         current_status(STATUS_INITDC);
00661         append_log_msg(__FILE__, __LINE__,
00662             "Datachunk sent to do_lookup is NULL\n");
00663         return(FAILURE);
00664     }
00665 
00666     return(SUCCESS);
00667 }
00668 
00669 /*******************************************************************************
00670 *
00671 * Description:
00672 *   The freeDC function will free the DataChunk passed.
00673 *
00674 * Inputs:
00675 *   dc: The DataChunk which should be destroyed.
00676 *
00677 * Outputs:
00678 *   None.
00679 *
00680 * Returns:
00681 *   dc: A NULL pointer to a DataChunk.
00682 *
00683 *******************************************************************************/
00684 DataChunk *freeDC(DataChunk *dc)
00685 {
00686     if (dc) {
00687         dc_DestroyDC(dc);
00688     }
00689     return((DataChunk *)NULL);
00690 }
00691 
00692 /*******************************************************************************
00693 *
00694 * Description:
00695 *   The get_dc_platform_datalevel function will get the datalevel from the
00696 *   data chunk platform name.
00697 *
00698 * Inputs:
00699 *   dc:   The DataChunk to get the datalevel from.
00700 *
00701 * Outputs:
00702 *   datalevel: The data level from the platform name.
00703 *
00704 * Returns:
00705 *   1 if the data level was found,
00706 *   or 0 if the datalevel could no be determined
00707 *
00708 *******************************************************************************/
00709 int get_dc_platform_datalevel(DataChunk *dc, char *datalevel)
00710 {
00711     char *chrp;
00712 
00713   /*  Get the data level from the platform name
00714    */
00715     if ((chrp = (char *)strrchr(ds_PlatformName(dc->dc_Platform), '.')) != NULL) {
00716         sprintf(datalevel, ++chrp);
00717     }
00718     else {
00719         datalevel[0] = '\0';
00720         return(0);
00721     }
00722 
00723     return(1);
00724 }
00725 
00726 /*******************************************************************************
00727 *
00728 * Description:
00729 *   The get_field_type function will get the DC_ElemType corresponding to the
00730 *   specified field type name. If the field type name is not valid float
00731 *   will be used. Valid field type names are:<blockquote><p>
00732 *
00733 *       float<br>
00734 *       double<br>
00735 *       long double<br>
00736 *       char<br>
00737 *       unsigned char<br>
00738 *       short int<br>
00739 *       unsigned short<br>
00740 *       int<br>
00741 *       unsigned int<br>
00742 *       long int<br>
00743 *       unsigned long<br>
00744 *       string</p></blockquote>
00745 *
00746 * Inputs:
00747 *   field_type: The name of the field type.
00748 *
00749 * Outputs:
00750 *   None.
00751 *
00752 * Returns:
00753 *   The DC_ElemType.
00754 *
00755 *******************************************************************************/
00756 DC_ElemType get_field_type(char *field_type)
00757 {
00758     int   field_type_num;
00759 
00760     field_type_num = (int)DCT_Unknown;
00761 
00762     while (strcmp(DC_ElemTypeNames[field_type_num++], field_type)) {
00763         if (field_type_num == (int)DCT_Element) {
00764             field_type_num = (int)DCT_Unknown;
00765             print_debug(__FILE__, __LINE__,
00766                 "Field type %s not found, using float instead.\n", field_type);
00767             break;
00768         }
00769     }
00770 
00771     if (field_type_num == (int)DCT_Unknown) {
00772         while (strcmp(DC_ElemTypeNames[field_type_num++], "float"))
00773             { /* do nothing */ };
00774     }
00775     field_type_num--;
00776 
00777     return((DC_ElemType)field_type_num);
00778 }
00779 
00780 /*******************************************************************************
00781 *
00782 * Description:
00783 *   The get_previous_dc function gets a datachunk from a time slice just
00784 *   previous to the current datachunk.
00785 *
00786 * Inputs:
00787 *   dc:   The current datachunk.
00788 *
00789 * Outputs:
00790 *   None.
00791 *
00792 * Returns:
00793 *   The datachunk from the previous time slice.
00794 *
00795 *******************************************************************************/
00796 DataChunk *get_previous_dc(DataChunk *dc)
00797 {
00798     ZebTime  curtime;
00799     ZebTime  when;
00800     ZebTime  start;
00801     ZebTime  end;
00802     FieldId  fields[MAX_FIELDS];
00803     int      nflds = 0;
00804     int      nfield;
00805 
00806  /*  If the dc requested does not match prev_dc, clean up.
00807   *  Note that store_datachunk will free the prev_dc because once
00808   *  a new datachunk is stored prev_dc will no longer be correct.
00809   */
00810     if (prev_dc != (DataChunk *)NULL ) {
00811         if (prev_dc->dc_Platform != dc->dc_Platform) {
00812             prev_dc = freeDC(prev_dc);
00813         }
00814     }
00815 
00816  /*  If prev_dc has not been set up already then do it,
00817   *  otherwise just return
00818   */
00819     if (prev_dc == (DataChunk *)NULL) {
00820 
00821       /*  Fill up the when ZebTime structure with the last datatime
00822        */
00823         dc_GetTime(dc, 0, &curtime);
00824 
00825         when.zt_Sec = when.zt_MicroSec = 0;
00826 
00827         ds_DataTimes(dc->dc_Platform, &curtime, 1, DsBefore, &when);
00828 
00829      /*  When dealing with datastreams that use microseconds we can get roundoff
00830       *  error in the zt_MicroSec value. This is because the time is stored in
00831       *  the NetCDF file as a double but is then converted to seconds and
00832       *  microseconds in the ZebTime structure. To get arround this we need to
00833       *  use a range arround the returned previous sample time. Since this is
00834       *  roundoff error an offset of 1 should work but lets use 2 to be on the
00835       *  safe side.
00836       */
00837         start = end = when;
00838 
00839         start.zt_MicroSec -= 2;
00840         end.zt_MicroSec   += 2;
00841 
00842         if (start.zt_MicroSec < 0) {
00843             start.zt_Sec      -= 1;
00844             start.zt_MicroSec += 1e6;
00845         }
00846 
00847         if (end.zt_MicroSec >= 1e6) {
00848             end.zt_Sec      += 1;
00849             end.zt_MicroSec -= 1e6;
00850         }
00851 
00852       /*  This needs to be set for ds_GetFields.
00853        */
00854         nfield = MAX_FIELDS;
00855 
00856       /*  Grab the field IDs from the data store
00857        */
00858         nflds = ds_GetFields(dc->dc_Platform, &when, &nfield, fields);
00859 
00860         if (nflds) {
00861 
00862           /*  Fetch the data chunk for the last sample
00863            */
00864             prev_dc = ds_Fetch(dc->dc_Platform, dc->dc_Class, &start,
00865                 &end, fields, nfield, 0, 0);
00866         }
00867         else {
00868             append_log_msg(__FILE__, __LINE__,
00869                 "Could not get fields from Data Store in get_previous_dc()!\n");
00870         }
00871     }
00872     return(prev_dc);
00873 }
00874 
00875 /*******************************************************************************
00876 *
00877 * Description:
00878 *   The get_previous_flattr function will get the value of a field level attribute
00879 *   just prior to the current datachunk.
00880 *
00881 * Inputs:
00882 *   dc:          The current datachunk.
00883 *
00884 *   fid:         The field id of the field to look in.
00885 *
00886 *   flattr_name: The name of the field's attribute.
00887 *
00888 * Outputs:
00889 *   None.
00890 *
00891 * Returns:
00892 *   The previous attribute value.
00893 *
00894 *******************************************************************************/
00895 char *get_previous_flattr(DataChunk *dc, FieldId fid, char *flattr_name)
00896 {
00897     static char  flattr_value[MAXSTRLEN];
00898     char        *previous_flattr;
00899 
00900     flattr_value[0] = '\0';
00901 
00902   /*  Fetch the data chunk for the last sample stored.
00903    */
00904     prev_dc = get_previous_dc(dc);
00905 
00906     if (prev_dc != (DataChunk *)NULL) {
00907 
00908       /*  Get the Value of the FLATTR
00909        */
00910         previous_flattr = dc_GetFieldAttr(prev_dc, fid, flattr_name);
00911         if (previous_flattr) {
00912             sprintf(flattr_value, "%s", previous_flattr);
00913         }
00914         else {
00915             flattr_value[0] = '\0';
00916         }
00917     }
00918     return(flattr_value);
00919 }
00920 
00921 /*******************************************************************************
00922 *
00923 * Description:
00924 *   The get_previous_glattr function will get the value of a global level attribute just prior
00925 *   to the current datachunk.
00926 *
00927 * Inputs:
00928 *   dc:          The current datachunk.
00929 *
00930 *   glattr_name: The name of the global attribute.
00931 *
00932 * Outputs:
00933 *   None.
00934 *
00935 * Returns:
00936 *   The previous attribute value.
00937 *
00938 *******************************************************************************/
00939 char *get_previous_glattr(DataChunk *dc, char *glattr_name)
00940 {
00941     static char  glattr_value[MAXSTRLEN];
00942     char        *previous_glattr;
00943 
00944     glattr_value[0] = '\0';
00945 
00946   /*  Fetch the data chunk for the last sample
00947    */
00948     prev_dc = get_previous_dc(dc);
00949 
00950     if (prev_dc != (DataChunk *)NULL) {
00951 
00952       /*  Get the Value of the Global Attribute
00953        */
00954         previous_glattr = dc_GetGlobalAttr(prev_dc, glattr_name);
00955         if (previous_glattr) {
00956             sprintf(glattr_value, "%s", previous_glattr);
00957         }
00958         else {
00959             glattr_value[0] = '\0';
00960         }
00961     }
00962     return(glattr_value);
00963 }
00964 
00965 void set_rename_raw_map_dir(char *dsc_name, char *dsc_level, char *base_name)
00966 {
00967     strcpy(gOutDirMap[gOutDirMapCount].dsc_name, dsc_name);
00968     strcpy(gOutDirMap[gOutDirMapCount].dsc_level, dsc_name);
00969     strcpy(gOutDirMap[gOutDirMapCount].base_name, base_name);
00970 
00971     gOutDirMapCount++;
00972 }
00973 
00974 char *get_rename_raw_map_dir(char *dsc_name, char *dsc_level)
00975 {
00976     int i;
00977 
00978     for (i = 0; i < gOutDirMapCount; i++) {
00979         if ((strcmp(gOutDirMap[i].dsc_name, dsc_name) == 0) &&
00980             (strcmp(gOutDirMap[i].dsc_level, dsc_level) == 0) ) {
00981 
00982             return(gOutDirMap[i].base_name);
00983         }
00984     }
00985 
00986     return((char *)NULL);
00987 }
00988 
00989 /*******************************************************************************
00990 *
00991 * Description:
00992 *   The rename_raw function is used to rename files into the datastream area.
00993 *   The file_move function is used to do the atuall move.  The path to the
00994 *   datastream directory is determined using the <b>get_datastream_home</b>
00995 *   function.
00996 *
00997 * Inputs:
00998 *   filename:   The full path of the file to rename.
00999 *
01000 *   start_time: The time (in seconds since 1970) of the first record in the file.
01001 *
01002 *   end_time:   The time (in seconds since 1970) of the last record in the file.
01003 *
01004 *   dsc_name:   The data stream class name this file belongs to.
01005 *
01006 *   dsc_level:  The data stream class level this file belongs to.
01007 *
01008 *   extension:  The extension to use when renaming the file.
01009 *
01010 *   preserve_dots: This is used to specify how much of the original file name
01011 *                  to preserve when renaming the file.  It specifies the number
01012 *                  of dots from the end of the file name.  For example, if a 2
01013 *                  is specified everything after the second to the last dot in
01014 *                  the original file name will be used in the new file name.
01015 *
01016 * Outputs:
01017 *   None.
01018 *
01019 * Returns:
01020 *   SUCCESS || FAILURE
01021 *
01022 *******************************************************************************/
01023 int rename_raw(
01024     char      *filename,
01025     time_t     start_time,
01026     time_t     end_time,
01027     char      *dsc_name,
01028     char      *dsc_level,
01029     char      *extension,
01030     int        preserve_dots)
01031 {
01032     char       *datastream_home;
01033     const char *site;
01034     const char *facility;
01035     struct tm  *start_tm;
01036     char       *chrp;
01037     char        out_dir[MAXPATHNAME];
01038     char        time_string[32];
01039     char        orig_name[MAXPATHNAME];
01040     char        dest_file[MAXPATHNAME];
01041     int         dot_count;
01042     char       *dir_base_name;
01043 
01044     /*  Verify that the specified data stream class
01045      *  is a known output for this process.
01046      */
01047 
01048     if (!validate_ingest_output_dsc(dsc_name, dsc_level)) {
01049         return(FAILURE);
01050     }
01051 
01052     site     = get_process_site();
01053     facility = get_process_facility();
01054 
01055     /*  Determine the time stamp to use for this raw file
01056      */
01057 
01058     if (start_time > 0) {
01059         start_tm = gmtime(&start_time);
01060     }
01061     else {
01062         append_log_msg(__FILE__, __LINE__,
01063             "Bad start time specified for: %s\n", filename);
01064         current_status(STATUS_NOMOVERAW);
01065         return(FAILURE);
01066     }
01067 
01068     strftime(time_string, 32, "%Y%m%d.%H%M%S", start_tm);
01069 
01070     /*  Build the output directory path and create it if it doesn't exist
01071      */
01072 
01073     datastream_home = get_datastream_home();
01074     if (!datastream_home) {
01075         return(FAILURE);
01076     }
01077 
01078     dir_base_name = get_rename_raw_map_dir(dsc_name, dsc_level);
01079     if (!dir_base_name) {
01080         dir_base_name = dsc_name;
01081     }
01082 
01083     sprintf(out_dir, "%s/%s/%s%s%s.%s",
01084         datastream_home, site, site, dsc_name, facility, dsc_level);
01085 
01086     if (!check_path(out_dir)) {
01087 
01088         print_debug(__FILE__, __LINE__,
01089             "Creating datastream directory: %s\n", out_dir);
01090 
01091         if (mkdir(out_dir, 00775) != 0) {
01092             append_log_msg(__FILE__, __LINE__,
01093                 "Error #%i creating datastream directory: %s\n -> %s\n",
01094                 errno, out_dir, strerror(errno));
01095             current_status(STATUS_NOMOVERAW);
01096             return(FAILURE);
01097         }
01098     }
01099 
01100     /*  Generate the full path to the destination file
01101      */
01102 
01103     sprintf(dest_file, "%s/%s%s%s.%s.%s",
01104         out_dir, site, dsc_name, facility, dsc_level, time_string);
01105 
01106     if (extension) {
01107         strcat(dest_file, ".");
01108         strcat(dest_file, extension);
01109     }
01110 
01111     if (preserve_dots > 0) {
01112 
01113         strcat(dest_file, ".");
01114 
01115         chrp = strrchr(filename, '/');
01116         strcpy(orig_name, ++chrp);
01117 
01118         chrp = orig_name + strlen(orig_name) - 1;
01119         for (dot_count = 0;; chrp--) {
01120 
01121             if (*chrp == '.') dot_count++;
01122 
01123             if (dot_count == preserve_dots) {
01124                 strcat(dest_file, ++chrp);
01125                 break;
01126             }
01127             else if (chrp == orig_name) {
01128                 strcat(dest_file, orig_name);
01129                 break;
01130             }
01131         }
01132     }
01133 
01134     /*  Rename the file into the datastream directory
01135      */
01136 
01137     if (!file_move(filename, dest_file)) {
01138         current_status(STATUS_NOMOVERAW);
01139         return(FAILURE);
01140     }
01141 
01142     /*  Record the stats for this file.
01143      */
01144 
01145     set_file_stats(dest_file);
01146 
01147     if (!end_time) {
01148         end_time = start_time;
01149     }
01150 
01151     update_datastream_times(dsc_name, dsc_level, start_time, end_time);
01152 
01153     /*  Now we will update the file time.  This should ensure it's getting
01154      *  transferred
01155      */
01156 
01157     if(utime(dest_file, NULL) < 0) {
01158         append_log_msg(__FILE__, __LINE__,
01159             "Error #%i updating file time for: %s\n -> %s\n",
01160             errno, dest_file, strerror(errno));
01161         current_status(STATUS_NOUTIME);
01162         return(FAILURE);
01163     }
01164 
01165     return(SUCCESS);
01166 }
01167 
01168 /*******************************************************************************
01169 *
01170 * Description:
01171 *   The move_ingested_raw function is used to move a file that has been ingested
01172 *   into its proper datastream directory.  The rename_raw function is used to do
01173 *   the actuall file renaming.  If a dsc_name is not specified the data chunk
01174 *   platform name will be used to determine it.
01175 *
01176 *   A file will be marked as bad if the data chunk is NULL or has zero samples.
01177 *   When this happens the badtime value must be specified or the move will fail.
01178 *
01179 * Inputs:
01180 *   dc:        The ZEBRA datachunk relating to the raw data.
01181 *
01182 *   dsc_name:  The data stream class name this file belongs to.
01183 *
01184 *   filename:  The full path to the raw file.
01185 *
01186 *   badtime:   The reference time of the file in seconds since 1970.
01187 *              It is used as the file time is the data chunk is NULL
01188 *              or has zero samples.
01189 *
01190 * Outputs:
01191 *   None.
01192 *
01193 * Returns:
01194 *   SUCCESS || FAILURE
01195 *
01196 *******************************************************************************/
01197 int move_ingested_raw(
01198     DataChunk *dc,
01199     char      *dsc_name,
01200     char      *filename,
01201     time_t     badtime)
01202 {
01203     const char      *site;
01204     const char      *facility;
01205     char            *extension;
01206     char             dc_platform[MAXPLATNAME];
01207     char            *chrp;
01208     int              nsamples;
01209     ZebTime          zeb_time;
01210     time_t           start_time;
01211     time_t           end_time;
01212     int              status;
01213 
01214     /*  If the dsc_name was not specified, get it from the data chunck
01215      */
01216 
01217     if (dsc_name == NULL) {
01218 
01219         site     = get_process_site();
01220         facility = get_process_facility();
01221 
01222         if (dc == NULL) {
01223             append_log_msg(__FILE__, __LINE__,
01224                 "Null Datachunk and NULL dsc_name while trying to move file: %s\n", filename);
01225             current_status(STATUS_NOMOVERAW);
01226             return(FAILURE);
01227         }
01228 
01229         sprintf(dc_platform, "%s", ds_PlatformName(dc->dc_Platform));
01230 
01231         dsc_name = dc_platform + strlen(site);
01232 
01233         chrp = strstr(dsc_name, facility);
01234 
01235         if (chrp == NULL) {
01236             append_log_msg(__FILE__, __LINE__,
01237                 "Could not find facility (%s) in platform name: %s\n",
01238                 facility, dc_platform);
01239             current_status(STATUS_NOMOVERAW);
01240             return(FAILURE);
01241         }
01242 
01243         *chrp = '\0';
01244     }
01245 
01246     /*  Determine the time of this file
01247      */
01248 
01249     if (dc) {
01250         nsamples = dc_GetNSample(dc);
01251     }
01252     else {
01253         nsamples = 0;
01254     }
01255 
01256     if (nsamples > 0) {
01257 
01258         dc_GetTime(dc, 0, &zeb_time);
01259         start_time = zeb_time.zt_Sec;
01260 
01261         dc_GetTime(dc, nsamples - 1, &zeb_time);
01262         end_time = zeb_time.zt_Sec;
01263 
01264         extension = "raw";
01265     }
01266     else {
01267         if (badtime > 0) {
01268             start_time = end_time = badtime;
01269         }
01270         else {
01271             append_log_msg(__FILE__, __LINE__,
01272                 "Could not determine time for bad file: %s\n", filename);
01273             current_status(STATUS_NOMOVERAW);
01274             return(FAILURE);
01275         }
01276 
01277         extension = "bad";
01278 
01279         append_log_msg(__FILE__, __LINE__,
01280             "Null DataChunk after processing file: %s\n", filename);
01281 
01282         /*  Set status to bad data file but don't return failure.  We do this
01283          *  so the ingest will move the raw file marking it as bad and then
01284          *  continue to work on the remaining files.
01285          */
01286 
01287         current_status(STATUS_NULLDC);
01288     }
01289 
01290     status = rename_raw(
01291         filename, start_time, end_time, dsc_name, "00", extension, 2);
01292 
01293     return(status);
01294 }
01295 
01296 /*******************************************************************************
01297 *
01298 * Description:
01299 *   The parse_dimension_string function will parse the tdbkey which contains
01300 *   information about the dimension(s) for the given field.
01301 *
01302 * Inputs:
01303 *   parse_string: The string containing the dimension information.
01304 *
01305 * Outputs:
01306 *   dim_num:   An array of dimension numbers which gets parsed out
01307 *              of the parse_string.
01308 *
01309 *   is_static: Boolean which we set to TRUE (1) if this is a static
01310 *              field. We pass this value by reference.
01311 *
01312 * Returns:
01313 *   The number of dimensions.
01314 *
01315 *******************************************************************************/
01316 int parse_dimension_string(char *parse_string, int *dim_num, int *is_static)
01317 {
01318     int     i;
01319     int     num;
01320     int     pstrlen;
01321     char    c;
01322 
01323     pstrlen = strlen(parse_string);
01324 
01325     for(i = 0, num = 0; i < pstrlen; num++) {
01326 
01327         while(!isdigit(parse_string[i])) {
01328             if(i > pstrlen) break;
01329             i++;
01330         }
01331 
01332         dim_num[num] = 0;
01333         while(isdigit(parse_string[i])) {
01334             c = parse_string[i];
01335             dim_num[num] = 10 * dim_num[num] + atoi(&c);
01336             i++;
01337         }
01338 
01339       /*  0 dimension means Static.
01340        */
01341         if(dim_num[num] == 0) {
01342             *is_static = 1;
01343 
01344           /*  We don't want to return this dimension.
01345            */
01346             num--;
01347         }
01348     }
01349 
01350     return(num);
01351 }
01352 
01353 /*******************************************************************************
01354 *
01355 * Description:
01356 *   The set_fields function will set up the fields and thier attributes in
01357 *   the given NSpace datachunk for the specified dc platform name and number.
01358 *   When setting the field attributes the standard attributes valid_min,
01359 *   valid_max, valid_delta, and resolution will have the same data type
01360 *   as the field they are defined for. The missing_value attribute will
01361 *   be defined as -9999 for all fields unless otherwise specified.  If the
01362 *   specified value of missing_value is NA, the missing_value attribute will
01363 *   not be created for that field.
01364 *
01365 * Inputs:
01366 *   dc:       The datachunk to define the fields in.
01367 *
01368 *   fields:   The array of FieldIds to fill up.
01369 *
01370 *   num_dims: A pointer to the integer to store the number of dimensions in
01371 *             or NULL if you don't need this information passed to the calling
01372 *             procedure.
01373 *
01374 *   dimsizes: The array of dimension sizes to fill up or NULL if you don't
01375 *             need this information passed to the calling procedure.
01376 *
01377 *   make_dims_fields: set to 1 to make the dimensions fields,
01378 *
01379 * Outputs:
01380 *   dc:       The data chunk with the fields defined.
01381 *
01382 *   fields:   The array of FieldIds.
01383 *
01384 *   num_dims: The number of dimensions for this dc if the input value wasn't NULL.
01385 *
01386 *   dimsizes: The sizes of the dimensions for this dc if the input value wasn't NULL.
01387 *
01388 * Returns:
01389 *   The number of fields defined in the datachunk.
01390 *
01391 *******************************************************************************/
01392 int set_fields(DataChunk *dc,
01393            FieldId   *fields,
01394            int       *num_dims,
01395            int       *dimsizes,
01396            int        make_dims_fields)
01397 {
01398     char  tdb_plat_base[SHORTSTRLEN];
01399     char  tdb_plat_name[SHORTSTRLEN];
01400     char  tdb_plat[SHORTSTRLEN];
01401     char  datalevel[8];
01402     int   pindex;
01403     char *chrp;
01404     int   ndims;
01405     int   ndimatts;
01406     int   nflds;
01407     int   nflds_total;
01408     int   natts;
01409     char *tdbvalue;
01410     char *tdbdimsize;
01411     char *datatype;
01412     unsigned long dimsize;
01413     FieldId dimids[DC_MaxDimension];
01414     FieldId vardims[DC_MaxDimension];
01415     int     dim_nums[DC_MaxDimension];
01416     int     ndim_fields;
01417     int     fielddims;
01418     int     is_static;
01419     int     i;
01420     int     j;
01421 
01422     int          make_qc_field;
01423     FieldId      qc_fid;
01424     FieldId      qc_time_fid;
01425 
01426     char         qc_name[MAX_QC_NAME_LENGTH];
01427     char         qc_descrip[MAX_QC_DESCRIP_LENGTH];
01428     char         qc_units[9];
01429     DC_ElemType  qc_fieldtype;
01430 
01431   /* These variables eliminate the need for reading keys from the
01432    * TDB if we need to come in here multiple times (mutiple files
01433    * being ingested).  This was done to increase performance when
01434    * ingesting multiple files and to reduce the demand on the TDB.
01435    * These changes increased the performance of the ecor_ingest from
01436    * 1.5 files/minute to 6 files per minute.
01437    */
01438 
01439   /*  Dimensions
01440    */
01441     static DC_ElemType dimtype[MAX_DCS][MAX_FIELDS];
01442     static char *dimname[MAX_DCS][MAX_DIMS];
01443     static char *dimdescrip[MAX_DCS][MAX_DIMS];
01444     static char *dimunits[MAX_DCS][MAX_DIMS];
01445     static char *dimres[MAX_DCS][MAX_DIMS];
01446     static char *dimattname[MAX_DCS][MAX_DIMS][MAX_FLDATTS];
01447     static char *dimattvalue[MAX_DCS][MAX_DIMS][MAX_FLDATTS];
01448 
01449   /*  Fields
01450    */
01451     static DC_ElemType fieldtype[MAX_DCS][MAX_FIELDS];
01452     static char *name[MAX_DCS][MAX_FIELDS];
01453     static char *dim[MAX_DCS][MAX_FIELDS];
01454     static char *descrip[MAX_DCS][MAX_FIELDS];
01455     static char *units[MAX_DCS][MAX_FIELDS];
01456 
01457     static int   qc_fields[MAX_DCS][MAX_FIELDS];
01458 
01459   /*  Standard flattrs
01460    */
01461     static char *min[MAX_DCS][MAX_FIELDS];
01462     static char *max[MAX_DCS][MAX_FIELDS];
01463     static char *delta[MAX_DCS][MAX_FIELDS];
01464     static char *missing[MAX_DCS][MAX_FIELDS];
01465     static char *res[MAX_DCS][MAX_FIELDS];
01466 
01467   /*  Platform flatters
01468    */
01469     static char *attname[MAX_DCS][MAX_FIELDS][MAX_FLDATTS];
01470     static char *attvalue[MAX_DCS][MAX_FIELDS][MAX_FLDATTS];
01471     static int   fields_done[MAX_DCS];
01472     static char  qc_comm[1800];
01473     static char  qc_min_delta[64];
01474     static char  qc_check_prior[64];
01475     static char  qc_max_delta[64];
01476     int          status;
01477     double       d_min_expected;
01478     double       d_max_expected;
01479     double       d_check_prior;
01480 
01481     print_debug(__FILE__, __LINE__,
01482         "Entering set_fields for platform: %s\n", ds_PlatformName(dc->dc_Platform));
01483 
01484     if (!db_reconnect()) {
01485         return(0);
01486     }
01487 
01488     pindex = set_pindex(dc);
01489 
01490     /*  Get the TDB platform base and name
01491      */
01492 
01493     get_tdb_plat_names(
01494             dc,
01495             tdb_plat_base,
01496             tdb_plat_name,
01497             NULL, NULL);
01498 
01499     /*  Get the data level from the platform name
01500      */
01501 
01502     get_dc_platform_datalevel(dc, datalevel);
01503 
01504     print_debug(__FILE__, __LINE__,
01505         "TDB lookup info: tdb_plat_base = '%s', tdb_plat_name = '%s', datalevel = '%s'\n",
01506         tdb_plat_base, tdb_plat_name, datalevel);
01507 
01508     /*  If the tdb_plat_name key is defined use that for the tdb_plat
01509      *  otherwise use tdb_plat_base for the tdb_plat.
01510      */
01511 
01512     tdbvalue = get_field_name(tdb_plat_name, datalevel, 1);
01513     if (tdbvalue) {
01514         strcpy(tdb_plat, tdb_plat_name);
01515         shared_tdb_free(tdbvalue);
01516 
01517         print_debug(__FILE__, __LINE__,
01518             "Using tdb_plat_name to set fields\n");
01519     }
01520     else if (is_db_error()) {
01521         db_disconnect();
01522         return(0);
01523     }
01524     else {
01525         strcpy(tdb_plat, tdb_plat_base);
01526 
01527         print_debug(__FILE__, __LINE__,
01528             "Using tdb_plat_base to set fields\n");
01529     }
01530 
01531     /*  Setup the qc_time field if it is needed
01532      */
01533 
01534     if (strcmp (datalevel, "b1") == 0) {
01535 
01536         /* If we're working on a b1 file, before we add any fields, we will add
01537          * the "qc_time" field, if there is an entry in the TDB for the qc_time
01538          * stuff.
01539          */
01540 
01541         status = get_qc_time_interval(tdb_plat_base, tdb_plat_name,
01542                     &d_min_expected, &d_max_expected, &d_check_prior);
01543 
01544         if (status) {
01545 
01546             strcpy (qc_name,    "qc_time");
01547             strcpy (qc_descrip, "Results of quality checks on sample time");
01548             strcpy (qc_units,   "unitless");
01549 
01550             qc_time_fid = F_DeclareField(qc_name, qc_descrip, qc_units);
01551 
01552             print_debug(__FILE__, __LINE__,
01553                 "Making QC field named: %s fid=%d\n", qc_name, qc_time_fid);
01554 
01555             dc_SetFieldAttr(dc, qc_time_fid, "long_name", qc_descrip);
01556             dc_SetFieldAttr(dc, qc_time_fid, "units", qc_units);
01557 
01558             qc_comm[0] = (char) NULL;
01559 
01560             /* Construct the comment */
01561 
01562             strcat(qc_comm, "The qc_time values are calculated by comparing each sample\n");
01563             strcat(qc_comm, "time with the previous time (i.e. delta_t = t[n] - t[n-1]).\n");
01564             strcat(qc_comm, "If the 'qc_check_prior' flag is set the first sample time\n");
01565             strcat(qc_comm, "from a new raw file will be compared against the time just\n");
01566             strcat(qc_comm, "previous to it in the stored data. If the 'qc_check_prior'\n");
01567             strcat(qc_comm, "flag is not set the qc_time value for the first sample time\n");
01568             strcat(qc_comm, "will be set to 0\n");
01569             strcat(qc_comm, "\n");
01570             strcat(qc_comm, "The qc_time bit values are as follows:\n");
01571             strcat(qc_comm, "=========================================================\n");
01572             strcat(qc_comm, "0x0 = delta time is within the specified range\n");
01573             strcat(qc_comm, "0x1 = delta time is equal to 0, duplicate sample times\n");
01574             strcat(qc_comm, "0x2 = delta time is less than the 'delta_t_lower_limit'\n");
01575             strcat(qc_comm, "0x4 = delta time is greater than the 'delta_t_upper_limit'\n");
01576             strcat(qc_comm, "\n");
01577 
01578             dc_SetFieldAttr(dc, qc_time_fid, "description", qc_comm);
01579 
01580             sprintf (qc_min_delta, "%lf", d_min_expected);
01581             sprintf (qc_max_delta, "%lf", d_max_expected);
01582             sprintf (qc_check_prior,"%lf", d_check_prior);
01583 
01584             set_flattr(dc, qc_time_fid,
01585                 "delta_t_lower_limit", DCT_Integer, 1, qc_min_delta);
01586             set_flattr(dc, qc_time_fid,
01587                 "delta_t_upper_limit", DCT_Integer, 1, qc_max_delta);
01588 
01589             set_flattr(dc, qc_time_fid,
01590                 "prior_sample_flag", DCT_Integer, 1, qc_check_prior);
01591 
01592             fielddims = 0;
01593             is_static = 0;
01594 
01595             dc_NSDefineVariable (dc,
01596                                  qc_time_fid,
01597                                  fielddims,
01598                                  vardims,
01599                                  is_static);
01600 
01601         } /* End of "if (status == 1)" block */
01602     }
01603 
01604     /*  Setup the Dimensions
01605      */
01606 
01607     print_debug(__FILE__, __LINE__,
01608         "Setting up the dimensions\n", ds_PlatformName(dc->dc_Platform));
01609 
01610     ndim_fields = 0;
01611     for(ndims = 1; ndims < DC_MaxDimension; ndims++) {
01612 
01613         if (fields_done[pindex]) {
01614             if (!dimname[pindex][ndims]) {
01615                 break;
01616             }
01617         }
01618         else {
01619             if ((dimname[pindex][ndims]
01620                 = get_dimension_name(tdb_plat, datalevel, ndims)) == NULL) {
01621                 break;
01622             }
01623 
01624             if (strcmp(dimname[pindex][ndims], "end_dimensions") == 0) {
01625                 shared_tdb_free(dimname[pindex][ndims]);
01626                 dimname[pindex][ndims] = NULL;
01627                 break;
01628             }
01629 
01630             if ((datatype = get_dimension_key(TDBFLDTYPE, tdb_plat, datalevel, ndims)) == NULL) {
01631                 dimtype[pindex][ndims] = get_field_type("float");
01632             }
01633             else {
01634                 dimtype[pindex][ndims] = get_field_type(datatype);
01635                 shared_tdb_free(datatype);
01636             }
01637 
01638             if ((dimdescrip[pindex][ndims]
01639                 = get_dimension_key(TDBFLDDESCRIP, tdb_plat, datalevel, ndims)) == NULL) {
01640                 dimdescrip[pindex][ndims] = (char *)malloc(2 * sizeof(char));
01641                 strcpy(dimdescrip[pindex][ndims], " ");
01642             }
01643             if ((dimunits[pindex][ndims]
01644                 = get_dimension_key(TDBFLDUNITS, tdb_plat, datalevel, ndims)) == NULL) {
01645                 dimunits[pindex][ndims] = (char *)malloc(2 * sizeof(char));
01646                 strcpy(dimunits[pindex][ndims], " ");
01647             }
01648 
01649             dimres[pindex][ndims] = get_dlattr_key(TDBFLDRES, tdb_plat, datalevel, ndims);
01650         }
01651 
01652         /*  Some ingests need to be able to set the dimension sizes on the fly.
01653          *  This means we must first look for an instrument specific dimension
01654          *  size before looking for the global one.
01655          */
01656 
01657         if ((tdbdimsize = get_dlattr_key(TDBDIMSIZE, tdb_plat_name, datalevel, ndims)) == NULL) {
01658             if ((tdbdimsize = get_dlattr_key(TDBDIMSIZE, tdb_plat_base, datalevel, ndims)) == NULL) {
01659                 break;
01660             }
01661         }
01662 
01663         sscanf(tdbdimsize, "%d", &dimsize);
01664         shared_tdb_free(tdbdimsize);
01665 
01666         dimids[ndims - 1] = F_DeclareField(dimname[pindex][ndims],
01667             dimdescrip[pindex][ndims], dimunits[pindex][ndims]);
01668 
01669         dc_NSDefineDimension(dc, dimids[ndims - 1], dimsize);
01670         if (dimsizes != NULL) dimsizes[ndims - 1] = dimsize;
01671 
01672       /*  We are going to create a coordinate variable for each dimension.
01673        */
01674 
01675         if (make_dims_fields) {
01676 
01677             print_debug(__FILE__, __LINE__,
01678                 "Making the dimensions fields\n");
01679 
01680             ndim_fields++;
01681             fields[ndims - 1] = dimids[ndims - 1];
01682 
01683             dc_NSDefineVariable(dc, fields[ndims - 1], 1, &dimids[ndims - 1], TRUE);
01684 
01685             if (dimres[pindex][ndims]) {
01686                 set_flattr(dc, dimids[ndims - 1], "resolution", dimtype[pindex][ndims], 1, dimres[pindex][ndims]);
01687             }
01688 
01689           /*  Loop through field attrs in TDB.  Stop when there are no more
01690            */
01691             for (ndimatts = 1; ndimatts < MAX_FLDATTS; ndimatts++) {
01692 
01693                 if (fields_done[pindex]) {
01694                     if (!dimattname[pindex][ndims][ndimatts]) {
01695                         break;
01696                     }
01697                 }
01698                 else {
01699                     if ((dimattname[pindex][ndims][ndimatts]
01700                         = get_dlattr_name(tdb_plat, datalevel, ndims, ndimatts)) == NULL) {
01701                         break;
01702                     }
01703                     dimattvalue[pindex][ndims][ndimatts]
01704                         = get_dlattr_value(tdb_plat, datalevel, ndims, ndimatts);
01705                 }
01706 
01707                 if (dimattvalue[pindex][ndims][ndimatts]) {
01708                     dc_SetFieldAttr(dc, dimids[ndims - 1],
01709                         dimattname[pindex][ndims][ndimatts], dimattvalue[pindex][ndims][ndimatts]);
01710                 }
01711             }
01712         }
01713     } /* end for(ndims ... */
01714     ndims--;
01715 
01716     if (num_dims != NULL) *num_dims = ndims;
01717 
01718     print_debug(__FILE__, __LINE__,
01719         "Setup %i dimensions\n", ndims);
01720 
01721   /************************************************************
01722    *  Setup the Fields
01723    */
01724     print_debug(__FILE__, __LINE__,
01725         "Setting up the fields\n", ds_PlatformName(dc->dc_Platform));
01726 
01727     for (nflds = 1; nflds < MAX_FIELDS - ndim_fields; nflds++) {
01728 
01729         make_qc_field = 0; /* We won't create a qc_<name> field unless one of min/max/delta is specified */
01730 
01731         print_debug (__FILE__, __LINE__,
01732            "Starting out with make_qc_field = 0 for nflds=%d\n", nflds);
01733 
01734         if (fields_done[pindex]) {
01735             if (!name[pindex][nflds]) {
01736                 break;
01737             }
01738         }
01739         else {
01740             if ((name[pindex][nflds] = get_field_name(tdb_plat, datalevel, nflds)) == NULL) {
01741                 break;
01742             }
01743             if (strcmp(name[pindex][nflds], "end_fields") == 0) {
01744                 shared_tdb_free(name[pindex][nflds]);
01745                 name[pindex][nflds] = NULL;
01746                 break;
01747             }
01748 
01749             if ((descrip[pindex][nflds] = get_field_key(TDBFLDDESCRIP, tdb_plat, datalevel, nflds)) == NULL) {
01750                 descrip[pindex][nflds] = (char *)malloc(2 * sizeof(char));
01751                 strcpy(descrip[pindex][nflds], " ");
01752             }
01753             if ((units[pindex][nflds] = get_field_key(TDBFLDUNITS, tdb_plat, datalevel, nflds)) == NULL) {
01754                 units[pindex][nflds] = (char *)malloc(2 * sizeof(char));
01755                 strcpy(units[pindex][nflds], " ");
01756             }
01757 
01758             if ((datatype = get_field_key(TDBFLDTYPE, tdb_plat, datalevel, nflds)) == NULL) {
01759                 fieldtype[pindex][nflds] = get_field_type("float");
01760             }
01761             else {
01762                 fieldtype[pindex][nflds] = get_field_type(datatype);
01763                 shared_tdb_free(datatype);
01764             }
01765 
01766             dim[pindex][nflds]     = get_field_key(TDBFLDDIMS, tdb_plat, datalevel, nflds);
01767             missing[pindex][nflds] = get_field_key(TDBFLDMISSING, tdb_plat, datalevel, nflds);
01768 
01769             min[pindex][nflds]     = get_flattr_key(TDBFLDMIN, tdb_plat, datalevel, nflds);
01770             max[pindex][nflds]     = get_flattr_key(TDBFLDMAX, tdb_plat, datalevel, nflds);
01771             delta[pindex][nflds]   = get_flattr_key(TDBFLDDELTA, tdb_plat, datalevel, nflds);
01772             res[pindex][nflds]     = get_flattr_key(TDBFLDRES, tdb_plat, datalevel, nflds);
01773 
01774             for (natts = 1; natts < MAX_FLDATTS; natts++) {
01775                 if ((attname[pindex][nflds][natts] = get_flattr_name(tdb_plat, datalevel, nflds, natts)) == NULL) {
01776                     break;
01777                 }
01778                 if (strcmp(attname[pindex][nflds][natts], "end_field_attributes") == 0) {
01779                     shared_tdb_free(attname[pindex][nflds][natts]);
01780                     attname[pindex][nflds][natts] = NULL;
01781                     break;
01782                 }
01783 
01784                 attvalue[pindex][nflds][natts] = get_flattr_value(tdb_plat, datalevel, nflds, natts);
01785             }
01786         }
01787 
01788         fields[nflds + ndim_fields - 1] = F_DeclareField(name[pindex][nflds],
01789                                descrip[pindex][nflds],
01790                                units[pindex][nflds]);
01791 
01792         print_debug (__FILE__, __LINE__,
01793              "Making non-QC field named %s with fid=%d\n",
01794              name[pindex][nflds], fields[nflds + ndim_fields - 1]);
01795 
01796       /*  We need to leave these in here, otherwise we may not get the
01797        *  expected attributes.  Zeb will use the attributes that were
01798        *  first set the first time a field name is used
01799        */
01800         dc_SetFieldAttr(dc, fields[nflds + ndim_fields - 1],
01801             "long_name", descrip[pindex][nflds]);
01802         dc_SetFieldAttr(dc, fields[nflds + ndim_fields - 1],
01803             "units", units[pindex][nflds]);
01804 
01805         print_debug(__FILE__, __LINE__,
01806             "Setting standard attributes for field: %s\n", name[pindex][nflds]);
01807 
01808         if (min[pindex][nflds]) {
01809             set_flattr(dc, fields[nflds + ndim_fields - 1],
01810                 "valid_min", fieldtype[pindex][nflds], 1, min[pindex][nflds]);
01811 
01812             make_qc_field = 1;
01813             print_debug (__FILE__, __LINE__,
01814                 "set make_qc_field=1 because we have min=%s\n", min[pindex][nflds]);
01815         }
01816         if (max[pindex][nflds]) {
01817             set_flattr(dc, fields[nflds + ndim_fields - 1],
01818                 "valid_max", fieldtype[pindex][nflds], 1, max[pindex][nflds]);
01819 
01820             make_qc_field = 1;
01821             print_debug (__FILE__, __LINE__,
01822                 "set make_qc_field=1 because we have max=%s\n", max[pindex][nflds]);
01823         }
01824         if (delta[pindex][nflds]) {
01825             set_flattr(dc, fields[nflds + ndim_fields - 1],
01826                 "valid_delta", fieldtype[pindex][nflds], 1, delta[pindex][nflds]);
01827 
01828             make_qc_field = 1;
01829             print_debug (__FILE__, __LINE__,
01830                 "set make_qc_field=1 because we have delta=%s\n", delta[pindex][nflds]);
01831         }
01832         if (res[pindex][nflds]) {
01833             set_flattr(dc, fields[nflds + ndim_fields - 1],
01834                 "resolution", fieldtype[pindex][nflds], 1, res[pindex][nflds]);
01835         }
01836         if (missing[pindex][nflds]) {
01837             if (strcmp(missing[pindex][nflds], "NA") != 0) {
01838                 set_flattr(dc, fields[nflds + ndim_fields - 1],
01839                     "missing_value", fieldtype[pindex][nflds], 1, missing[pindex][nflds]);
01840             }
01841         }
01842         else {
01843             set_flattr(dc, fields[nflds + ndim_fields - 1],
01844                 "missing_value", fieldtype[pindex][nflds], 1, DEFAULT_MISSING);
01845         }
01846 
01847       /*  Loop through field attrs.
01848        */
01849         print_debug(__FILE__, __LINE__,
01850             "Setting non-standard attributes for field: %s\n", name[pindex][nflds]);
01851 
01852         for (natts = 1; natts < MAX_FLDATTS; natts++) {
01853 
01854             if (attname[pindex][nflds][natts] == NULL) {
01855                 break;
01856             }
01857 
01858             if (attvalue[pindex][nflds][natts] != NULL) {
01859                 dc_SetFieldAttr(dc, fields[nflds + ndim_fields - 1],
01860                     attname[pindex][nflds][natts], attvalue[pindex][nflds][natts]);
01861             }
01862         }
01863 
01864       /*  Loop through dimensions
01865        *
01866        * parse_dimension_string will load dimNum up with an array of dimension
01867        * numbers.  We need to subtract 1 from the dimNum to get the
01868        * corresponding fieldId.  These Ids are loaded into an array
01869        * of FieldIds (vardims) and are then passed at the Dimensions
01870        * to dc_NSDefineVariable.
01871        */
01872         fielddims = 0;
01873         is_static = 0;
01874         if(dim[pindex][nflds]) {
01875             fielddims = parse_dimension_string(dim[pindex][nflds], dim_nums, &is_static);
01876             for(i = 0; i < fielddims; i++) {
01877                 vardims[i] = dimids[dim_nums[i] - 1];
01878             }
01879         }
01880         dc_NSDefineVariable(dc, fields[nflds + ndim_fields - 1],
01881             fielddims, vardims, is_static);
01882 
01883         print_debug(__FILE__, __LINE__,
01884             "Finished declaring field: %s\n", name[pindex][nflds]);
01885 
01886         if (make_qc_field == 1 && strcmp(datalevel, "b1") == 0) {
01887 
01888             print_debug (__FILE__, __LINE__,
01889                 "make_qc_field is 1 for %s\n", name[pindex][nflds]);
01890             /* We need to generate a qc_<name> field */
01891 
01892             sprintf (qc_name, "qc_%s", name[pindex][nflds]);
01893             sprintf (qc_descrip, "Quality check results on field: %s", descrip[pindex][nflds]);
01894             sprintf (qc_units, "unitless");
01895 
01896             qc_fid = F_DeclareField(qc_name,
01897                                     qc_descrip,
01898                                     qc_units);
01899 
01900             print_debug(__FILE__, __LINE__,
01901                 "Making QC field named: %s fid=%d\n", qc_name, qc_fid);
01902 
01903             dc_NSDefineVariable(dc,
01904                                 qc_fid,
01905                                 fielddims,
01906                                 vardims,
01907                                 is_static);
01908 
01909             /* We need to remember which fields we defined
01910              * as QC fields so that we can set the type
01911              * of those fields below
01912              */
01913 
01914             qc_fields[pindex][qc_fid] = 1;
01915         }
01916     } /* End of nflds loop */
01917     nflds--;
01918 
01919     nflds_total = nflds;
01920 
01921   /*  Disconnect from the database if we made the connection
01922    */
01923 
01924     db_disconnect();
01925 
01926   /*  Close out definition and set the field types
01927    */
01928     dc_NSDefineComplete (dc);
01929 
01930     for(i = 1; i <= ndim_fields; i++) {
01931         dc_SetType(dc, fields[i - 1], dimtype[pindex][i]);
01932     }
01933 
01934     if (strcmp (datalevel, "b1") == 0) {
01935 
01936         /* We have to set the field type for the qc_time to "int" */
01937 
01938         qc_fieldtype = get_field_type("int");
01939         dc_SetType (dc, qc_time_fid, qc_fieldtype);
01940     }
01941 
01942     for(nflds = 1; nflds <= nflds_total; nflds++) {
01943 
01944         dc_SetType(dc,
01945                    fields[nflds + ndim_fields - 1],
01946                    fieldtype[pindex][nflds]);
01947 
01948         print_debug(__FILE__, __LINE__,
01949             "Set field type for fid=%d\n",
01950             fields[nflds + ndim_fields - 1]);
01951     }
01952 
01953     for (i=1; i < MAX_FIELDS; i++) {
01954 
01955         if (qc_fields[pindex][i] == 1) {
01956             dc_SetType (dc, i, DCT_Integer);
01957             print_debug(__FILE__, __LINE__,
01958                 "Set field type for fid=%d (QC field) \n", i);
01959         }
01960     }
01961 
01962     if (nflds_total) {
01963         fields_done[pindex] = 1;
01964         print_debug(__FILE__, __LINE__,
01965             "Set %d fields for platform %s\n", nflds_total, tdb_plat);
01966     }
01967     else {
01968         append_log_msg(__FILE__, __LINE__,
01969             "Failed to set fields for: %s\n", tdb_plat);
01970         current_status(STATUS_INITDC);
01971         return(0);
01972     }
01973 
01974     return(nflds_total);
01975 }
01976 
01977 /*******************************************************************************
01978 *
01979 * Description:
01980 *   The set_flattr function sets a field attribute in the datachunck.  If an
01981 *   invalid atttype is specified the attribute will be stored as a string.
01982 *
01983 * Inputs:
01984 *   dc:           The datachunk to store the field attribute in.
01985 *
01986 *   field:        The FieldId of the field to set the attribute for.
01987 *
01988 *   attname:      The name of the attribute.
01989 *
01990 *   atttype:      The DC_ElemType of the attribute.
01991 *
01992 *   attvalue:     A string containing the attribute value.
01993 *
01994 * Outputs:
01995 *   None.
01996 *
01997 * Returns:
01998 *   None.
01999 *
02000 *******************************************************************************/
02001 void set_flattr(DataChunk *dc, FieldId field, char *attname,
02002                 DC_ElemType atttype, int nelems, char *attvalue)
02003 {
02004     float          fdata;
02005     double         ddata;
02006     long double    lddata;
02007     unsigned char  bytes;
02008     short          sdata;
02009     unsigned short usdata;
02010     int            idata;
02011     unsigned int   uidata;
02012     long           ldata;
02013     unsigned long  uldata;
02014 
02015     switch (atttype) {
02016         case DCT_Float:
02017             fdata = (float)atof(attvalue);
02018             dc_SetFieldAttrArray(dc, field, attname, DCT_Float, 1, (void *)&fdata);
02019             break;
02020         case DCT_Double:
02021             ddata = atof(attvalue);
02022             dc_SetFieldAttrArray(dc, field, attname, DCT_Double, 1, (void *)&ddata);
02023             break;
02024         case DCT_LongDouble:
02025             lddata = (long double)atof(attvalue);
02026             dc_SetFieldAttrArray(dc, field, attname, DCT_LongDouble, 1, (void *)&lddata);
02027             break;
02028         case DCT_Char:
02029             dc_SetFieldAttrArray(dc, field, attname, DCT_Char, strlen(attvalue), (void *)attvalue);
02030             break;
02031         case DCT_UnsignedChar:
02032             bytes = (unsigned char)atoi(attvalue);
02033             dc_SetFieldAttrArray(dc, field, attname, DCT_UnsignedChar, 1, (void *)&bytes);
02034             break;
02035         case DCT_ShortInt:
02036             sdata = (short)atoi(attvalue);
02037             dc_SetFieldAttrArray(dc, field, attname, DCT_ShortInt, 1, (void *)&sdata);
02038             break;
02039         case DCT_UnsignedShort:
02040             usdata = (unsigned short)atoi(attvalue);
02041             dc_SetFieldAttrArray(dc, field, attname, DCT_UnsignedShort, 1, (void *)&usdata);
02042             break;
02043         case DCT_Integer:
02044             idata = atoi(attvalue);
02045             dc_SetFieldAttrArray(dc, field, attname, DCT_Integer, 1, (void *)&idata);
02046             break;
02047         case DCT_UnsignedInt:
02048             uidata = (unsigned int)atoi(attvalue);
02049             dc_SetFieldAttrArray(dc, field, attname, DCT_UnsignedInt, 1, (void *)&uidata);
02050             break;
02051         case DCT_LongInt:
02052             ldata = atol(attvalue);
02053             dc_SetFieldAttrArray(dc, field, attname, DCT_LongInt, 1, (void *)&ldata);
02054             break;
02055         case DCT_UnsignedLong:
02056             uldata = (unsigned long)atol(attvalue);
02057             dc_SetFieldAttrArray(dc, field, attname, DCT_UnsignedLong, 1, (void *)&uldata);
02058             break;
02059         default:
02060             dc_SetFieldAttrArray(dc, field, attname, DCT_String, 1, (void *)attvalue);
02061             break;
02062     }
02063 }
02064 
02065 /*******************************************************************************
02066 *
02067 * Description:
02068 *   The set_flattr_value function will set the value of a predefined field level
02069 *   attribute in the datachuck that is passed.
02070 *
02071 * Inputs:
02072 *   dc:           DataChunk with Field Level Attribute to change.
02073 *
02074 *   field_name:   Name of the field which contains FLATTR.
02075 *
02076 *   flattr_name:  Name of FLATTR to change.
02077 *
02078 *   flattr_value: New value of FLATTR.
02079 *
02080 * Outputs:
02081 *   dc:           DataChunk with new Field Level Attribute.
02082 *
02083 * Returns:
02084 *   1 on success,
02085 *   or 0 if the field name doesn't exist in the datachunk.
02086 *
02087 *******************************************************************************/
02088 int set_flattr_value (DataChunk *dc, char *field_name, char *flattr_name, char *flattr_value)
02089 {
02090     FieldId  fid;
02091 
02092   /*  If fid is less then 0, it has not been defined.
02093    */
02094     if ((fid = F_Declared(field_name)) < 0) {
02095         append_log_msg(__FILE__, __LINE__,
02096             "Field %s is not in the specified datachunk!", field_name);
02097         return(0);
02098     }
02099 
02100   /*  Set the New Field Level Attribute
02101    */
02102     dc_SetFieldAttr(dc, fid, flattr_name, flattr_value);
02103     print_debug(__FILE__, __LINE__,
02104         "Set flatter value, %s:%s = '%s'\n",
02105             field_name, flattr_name, flattr_value);
02106 
02107     return (1);
02108 }
02109 
02110 
02111 /*******************************************************************************
02112 *
02113 * Description:
02114 *   The set_global function will set up the global attributes in the datachunk.
02115 *
02116 * Inputs:
02117 *   dc:       The data chunk to define the global attributes in.
02118 *
02119 *   filename: The name of the file which is being ingested.
02120 *
02121 * Outputs:
02122 *   dc:    The data chunk with the global attributes defined.
02123 *
02124 * Returns:
02125 *   None.
02126 *
02127 *******************************************************************************/
02128 int set_global(DataChunk *dc, char *filename)
02129 {
02130     char  ingest_version[128];
02131     char  tdb_plat_base[SHORTSTRLEN];
02132     char  tdb_plat_name[SHORTSTRLEN];
02133     char  tdb_alias_base[SHORTSTRLEN];
02134     char  tdb_alias_name[SHORTSTRLEN];
02135     char  datalevel[8];
02136     char  input_source[MAXSTRLEN];
02137     char  facility_loc[SHORTSTRLEN];
02138 
02139     const char *rcsid;
02140     const char *rcsstate;
02141     const char *site_name;
02142     const char *facility;
02143     ProcLoc    *proc_loc;
02144 
02145     char    *chrp;
02146     char    *fld_ind_descrip;
02147     char    *res_descrip;
02148     char    *tdbvalue;
02149 
02150     int   attnum;
02151     char *attname;
02152     char *attvalue;
02153 
02154     print_debug(__FILE__, __LINE__,
02155         "Setting global attributes for platform: %s\n", ds_PlatformName(dc->dc_Platform));
02156 
02157     if (!db_reconnect()) {
02158         return(FAILURE);
02159     }
02160 
02161     /*  Get the TDB platform base and name
02162      */
02163 
02164     get_tdb_plat_names(
02165             dc,
02166             tdb_plat_base,
02167             tdb_plat_name,
02168             tdb_alias_base,
02169             tdb_alias_name);
02170 
02171     rcsid     = get_ingest_rcsid();
02172     rcsstate  = get_ingest_rcsstate();
02173     site_name = get_process_site();
02174     facility  = get_process_facility();
02175     proc_loc  = get_ingest_location();
02176 
02177   /*  First, we want to set the Standard global attributes
02178         ingest_software
02179         proc_level
02180         input_source
02181         site_id
02182         facility_id
02183         sample_int
02184         averaging_int
02185         serial_number
02186         comment
02187         resolution_description
02188    */
02189 
02190   /*  Set the ingest_version to the rcs state
02191    */
02192     dslib_trim_rcs_string(rcsstate, ingest_version, 128);
02193     dc_SetGlobalAttr(dc, "ingest_version", ingest_version);
02194 
02195   /*  Set ingest_lib_version
02196    */
02197     dc_SetGlobalAttr(dc, "libingest_version", get_ingest_lib_version());
02198 
02199   /*  Set dslibc_version
02200    */
02201     dc_SetGlobalAttr(dc, "libdslibc_version", dslib_get_version());
02202 
02203   /*  Set dsdb_lib_version
02204    */
02205     dc_SetGlobalAttr(dc, "libdsdb_version", dsdb_get_version());
02206 
02207   /*  Set the ingest_software to the rcsid.
02208    */
02209     dc_SetGlobalAttr(dc, "ingest_software", (char *)&rcsid[4]);
02210 
02211   /*  Get the data level from the platform name
02212    */
02213     get_dc_platform_datalevel(dc, datalevel);
02214     dc_SetGlobalAttr(dc, "proc_level", datalevel);
02215 
02216   /*  At this level we know that our data is coming from the instrument
02217    */
02218     sprintf(input_source, "%s", filename);
02219     dc_SetGlobalAttr(dc, "input_source", input_source);
02220 
02221   /*  Set the ingest_site from tdb and set site_id
02222    */
02223     dc_SetGlobalAttr(dc,"site_id", (char *)site_name);
02224 
02225   /*  Set the facility location from the TDB based on aliasplatname
02226    */
02227 
02228     sprintf(facility_loc, "%s: %s", facility, proc_loc->name);
02229 
02230     dc_SetGlobalAttr(dc,"facility_id", facility_loc);
02231 
02232   /*  Set the SDS-mode to the mode passed from ingest module
02233    *
02234    * dc_SetGlobalAttr(dc, "sds-mode", get_sds_mode());
02235    */
02236 
02237   /*  Set the sample interval. Sample will be looked for in this order:
02238    *      platname_sample       30ebbr13_sample
02239    *      platbase_sample       30ebbr_sample
02240    *      aliasplatname_sample  ebbr13_sample
02241    *      aliasplatbase_sample  ebbr_sample
02242    */
02243     tdbvalue = get_glattr_key("sample",
02244         tdb_plat_name, tdb_plat_base,
02245         tdb_alias_name, tdb_alias_base);
02246 
02247     if (tdbvalue != NULL) {
02248         dc_SetGlobalAttr(dc, "sample_int", tdbvalue);
02249         shared_tdb_free(tdbvalue);
02250     }
02251     else {
02252         dc_SetGlobalAttr(dc, "sample_int", "Not Specified");
02253     }
02254 
02255   /*  Set the averaging interval. Averaging will be looked for in this order:
02256    *      platname_averaging       30ebbr13_averaging
02257    *      platbase_averaging       30ebbr_averaging
02258    *      aliasplatname_averaging  ebbr13_averaging
02259    *      aliasplatbase_averaging  ebbr_averaging
02260    */
02261     tdbvalue = get_glattr_key("averaging",
02262         tdb_plat_name, tdb_plat_base,
02263         tdb_alias_name, tdb_alias_base);
02264 
02265     if (tdbvalue != NULL) {
02266         dc_SetGlobalAttr(dc, "averaging_int", tdbvalue);
02267         shared_tdb_free(tdbvalue);
02268     }
02269     else {
02270         dc_SetGlobalAttr(dc, "averaging_int", "None");
02271     }
02272 
02273   /*  Set the serial number
02274    */
02275     tdbvalue = get_glattr_key("serial",
02276         tdb_plat_name, tdb_plat_base,
02277         tdb_alias_name, tdb_alias_base);
02278 
02279     if (tdbvalue != NULL) {
02280         dc_SetGlobalAttr(dc, "serial_number", tdbvalue);
02281         shared_tdb_free(tdbvalue);
02282     }
02283     else {
02284         dc_SetGlobalAttr(dc,"serial_number", "Not Specified");
02285     }
02286 
02287   /*  Set the missing data value
02288    *
02289    * tdbvalue = get_glattr_key("missing", platname, platbase, aliasplatname, aliasplatbase);
02290    * if (tdbvalue != NULL) {
02291    *     dc_SetGlobalAttr(dc, "missing-data", tdbvalue);
02292    *     shared_tdb_free(tdbvalue);
02293    * }
02294    * else {
02295    *     dc_SetGlobalAttr(dc, "missing-data", "N/A");
02296    * }
02297    */
02298 
02299   /*  Set the comment field. Comment will be looked for in this order:
02300    *      platname_comment       30ebbr13_comment
02301    *      platbase_comment       30ebbr_comment
02302    *      aliasplatname_comment  ebbr13_comment
02303    *      aliasplatbase_comment  ebbr_comment
02304    */
02305     tdbvalue = get_glattr_key("comment",
02306         tdb_plat_name, tdb_plat_base,
02307         tdb_alias_name, tdb_alias_base);
02308 
02309     if (tdbvalue != NULL) {
02310         dc_SetGlobalAttr(dc, "comment", tdbvalue);
02311         shared_tdb_free(tdbvalue);
02312     }
02313     else {
02314         dc_SetGlobalAttr(dc, "comment", "");
02315     }
02316 
02317   /*  Fetch the field_indices glattr (global attribute) now
02318    *
02319    * if ((fld_ind_descrip = get_field_indices_descrip()) == NULL) {
02320    *     dc_SetGlobalAttr(dc, "field_indices", " ");
02321    * }
02322    * else {
02323    *     dc_SetGlobalAttr(dc, "field_indices", fld_ind_descrip);
02324    * }
02325    */
02326 
02327   /*  Fetch the resolution_description glattr (global attribute) now
02328    */
02329     if ((res_descrip = get_resolution_descrip()) == NULL) {
02330         dc_SetGlobalAttr(dc, "resolution_description", "Not Specified");
02331     }
02332     else {
02333         dc_SetGlobalAttr(dc,"resolution_description", res_descrip);
02334     }
02335 
02336   /*  Now set the platform specific metatdata
02337    */
02338     for(attnum = 1; attnum < MAX_METADATA; attnum++) {
02339 
02340         attname  = get_glattr_name(attnum,
02341                         tdb_plat_name, tdb_plat_base,
02342                         tdb_alias_name, tdb_alias_base);
02343 
02344         if (attname == NULL) {
02345             break;
02346         }
02347         if (strcmp(attname, "end_global_attributes") == 0) {
02348             shared_tdb_free(attname);
02349             break;
02350         }
02351 
02352         attvalue = get_glattr_value(attnum,
02353                         tdb_plat_name, tdb_plat_base,
02354                         tdb_alias_name, tdb_alias_base);
02355 
02356         if (attvalue != NULL) {
02357             dc_SetGlobalAttr(dc, attname, attvalue);
02358             shared_tdb_free(attvalue);
02359         }
02360         else {
02361             dc_SetGlobalAttr(dc, attname, "");
02362         }
02363         shared_tdb_free(attname);
02364     }
02365 
02366     db_disconnect();
02367 
02368     return(SUCCESS);
02369 }
02370 
02371 /*******************************************************************************
02372 *
02373 * Description:
02374 *   The set_location function will set up the location values in the
02375 *   given datachunk.
02376 *
02377 * Inputs:
02378 *   dc:       The dc in which to set the location.
02379 *
02380 * Outputs:
02381 *   dc:   The data chunk with the location set.
02382 *
02383 * Returns:
02384 *   None.
02385 *
02386 *******************************************************************************/
02387 ProcLoc *set_location(DataChunk *dc)
02388 {
02389     static Location  loc;
02390     ProcLoc         *proc_loc;
02391 
02392     print_debug(__FILE__, __LINE__,
02393         "Setting location for platform: %s\n", ds_PlatformName(dc->dc_Platform));
02394 
02395     proc_loc = get_ingest_location();
02396 
02397     if (proc_loc) {
02398         loc.l_alt = proc_loc->alt;
02399         loc.l_lat = proc_loc->lat;
02400         loc.l_lon = proc_loc->lon;
02401     }
02402     else {
02403         loc.l_alt = 0;
02404         loc.l_lat = 0;
02405         loc.l_lon = 0;
02406     }
02407 
02408     dc_SetStaticLoc(dc, &loc);
02409 
02410     return(proc_loc);
02411 }
02412 
02413 /*******************************************************************************
02414 *
02415 * Description:
02416 *   The set_location_from_data function sets the location portion of the dc
02417 *   statically using values passed as parameters.
02418 *
02419 * Inputs:
02420 *   dc:   The dc in which to set the location.
02421 *
02422 *   lat:  The latitude
02423 *
02424 *   lon:  The longitude
02425 *
02426 *   alt:  The altitude
02427 *
02428 * Outputs:
02429 *   dc:   The data chunk with the location set.
02430 *
02431 * Returns:
02432 *   None.
02433 *
02434 *******************************************************************************/
02435 void set_location_from_data(DataChunk *dc, float *lat, float *lon, float *alt)
02436 {
02437     Location loc;
02438 
02439     print_debug(__FILE__, __LINE__,
02440         "Setting location for platform: %s\n", ds_PlatformName(dc->dc_Platform));
02441 
02442     loc.l_lat = *lat;
02443     loc.l_lon = *lon;
02444     loc.l_alt = *alt;
02445 
02446     dc_SetStaticLoc(dc, &loc);
02447 
02448 }
02449 
02450 /*******************************************************************************
02451 *
02452 * Description:
02453 *   The set_pindex will return a unique platform index based on dc platform
02454 *   name. We need to keep an array of platform names because set_fields can be
02455 *   used for multiple platforms in the same ingest.  We will index into the
02456 *   field name, descrip, etc arrays based on the pindex assigned using the
02457 *   platform names.
02458 *
02459 * Inputs:
02460 *   dc:  The datachunk to get the platform index for.
02461 *
02462 * Outputs:
02463 *   None.
02464 *
02465 * Returns:
02466 *   The platform index.
02467 *
02468 *******************************************************************************/
02469 int set_pindex(DataChunk *dc)
02470 {
02471     static char platform_names[MAX_DCS][MAXSTRLEN];
02472     int pindex = 0;
02473 
02474   /*  Now, we need to figure out the pindex
02475    */
02476     while (platform_names[pindex][0] != '\0') {
02477         if (strcmp(platform_names[pindex], ds_PlatformName(dc->dc_Platform)) == 0) {
02478             break;
02479         }
02480         pindex++;
02481     }
02482 
02483     if (platform_names[pindex][0] == '\0') {
02484 
02485       /*  We haven't seen this platname before, so put it in our list
02486        */
02487         sprintf(platform_names[pindex], ds_PlatformName(dc->dc_Platform));
02488     }
02489 
02490     return(pindex);
02491 }
02492 
02493 /*******************************************************************************
02494 *
02495 * Description:
02496 *   The set_mobile_location_from_data function sets the location portion of
02497 *   the dc statically using values passed as parameters.
02498 *
02499 * Inputs:
02500 *   dc:    The dc in which to set the location.
02501 *
02502 *   nlocs: The number of locations stored.
02503 *
02504 *   lat:   The latitude array
02505 *
02506 *   lon:   The longitude array
02507 *
02508 *   alt:   The altitude array
02509 *
02510 * Outputs:
02511 *   dc:   The data chunk with the locations set.
02512 *
02513 * Returns:
02514 *   None.
02515 *
02516 *******************************************************************************/
02517 void set_mobile_location_from_data(DataChunk *dc, int nlocs,
02518                                    float *lat, float *lon, float *alt)
02519 {
02520     int      i;
02521     Location loc;
02522 
02523     print_debug(__FILE__, __LINE__,
02524         "Setting location for platform: %s\n", ds_PlatformName(dc->dc_Platform));
02525 
02526     for(i = 0; i < nlocs; i++) {
02527         loc.l_lat = lat[i];
02528         loc.l_lon = lon[i];
02529         loc.l_alt = alt[i];
02530 
02531         dc_SetLoc(dc, i, &loc);
02532     }
02533 
02534 }
02535 
02536 /*******************************************************************************
02537 *
02538 * Description:
02539 *   This function will fill up the ZebTime variable dotime based on hourmin,
02540 *   day and year. This function will also check to make sure that the year is
02541 *   greater than or equal to 1990 and the calculated time is not in the future.
02542 *
02543 * Inputs:
02544 *   hourmin: Hour and minute in the form HHMM
02545 *
02546 *   jday:    The julian day.
02547 *
02548 *   year:    The year since 1900.  (actually any year format will work
02549 *            but this was only added to be more forgiving.)
02550 *
02551 * Outputs:
02552 *   dotime:  The ZebTime struct with the correct time filled in.
02553 *
02554 * Returns:
02555 *   SUCCESS or FAILURE
02556 *
02557 *******************************************************************************/
02558 int set_sample_time(int hourmin, int jday, int year, ZebTime *dotime)
02559 {
02560     int total_days;
02561 
02562   /*  Make sure year is years since 1900.
02563    */
02564     year = four_digit_year(year);
02565     year -= 1900;
02566 
02567   /* We will not accept the sample if the year is less than 1990 or greater
02568    * than The current year.
02569    */
02570     if (year < 90 ) {
02571         print_debug(__FILE__, __LINE__,
02572             "In set_sample_time the year is less than 90.\n");
02573         return (FAILURE);
02574     }
02575 
02576   /* We will not accept the sample if the day is less than 1 or greater than
02577    * 366.  This will ensure a proper date came accross in the raw data file.
02578    */
02579     if ((jday < 1) || (jday > 366)) {
02580         print_debug(__FILE__, __LINE__,
02581             "In set_sample_time the jday is not in the range 1-366.\n");
02582         return (FAILURE);
02583     }
02584 
02585   /* We will not accept the sample if the hhmm is less than 0 or greater than
02586    * 2400.  This will ensure a proper time came across in the raw data file.
02587    */
02588     if ((hourmin < 0) || (hourmin > 2400)) {
02589         print_debug(__FILE__, __LINE__,
02590             "In set_sample_time the hourmin is not in the range 0-2400.\n");
02591         return (FAILURE);
02592     }
02593 
02594     total_days = days_since1970(year) + jday - 1;
02595     dotime->zt_Sec =
02596         (total_days * 86400L)
02597         + (((int)(hourmin * .01)) * 3600)
02598         + (((int)(hourmin % 100)) * 60);
02599     dotime->zt_MicroSec = 0;
02600 
02601   /*  Now make sure this time isn't in the future.
02602    */
02603     if (dotime->zt_Sec > time(NULL)) {
02604         print_debug(__FILE__, __LINE__,
02605             "In set_sample_time the calculated time is in the future.\n");
02606         dotime->zt_Sec = 0;
02607     }
02608 
02609     return (SUCCESS);
02610 }
02611 
02612 /*******************************************************************************
02613 *
02614 * Description:
02615 *   This function will call the appropriate ZEB data store calls to store the
02616 *   dc. Newfile tells the data store if a new file should be created. This will
02617 *   clean up the prev_dc since it will no longer be correct after this
02618 *   datachunk is stored.
02619 *
02620 * Inputs:
02621 *   dc:       The filled DataChunk which is to be stored.
02622 *
02623 *   newfile:  1 for new file, 0 no new file.
02624 *
02625 * Outputs:
02626 *   None.
02627 *
02628 * Returns:
02629 *   None.
02630 *
02631 *******************************************************************************/
02632 void store_datachunk(DataChunk *dc, int newfile)
02633 {
02634   /*  Set an alarm for 30 minutes.  Not sure why it is for so long but I'm not
02635    *  going to change it.  It could be that and ingest for and entire day
02636    *  could take this long (but I really doubt it!!).
02637    */
02638     alarm(30*60);
02639 
02640   /*  Record stats for this DataChunk
02641    */
02642     set_dc_stats(dc);
02643 
02644   /*  Store the data using current ZEB calls
02645    */
02646     ds_StoreBlocks(dc, newfile, NULL, 0);
02647 
02648   /*  Turn off the alarm if done
02649    */
02650     alarm(0);
02651 
02652   /*  Now clean up dc_last, we are done with it at this point
02653    */
02654     prev_dc = freeDC(prev_dc);
02655 }

Generated on Tue Sep 12 20:12:37 2006 for DSUTIL-INGEST_LIB by doxygen 1.3.5