示例#1
0
int                                  /* O [rcd] Return code */
nco_cnv_cf_cll_mth_add               /* [fnc] Add cell_methods attributes */
(const int out_id,                   /* I [id] netCDF file ID */
 var_sct * const * const var,        /* I [sct] Variable to reduce (e.g., average) (destroyed) */
 const int var_nbr,                  /* I [nbr] Number of variables to be defined */
 dmn_sct * const * const dmn_rdc,    /* I [sct] Dimensions over which to reduce variable */
 const int dmn_nbr_rdc,              /* I [sct] Number of dimensions to reduce variable over */
 const int nco_op_typ,               /* I [enm] Operation type, default is average */
 gpe_sct *gpe,                       /* I [sng] Group Path Editing (GPE) structure */
 const clm_bnd_sct * const cb,       /* I [sct] Climatology bounds structure */
 const trv_tbl_sct * const trv_tbl)  /* I [sct] Traversal table */
{
  /* Purpose: Add/modify CF cell_methods attribute
     http://cfconventions.org/Data/cf-conventions/cf-conventions-1.7/build/cf-conventions.html#cell-methods
     
     cell_methods values and description:
     point	: Data values are representative of points in space or time (instantaneous)
     sum	: Data values are representative of a sum or accumulation over the cell
     maximum_absolute_value	: Maximum absolute value
     maximum	: Maximum
     median	: Median
     mid_range	: Average of maximum and minimum
     minimum	: Minimum
     mean	: Mean (average value)
     mode	: Mode (most common value)
     range	: Absolute difference between maximum and minimum
     standard_deviation : Standard deviation
     variance	: Variance
     
     NCO operation types:
     avg Mean value
     avgsqr Mean of sum of squares
     mabs Maximum absolute value
     max Maximum value
     mebs Mean absolute value
     mibs Minimum absolute value
     min Minimum value
     rms Root-mean-square (normalized by N)
     rmssdn Root-mean square (normalized by N-1)
     sqravg Square of the mean
     sqrt Square root of the mean
     ttl Sum of values */

  const char fnc_nm[]="nco_cnv_cf_cll_mth_add()"; /* [sng] Function name */

  aed_sct aed; /* [sct] Attribute-edit information */

  char att_op_sng[23]; /* [sng] Operation type (longest is nco_op_mabs which translates to "maximum_absolute_value") */

  char *att_val=NULL; /* [sng] Coordinates attribute */
  char *att_val_cpy; /* [sng] Copy of attribute */
  char *grp_out_fll=NULL; /* [sng] Group name */
  char *sbs_ptr; /* [sng] Pointer to substring */
  char *cll_mth_clm; /* [sng] Cell methods for climatology */
  
  int *dmn_mch; /* [idx] Indices of dimensions reduced in this variable */

  int dmn_idx_rdc;
  int dmn_idx_var;
  int dmn_nbr_mch; /* [nbr] Number of dimension names to add to cell_methods */
  int grp_out_id; /* [ID] Group ID (output) */
  int nco_op_typ_lcl; /* [enm] Operation type, default is average */
  int rcd=NC_NOERR; /* [rcd] Return code */
  int var_idx;
  int var_out_id; /* [ID] Variable ID (output) */

  long int att_lng; /* [nbr] Length of attribute string */
  
  nc_type att_typ; /* [nbr] Attribute type */

  nco_bool FIRST_WARNING=True;
  nco_bool flg_dpl; /* [flg] New cell_methods attribute duplicates old */
  nco_bool mlt_dmn_rdc; /* [flg] Multiple dimension reduction flag */

  size_t dmn_sng_lng; /* [nbr] Length of dimension string */
  size_t sbs_sng_lng; /* [nbr] Length of substring */

  trv_sct *var_trv=NULL;  /* [sct] Variable GTT object */

  /* Initialize unchanging structure members */
  aed.att_nm=strdup("cell_methods");
  aed.type=NC_CHAR;

  /* Allocate space for maximum number of matching dimensions */
  dmn_mch=(int *)nco_calloc(dmn_nbr_rdc,sizeof(int));

  if(cb){
    if(cb->bnd2clm || cb->clm2clm) cll_mth_clm=strdup("time: mean within years time: mean over years");
    if(cb->clm2bnd) cll_mth_clm=strdup("time: mean");
  } /* !cb */

  /* Process all variables */
  for(var_idx=0;var_idx<var_nbr;var_idx++){ 

    /* Obtain variable GTT object using full variable name */
    var_trv=trv_tbl_var_nm_fll(var[var_idx]->nm_fll,trv_tbl);

    /* Edit group name for output */
    if(gpe) grp_out_fll=nco_gpe_evl(gpe,var_trv->grp_nm_fll); else grp_out_fll=(char *)strdup(var_trv->grp_nm_fll);

    /* Obtain output group ID */
    (void)nco_inq_grp_full_ncid(out_id,grp_out_fll,&grp_out_id);

    /* Memory management after current extracted group */
    if(grp_out_fll) grp_out_fll=(char *)nco_free(grp_out_fll);

    /* Get variable ID */
    (void)nco_inq_varid(grp_out_id,var_trv->nm,&var_out_id);

    /* Initialize attribute-edit structure for this variable */
    aed.var_nm=var_trv->nm;
    aed.id=var_out_id;
    aed.sz=0L;
    dmn_nbr_mch=0;
    flg_dpl=False;

    if(cb){
      /* Does variable use time coordinate? */
      for(dmn_idx_var=0;dmn_idx_var<var_trv->nbr_dmn;dmn_idx_var++)
	if(!strcmp(var_trv->var_dmn[dmn_idx_var].dmn_nm,cb->tm_crd_nm)) break;
      if(dmn_idx_var < var_trv->nbr_dmn){
	/* Stamp with appropriate cell_methods temporal attribute */
	att_val=strdup(cll_mth_clm);
	aed.sz=strlen(att_val);
	aed.type=NC_CHAR;
	aed.val.cp=att_val;
	aed.mode=aed_overwrite;
	(void)nco_aed_prc(grp_out_id,var_out_id,aed);
	if(att_val) att_val=(char *)nco_free(att_val);
	continue;
      } /* !dmn_idx_var */
    } /* !cb */

    /* cell_methods format: blank-separated phrases of form "dmn1[, dmn2[...]]: op_typ", e.g., "lat, lon: mean" */ 
    for(dmn_idx_var=0;dmn_idx_var<var_trv->nbr_dmn;dmn_idx_var++){
      for(dmn_idx_rdc=0;dmn_idx_rdc<dmn_nbr_rdc;dmn_idx_rdc++){
        assert(dmn_rdc[dmn_idx_rdc]->nm_fll);
        /* Compare full names */
        if(!strcmp(var_trv->var_dmn[dmn_idx_var].dmn_nm_fll,dmn_rdc[dmn_idx_rdc]->nm_fll)){
          /* Add length of each matching dimension to accumulating attribute size */
          aed.sz+=strlen(dmn_rdc[dmn_idx_rdc]->nm);
          dmn_mch[dmn_nbr_mch++]=dmn_idx_rdc;
        } /* !match */
      } /* dmn_idx_rdc */
    } /* dmn_idx_var */

    assert(dmn_nbr_mch > 0);

    /* Preserve rule to always return averages (never extrema or other statistics) of coordinates */
    if(var[var_idx]->is_crd_var) nco_op_typ_lcl=nco_op_avg; else nco_op_typ_lcl=nco_op_typ;

    /* NUL-terminate before concatenation */
    att_op_sng[0]='\0';
    switch(nco_op_typ_lcl){
      /* Next five operations are defined in CF Conventions */
    case nco_op_avg: strcpy(att_op_sng,"mean"); break;
    case nco_op_min: strcpy(att_op_sng,"minimum"); break;
    case nco_op_max: strcpy(att_op_sng,"maximum"); break;
    case nco_op_ttl: strcpy(att_op_sng,"sum"); break;
    case nco_op_avgsqr: strcpy(att_op_sng,"variance"); break; /* Mean of sum of squares */
      /* Remaining operations are supported by NCO yet are not in CF Conventions */
    case nco_op_mabs: strcpy(att_op_sng,"maximum_absolute_value"); break; /* Maximum absolute value */
    case nco_op_mebs: strcpy(att_op_sng,"mean_absolute_value"); break; /* Mean absolute value */
    case nco_op_mibs: strcpy(att_op_sng,"minimum_absolute_value"); break; /* Minimum absolute value */
    case nco_op_sqravg: strcpy(att_op_sng,"square_of_mean"); break; /* Square of mean */
    case nco_op_sqrt: strcpy(att_op_sng,"square_root_of_mean"); break; /* Square root of mean */ 
    case nco_op_rms: strcpy(att_op_sng,"root_mean_square"); break; /* Root-mean-square (normalized by N) */
    case nco_op_rmssdn: strcpy(att_op_sng,"root_mean_square_nm1"); break; /* Root-mean square normalized by N-1 */
    case nco_op_nil: /* nco_op_nil, Undefined operation type */
      if(nco_dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: DEBUG %s reports variable %s cell_method not implemented for operation %d\n",nco_prg_nm_get(),fnc_nm,var_trv->nm_fll,nco_op_typ);
      continue;
    } /* End switch */

    /* Initialize to size of ": " plus length of operation string */
    aed.sz+=2L+strlen(att_op_sng);
    /* Add room for commas and spaces, i.e., "dmn1, dmn2, dmn3" */
    if(dmn_nbr_mch > 1) aed.sz+=2*(dmn_nbr_mch-1);
    /* Add room for NUL-terminator */
    aed.val.cp=(char *)nco_malloc((aed.sz+1L)*sizeof(char));
    aed.val.cp[0]='\0';

    /* Build single string by concatenating known matches */
    for(int dmn_idx_mch=0;dmn_idx_mch<dmn_nbr_mch;dmn_idx_mch++){
      (void)strcat(aed.val.cp,dmn_rdc[dmn_mch[dmn_idx_mch]]->nm);
      if(dmn_idx_mch<dmn_nbr_mch-1) (void)strcat(aed.val.cp,", ");
    } /* dmn_idx_mch>=dmn_nbr_mch */
    (void)strcat(aed.val.cp,": ");
    (void)strcat(aed.val.cp,att_op_sng);

    /* 20150625: Older versions of CAM, e.g., CAM3, used "cell_method" instead of "cell_methods" 
       If old attribute is not deleted then the output file will contain both attributes
       Does variable already have "cell_method" attribute? */
    strcpy(aed.att_nm,"cell_method");
    rcd=nco_inq_att_flg(grp_out_id,var_out_id,aed.att_nm,&att_typ,&att_lng);
    if(rcd == NC_NOERR){
      if(FIRST_WARNING) (void)fprintf(stderr,"%s: WARNING: Variable \"%s\" uses the non-standard attribute name \"cell_method\" instead of \"cell_methods\", the correct attribute name. The CAM3 model (and others?) have this problem. Expect \"double attributes\" in output. This message is printed only once per invocation, although the problem likely occurs in more variables.\n",nco_prg_nm_get(),aed.var_nm);
      FIRST_WARNING=False;
    } /* endif attribute exists */

    /* Does variable already have "cell_methods" attribute? */
    strcpy(aed.att_nm,"cell_methods");
    rcd=nco_inq_att_flg(grp_out_id,var_out_id,aed.att_nm,&att_typ,&att_lng);
    if(rcd == NC_NOERR){
      if(att_typ == NC_STRING) (void)fprintf(stderr,"%s: WARNING %s reports existing cell_methods attribute for variable %s is type NC_STRING. Unpredictable results...\n",nco_prg_nm_get(),fnc_nm,aed.var_nm);
      if(att_typ != NC_STRING && att_typ != NC_CHAR) (void)fprintf(stderr,"%s: WARNING %s reports existing cell_methods attribute for variable %s is type %s. Unpredictable results...\n",nco_prg_nm_get(),fnc_nm,aed.var_nm,nco_typ_sng(att_typ));

      /* Often climatologies are multiply-averaged over time
	 NCO's treatment of this has changed with time
	 pre-20140131: 
	 NCO has no special treatment of cell_methods
	 20140131: 
	 First NCO implementation (ncra, ncea, ncwa) of cell_methods with 
	 20150625: 
	 For example, climate model output is often archived as monthly means in each gridcell
	 cell_methods attributes of these monthly data begin as "time: mean" (i.e., monthly mean).
	 We then create a climatology by a sequence of one or two more temporal-averaging steps
	 The one-step method puts all the months in the hopper and averages those
	 Variables in the resultiing file may have cell_methods = "time: mean time: mean"
	 The two-step method first averages the months into four climatological seasons
	 Then it averages those four seasons into the climatological annual mean
	 Variables in the resultiing file may have cell_methods = "time: mean time: mean time: mean"
	 To avoid this redundancy, we check that the new cell_method does not duplicate the old 
	 If it would, then skip adding the new
	 20160418: 
	 Treatment of multiply-time-averaged quantities requires climatology bounds attribute
	 One-step methods (e.g., monthly mean) should have time-bounds attribute
	 cell_methods = "time: mean"
	 Two-step methods (e.g., climatological March) should have climatology-bounds attribute
	 cell_methods = "time: mean within years time: mean over years"
	 Three-step methods (e.g., climatological MAM) should have climatology-bounds attribute
	 cell_methods = "time: mean within years time: mean over years"
	 Four-step methods (e.g., climatological ANN) should have time-bounds attribute
	 cell_methods = "time: mean" */
      ptr_unn val_old; /* [sng] Old cell_methods attribute */
      val_old.vp=(void *)nco_malloc((att_lng+1L)*sizeof(char));
      (void)nco_get_att(grp_out_id,var_out_id,aed.att_nm,val_old.vp,NC_CHAR);
      val_old.cp[att_lng]='\0';
      if(strstr(val_old.cp,aed.val.cp)) flg_dpl=True;
      if(val_old.vp) val_old.vp=(void *)nco_free(val_old.vp);
      
      aed.mode=aed_append;
      /* Insert space between existing attribute and appended attribute */
      att_val_cpy=(char *)strdup(aed.val.cp);
      /* Add one for space character */
      aed.sz++;
      /* Add one for NUL-terminator */
      aed.val.cp=(char *)nco_realloc(aed.val.cp,(aed.sz+1L)*sizeof(char));
      aed.val.cp[0]=' ';
      aed.val.cp[1]='\0';
      (void)strncat(aed.val.cp,att_val_cpy,aed.sz-1L);
      if(att_val_cpy) att_val_cpy=(char *)nco_free(att_val_cpy);
    }else{ /* !cell_methods attribute already exists */
      aed.mode=aed_create;
    } /* !cell_methods attribute already exists */

    /* Edit attribute */
    if(!flg_dpl) (void)nco_aed_prc(grp_out_id,var_out_id,aed);

    /* 20150308 */
    /* Does variable already have "coordinates" attribute?
       NB: This reuses att_nm which has only enough space to hold "cell_methods" */
    strcpy(aed.att_nm,"coordinates");
    rcd=nco_inq_att_flg(grp_out_id,var_out_id,aed.att_nm,&att_typ,&att_lng);
    if(rcd == NC_NOERR && att_typ == NC_CHAR){
      /* Remove reduced dimensions from coordinates string
	 coordinates format: blank-separated names of form "dmn1 [dmn2 [...]] dmnN", e.g., "time lat lon" */ 
      /* Add room for NUL-terminator */
      att_val=(char *)nco_malloc((att_lng+1L)*sizeof(char));
      rcd=nco_get_att(grp_out_id,var_out_id,aed.att_nm,att_val,att_typ);
      /* Reset value from previous use */
      aed.val.cp[0]='\0';
      att_val[att_lng]='\0';
      mlt_dmn_rdc=False;
      assert(rcd == NC_NOERR);
      for(dmn_idx_var=0;dmn_idx_var<var_trv->nbr_dmn;dmn_idx_var++){
	for(dmn_idx_rdc=0;dmn_idx_rdc<dmn_nbr_rdc;dmn_idx_rdc++){
	  /* Is reduced dimension in variable? */
	  if(!strcmp(var_trv->var_dmn[dmn_idx_var].dmn_nm_fll,dmn_rdc[dmn_idx_rdc]->nm_fll)){
	    if(mlt_dmn_rdc){
	      /* At least one other dimension has already been reduced/excised
		 Hence multiple dimensions of this variable may be reduced
		 Start next excision from ending point of last excision, not from disk-values */
	      strcpy(att_val,aed.val.cp);
	      att_lng=strlen(aed.val.cp);
	    } /* endif */
	    /* Is dimension in current (possibly locally-modified) "coordinates" attribute? NB: Assume short name not full name */
	    if((sbs_ptr=strstr(att_val,dmn_rdc[dmn_idx_rdc]->nm))){
	      /* Is this the only dimension in "coordinates" attribute? */
	      if(!strcmp(dmn_rdc[dmn_idx_rdc]->nm,att_val)){
		/* Variable will become scalar so delete "coordinates" attribute */
		aed.mode=aed_delete;
	      }else{ /* endif scalar */
		/* Excise dimension from "coordinates" attribute */
		dmn_sng_lng=strlen(dmn_rdc[dmn_idx_rdc]->nm);
		sbs_sng_lng=(size_t)(sbs_ptr-att_val);
		aed.mode=aed_overwrite;
		/* Remove whitespace immediately following excised dimension, i.e., count it as part of dimension string
		   True for all dimensions except final dimension (trailed by a NUL, not a space) */
		if(sbs_ptr[dmn_sng_lng] == ' ') dmn_sng_lng++;
		aed.sz=att_lng-dmn_sng_lng;
		/* Add one for NUL-terminator */
		aed.val.cp=(char *)nco_realloc(aed.val.cp,(aed.sz+1L)*sizeof(char));
		strncpy(aed.val.cp,att_val,sbs_sng_lng);
		aed.val.cp[sbs_sng_lng]='\0';
		strcat(aed.val.cp,sbs_ptr+dmn_sng_lng);
	      } /* endelse scalar */
	      /* Edit attribute */
	      (void)nco_aed_prc(grp_out_id,var_out_id,aed);
	      mlt_dmn_rdc=True;
	    } /* !match attribute */
	  } /* !match variable */
	} /* dmn_idx_rdc */
      } /* dmn_idx_var */
    } /* endif attribute exists */

    if(att_val) att_val=(char *)nco_free(att_val);
    if(aed.val.cp) aed.val.cp=(char *)nco_free(aed.val.cp);

  } /* var_idx >= var_nbr */

  if(aed.att_nm) aed.att_nm=(char *)nco_free(aed.att_nm);
  if(dmn_mch) dmn_mch=(int *)nco_free(dmn_mch);

  return NC_NOERR;

} /* end nco_cnv_cf_cll_mth_add() */
示例#2
0
nm_id_sct * /* O [sct] Extraction list */
nco_cnv_cf_crd_add /* [fnc] Add coordinates defined by CF convention */
(const int nc_id, /* I netCDF file ID */
 nm_id_sct *xtr_lst, /* I/O current extraction list (destroyed) */
 int * const xtr_nbr) /* I/O number of variables in current extraction list */
{
  /* Purpose: Detect coordinates specified by CF convention and add them to extraction list
     http://www.cgd.ucar.edu/cms/eaton/cf-metadata/CF-1.0.html#grid_ex2 */

  const char dlm_sng[]=" "; /* [sng] Delimiter string */
  const char fnc_nm[]="nco_cnv_cf_crd_add()"; /* [sng] Function name */

  char **crd_lst; /* [sng] 1D array of list elements */
  char *att_val;
  char att_nm[NC_MAX_NAME];

  int crd_id;
  int idx_att;
  int idx_crd;
  int idx_var;
  int idx_var2;
  int nbr_att;
  int nbr_crd; /* [nbr] Number of coordinates specified in "coordinates" attribute */
  int rcd=NC_NOERR; /* [rcd] Return code */
  int var_id;

  long att_sz;

  nc_type att_typ;
  
  /* ...for each variable in extraction list... */
  for(idx_var=0;idx_var<*xtr_nbr;idx_var++){
    /* Eschew indirection */
    var_id=xtr_lst[idx_var].id;
    /* Find number of attributes */
    (void)nco_inq_varnatts(nc_id,var_id,&nbr_att);
    for(idx_att=0;idx_att<nbr_att;idx_att++){
      (void)nco_inq_attname(nc_id,var_id,idx_att,att_nm);
      /* Is attribute part of CF convention? */
      if(!strcmp(att_nm,"coordinates")){
	/* Yes, get list of specified attributes */
	(void)nco_inq_att(nc_id,var_id,att_nm,&att_typ,&att_sz);
	if(att_typ != NC_CHAR){
	  (void)fprintf(stderr,"%s: WARNING the \"%s\" attribute for variable %s is type %s, not %s. This violates the CF convention for specifying additional attributes. Therefore %s will skip this attribute.\n",nco_prg_nm_get(),att_nm,xtr_lst[idx_var].nm,nco_typ_sng(att_typ),nco_typ_sng(NC_CHAR),fnc_nm);
	  return xtr_lst;
	} /* end if */
	att_val=(char *)nco_malloc((att_sz+1L)*sizeof(char));
	if(att_sz > 0) (void)nco_get_att(nc_id,var_id,att_nm,(void *)att_val,NC_CHAR);	  
	/* NUL-terminate attribute */
	att_val[att_sz]='\0';
	/* Split list into separate coordinate names */
        /* using nco_lst_prs_sgl_2D() and not nco_lst_prs_2D */
        /* see TODO 944   */
        crd_lst=nco_lst_prs_sgl_2D(att_val,dlm_sng,&nbr_crd);
	/* ...for each coordinate in "coordinates" attribute... */
	for(idx_crd=0;idx_crd<nbr_crd;idx_crd++){
	  /* Verify "coordinate" exists in input file */
	  rcd=nco_inq_varid_flg(nc_id,crd_lst[idx_crd],&crd_id);
	  /* NB: Do not check that dimension by this name exists
	     CF files often use "coordinates" convention to identify
	     two-dimensional (or greater) variables which serve as coordinates.
	     In other words, we want to allow N-D variables to work as coordinates
	     for the purpose of adding them to the extraction list only. */
	  if(rcd == NC_NOERR){
	    /* idx_var2 labels inner loop over variables */
	    /* Is "coordinate" already on extraction list? */
	    for(idx_var2=0;idx_var2<*xtr_nbr;idx_var2++){
	      if(crd_id == xtr_lst[idx_var2].id) break;
	    } /* end loop over idx_var2 */
	    if(idx_var2 == *xtr_nbr){
	      /* Add coordinate to list */
	      xtr_lst=(nm_id_sct *)nco_realloc((void *)xtr_lst,(*xtr_nbr+1)*sizeof(nm_id_sct));
	      xtr_lst[*xtr_nbr].nm=(char *)strdup(crd_lst[idx_crd]);
	      xtr_lst[*xtr_nbr].id=crd_id;
	      (*xtr_nbr)++; /* NB: Changes size of current loop! */
	      /* Continue to next coordinate in loop */
	      continue;
	    } /* end if coordinate was not already in list */
	  } /* end if named coordinate exists in input file */
	} /* end loop over idx_crd */
	  /* Free allocated memory */
	att_val=(char *)nco_free(att_val);
	crd_lst=nco_sng_lst_free(crd_lst,nbr_crd);
      } /* !coordinates */
    } /* end loop over attributes */
  } /* end loop over idx_var */
  
  return xtr_lst;
  
} /* end nco_cnv_cf_crd_add() */
示例#3
0
aed_sct * /* O [sct] List of attribute edit structures */
nco_prs_aed_lst /* [fnc] Parse user-specified attribute edits into structure list */
(const int nbr_aed, /* I [nbr] Number of attributes in list */
 X_CST_PTR_CST_PTR_Y(char,aed_arg)) /* I/O [sng] List of user-specified attribute edits (delimiters are changed to NULL on output */
{
  /* Purpose: Parse name, type, size, and value elements of comma-separated list of attribute edit information
     Routine merely evaluates syntax of input expressions
     Routine does not validate attributes or variables against those present in input netCDF file */

  /* Options are:
     -a att_nm,var_nm,mode,att_typ,att_val (modifies attribute att_nm for the single variable var_nm)

     -a att_nm,,mode,att_typ,att_val (modifies attribute att_nm for every variable in file)
     If option -a is given with var_nm = NULL, then var_nm is expanded into every variable name in file
     Thus attribute editing operation is performed on every variable in file.

     mode,att_nm,att_typ,att_val (modifies global attribute att_nm for file)
     This option may be combined with modes -a, -c, -d, or -o to specify 
     appending to, changing, deleting, or overwriting, any existing global attribute named att_nm

     One mode must be set for each edited attribute: append (a), create (c), delete (d), modify (m), or overwrite (o).
     -a: Attribute append mode
     Append value att_val to current var_nm attribute att_nm value att_val, if any. 
     If var_nm does not have an attribute att_nm, there is not effect.

     -c: Attribute create mode
     Create variable var_nm attribute att_nm with att_val if att_nm does not yet exist. 
     If var_nm already has an attribute att_nm, there is not effect.

     -d: Attribute delete mode
     Delete current var_nm attribute att_nm.
     If var_nm does not have an attribute att_nm, there is not effect.

     -m: Attribute modify mode
     Change value of current var_nm attribute att_nm to value att_val.
     If var_nm does not have an attribute att_nm, there is not effect.

     -o: Attribute overwrite mode
     Write attribute att_nm with value att_val to variable var_nm, overwriting existing attribute att_nm, if any.
     This is default mode.
   */

  char **arg_lst;

  const char * const dlm_sng=",";

  const long idx_att_val_arg=4L; /* Number of required delimiters preceding attribute values in -a argument list */

  aed_sct *aed_lst;

  int idx;
  int arg_nbr;

  aed_lst=(aed_sct *)nco_malloc(nbr_aed*sizeof(aed_sct));

  for(idx=0;idx<nbr_aed;idx++){

    /* Process attribute edit specifications as normal text list */
    arg_lst=nco_lst_prs_2D(aed_arg[idx],dlm_sng,&arg_nbr);

    /* Check syntax */
    if(
       arg_nbr < 5 || /* Need more info */
       /* arg_lst[0] == NULL || */ /* att_nm not specified */
       arg_lst[2] == NULL || /* mode not specified */
       (*(arg_lst[2]) != 'd' && (arg_lst[3] == NULL || (arg_lst[idx_att_val_arg] == NULL && *(arg_lst[3]) != 'c'))) || /* att_typ and att_val must be specified when mode is not delete, except that att_val = "" is valid for character type */
       False){
      (void)fprintf(stdout,"%s: ERROR in attribute edit specification %s\n",prg_nm_get(),aed_arg[idx]);
      nco_exit(EXIT_FAILURE);
    } /* end if */

    /* Initialize structure */
    /* aed strings not explicitly set by user remain NULL,
       i.e., specifying default setting appears as if nothing was set.
       Hopefully, in routines that follow, the branch followed by an aed for which
       all default settings were specified (e.g.,"-a foo,,,,") will yield same result
       as branch for which all defaults were set. */
    aed_lst[idx].att_nm=NULL;
    aed_lst[idx].var_nm=NULL;
    aed_lst[idx].val.vp=NULL;
    aed_lst[idx].type=NC_CHAR;
    aed_lst[idx].mode=aed_overwrite;
    aed_lst[idx].sz=-1L;
    aed_lst[idx].id=-1;

    /* Fill in structure */
    if(arg_lst[0]) aed_lst[idx].att_nm=strdup(arg_lst[0]);
    if(arg_lst[1]) aed_lst[idx].var_nm=strdup(arg_lst[1]);

    /* fxm: Change these switches to string comparisons someday */
    /* Set mode of current aed structure */
    /* Convert single letter code to mode enum */
    /*    if(!strcmp("append",arg_lst[2])){aed_lst[idx].mode=aed_append;
    }else if(!strcmp("create",arg_lst[2])){aed_lst[idx].mode=aed_create;
    }else if(!strcmp("delete",arg_lst[2])){aed_lst[idx].mode=aed_delete;
    }else if(!strcmp("modify",arg_lst[2])){aed_lst[idx].mode=aed_modify;
    }else if(!strcmp("overwrite",arg_lst[2])){aed_lst[idx].mode=aed_overwrite;} */
    switch(*(arg_lst[2])){
    case 'a': aed_lst[idx].mode=aed_append; break;
    case 'c': aed_lst[idx].mode=aed_create; break;
    case 'd': aed_lst[idx].mode=aed_delete; break;
    case 'm': aed_lst[idx].mode=aed_modify; break;
    case 'o': aed_lst[idx].mode=aed_overwrite; break;
    default: 
      (void)fprintf(stderr,"%s: ERROR `%s' is not a supported mode\n",prg_nm_get(),arg_lst[2]);
      (void)fprintf(stderr,"%s: HINT: Valid modes are `a' = append, `c' = create,`d' = delete, `m' = modify, and `o' = overwrite",prg_nm_get());
      nco_exit(EXIT_FAILURE);
      break;
    } /* end switch */

    /* Attribute type and value do not matter if we are deleting it */
    if(aed_lst[idx].mode != aed_delete){

      /* Set type of current aed structure */
      /* Convert single letter code to type enum */
      switch(*(arg_lst[3])){
      case 'f':	aed_lst[idx].type=(nc_type)NC_FLOAT; break;
      case 'd':	aed_lst[idx].type=(nc_type)NC_DOUBLE; break;
      case 'l':	
      case 'i':	aed_lst[idx].type=(nc_type)NC_INT; break;
      case 's':	aed_lst[idx].type=(nc_type)NC_SHORT; break;
      case 'c':	aed_lst[idx].type=(nc_type)NC_CHAR; break;
      case 'b':	aed_lst[idx].type=(nc_type)NC_BYTE; break;
      default: 
	if(!strcasecmp(arg_lst[3],"ub")) aed_lst[idx].type=(nc_type)NC_UBYTE; 
	else if(!strcasecmp(arg_lst[3],"us")) aed_lst[idx].type=(nc_type)NC_USHORT; 
	else if(!strcasecmp(arg_lst[3],"u") || !strcasecmp(arg_lst[3],"ui") || !strcasecmp(arg_lst[3],"ul")) aed_lst[idx].type=(nc_type)NC_UINT; 
	else if(!strcasecmp(arg_lst[3],"ll") || !strcasecmp(arg_lst[3],"int64")) aed_lst[idx].type=(nc_type)NC_INT64; 
	else if(!strcasecmp(arg_lst[3],"ull") || !strcasecmp(arg_lst[3],"uint64")) aed_lst[idx].type=(nc_type)NC_UINT64; 
	else if(!strcasecmp(arg_lst[3],"sng")) aed_lst[idx].type=(nc_type)NC_STRING; 
	else{
	  (void)fprintf(stderr,"%s: ERROR `%s' is not a supported netCDF data type\n",prg_nm_get(),arg_lst[3]);
	  (void)fprintf(stderr,"%s: HINT: Valid data types are `c' = char, `f' = float, `d' = double,`s' = short, 'l' = `i' = integer, `b' = byte",prg_nm_get());
	  nco_exit(EXIT_FAILURE);} /*  end if error */
      break;
      } /* end switch */
      
      /* Re-assemble string list values which inadvertently contain delimiters */
      if(aed_lst[idx].type == NC_CHAR && arg_nbr > idx_att_val_arg+1){
	/* Number of elements which must be concatenated into single string value */
	long lmn_nbr;
	lmn_nbr=arg_nbr-idx_att_val_arg; 
	if(dbg_lvl_get() >= nco_dbg_var) (void)fprintf(stdout,"%s: WARNING NC_CHAR (string) attribute is embedded with %li literal element delimiters (\"%s\"), re-assembling...\n",prg_nm_get(),lmn_nbr-1L,dlm_sng);
	/* Rewrite list, splicing in original delimiter string */
	/* fxm: TODO nco527 ncatted memory may be lost here */
	arg_lst[idx_att_val_arg]=sng_lst_cat(arg_lst+idx_att_val_arg,lmn_nbr,dlm_sng);
	/* Keep bookkeeping straight, just in case */
	arg_nbr=idx_att_val_arg+1L;
	lmn_nbr=1L;
      } /* endif arg_nbr > idx_att_val_arg+1 */
      
      /* Replace any C language '\X' escape codes with ASCII bytes */
      if(aed_lst[idx].type == NC_CHAR) (void)sng_ascii_trn(arg_lst[idx_att_val_arg]);

      /* Set size of current aed structure */
      if(aed_lst[idx].type == NC_CHAR){
	/* 20100409 Remove extra space formerly allocated for NUL-terminator 
	   This caused each append to insert a NUL at end of NC_CHAR attributes
	   Multiple appends would then result in attributes pockmarked with NULs
	   Solves TODO nco985
	   Not yet sure there are no ill side-effects though... */ 
	aed_lst[idx].sz=(arg_lst[idx_att_val_arg] == NULL) ? 0L : strlen(arg_lst[idx_att_val_arg]);
      }else{
	/* Number of elements of numeric types is determined by number of delimiters */
	aed_lst[idx].sz=arg_nbr-idx_att_val_arg;
      } /* end else */
      
      /* Set value of current aed structure */
      if(aed_lst[idx].type == NC_CHAR){
	aed_lst[idx].val.cp=(nco_char *)strdup(arg_lst[idx_att_val_arg]);
      }else{
	double *val_arg_dbl=NULL_CEWI;
	long long *val_arg_lng_lng=NULL_CEWI;
	unsigned long long *val_arg_ulng_lng=NULL_CEWI;
	
	long lmn;
	
	aed_lst[idx].val.vp=(void *)nco_malloc(aed_lst[idx].sz*nco_typ_lng(aed_lst[idx].type));
	
	/* Use type-appropriate conversion */
	switch(aed_lst[idx].type){
	case NC_FLOAT: 
	case NC_DOUBLE: 
	  val_arg_dbl=(double *)nco_malloc(aed_lst[idx].sz*sizeof(double));
	  for(lmn=0L;lmn<aed_lst[idx].sz;lmn++){val_arg_dbl[lmn]=strtod(arg_lst[idx_att_val_arg+lmn],(char **)NULL);} break; 
	case NC_BYTE:
	case NC_INT: 
	case NC_SHORT: 
	case NC_INT64: 
	  val_arg_lng_lng=(long long *)nco_malloc(aed_lst[idx].sz*sizeof(long long));
	  for(lmn=0L;lmn<aed_lst[idx].sz;lmn++){val_arg_lng_lng[lmn]=strtoll(arg_lst[idx_att_val_arg+lmn],(char **)NULL,10);} break;
	case NC_CHAR:
	case NC_UBYTE: 
	case NC_USHORT: 
	case NC_UINT: 
	case NC_UINT64: 
	  val_arg_ulng_lng=(unsigned long long *)nco_malloc(aed_lst[idx].sz*sizeof(unsigned long long));
	  for(lmn=0L;lmn<aed_lst[idx].sz;lmn++){val_arg_ulng_lng[lmn]=strtoull(arg_lst[idx_att_val_arg+lmn],(char **)NULL,10);} break;
	case NC_STRING: break;
	default: nco_dfl_case_nc_type_err(); break;
	} /* end switch */
	
	/* Copy and typecast entire array of values, using implicit coercion rules of C */
	/* 20011001: Use explicit coercion rules to quiet C++ compiler warnings */
	switch(aed_lst[idx].type){
	case NC_FLOAT: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.fp[lmn]=(float)val_arg_dbl[lmn];} break; 
	case NC_DOUBLE: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.dp[lmn]=(double)val_arg_dbl[lmn];} break; 
	case NC_INT: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.ip[lmn]=(nco_int)val_arg_lng_lng[lmn];} break; 
	case NC_SHORT: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.sp[lmn]=(nco_short)val_arg_lng_lng[lmn];} break; 
	case NC_CHAR: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.cp[lmn]=(nco_char)val_arg_ulng_lng[lmn];} break; 
	case NC_BYTE: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.bp[lmn]=(nco_byte)val_arg_lng_lng[lmn];} break; 
	case NC_UBYTE: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.ubp[lmn]=(nco_ubyte)val_arg_ulng_lng[lmn];} break; 
	case NC_USHORT: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.usp[lmn]=(nco_ushort)val_arg_ulng_lng[lmn];} break; 
	case NC_UINT: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.uip[lmn]=(nco_uint)val_arg_ulng_lng[lmn];} break; 
	case NC_INT64: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.i64p[lmn]=(nco_int64)val_arg_lng_lng[lmn];} break; 
	case NC_UINT64: for(lmn=0L;lmn<aed_lst[idx].sz;lmn++) {aed_lst[idx].val.ui64p[lmn]=(nco_uint64)val_arg_ulng_lng[lmn];} break; 
	case NC_STRING: break;
	default: nco_dfl_case_nc_type_err(); break;
	} /* end switch */
	
	/* Free array used to hold input values */
	if(val_arg_dbl) val_arg_dbl=(double *)nco_free(val_arg_dbl);
	if(val_arg_lng_lng) val_arg_lng_lng=(long long *)nco_free(val_arg_lng_lng);
	if(val_arg_ulng_lng) val_arg_ulng_lng=(unsigned long long *)nco_free(val_arg_ulng_lng);
      } /* end else */
      /* Un-typecast pointer to values after access */
      (void)cast_nctype_void(aed_lst[idx].type,&aed_lst[idx].val);
      
    } /* end if mode is not delete */

    arg_lst=nco_sng_lst_free(arg_lst,arg_nbr);

  } /* end loop over aed */
  
  if(dbg_lvl_get() >= nco_dbg_io){
    for(idx=0;idx<nbr_aed;idx++){
      (void)fprintf(stderr,"aed_lst[%d].att_nm = %s\n",idx,aed_lst[idx].att_nm);
      (void)fprintf(stderr,"aed_lst[%d].var_nm = %s\n",idx,aed_lst[idx].var_nm == NULL ? "NULL" : aed_lst[idx].var_nm);
      (void)fprintf(stderr,"aed_lst[%d].id = %i\n",idx,aed_lst[idx].id);
      (void)fprintf(stderr,"aed_lst[%d].sz = %li\n",idx,aed_lst[idx].sz);
      (void)fprintf(stderr,"aed_lst[%d].type = %s\n",idx,nco_typ_sng(aed_lst[idx].type));
      /*      (void)fprintf(stderr,"aed_lst[%d].val = %s\n",idx,aed_lst[idx].val);*/
      (void)fprintf(stderr,"aed_lst[%d].mode = %i\n",idx,aed_lst[idx].mode);
    } /* end loop over idx */
  } /* end debug */
  
  return aed_lst;
  
} /* end nco_prs_aed_lst() */
示例#4
0
void 
nco_hst_att_cat /* [fnc] Add command line, date stamp to history attribute */
(const int out_id, /* I [id] netCDF output-file ID */
 const char * const hst_sng) /* I [sng] String to add to history attribute */
{
  /* Purpose: Add command line and date stamp to existing history attribute, if any,
     and write them to specified output file */
  
  /* Length of string + NUL required to hold output of ctime() */
#define TIME_STAMP_SNG_LNG 25 
  
  char att_nm[NC_MAX_NAME];
  char *ctime_sng;
  char *history_crr=NULL;
  char *history_new;
  char time_stamp_sng[TIME_STAMP_SNG_LNG];
  
  const char sng_history[]="history"; /* [sng] Possible name of history attribute */
  
  int idx;
  int glb_att_nbr;

  long att_sz=0;

  nc_type att_typ;
  
  time_t time_crr_time_t;

  /* Create timestamp string */
  time_crr_time_t=time((time_t *)NULL);
  ctime_sng=ctime(&time_crr_time_t);
  /* NUL-terminate time_stamp_sng */
  time_stamp_sng[TIME_STAMP_SNG_LNG-1]='\0';
  /* Get rid of carriage return in ctime_sng */
  (void)strncpy(time_stamp_sng,ctime_sng,TIME_STAMP_SNG_LNG-1);

  /* Get number of global attributes in file */
  (void)nco_inq(out_id,(int *)NULL,(int *)NULL,&glb_att_nbr,(int *)NULL);

  for(idx=0;idx<glb_att_nbr;idx++){
    (void)nco_inq_attname(out_id,NC_GLOBAL,idx,att_nm);
    if(!strcasecmp(att_nm,sng_history)) break;
  } /* end loop over att */

  /* Fill in history string */
  if(idx == glb_att_nbr){
    /* Global attribute "[hH]istory" does not yet exist */

    /* Add 3 for formatting characters */
    history_new=(char *)nco_malloc((strlen(hst_sng)+strlen(time_stamp_sng)+3)*sizeof(char));
    (void)sprintf(history_new,"%s: %s",time_stamp_sng,hst_sng);
    /* Set attribute name to default */
    (void)strcpy(att_nm,sng_history);

  }else{ 
    /* Global attribute "[hH]istory" currently exists */
  
    /* NB: ncattinq(), unlike strlen(), counts terminating NUL for stored NC_CHAR arrays */
    (void)nco_inq_att(out_id,NC_GLOBAL,att_nm,&att_typ,&att_sz);
    if(att_typ != NC_CHAR){
      if(dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: WARNING the \"%s\" global attribute is type %s, not %s. Therefore current command line will not be appended to %s in output file.\n",prg_nm_get(),att_nm,nco_typ_sng(att_typ),nco_typ_sng(NC_CHAR),att_nm);
      return;
    } /* end if */

    /* Allocate and NUL-terminate space for current history attribute
       If history attribute is of size zero then ensure strlen(history_crr) = 0 */
    history_crr=(char *)nco_malloc((att_sz+1)*sizeof(char));
    history_crr[att_sz]='\0';
    if(att_sz > 0) (void)nco_get_att(out_id,NC_GLOBAL,att_nm,(void *)history_crr,NC_CHAR);

    /* Add 4 for formatting characters */
    history_new=(char *)nco_malloc((strlen(history_crr)+strlen(hst_sng)+strlen(time_stamp_sng)+4)*sizeof(char));
    (void)sprintf(history_new,"%s: %s\n%s",time_stamp_sng,hst_sng,history_crr);
  } /* endif history global attribute currently exists */

  (void)nco_put_att(out_id,NC_GLOBAL,att_nm,NC_CHAR,(long)(strlen(history_new)+1UL),(void *)history_new);

  history_crr=(char *)nco_free(history_crr);
  history_new=(char *)nco_free(history_new);

  return; /* 20050109: fxm added return to void function to squelch erroneous gcc-3.4.2 warning */ 
} /* end nco_hst_att_cat() */
示例#5
0
void
nco_aed_prc /* [fnc] Process single attribute edit for single variable */
(const int nc_id, /* I [id] Input netCDF file ID */
 const int var_id, /* I [id] ID of variable on which to perform attribute editing */
 const aed_sct aed) /* I [sct] Structure containing information necessary to edit */
{
  /* Purpose: Process single attribute edit for single variable */
  
  /* If var_id == NC_GLOBAL ( = -1) then global attribute will be edited */

#ifdef NCO_NETCDF4_AND_FILLVALUE
  char att_nm_tmp[]="eulaVlliF_"; /* String of same length as "_FillValue" for name hack with netCDF4 */
  nco_bool flg_netCDF4=False; /* [flg] File format is netCDF4 */
#endif /* !NCO_NETCDF4_AND_FILLVALUE */

  char att_nm[NC_MAX_NAME];
  char var_nm[NC_MAX_NAME];
  
  /* NB: netCDF2 specifies att_sz is type int, netCDF3 and netCDF4 use size_t */
  int nbr_att; /* [nbr] Number of attributes */
  int rcd=NC_NOERR; /* [rcd] Return code */
  long att_sz;
     
  nc_type att_typ;
  
  void *att_val_new=NULL;

  if(var_id == NC_GLOBAL){
    /* Get number of global attributes in file */
    (void)nco_inq(nc_id,(int *)NULL,(int *)NULL,&nbr_att,(int *)NULL);
    (void)strcpy(var_nm,"Global");
  }else{
    /* Get name and number of attributes for variable */
    (void)nco_inq_var(nc_id,var_id,var_nm,(nc_type *)NULL,(int *)NULL,(int *)NULL,&nbr_att);
  } /* end else */

  /* Query attribute metadata when attribute name was specified */
  if(aed.att_nm) rcd=nco_inq_att_flg(nc_id,var_id,aed.att_nm,&att_typ,&att_sz);

  /* Before changing metadata, change missing values to new missing value if warranted 
     This capability is add-on feature not implemented too cleanly or efficiently
     If every variable has "_FillValue" attribute and "_FillValue" is changed
     globally, then algorithm goes into and out of define mode for each variable,
     rather than collecting all information in first pass and replacing all data in second pass.
     This is because ncatted was originally designed to change only metadata and so was
     architected differently from other NCO operators. */
  if(
     aed.att_nm /* Linux strcmp() dumps core if attribute name is blank */
     && strcmp(aed.att_nm,nco_mss_val_sng_get()) == 0 /* Current attribute is "_FillValue" */
     && var_id != NC_GLOBAL /* Current attribute is not global */
     && (aed.mode == aed_modify || aed.mode == aed_overwrite)  /* Modifying or overwriting existing value */
     && rcd == NC_NOERR /* Only when existing _FillValue attribute is modified */
     && att_sz == 1L /* Old _FillValue attribute must be of size 1 */
     && aed.sz == 1L /* New _FillValue attribute must be of size 1 */
     ){

    int *dmn_id;
    long *dmn_sz;
    long *dmn_srt;
    long idx;
    long var_sz=long_CEWI;
    ptr_unn mss_val_crr;
    ptr_unn mss_val_new;
    ptr_unn var_val;
    var_sct *var=NULL_CEWI;

    if(dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stdout,"%s: INFO Replacing missing value data in variable %s\n",prg_nm_get(),var_nm);

    /* Take file out of define mode */
    (void)nco_enddef(nc_id);
  
    /* Initialize (partially) variable structure */
    var=(var_sct *)nco_malloc(sizeof(var_sct));
    var->nc_id=nc_id;
    var->id=var_id;
    var->sz=1L;

    /* Get type of variable and number of dimensions */
    (void)nco_inq_var(nc_id,var_id,(char *)NULL,&var->type,&var->nbr_dim,(int *)NULL,(int *)NULL);
    dmn_id=(int *)nco_malloc(var->nbr_dim*sizeof(int));
    dmn_sz=(long *)nco_malloc(var->nbr_dim*sizeof(long));
    dmn_srt=(long *)nco_malloc(var->nbr_dim*sizeof(long));
    (void)nco_inq_vardimid(nc_id,var_id,dmn_id);

    /* Get dimension sizes and construct variable size */
    for(idx=0;idx<var->nbr_dim;idx++){
      (void)nco_inq_dimlen(nc_id,dmn_id[idx],dmn_sz+idx);
      var->sz*=dmn_sz[idx];
      dmn_srt[idx]=0L;
    } /* end loop over dim */
    var->dmn_id=dmn_id;
    var->cnt=dmn_sz;
    var->srt=dmn_srt;
      
    /* Place nco_var_get() code inline since var struct is not truly complete */
    if((var->val.vp=(void *)nco_malloc_flg(var->sz*nco_typ_lng(var->type))) == NULL){
      (void)fprintf(stdout,"%s: ERROR Unable to malloc() %ld*%lu bytes in nco_aed_prc()\n",prg_nm_get(),var->sz,(unsigned long)nco_typ_lng(var->type));
      nco_exit(EXIT_FAILURE); 
    } /* end if */
    if(var->sz > 1L){
      (void)nco_get_vara(nc_id,var_id,var->srt,var->cnt,var->val.vp,var->type);
    }else{
      (void)nco_get_var1(nc_id,var_id,var->srt,var->val.vp,var->type);
    } /* end else */
    
    /* Get current missing value attribute */
    var->mss_val.vp=NULL;
    var->has_mss_val=nco_mss_val_get(nc_id,var);

    /* Sanity check */
    if(var->has_mss_val == False){
      (void)fprintf(stdout,"%s: ERROR variable %s does not have \"%s\" attribute in nco_aed_prc()\n",prg_nm_get(),var_nm,nco_mss_val_sng_get());
      nco_exit(EXIT_FAILURE);
    } /* end if */

    /* Shortcuts to avoid indirection */
    var_val=var->val;
    var_sz=var->sz;

    /* Get new and old missing values in same type as variable */
    mss_val_crr.vp=(void *)nco_malloc(att_sz*nco_typ_lng(var->type));
    mss_val_new.vp=(void *)nco_malloc(aed.sz*nco_typ_lng(var->type));

    (void)nco_val_cnf_typ(var->type,var->mss_val,var->type,mss_val_crr); 
    (void)nco_val_cnf_typ(aed.type,aed.val,var->type,mss_val_new);

    /* Typecast pointer to values before access */
    (void)cast_void_nctype(var->type,&var_val);
    (void)cast_void_nctype(var->type,&mss_val_crr);
    (void)cast_void_nctype(var->type,&mss_val_new);
  
    switch(var->type){
    case NC_FLOAT: for(idx=0L;idx<var_sz;idx++) {if(var_val.fp[idx] == *mss_val_crr.fp) var_val.fp[idx]=*mss_val_new.fp;} break;
    case NC_DOUBLE: for(idx=0L;idx<var_sz;idx++) {if(var_val.dp[idx] == *mss_val_crr.dp) var_val.dp[idx]=*mss_val_new.dp;} break;
    case NC_INT: for(idx=0L;idx<var_sz;idx++) {if(var_val.ip[idx] == *mss_val_crr.ip) var_val.ip[idx]=*mss_val_new.ip;} break;
    case NC_SHORT: for(idx=0L;idx<var_sz;idx++) {if(var_val.sp[idx] == *mss_val_crr.sp) var_val.sp[idx]=*mss_val_new.sp;} break;
    case NC_CHAR: for(idx=0L;idx<var_sz;idx++) {if(var_val.cp[idx] == *mss_val_crr.cp) var_val.cp[idx]=*mss_val_new.cp;} break;
    case NC_BYTE: for(idx=0L;idx<var_sz;idx++) {if(var_val.bp[idx] == *mss_val_crr.bp) var_val.bp[idx]=*mss_val_new.bp;} break;
    case NC_UBYTE: for(idx=0L;idx<var_sz;idx++) {if(var_val.ubp[idx] == *mss_val_crr.ubp) var_val.ubp[idx]=*mss_val_new.ubp;} break;
    case NC_USHORT: for(idx=0L;idx<var_sz;idx++) {if(var_val.usp[idx] == *mss_val_crr.usp) var_val.usp[idx]=*mss_val_new.usp;} break;
    case NC_UINT: for(idx=0L;idx<var_sz;idx++) {if(var_val.uip[idx] == *mss_val_crr.uip) var_val.uip[idx]=*mss_val_new.uip;} break;
    case NC_INT64: for(idx=0L;idx<var_sz;idx++) {if(var_val.i64p[idx] == *mss_val_crr.i64p) var_val.i64p[idx]=*mss_val_new.i64p;} break;
    case NC_UINT64: for(idx=0L;idx<var_sz;idx++) {if(var_val.ui64p[idx] == *mss_val_crr.ui64p) var_val.ui64p[idx]=*mss_val_new.ui64p;} break;
    case NC_STRING: for(idx=0L;idx<var_sz;idx++) {if(var_val.sngp[idx] == *mss_val_crr.sngp) var_val.sngp[idx]=*mss_val_new.sngp;} break;
    default: nco_dfl_case_nc_type_err(); break;
    } /* end switch */

    /* Un-typecast the pointer to values after access */
    (void)cast_nctype_void(var->type,&var_val);
    (void)cast_nctype_void(var->type,&mss_val_crr);
    (void)cast_nctype_void(var->type,&mss_val_new);

    /* Write to disk */
    if(var->nbr_dim == 0){
      (void)nco_put_var1(nc_id,var_id,var->srt,var->val.vp,var->type);
    }else{ /* end if variable is scalar */
      (void)nco_put_vara(nc_id,var_id,var->srt,var->cnt,var->val.vp,var->type);
    } /* end else */

    /* Free memory */
    mss_val_crr.vp=nco_free(mss_val_crr.vp);
    mss_val_new.vp=nco_free(mss_val_new.vp);
    var->mss_val.vp=nco_free(var->mss_val.vp);
    var->val.vp=nco_free(var->val.vp);
    var->dmn_id=(int *)nco_free(var->dmn_id);
    var->srt=(long *)nco_free(var->srt);
    var->cnt=(long *)nco_free(var->cnt);
    /* 20050704 try and use nco_free() to avoid valgrind error message */
    var=(var_sct *)nco_free(var);

    /* Put file back in define mode */
    (void)nco_redef(nc_id);
  } /* end if replacing missing value data */

  /* Change metadata (as written, this must be done after _FillValue data is replaced) */

#ifdef NCO_NETCDF4_AND_FILLVALUE
  /* Bold hack which gets around problem of modifying netCDF4 "_FillValue" attributes
     netCDF4 does not allow this by default, though netCDF3 does
     Change attribute name to att_nm_tmp, modify value, then restore name */

  /* Check if file is netCDF3 classic with netCDF4 library
     If so, do not kludge. NB: create global variable for output file format? */
  { /* scope for fl_fmt temporary */
    int fl_fmt; 
    (void)nco_inq_format(nc_id,&fl_fmt);
    flg_netCDF4=(fl_fmt==NC_FORMAT_NETCDF4 || fl_fmt==NC_FORMAT_NETCDF4_CLASSIC);
  } /* end scope */

  if(flg_netCDF4 && !strcmp(aed.att_nm,nco_mss_val_sng_get()) && aed.mode != aed_delete){
    if(aed.mode != aed_create) (void)nco_rename_att(nc_id,var_id,aed.att_nm,att_nm_tmp);
    strcpy(aed.att_nm,att_nm_tmp); 
  } /* endif libnetCDF may have netCDF4 restrictions */
#endif /* !NCO_NETCDF4_AND_FILLVALUE */

  switch(aed.mode){
  case aed_append:	
    if(rcd == NC_NOERR){
      /* Append to existing attribute value */
      if(aed.type != att_typ){
	(void)fprintf(stdout,"%s: ERROR %s attribute %s is of type %s not %s, unable to append\n",prg_nm_get(),var_nm,aed.att_nm,nco_typ_sng(att_typ),nco_typ_sng(aed.type));
	nco_exit(EXIT_FAILURE);
      } /* end if */
      att_val_new=(void *)nco_malloc((att_sz+aed.sz)*nco_typ_lng(aed.type));
      (void)nco_get_att(nc_id,var_id,aed.att_nm,(void *)att_val_new,aed.type);
      /* NB: Following assumes sizeof(char) = 1 byte */
      (void)memcpy((void *)((char *)att_val_new+att_sz*nco_typ_lng(aed.type)),
		   (void *)aed.val.vp,
		   aed.sz*nco_typ_lng(aed.type));
      (void)nco_put_att(nc_id,var_id,aed.att_nm,aed.type,att_sz+aed.sz,att_val_new);
      att_val_new=nco_free(att_val_new);
    }else{
      /* Create new attribute */
      (void)nco_put_att(nc_id,var_id,aed.att_nm,aed.type,aed.sz,aed.val.vp);
    } /* end else */
    break;
  case aed_create:	
    if(rcd != NC_NOERR) (void)nco_put_att(nc_id,var_id,aed.att_nm,aed.type,aed.sz,aed.val.vp);  
    break;
  case aed_delete:	
    /* Delete specified attribute if attribute name was specified... */
    if(aed.att_nm){
      /* ...and if attribute is known to exist from previous inquire call... */
      if(rcd == NC_NOERR) (void)nco_del_att(nc_id,var_id,aed.att_nm);
    }else{
      /* ...else delete all attributes for this variable... */
      while(nbr_att){
	(void)nco_inq_attname(nc_id,var_id,nbr_att-1,att_nm);
	(void)nco_del_att(nc_id,var_id,att_nm);
	nbr_att--;
      } /* end while */
    } /* end else */
    break;
  case aed_modify:	
    if(rcd == NC_NOERR) (void)nco_put_att(nc_id,var_id,aed.att_nm,aed.type,aed.sz,aed.val.vp);
    break;
  case aed_overwrite:	
    (void)nco_put_att(nc_id,var_id,aed.att_nm,aed.type,aed.sz,aed.val.vp);  
    break;
  default: 
    break;
  } /* end switch */

#ifdef NCO_NETCDF4_AND_FILLVALUE
    if(flg_netCDF4 && !strcmp(aed.att_nm,att_nm_tmp) && aed.mode != aed_delete){
      (void)nco_rename_att(nc_id,var_id,att_nm_tmp,nco_mss_val_sng_get());
      /* Restore original name (space already allocated) */
      strcpy(aed.att_nm,nco_mss_val_sng_get()); 
    } /* !flg_netCDF4 */
#endif /* !NCO_NETCDF4_AND_FILLVALUE */

} /* end nco_aed_prc() */
示例#6
0
文件: nco_ppc.c 项目: geoslegend/nco
void
nco_ppc_ini /* Set PPC based on user specifications */
(const int nc_id, /* I [id] netCDF input file ID */
 int *dfl_lvl, /* O [enm] Deflate level */
 const int fl_out_fmt,  /* I [enm] Output file format */
 char * const ppc_arg[], /* I [sng] List of user-specified PPCs */
 const int ppc_arg_nbr, /* I [nbr] Number of PPC specified */
 trv_tbl_sct * const trv_tbl) /* I/O [sct] Traversal table */
{
  int ppc_arg_idx; /* [idx] Index over ppc_arg (i.e., separate invocations of "--ppc var1[,var2]=val") */
  int ppc_var_idx; /* [idx] Index over ppc_lst (i.e., all names explicitly specified in all "--ppc var1[,var2]=val" options) */
  int ppc_var_nbr=0;
  kvm_sct *ppc_lst; /* [sct] List of all PPC specifications */
  kvm_sct kvm;

  if(fl_out_fmt == NC_FORMAT_NETCDF4 || fl_out_fmt == NC_FORMAT_NETCDF4_CLASSIC){
    /* If user did not explicitly set deflate level for this file ... */
    if(*dfl_lvl == NCO_DFL_LVL_UNDEFINED){
      *dfl_lvl=1;
      if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Precision-Preserving Compression (PPC) automatically activating file-wide deflation level = %d\n",nco_prg_nm_get(),*dfl_lvl);
    } /* endif */
  }else{
    if(nco_dbg_lvl_get() >= nco_dbg_std) (void)fprintf(stderr,"%s: INFO Requested Precision-Preserving Compression (PPC) on netCDF3 output dataset. Unlike netCDF4, netCDF3 does not support internal compression. To take full advantage of PPC consider writing file as netCDF4 enhanced (e.g., %s -4 ...) or classic (e.g., %s -7 ...). Or consider compressing the netCDF3 file afterwards with, e.g., gzip or bzip2. File must then be uncompressed with, e.g., gunzip or bunzip2 before netCDF readers will recognize it. See http://nco.sf.net/nco.html#ppc for more information on PPC strategies.\n",nco_prg_nm_get(),nco_prg_nm_get(),nco_prg_nm_get());
  } /* endelse */

  ppc_lst=(kvm_sct *)nco_malloc(NC_MAX_VARS*sizeof(kvm_sct));

  /* Parse PPCs */
  for(ppc_arg_idx=0;ppc_arg_idx<ppc_arg_nbr;ppc_arg_idx++){
    if(!strstr(ppc_arg[ppc_arg_idx],"=")){
      (void)fprintf(stdout,"%s: Invalid --ppc specification: %s. Must contain \"=\" sign.\n",nco_prg_nm_get(),ppc_arg[ppc_arg_idx]);
      if(ppc_lst) ppc_lst=(kvm_sct *)nco_free(ppc_lst);
      nco_exit(EXIT_FAILURE);
    } /* endif */
    kvm=nco_sng2kvm(ppc_arg[ppc_arg_idx]);
    /* nco_sng2kvm() converts argument "--ppc one,two=3" into kvm.key="one,two" and kvm.val=3
       Then nco_lst_prs_2D() converts kvm.key into two items, "one" and "two", with the same value, 3 */
    if(kvm.key){
      int var_idx; /* [idx] Index over variables in current PPC argument */
      int var_nbr; /* [nbr] Number of variables in current PPC argument */
      char **var_lst;
      var_lst=nco_lst_prs_2D(kvm.key,",",&var_nbr);
      for(var_idx=0;var_idx<var_nbr;var_idx++){ /* Expand multi-variable specification */
        ppc_lst[ppc_var_nbr].key=strdup(var_lst[var_idx]);
        ppc_lst[ppc_var_nbr].val=strdup(kvm.val);
        ppc_var_nbr++;
      } /* end for */
      var_lst=nco_sng_lst_free(var_lst,var_nbr);
    } /* end if */
  } /* end for */

  /* PPC "default" specified, set all non-coordinate variables to default first */
  for(ppc_var_idx=0;ppc_var_idx<ppc_var_nbr;ppc_var_idx++){
    if(!strcasecmp(ppc_lst[ppc_var_idx].key,"default")){
      nco_ppc_set_dflt(nc_id,ppc_lst[ppc_var_idx].val,trv_tbl);
      break; /* Only one default is needed */
    } /* endif */
  } /* end for */

  /* Set explicit, non-default PPCs that can overwrite default */
  for(ppc_var_idx=0;ppc_var_idx<ppc_var_nbr;ppc_var_idx++){
    if(!strcasecmp(ppc_lst[ppc_var_idx].key,"default")) continue;
    nco_ppc_set_var(ppc_lst[ppc_var_idx].key,ppc_lst[ppc_var_idx].val,trv_tbl);
  } /* end for */

  /* Unset PPC and flag for all variables with excessive PPC
     Operational definition of maximum PPC is maximum decimal precision of float/double = FLT_DIG/DBL_DIG = 7/15 */
  const int nco_max_ppc_dbl=15;
  const int nco_max_ppc_flt=7;
  /* Maximum digits for integers taken based on LONG_MAX ... from limits.h */
  const int nco_max_ppc_short=5;
  const int nco_max_ppc_ushort=5;
  const int nco_max_ppc_int=10;
  const int nco_max_ppc_uint=10;
  const int nco_max_ppc_int64=19;
  const int nco_max_ppc_uint64=20;
  int nco_max_ppc=int_CEWI;

  for(unsigned idx_tbl=0;idx_tbl<trv_tbl->nbr;idx_tbl++){
    if(trv_tbl->lst[idx_tbl].ppc != NC_MAX_INT){
      switch(trv_tbl->lst[idx_tbl].var_typ){
      case NC_FLOAT: nco_max_ppc=nco_max_ppc_flt; break;
      case NC_DOUBLE: nco_max_ppc=nco_max_ppc_dbl; break;
      case NC_SHORT: nco_max_ppc=nco_max_ppc_short; break;
      case NC_USHORT: nco_max_ppc=nco_max_ppc_ushort; break;
      case NC_INT: nco_max_ppc=nco_max_ppc_int; break;
      case NC_UINT: nco_max_ppc=nco_max_ppc_uint; break;
      case NC_INT64: nco_max_ppc=nco_max_ppc_int64; break;
      case NC_UINT64: nco_max_ppc=nco_max_ppc_uint64; break;
	/* Do nothing for non-numeric types ...*/
      case NC_CHAR:
      case NC_BYTE:
      case NC_UBYTE:
      case NC_STRING: break;
      default: 
	nco_dfl_case_nc_type_err();
	break;
      } /* end switch */

      switch(trv_tbl->lst[idx_tbl].var_typ){
	/* Floating point types */
      case NC_FLOAT: 
      case NC_DOUBLE: 
	if(trv_tbl->lst[idx_tbl].ppc > nco_max_ppc){
	  if(trv_tbl->lst[idx_tbl].flg_nsd) (void)fprintf(stdout,"%s: INFO Number of Significant Digits (NSD) requested = %d too high for variable %s which is of type %s. No quantization or rounding will be performed for this variable. HINT: Maximum precisions for NC_FLOAT and NC_DOUBLE are %d and %d, respectively.\n",nco_prg_nm_get(),trv_tbl->lst[idx_tbl].ppc,trv_tbl->lst[idx_tbl].nm,nco_typ_sng(trv_tbl->lst[idx_tbl].var_typ),nco_max_ppc_flt,nco_max_ppc_dbl);
	  trv_tbl->lst[idx_tbl].ppc=NC_MAX_INT;
	} /* endif */
	break;
	/* Integer types */
      case NC_SHORT:
      case NC_USHORT:
      case NC_INT:
      case NC_UINT:
      case NC_INT64:
      case NC_UINT64:
	if(
	   /* ...rounding requested with NSD or ... */
	   (trv_tbl->lst[idx_tbl].flg_nsd) ||
	   /* ...more rounding requested with DSD than available or ... */
	   (!trv_tbl->lst[idx_tbl].flg_nsd && (trv_tbl->lst[idx_tbl].ppc < -1*nco_max_ppc)) ||
	   /* ...more precision requested than integers have or ... */
	   (!trv_tbl->lst[idx_tbl].flg_nsd && (trv_tbl->lst[idx_tbl].ppc >= 0)) ||
	   False)
	trv_tbl->lst[idx_tbl].ppc=NC_MAX_INT;
	break;
      case NC_CHAR: /* Do nothing for non-numeric types ...*/
      case NC_BYTE:
      case NC_UBYTE:
      case NC_STRING:
	trv_tbl->lst[idx_tbl].ppc=NC_MAX_INT;
	break;
      default: 
	nco_dfl_case_nc_type_err();
	break;
      } /* end switch */
      /* For consistency reset flg_nsd as well */
      if(trv_tbl->lst[idx_tbl].ppc == NC_MAX_INT) trv_tbl->lst[idx_tbl].flg_nsd=True;
    } /* endif */
  } /* endfor */

  if(ppc_lst) ppc_lst=nco_kvm_lst_free(ppc_lst,ppc_var_nbr);
} /* end nco_ppc_ini() */