nco/nco_var_avg.h File Reference

#include <stdio.h>
#include <netcdf.h>
#include "nco_netcdf.h"
#include "nco.h"
#include "nco_cnf_typ.h"
#include "nco_mmr.h"
#include "nco_rth_utl.h"
#include "nco_var_rth.h"
#include "nco_var_utl.h"

Include dependency graph for nco_var_avg.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

var_sctnco_var_avg (var_sct *var, dmn_sct *const *const dim, const int nbr_dim, const int nco_op_typ)
void nco_var_avg_reduce_ttl (const nc_type type, const long sz_op1, const long sz_op2, const int has_mss_val, ptr_unn mss_val, long *const tally, ptr_unn op1, ptr_unn op2)
void nco_var_avg_reduce_min (const nc_type type, const long sz_op1, const long sz_op2, const int has_mss_val, ptr_unn mss_val, ptr_unn op1, ptr_unn op2)
void nco_var_avg_reduce_max (const nc_type type, const long sz_op1, const long sz_op2, const int has_mss_val, ptr_unn mss_val, ptr_unn op1, ptr_unn op2)


Function Documentation

var_sct* nco_var_avg var_sct var,
dmn_sct *const *const   dim,
const int  nbr_dim,
const int  nco_op_typ
 

Definition at line 13 of file nco_var_avg.c.

References var_sct_tag::cnt, dmn_sct_tag::cnt, dbg_lvl_get(), var_sct_tag::dim, var_sct_tag::dmn_id, var_sct_tag::end, False, var_sct_tag::has_mss_val, dmn_sct_tag::id, dmn_sct_tag::is_crd_dmn, var_sct_tag::is_crd_var, dmn_sct_tag::is_rec_dmn, var_sct_tag::is_rec_var, var_sct_tag::mss_val, var_sct_tag::nbr_dim, NC_MAX_DIMS, nco_free(), nco_malloc(), nco_op_avg, nco_op_avgsqr, nco_op_max, nco_op_min, nco_op_rms, nco_op_rmssdn, nco_op_sqravg, nco_op_ttl, nco_realloc(), nco_typ_lng(), nco_var_avg_reduce_max(), nco_var_avg_reduce_min(), nco_var_avg_reduce_ttl(), nco_var_dpl(), nco_var_free(), nco_var_zero(), nco_zero_long(), var_sct_tag::nm, prg_nm_get(), var_sct_tag::srt, var_sct_tag::sz, var_sct_tag::sz_rec, var_sct_tag::tally, True, var_sct_tag::type, var_sct_tag::val, and ptr_unn::vp.

Referenced by main().

00017 {
00018   /* Threads: Routine is thread safe and calls no unsafe routines */
00019   /* Purpose: Reduce given variable over specified dimensions 
00020      "Reduce" means to rank-reduce variable by performing arithmetic operation
00021      Output variable is duplicate of input variable, except for averaging dimensions
00022      Default operation is averaging, but nco_op_typ can also be min, max, etc.
00023      nco_var_avg() overwrites contents, if any, of tally array with number of valid input elements contributing to each valid output element
00024 
00025      Input variable structure is destroyed and routine returns resized, partially reduced variable
00026      For some operations, such as min, max, ttl, variable returned by nco_var_avg() is complete and need not be further processed
00027      For averaging operation, output variable must be normalized by its tally array
00028      In other words, nco_var_nrm() should be called subsequently if normalization is desired
00029      Normalization is not done internally to nco_var_avg() to allow user more flexibility */ 
00030 
00031   /* Routine keeps track of three variables whose abbreviations are:
00032      var: Input variable (already hyperslabbed)
00033      avg: An array of averaging blocks, each a contiguous arrangement of all 
00034           elements of var which contribute to a single element of fix.
00035      fix: Output (averaged) variable */
00036 
00037   dmn_sct **dmn_avg;
00038   dmn_sct **dmn_fix;
00039 
00040   int idx_avg_var[NC_MAX_DIMS];
00041   /*  int idx_var_avg[NC_MAX_DIMS];*/ /* Variable is unused but instructive anyway */
00042   int idx_fix_var[NC_MAX_DIMS];
00043   /*  int idx_var_fix[NC_MAX_DIMS];*/ /* Variable is unused but instructive anyway */
00044   int idx;
00045   int idx_dmn;
00046   int dmn_avg_nbr;
00047   int nbr_dmn_fix;
00048   int nbr_dmn_var;
00049 
00050   long avg_sz;
00051   long fix_sz;
00052   long var_sz;
00053 
00054   var_sct *fix;
00055 
00056   /* Copy basic attributes of input variable into output (averaged) variable */
00057   fix=nco_var_dpl(var);
00058 
00059   /* Create lists of averaging and fixed dimensions (in order of their appearance 
00060      in the variable). We do not know a priori how many dimensions remain in the 
00061      output (averaged) variable, but nbr_dmn_var is an upper bound. Similarly, we do
00062      not know a priori how many of the dimensions in the input list of averaging 
00063      dimensions (dim) actually occur in the current variable, so we do not know
00064      dmn_avg_nbr, but nbr_dim is an upper bound on it. */
00065   nbr_dmn_var=var->nbr_dim;
00066   nbr_dmn_fix=0;
00067   dmn_avg_nbr=0;
00068   dmn_avg=(dmn_sct **)nco_malloc(nbr_dim*sizeof(dmn_sct *));
00069   dmn_fix=(dmn_sct **)nco_malloc(nbr_dmn_var*sizeof(dmn_sct *));
00070   for(idx=0;idx<nbr_dmn_var;idx++){
00071     for(idx_dmn=0;idx_dmn<nbr_dim;idx_dmn++){
00072       /* Comparing dimension IDs is faster than comparing dimension names 
00073          but requires assumption that all dimensions are from same file */
00074       if(var->dmn_id[idx] == dim[idx_dmn]->id){
00075         /* Although structures in dim are never altered, linking them into
00076            dmn_avg list makes them vulnerable to manipulation and forces 
00077            dim to lose const protection in prototype */
00078         dmn_avg[dmn_avg_nbr]=dim[idx_dmn];
00079         /* idx_avg_var[i]=j means that the ith averaging dimension is the jth dimension of var */
00080         idx_avg_var[dmn_avg_nbr]=idx;
00081         /* idx_var_avg[j]=i means that the jth dimension of var is the ith averaging dimension */
00082         /*      idx_var_avg[idx]=dmn_avg_nbr;*/ /* Variable is unused but instructive anyway */
00083         dmn_avg_nbr++;
00084         break;
00085       } /* end if */
00086     } /* end loop over idx_dmn */
00087     if(idx_dmn == nbr_dim){
00088       dmn_fix[nbr_dmn_fix]=var->dim[idx];
00089       /* idx_fix_var[i]=j means that the ith fixed dimension is the jth dimension of var */
00090       idx_fix_var[nbr_dmn_fix]=idx;
00091       /* idx_var_fix[j]=i means that the jth dimension of var is the ith fixed dimension */
00092       /*      idx_var_fix[idx]=nbr_dmn_fix;*/ /* Variable is unused but instructive anyway */
00093       nbr_dmn_fix++;
00094     } /* end if */
00095   } /* end loop over idx */
00096 
00097   if(dmn_avg_nbr == 0){
00098     /* 20050517: ncwa only calls nco_var_avg() with variables containing averaging dimensions
00099        Variables without averaging dimensions are in the var_fix list 
00100        We preserve nco_var_avg() capability to work on var_fix variables for future flexibility */
00101     (void)fprintf(stderr,"%s: WARNING %s does not contain any averaging dimensions\n",prg_nm_get(),fix->nm);
00102     /* Variable does not contain any averaging dimensions so we are done
00103        For consistency, return copy of variable held in fix and free() original
00104        Hence, nco_var_avg() always destroys original input and returns valid output */
00105     goto cln_and_xit;
00106   } /* end if */
00107 
00108   /* Free extra list space */
00109   dmn_fix=(dmn_sct **)nco_realloc(dmn_fix,nbr_dmn_fix*sizeof(dmn_sct *));
00110   dmn_avg=(dmn_sct **)nco_realloc(dmn_avg,dmn_avg_nbr*sizeof(dmn_sct *));
00111 
00112   /* Get rid of averaged dimensions */
00113   fix->nbr_dim=nbr_dmn_fix;
00114 
00115   avg_sz=1L;
00116   for(idx=0;idx<dmn_avg_nbr;idx++){
00117     avg_sz*=dmn_avg[idx]->cnt;
00118     fix->sz/=dmn_avg[idx]->cnt;
00119     if(!dmn_avg[idx]->is_rec_dmn) fix->sz_rec/=dmn_avg[idx]->cnt;
00120   } /* end loop over idx */
00121   /* Convenience variable to avoid repetitive indirect addressing */
00122   fix_sz=fix->sz;
00123 
00124   fix->is_rec_var=False;
00125   for(idx=0;idx<nbr_dmn_fix;idx++){
00126     if(dmn_fix[idx]->is_rec_dmn) fix->is_rec_var=True;
00127     fix->dim[idx]=dmn_fix[idx];
00128     fix->dmn_id[idx]=dmn_fix[idx]->id;
00129     fix->srt[idx]=var->srt[idx_fix_var[idx]];
00130     fix->cnt[idx]=var->cnt[idx_fix_var[idx]];
00131     fix->end[idx]=var->end[idx_fix_var[idx]];
00132   } /* end loop over idx */
00133   
00134   fix->is_crd_var=False;
00135   if(nbr_dmn_fix == 1)
00136     if(dmn_fix[0]->is_crd_dmn) 
00137       fix->is_crd_var=True;
00138 
00139   /* Trim dimension arrays to their new sizes */
00140   fix->dim=(dmn_sct **)nco_realloc(fix->dim,nbr_dmn_fix*sizeof(dmn_sct *));
00141   fix->dmn_id=(int *)nco_realloc(fix->dmn_id,nbr_dmn_fix*sizeof(int));
00142   fix->srt=(long *)nco_realloc(fix->srt,nbr_dmn_fix*sizeof(long));
00143   fix->cnt=(long *)nco_realloc(fix->cnt,nbr_dmn_fix*sizeof(long));
00144   fix->end=(long *)nco_realloc(fix->end,nbr_dmn_fix*sizeof(long));
00145   
00146   if(avg_sz == 1L){
00147     /* If averaging block size is 1, input and output value arrays are identical 
00148        var->val was copied to fix->val by nco_var_dpl() at beginning of routine
00149        Only one task remains: to set fix->tally appropriately */
00150     long *fix_tally;
00151 
00152     fix_tally=fix->tally;
00153 
00154     /* First set tally field to 1 */
00155     for(idx=0;idx<fix_sz;idx++) fix_tally[idx]=1L;
00156     /* Next overwrite any missing value locations with zero */
00157     if(fix->has_mss_val){
00158       int val_sz_byte;
00159 
00160       char *val;
00161       char *mss_val;
00162 
00163       /* NB: Use char * rather than void * because some compilers (acc) will not do pointer
00164          arithmetic on void * */
00165       mss_val=(char *)fix->mss_val.vp;
00166       val_sz_byte=nco_typ_lng(fix->type);
00167       val=(char *)fix->val.vp;
00168       for(idx=0;idx<fix_sz;idx++,val+=val_sz_byte)
00169         if(!memcmp(val,mss_val,(size_t)val_sz_byte)) fix_tally[idx]=0L;
00170     } /* fix->has_mss_val */
00171   } /* end if avg_sz == 1L */
00172 
00173   /* Distribute all elements of input hyperslab into averaging block in avg_val
00174      Each block contains avg_sz elements in contiguous buffer 
00175      Reduction step then "reduces" each block into single output element */
00176   if(avg_sz != 1L){
00177     bool AVG_DMN_ARE_MRV=False; /* [flg] Avergaging dimensions are MRV dimensions */
00178     ptr_unn avg_val;
00179     
00180     /* Initialize data needed by reduction step independent of collection algorithm */
00181     var_sz=var->sz;
00182 
00183     /* Value buffer of size var_sz is currently duplicate of input values
00184        MRV algorithm uses these values without re-arranging
00185        General collection algorithm overwrites avg_val with averaging blocks */
00186     avg_val=fix->val;
00187     /* Create new value buffer for output (averaged) size */
00188     fix->val.vp=(void *)nco_malloc(fix_sz*nco_typ_lng(fix->type));
00189     /* Resize (or just plain allocate) tally array */
00190     fix->tally=(long *)nco_realloc(fix->tally,fix_sz*sizeof(long));
00191     
00192     /* Initialize value and tally arrays */
00193     (void)nco_zero_long(fix_sz,fix->tally);
00194     (void)nco_var_zero(fix->type,fix_sz,fix->val);
00195 
00196     /* Complex expensive collection step for creating averaging blocks works 
00197        in all cases though is unnecessary in one important case.
00198        If averaging dimensions are most rapidly varying (MRV) dimensions, then no 
00199        re-arrangement is necessary because original variable is stored in averaging
00200        block order.
00201        Averaging dimensions are MRV dimensions iff nbr_dmn_fix fixed dimensions are 
00202        one-to-one with first nbr_dmn_fix input dimensions. 
00203        Alternatively, could compare dmn_avg_nbr averaging dimensions to last 
00204        dmn_avg_nbr dimensions of input variable.
00205        However, averaging dimensions may appear in any order so it is more
00206        straightforward to compare fixed dimensions to LRV input dimensions. */
00207     for(idx=0;idx<nbr_dmn_fix;idx++) 
00208       if(idx_fix_var[idx] != idx) break;
00209     if(idx == nbr_dmn_fix){
00210       if(dbg_lvl_get() > 0) (void)fprintf(stderr,"%s: INFO Reduction dimensions are %d most-rapidly-varying (MRV) dimensions of %s. Will skip collection step and proceed straight to reduction step.\n",prg_nm_get(),dmn_avg_nbr,fix->nm);
00211       AVG_DMN_ARE_MRV=True; /* [flg] Avergaging dimensions are MRV dimensions */
00212     } /* idx != nbr_dmn_fix */
00213     
00214     /* MRV algorithm simply skips this collection step */
00215     if(!AVG_DMN_ARE_MRV){
00216       /* Dreaded, expensive collection algorithm sorts input into averaging blocks */
00217       char *avg_cp;
00218       char *var_cp;
00219       
00220       int typ_sz;
00221       int nbr_dmn_var_m1;
00222       
00223       long *var_cnt;
00224       long avg_lmn;
00225       long fix_lmn;
00226       long var_lmn;
00227       long dmn_ss[NC_MAX_DIMS];
00228       long dmn_var_map[NC_MAX_DIMS];
00229       long dmn_avg_map[NC_MAX_DIMS];
00230       long dmn_fix_map[NC_MAX_DIMS];
00231       
00232       nbr_dmn_var_m1=nbr_dmn_var-1;
00233       typ_sz=nco_typ_lng(fix->type);
00234       var_cnt=var->cnt;
00235       var_cp=(char *)var->val.vp;
00236       avg_cp=(char *)avg_val.vp;
00237       
00238       /* Compute map for each dimension of input variable */
00239       for(idx=0;idx<nbr_dmn_var;idx++) dmn_var_map[idx]=1L;
00240       for(idx=0;idx<nbr_dmn_var-1;idx++)
00241         for(idx_dmn=idx+1;idx_dmn<nbr_dmn_var;idx_dmn++)
00242           dmn_var_map[idx]*=var->cnt[idx_dmn];
00243       
00244       /* Compute map for each dimension of output variable */
00245       for(idx=0;idx<nbr_dmn_fix;idx++) dmn_fix_map[idx]=1L;
00246       for(idx=0;idx<nbr_dmn_fix-1;idx++)
00247         for(idx_dmn=idx+1;idx_dmn<nbr_dmn_fix;idx_dmn++)
00248           dmn_fix_map[idx]*=fix->cnt[idx_dmn];
00249       
00250       /* Compute map for each dimension of averaging buffer */
00251       for(idx=0;idx<dmn_avg_nbr;idx++) dmn_avg_map[idx]=1L;
00252       for(idx=0;idx<dmn_avg_nbr-1;idx++)
00253         for(idx_dmn=idx+1;idx_dmn<dmn_avg_nbr;idx_dmn++)
00254           dmn_avg_map[idx]*=dmn_avg[idx_dmn]->cnt;
00255       
00256       /* var_lmn is offset into 1-D array */
00257       for(var_lmn=0;var_lmn<var_sz;var_lmn++){
00258         /* dmn_ss are corresponding indices (subscripts) into N-D array */
00259         /* Operations: 1 modulo, 1 pointer offset, 1 user memory fetch
00260            Repetitions: \lmnnbr
00261            Total Counts: \rthnbr=2\lmnnbr, \mmrusrnbr=\lmnnbr
00262            NB: LHS assumed compact and cached, counted RHS offsets and fetches only */
00263         dmn_ss[nbr_dmn_var_m1]=var_lmn%var_cnt[nbr_dmn_var_m1];
00264         for(idx=0;idx<nbr_dmn_var_m1;idx++){
00265           /* Operations: 1 divide, 1 modulo, 2 pointer offset, 2 user memory fetch
00266              Repetitions: \lmnnbr(\dmnnbr-1)
00267              Counts: \rthnbr=4\lmnnbr(\dmnnbr-1), \mmrusrnbr=2\lmnnbr(\dmnnbr-1)
00268              NB: LHS assumed compact and cached, counted RHS offsets and fetches only
00269              NB: Neglected loop arithmetic/compare */
00270           dmn_ss[idx]=(long)(var_lmn/dmn_var_map[idx]);
00271           dmn_ss[idx]%=var_cnt[idx];
00272         } /* end loop over dimensions */
00273         
00274         /* Map variable's N-D array indices into a 1-D index into averaged data */
00275         fix_lmn=0L;
00276         /* Operations: 1 add, 1 multiply, 3 pointer offset, 3 user memory fetch
00277            Repetitions: \lmnnbr(\dmnnbr-\avgnbr)
00278            Counts: \rthnbr=5\lmnnbr(\dmnnbr-\avgnbr), \mmrusrnbr=3\lmnnbr(\dmnnbr-\avgnbr) */
00279         for(idx=0;idx<nbr_dmn_fix;idx++) fix_lmn+=dmn_ss[idx_fix_var[idx]]*dmn_fix_map[idx];
00280         
00281         /* Map N-D array indices into 1-D offset from group offset */
00282         avg_lmn=0L;
00283         /* Operations: 1 add, 1 multiply, 3 pointer offset, 3 user memory fetch
00284            Repetitions: \lmnnbr\avgnbr
00285            Counts: \rthnbr=5\lmnnbr\avgnbr, \mmrusrnbr=3\lmnnbr\avgnbr */
00286         for(idx=0;idx<dmn_avg_nbr;idx++) avg_lmn+=dmn_ss[idx_avg_var[idx]]*dmn_avg_map[idx];
00287         
00288         /* Copy current element in input array into its slot in sorted avg_val */
00289         /* Operations: 3 add, 3 multiply, 0 pointer offset, 1 system memory copy
00290            Repetitions: \lmnnbr
00291            Counts: \rthnbr=6\lmnnbr, \mmrusrnbr=0, \mmrsysnbr=1 */
00292         (void)memcpy(avg_cp+(fix_lmn*avg_sz+avg_lmn)*typ_sz,var_cp+var_lmn*typ_sz,(size_t)typ_sz);
00293       } /* end loop over var_lmn */
00294     } /* AVG_DMN_ARE_MRV */
00295     
00296     /* Input data are now sorted and stored (in avg_val) in blocks (of length avg_sz)
00297        in same order as blocks' average values will appear in output buffer. 
00298        Averaging routines can take advantage of this by casting avg_val to 
00299        two dimensional variable and averaging over inner dimension. 
00300        nco_var_avg_reduce_*() sets tally array */
00301     switch(nco_op_typ){
00302     case nco_op_max:
00303       (void)nco_var_avg_reduce_max(fix->type,var_sz,fix_sz,fix->has_mss_val,fix->mss_val,avg_val,fix->val);
00304       break;
00305     case nco_op_min:
00306       (void)nco_var_avg_reduce_min(fix->type,var_sz,fix_sz,fix->has_mss_val,fix->mss_val,avg_val,fix->val);
00307       break;
00308     case nco_op_avg: /* Operations: Previous=none, Current=sum, Next=normalize and root */
00309     case nco_op_sqravg: /* Operations: Previous=none, Current=sum, Next=normalize and square */
00310     case nco_op_avgsqr: /* Operations: Previous=square, Current=sum, Next=normalize */
00311     case nco_op_rms: /* Operations: Previous=square, Current=sum, Next=normalize and root */
00312     case nco_op_rmssdn: /* Operations: Previous=square, Current=sum, Next=normalize and root */
00313     case nco_op_ttl: /* Operations: Previous=none, Current=sum, Next=none */
00314     default:
00315       (void)nco_var_avg_reduce_ttl(fix->type,var_sz,fix_sz,fix->has_mss_val,fix->mss_val,fix->tally,avg_val,fix->val);                  
00316       break;
00317     } /* end case */
00318     
00319     /* Free dynamic memory that held rearranged input variable values */
00320     avg_val.vp=nco_free(avg_val.vp);
00321   } /* end if avg_sz != 1 */
00322   
00323   /* Jump here when variable is not to be reduced. This occurs when
00324      1. Variable contains no averaging dimensions
00325      2. Averaging block size is 1 */
00326  cln_and_xit:
00327   
00328   /* Free input variable */
00329   var=nco_var_free(var);
00330   dmn_avg=(dmn_sct **)nco_free(dmn_avg);
00331   dmn_fix=(dmn_sct **)nco_free(dmn_fix);
00332   
00333   /* Return averaged variable */
00334   return fix;
00335 } /* end nco_var_avg() */

void nco_var_avg_reduce_max const nc_type  type,
const long  sz_op1,
const long  sz_op2,
const int  has_mss_val,
ptr_unn  mss_val,
ptr_unn  op1,
ptr_unn  op2
 

Definition at line 907 of file nco_var_avg.c.

References cast_void_nctype(), double_CEWI, False, float_CEWI, NC_BYTE, NC_CHAR, NC_DOUBLE, NC_FLOAT, NC_INT, NC_SHORT, nco_dfl_case_nc_type_err(), nco_int_CEWI, nco_typ_lng(), short_CEWI, True, and type.

Referenced by nco_var_avg(), and nco_var_pck().

00914 {
00915   /* Purpose: Find maximum value of each contiguous block of first operand and place
00916      result in corresponding element in second operand. Operands are assumed to have
00917      conforming types, but not dimensions or sizes. */
00918 
00919   /* nco_var_avg_reduce_min() is derived from nco_var_avg_reduce_ttl()
00920      Routines are very similar but tallies are not incremented
00921      See nco_var_avg_reduce_ttl() for more algorithmic documentation
00922      nco_var_avg_reduce_max() is derived from nco_var_avg_reduce_min() */
00923 
00924 #define FXM_NCO315 1
00925 #ifdef FXM_NCO315
00926   long idx_op1;
00927 #endif /* __GNUC__ */
00928   const long sz_blk=sz_op1/sz_op2;
00929   long idx_op2;
00930   long idx_blk;
00931   
00932   double mss_val_dbl=double_CEWI;
00933   float mss_val_flt=float_CEWI;
00934   nco_int mss_val_lng=nco_int_CEWI;
00935   short mss_val_sht=short_CEWI;
00936   nco_char mss_val_chr;
00937   nco_byte mss_val_byt;
00938   
00939   bool flg_mss=False;
00940   
00941   /* Typecast pointer to values before access */
00942   (void)cast_void_nctype(type,&op1);
00943   (void)cast_void_nctype(type,&op2);
00944   if(has_mss_val) (void)cast_void_nctype(type,&mss_val);
00945   
00946   if(has_mss_val){
00947     switch(type){
00948     case NC_FLOAT: mss_val_flt=*mss_val.fp; break;
00949     case NC_DOUBLE: mss_val_dbl=*mss_val.dp; break;
00950     case NC_SHORT: mss_val_sht=*mss_val.sp; break;
00951     case NC_INT: mss_val_lng=*mss_val.lp; break;
00952     case NC_BYTE: mss_val_byt=*mss_val.bp; break;
00953     case NC_CHAR: mss_val_chr=*mss_val.cp; break;
00954     default: nco_dfl_case_nc_type_err(); break;
00955     } /* end switch */
00956   } /* endif */
00957   
00958   switch(type){
00959   case NC_FLOAT:
00960     
00961 #define FXM_NCO315 1
00962 #ifdef FXM_NCO315
00963     /* ANSI-compliant branch */
00964     if(!has_mss_val){ 
00965       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00966         const long blk_off=idx_op2*sz_blk;
00967         op2.fp[idx_op2]=op1.fp[blk_off];
00968         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00969           if(op2.fp[idx_op2] < op1.fp[blk_off+idx_blk]) op2.fp[idx_op2]=op1.fp[blk_off+idx_blk];
00970       } /* end loop over idx_op2 */
00971     }else{
00972       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00973         const long blk_off=idx_op2*sz_blk;
00974         flg_mss=False;
00975         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00976           idx_op1=blk_off+idx_blk;
00977           if(op1.fp[idx_op1] != mss_val_flt) {
00978             if(!flg_mss || op2.fp[idx_op2] < op1.fp[idx_op1]) op2.fp[idx_op2]=op1.fp[idx_op1];
00979             flg_mss=True;
00980           } /* end if */
00981         } /* end loop over idx_blk */
00982         if(!flg_mss) op2.fp[idx_op2]=mss_val_flt;
00983       } /* end loop over idx_op2 */
00984     } /* end else */
00985 #else /* __GNUC__ */
00986     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00987     if(True){
00988       float op1_2D[sz_op2][sz_blk];
00989       
00990       (void)memcpy((void *)op1_2D,(void *)(op1.fp),sz_op1*nco_typ_lng(type));
00991       
00992       if(!has_mss_val){
00993         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00994           op2.fp[idx_op2]=op1_2D[idx_op2][0];
00995           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00996             if(op2.fp[idx_op2] < op1_2D[idx_op2][idx_blk]) op2.fp[idx_op2]=op1_2D[idx_op2][idx_blk];
00997         } /* end loop over idx_op2 */
00998       }else{
00999         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01000           flg_mss=False;
01001           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
01002             if(op1_2D[idx_op2][idx_blk] != mss_val_flt) {
01003               if(!flg_mss || op2.fp[idx_op2] < op1_2D[idx_op2][idx_blk]) op2.fp[idx_op2]=op1_2D[idx_op2][idx_blk];
01004               flg_mss=True;
01005             } /* end if */
01006           } /* end loop over idx_blk */
01007           if(!flg_mss) op2.fp[idx_op2]=mss_val_flt;
01008         } /* end loop over idx_op2 */
01009       } /* end else */
01010     } /* end if */
01011 #endif /* __GNUC__ */
01012     
01013     break;
01014   case NC_DOUBLE:
01015     
01016 #define FXM_NCO315 1
01017 #ifdef FXM_NCO315
01018     /* ANSI-compliant branch */
01019     if(!has_mss_val){
01020       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01021         const long blk_off=idx_op2*sz_blk;
01022         op2.dp[idx_op2]=op1.dp[blk_off];
01023         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
01024           if(op2.dp[idx_op2] < op1.dp[blk_off+idx_blk]) op2.dp[idx_op2]=op1.dp[blk_off+idx_blk];
01025       } /* end loop over idx_op2 */
01026     }else{
01027       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01028         const long blk_off=idx_op2*sz_blk;
01029         flg_mss=False;
01030         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
01031           idx_op1=blk_off+idx_blk;
01032           if(op1.dp[idx_op1] != mss_val_dbl) {
01033             if(!flg_mss || (op2.dp[idx_op2] < op1.dp[idx_op1])) op2.dp[idx_op2]=op1.dp[idx_op1];
01034             flg_mss=True;
01035           } /* end if */
01036         } /* end loop over idx_blk */
01037         if(!flg_mss) op2.dp[idx_op2]=mss_val_dbl;
01038       } /* end loop over idx_op2 */
01039     } /* end else */
01040 #else /* __GNUC__ */
01041     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
01042     if(True){
01043       double op1_2D[sz_op2][sz_blk];
01044       
01045       (void)memcpy((void *)op1_2D,(void *)(op1.dp),sz_op1*nco_typ_lng(type));
01046       
01047       if(!has_mss_val){
01048         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01049           op2.dp[idx_op2]=op1_2D[idx_op2][0];
01050           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
01051             if(op2.dp[idx_op2] < op1_2D[idx_op2][idx_blk]) op2.dp[idx_op2]=op1_2D[idx_op2][idx_blk] ;
01052         } /* end loop over idx_op2 */
01053       }else{
01054         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01055           flg_mss=False;
01056           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
01057             if(op1_2D[idx_op2][idx_blk] != mss_val_dbl){
01058               if(!flg_mss || (op2.dp[idx_op2] < op1_2D[idx_op2][idx_blk])) op2.dp[idx_op2]=op1_2D[idx_op2][idx_blk];        
01059               flg_mss=True;
01060             } /* end if */
01061           } /* end loop over idx_blk */
01062           if(!flg_mss) op2.dp[idx_op2]=mss_val_dbl;
01063         } /* end loop over idx_op2 */
01064       } /* end else */
01065     } /* end if */
01066 #endif /* __GNUC__ */
01067     break;
01068   case NC_INT:
01069 #define FXM_NCO315 1
01070 #ifdef FXM_NCO315
01071     /* ANSI-compliant branch */
01072     if(!has_mss_val){
01073       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01074         const long blk_off=idx_op2*sz_blk;
01075         op2.lp[idx_op2]=op1.lp[blk_off];
01076         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
01077           if(op2.lp[idx_op2] < op1.lp[blk_off+idx_blk]) op2.lp[idx_op2]=op1.lp[blk_off+idx_blk];
01078       } /* end loop over idx_op2 */
01079     }else{
01080       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01081         const long blk_off=idx_op2*sz_blk;
01082         flg_mss=False;
01083         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
01084           idx_op1=blk_off+idx_blk;
01085           if(op1.lp[idx_op1] != mss_val_lng){
01086             if(!flg_mss || op2.lp[idx_op2] < op1.lp[idx_op1]) op2.lp[idx_op2]=op1.lp[idx_op1];
01087             flg_mss= True;
01088           } /* end if */
01089         } /* end loop over idx_blk */
01090         if(!flg_mss) op2.lp[idx_op2]=mss_val_lng;
01091       } /* end loop over idx_op2 */
01092     } /* end else */
01093 #else /* __GNUC__ */
01094     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
01095     if(True){
01096       long op1_2D[sz_op2][sz_blk];
01097       
01098       (void)memcpy((void *)op1_2D,(void *)(op1.lp),sz_op1*nco_typ_lng(type));
01099       
01100       if(!has_mss_val){
01101         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01102           op2.lp[idx_op2]=op1_2D[idx_op2][0];
01103           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
01104             if(op2.lp[idx_op2] < op1_2D[idx_op2][idx_blk]) op2.lp[idx_op2]=op1_2D[idx_op2][idx_blk];
01105         } /* end loop over idx_op2 */
01106       }else{
01107         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01108           flg_mss=False;
01109           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
01110             if(op1_2D[idx_op2][idx_blk] != mss_val_lng){
01111               if(!flg_mss || op2.lp[idx_op2] < op1_2D[idx_op2][idx_blk]) op2.lp[idx_op2]=op1_2D[idx_op2][idx_blk];            
01112               flg_mss=True;
01113             } /* end if */
01114           } /* end loop over idx_blk */
01115           if(!flg_mss) op2.lp[idx_op2]=mss_val_lng;
01116         } /* end loop over idx_op2 */
01117       } /* end else */
01118     } /* end if */
01119 #endif /* __GNUC__ */
01120     break;
01121   case NC_SHORT:
01122 #define FXM_NCO315 1
01123 #ifdef FXM_NCO315
01124     /* ANSI-compliant branch */
01125     if(!has_mss_val){
01126       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01127         const long blk_off=idx_op2*sz_blk;
01128         op2.sp[idx_op2]=op1.sp[blk_off];
01129         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
01130           if(op2.sp[idx_op2] < op1.sp[blk_off+idx_blk]) op2.sp[idx_op2]=op1.sp[blk_off+idx_blk];
01131       } /* end loop over idx_op2 */
01132     }else{
01133       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01134         const long blk_off=idx_op2*sz_blk;
01135         flg_mss=False;
01136         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
01137           idx_op1=blk_off+idx_blk;
01138           if(op1.sp[idx_op1] != mss_val_sht){
01139             if(!flg_mss || op2.sp[idx_op2] < op1.sp[idx_op1]) op2.sp[idx_op2]=op1.sp[idx_op1];
01140             flg_mss=True;
01141           } /* end if */
01142         } /* end loop over idx_blk */
01143         if(!flg_mss) op2.sp[idx_op2]=mss_val_sht;
01144       } /* end loop over idx_op2 */
01145     } /* end else */
01146 #else /* __GNUC__ */
01147     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
01148     if(True){
01149       short op1_2D[sz_op2][sz_blk];
01150       
01151       (void)memcpy((void *)op1_2D,(void *)(op1.sp),sz_op1*nco_typ_lng(type));
01152       
01153       if(!has_mss_val){
01154         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01155           op2.sp[idx_op2]=op1_2D[idx_op2][0];
01156           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
01157             if(op2.sp[idx_op2] < op1_2D[idx_op2][idx_blk]) op2.sp[idx_op2]=op1_2D[idx_op2][idx_blk];
01158         } /* end loop over idx_op2 */
01159       }else{
01160         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
01161           flg_mss=False;
01162           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
01163             if(op1_2D[idx_op2][idx_blk] != mss_val_sht){
01164               if(!flg_mss  || op2.sp[idx_op2] < op1_2D[idx_op2][idx_blk]) op2.sp[idx_op2]=op1_2D[idx_op2][idx_blk];           
01165               flg_mss=True;
01166             } /* end if */
01167           } /* end loop over idx_blk */
01168           if(!flg_mss) op2.sp[idx_op2]=mss_val_sht;
01169         } /* end loop over idx_op2 */
01170       } /* end else */
01171     } /* end if */
01172 #endif /* __GNUC__ */
01173     break;
01174   case NC_CHAR:
01175     /* Do nothing except avoid compiler warnings */
01176     mss_val_chr=mss_val_chr;
01177     break;
01178   case NC_BYTE:
01179     /* Do nothing except avoid compiler warnings */
01180     mss_val_byt=mss_val_byt;
01181     break;
01182   default: nco_dfl_case_nc_type_err(); break;
01183   } /* end  switch */
01184   
01185   /* NB: it is not neccessary to un-typecast pointers to values after access 
01186      because we have only operated on local copies of them. */
01187 
01188 } /* end nco_var_avg_reduce_max() */

void nco_var_avg_reduce_min const nc_type  type,
const long  sz_op1,
const long  sz_op2,
const int  has_mss_val,
ptr_unn  mss_val,
ptr_unn  op1,
ptr_unn  op2
 

Definition at line 622 of file nco_var_avg.c.

References cast_void_nctype(), double_CEWI, False, float_CEWI, NC_BYTE, NC_CHAR, NC_DOUBLE, NC_FLOAT, NC_INT, NC_SHORT, nco_dfl_case_nc_type_err(), nco_int_CEWI, nco_typ_lng(), short_CEWI, True, and type.

Referenced by nco_var_avg(), and nco_var_pck().

00629 {
00630   /* Purpose: Find minimum value of each contiguous block of first operand and place
00631      result in corresponding element in second operand. Operands are assumed to have
00632      conforming types, but not dimensions or sizes. */
00633 
00634   /* nco_var_avg_reduce_min() is derived from nco_var_avg_reduce_ttl()
00635      Routines are very similar but tallies are not incremented
00636      See nco_var_avg_reduce_ttl() for more algorithmic documentation
00637      nco_var_avg_reduce_max() is derived from nco_var_avg_reduce_min() */
00638 
00639 #define FXM_NCO315 1
00640 #ifdef FXM_NCO315
00641   long idx_op1;
00642 #endif /* __GNUC__ */
00643   const long sz_blk=sz_op1/sz_op2;
00644   long idx_op2;
00645   long idx_blk;
00646 
00647   double mss_val_dbl=double_CEWI;
00648   float mss_val_flt=float_CEWI;
00649   nco_int mss_val_lng=nco_int_CEWI;
00650   short mss_val_sht=short_CEWI;
00651   nco_char mss_val_chr;
00652   nco_byte mss_val_byt;
00653   
00654   bool flg_mss=False; /* [flg] Block has valid (non-missing) values */
00655   
00656   /* Typecast pointer to values before access */
00657   (void)cast_void_nctype(type,&op1);
00658   (void)cast_void_nctype(type,&op2);
00659   if(has_mss_val) (void)cast_void_nctype(type,&mss_val);
00660   
00661   if(has_mss_val){
00662     switch(type){
00663     case NC_FLOAT: mss_val_flt=*mss_val.fp; break;
00664     case NC_DOUBLE: mss_val_dbl=*mss_val.dp; break;
00665     case NC_SHORT: mss_val_sht=*mss_val.sp; break;
00666     case NC_INT: mss_val_lng=*mss_val.lp; break;
00667     case NC_BYTE: mss_val_byt=*mss_val.bp; break;
00668     case NC_CHAR: mss_val_chr=*mss_val.cp; break;
00669     default: nco_dfl_case_nc_type_err(); break;
00670     } /* end switch */
00671   } /* endif */
00672   
00673   switch(type){
00674   case NC_FLOAT:
00675     
00676 #define FXM_NCO315 1
00677 #ifdef FXM_NCO315
00678     /* ANSI-compliant branch */
00679     if(!has_mss_val){ 
00680       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00681         const long blk_off=idx_op2*sz_blk;
00682         op2.fp[idx_op2]=op1.fp[blk_off];
00683         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00684           if(op2.fp[idx_op2] > op1.fp[blk_off+idx_blk]) op2.fp[idx_op2]=op1.fp[blk_off+idx_blk];
00685       } /* end loop over idx_op2 */
00686     }else{
00687       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00688         const long blk_off=idx_op2*sz_blk;
00689         flg_mss=False;
00690         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00691           idx_op1=blk_off+idx_blk;
00692           if(op1.fp[idx_op1] != mss_val_flt) {
00693             if(!flg_mss || op2.fp[idx_op2] > op1.fp[idx_op1]) op2.fp[idx_op2]=op1.fp[idx_op1];
00694             flg_mss=True;
00695           } /* end if */
00696         } /* end loop over idx_blk */
00697         if(!flg_mss) op2.fp[idx_op2]=mss_val_flt;
00698       } /* end loop over idx_op2 */
00699     } /* end else */
00700 #else /* __GNUC__ */
00701     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00702     if(True){
00703       float op1_2D[sz_op2][sz_blk];
00704       
00705       (void)memcpy((void *)op1_2D,(void *)(op1.fp),sz_op1*nco_typ_lng(type));
00706       
00707       if(!has_mss_val){
00708         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00709           op2.fp[idx_op2]=op1_2D[idx_op2][0];
00710           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00711             if(op2.fp[idx_op2] > op1_2D[idx_op2][idx_blk]) op2.fp[idx_op2]=op1_2D[idx_op2][idx_blk];
00712         } /* end loop over idx_op2 */
00713       }else{
00714         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00715           flg_mss=False;
00716           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00717             if(op1_2D[idx_op2][idx_blk] != mss_val_flt) {
00718               if(!flg_mss || op2.fp[idx_op2] > op1_2D[idx_op2][idx_blk]) op2.fp[idx_op2]=op1_2D[idx_op2][idx_blk];
00719               flg_mss=True;
00720             } /* end if */
00721           } /* end loop over idx_blk */
00722           if(!flg_mss) op2.fp[idx_op2]=mss_val_flt;
00723         } /* end loop over idx_op2 */
00724       } /* end else */
00725     } /* end if */
00726 #endif /* __GNUC__ */
00727     
00728     break;
00729   case NC_DOUBLE:
00730     
00731 #define FXM_NCO315 1
00732 #ifdef FXM_NCO315
00733     /* ANSI-compliant branch */
00734     if(!has_mss_val){
00735       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00736         const long blk_off=idx_op2*sz_blk;
00737         op2.dp[idx_op2]=op1.dp[blk_off];
00738         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00739           if(op2.dp[idx_op2] > op1.dp[blk_off+idx_blk]) op2.dp[idx_op2]=op1.dp[blk_off+idx_blk];
00740       } /* end loop over idx_op2 */
00741     }else{
00742       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00743         const long blk_off=idx_op2*sz_blk;
00744         flg_mss=False;
00745         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00746           idx_op1=blk_off+idx_blk;
00747           if(op1.dp[idx_op1] != mss_val_dbl) {
00748             if(!flg_mss || (op2.dp[idx_op2] > op1.dp[idx_op1])) op2.dp[idx_op2]=op1.dp[idx_op1];
00749             flg_mss=True;
00750           } /* end if */
00751         } /* end loop over idx_blk */
00752         if(!flg_mss) op2.dp[idx_op2]=mss_val_dbl;
00753       } /* end loop over idx_op2 */
00754     } /* end else */
00755 #else /* __GNUC__ */
00756     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00757     if(True){
00758       double op1_2D[sz_op2][sz_blk];
00759       
00760       (void)memcpy((void *)op1_2D,(void *)(op1.dp),sz_op1*nco_typ_lng(type));
00761       
00762       if(!has_mss_val){
00763         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00764           op2.dp[idx_op2]=op1_2D[idx_op2][0];
00765           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00766             if(op2.dp[idx_op2] > op1_2D[idx_op2][idx_blk]) op2.dp[idx_op2]=op1_2D[idx_op2][idx_blk] ;
00767         } /* end loop over idx_op2 */
00768       }else{
00769         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00770           flg_mss=False;
00771           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00772             if(op1_2D[idx_op2][idx_blk] != mss_val_dbl){
00773               if(!flg_mss || (op2.dp[idx_op2] > op1_2D[idx_op2][idx_blk])) op2.dp[idx_op2]=op1_2D[idx_op2][idx_blk];        
00774               flg_mss=True;
00775             } /* end if */
00776           } /* end loop over idx_blk */
00777           if(!flg_mss) op2.dp[idx_op2]=mss_val_dbl;
00778         } /* end loop over idx_op2 */
00779       } /* end else */
00780     } /* end if */
00781 #endif /* __GNUC__ */
00782     break;
00783   case NC_INT:
00784 #define FXM_NCO315 1
00785 #ifdef FXM_NCO315
00786     /* ANSI-compliant branch */
00787     if(!has_mss_val){
00788       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00789         const long blk_off=idx_op2*sz_blk;
00790         op2.lp[idx_op2]=op1.lp[blk_off];
00791         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00792           if(op2.lp[idx_op2] > op1.lp[blk_off+idx_blk]) op2.lp[idx_op2]=op1.lp[blk_off+idx_blk];
00793       } /* end loop over idx_op2 */
00794     }else{
00795       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00796         const long blk_off=idx_op2*sz_blk;
00797         flg_mss=False;
00798         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00799           idx_op1=blk_off+idx_blk;
00800           if(op1.lp[idx_op1] != mss_val_lng){
00801             if(!flg_mss || op2.lp[idx_op2] > op1.lp[idx_op1]) op2.lp[idx_op2]=op1.lp[idx_op1];
00802             flg_mss= True;
00803           } /* end if */
00804         } /* end loop over idx_blk */
00805         if(!flg_mss) op2.lp[idx_op2]=mss_val_lng;
00806       } /* end loop over idx_op2 */
00807     } /* end else */
00808 #else /* __GNUC__ */
00809     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00810     if(True){
00811       long op1_2D[sz_op2][sz_blk];
00812       
00813       (void)memcpy((void *)op1_2D,(void *)(op1.lp),sz_op1*nco_typ_lng(type));
00814       
00815       if(!has_mss_val){
00816         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00817           op2.lp[idx_op2]=op1_2D[idx_op2][0];
00818           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00819             if(op2.lp[idx_op2] > op1_2D[idx_op2][idx_blk]) op2.lp[idx_op2]=op1_2D[idx_op2][idx_blk];
00820         } /* end loop over idx_op2 */
00821       }else{
00822         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00823           flg_mss=False;
00824           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00825             if(op1_2D[idx_op2][idx_blk] != mss_val_lng){
00826               if(!flg_mss || op2.lp[idx_op2] > op1_2D[idx_op2][idx_blk]) op2.lp[idx_op2]=op1_2D[idx_op2][idx_blk];            
00827               flg_mss=True;
00828             } /* end if */
00829           } /* end loop over idx_blk */
00830           if(!flg_mss) op2.lp[idx_op2]=mss_val_lng;
00831         } /* end loop over idx_op2 */
00832       } /* end else */
00833     } /* end if */
00834 #endif /* __GNUC__ */
00835     break;
00836   case NC_SHORT:
00837 #define FXM_NCO315 1
00838 #ifdef FXM_NCO315
00839     /* ANSI-compliant branch */
00840     if(!has_mss_val){
00841       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00842         const long blk_off=idx_op2*sz_blk;
00843         op2.sp[idx_op2]=op1.sp[blk_off];
00844         for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00845           if(op2.sp[idx_op2] > op1.sp[blk_off+idx_blk]) op2.sp[idx_op2]=op1.sp[blk_off+idx_blk];
00846       } /* end loop over idx_op2 */
00847     }else{
00848       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00849         const long blk_off=idx_op2*sz_blk;
00850         flg_mss=False;
00851         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00852           idx_op1=blk_off+idx_blk;
00853           if(op1.sp[idx_op1] != mss_val_sht){
00854             if(!flg_mss || op2.sp[idx_op2] > op1.sp[idx_op1]) op2.sp[idx_op2]=op1.sp[idx_op1];
00855             flg_mss=True;
00856           } /* end if */
00857         } /* end loop over idx_blk */
00858         if(!flg_mss) op2.sp[idx_op2]=mss_val_sht;
00859       } /* end loop over idx_op2 */
00860     } /* end else */
00861 #else /* __GNUC__ */
00862     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00863     if(True){
00864       short op1_2D[sz_op2][sz_blk];
00865       
00866       (void)memcpy((void *)op1_2D,(void *)(op1.sp),sz_op1*nco_typ_lng(type));
00867       
00868       if(!has_mss_val){
00869         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00870           op2.sp[idx_op2]=op1_2D[idx_op2][0];
00871           for(idx_blk=1;idx_blk<sz_blk;idx_blk++) 
00872             if(op2.sp[idx_op2] > op1_2D[idx_op2][idx_blk]) op2.sp[idx_op2]=op1_2D[idx_op2][idx_blk];
00873         } /* end loop over idx_op2 */
00874       }else{
00875         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00876           flg_mss=False;
00877           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00878             if(op1_2D[idx_op2][idx_blk] != mss_val_sht){
00879               if(!flg_mss  || op2.sp[idx_op2] > op1_2D[idx_op2][idx_blk]) op2.sp[idx_op2]=op1_2D[idx_op2][idx_blk];           
00880               flg_mss=True;
00881             } /* end if */
00882           } /* end loop over idx_blk */
00883           if(!flg_mss) op2.sp[idx_op2]=mss_val_sht;
00884         } /* end loop over idx_op2 */
00885       } /* end else */
00886     } /* end if */
00887 #endif /* __GNUC__ */
00888     break;
00889   case NC_CHAR:
00890     /* Do nothing except avoid compiler warnings */
00891     mss_val_chr=mss_val_chr;
00892     break;
00893   case NC_BYTE:
00894     /* Do nothing except avoid compiler warnings */
00895     mss_val_byt=mss_val_byt;
00896     break;
00897   default: nco_dfl_case_nc_type_err(); break;
00898   } /* end  switch */
00899   
00900   /* NB: it is not neccessary to un-typecast pointers to values after access 
00901      because we have only operated on local copies of them. */
00902   
00903 } /* end nco_var_avg_reduce_min() */

void nco_var_avg_reduce_ttl const nc_type  type,
const long  sz_op1,
const long  sz_op2,
const int  has_mss_val,
ptr_unn  mss_val,
long *const   tally,
ptr_unn  op1,
ptr_unn  op2
 

Definition at line 339 of file nco_var_avg.c.

References cast_void_nctype(), double_CEWI, float_CEWI, NC_BYTE, NC_CHAR, NC_DOUBLE, NC_FLOAT, NC_INT, NC_SHORT, nco_dfl_case_nc_type_err(), nco_int_CEWI, nco_typ_lng(), short_CEWI, True, and type.

Referenced by nco_var_avg().

00347 {
00348   /* Threads: Routine is thread safe and calls no unsafe routines */
00349   /* Purpose: Sum values in each contiguous block of first operand and place
00350      result in corresponding element in second operand. 
00351      Currently arithmetic operation performed is summation of elements in op1
00352      Input operands are assumed to have conforming types, but not dimensions or sizes
00353      nco_var_avg_reduce() knows nothing about dimensions
00354      Routine is one dimensional array operator acting serially on each element of input buffer op1
00355      Calling rouine knows exactly how rank of output, op2, is reduced from rank of input
00356      Routine only does summation rather than averaging in order to remain flexible
00357      Operations which require normalization, e.g., averaging, must call nco_var_nrm() 
00358      or nco_var_dvd() to divide sum set in this routine by tally set in this routine. */
00359   
00360   /* Each operation has GNUC and non-GNUC blocks:
00361      GNUC: Utilize (non-ANSI-compliant) compiler support for local automatic arrays
00362      This results in more elegent loop structure and, theoretically, in faster performance
00363      20040225: In reality, the GNUC non-ANSI blocks fail on some large files
00364      This may be because they allocate significant local storage on the stack
00365      
00366      non-GNUC: Fully ANSI-compliant structure
00367      Fortran: Support deprecated */
00368   
00369 #define FXM_NCO315 1
00370 #ifdef FXM_NCO315
00371   long idx_op1;
00372 #endif /* __GNUC__ */
00373   const long sz_blk=sz_op1/sz_op2;
00374   long idx_op2;
00375   long idx_blk;
00376   double mss_val_dbl=double_CEWI;
00377   float mss_val_flt=float_CEWI;
00378   nco_char mss_val_chr;
00379   nco_byte mss_val_byt;
00380   nco_int mss_val_lng=nco_int_CEWI;
00381   short mss_val_sht=short_CEWI;
00382 
00383   /* Typecast pointer to values before access */
00384   (void)cast_void_nctype(type,&op1);
00385   (void)cast_void_nctype(type,&op2);
00386   if(has_mss_val) (void)cast_void_nctype(type,&mss_val);
00387 
00388   if(has_mss_val){
00389     switch(type){
00390     case NC_FLOAT: mss_val_flt=*mss_val.fp; break;
00391     case NC_DOUBLE: mss_val_dbl=*mss_val.dp; break;
00392     case NC_SHORT: mss_val_sht=*mss_val.sp; break;
00393     case NC_INT: mss_val_lng=*mss_val.lp; break;
00394     case NC_BYTE: mss_val_byt=*mss_val.bp; break;
00395     case NC_CHAR: mss_val_chr=*mss_val.cp; break;
00396     default: nco_dfl_case_nc_type_err(); break;
00397     } /* end switch */
00398   } /* endif */
00399 
00400   switch(type){
00401   case NC_FLOAT:
00402 #define FXM_NCO315 1
00403 #ifdef FXM_NCO315
00404     /* ANSI-compliant branch */
00405     if(!has_mss_val){ 
00406       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00407         /* Operations: 1 multiply 
00408            Repetitions: \dmnszavg^(\dmnnbr-\avgnbr)
00409            Total Counts: \rthnbr=\dmnszavg^(\dmnnbr-\avgnbr) */
00410         const long blk_off=idx_op2*sz_blk;
00411         /* Operations: 1 fp add, 3 pointer offsets, 3 user memory fetch
00412            Repetitions: \lmnnbr
00413            Total Counts: \flpnbr=\lmnnbr, \rthnbr=3\lmnnbr, \mmrusrnbr=3\lmnnbr,
00414            NB: Counted LHS+RHS+tally offsets and fetches */
00415         for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.fp[idx_op2]+=op1.fp[blk_off+idx_blk];
00416         tally[idx_op2]=sz_blk;
00417       } /* end loop over idx_op2 */
00418     }else{
00419       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00420         const long blk_off=idx_op2*sz_blk;
00421         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00422           idx_op1=blk_off+idx_blk;
00423           if(op1.fp[idx_op1] != mss_val_flt){
00424             op2.fp[idx_op2]+=op1.fp[idx_op1];
00425             tally[idx_op2]++;
00426           } /* end if */
00427         } /* end loop over idx_blk */
00428         if(tally[idx_op2] == 0L) op2.fp[idx_op2]=mss_val_flt;
00429       } /* end loop over idx_op2 */
00430     } /* end else */
00431 #else /* __GNUC__ */
00432     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00433     if(True){
00434       float op1_2D[sz_op2][sz_blk];
00435       
00436       (void)memcpy((void *)op1_2D,(void *)(op1.fp),sz_op1*nco_typ_lng(type));
00437       
00438       if(!has_mss_val){
00439         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00440           for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.fp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00441           tally[idx_op2]=sz_blk;
00442         } /* end loop over idx_op2 */
00443       }else{
00444         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00445           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00446             if(op1_2D[idx_op2][idx_blk] != mss_val_flt){
00447               op2.fp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00448               tally[idx_op2]++;
00449             } /* end if */
00450           } /* end loop over idx_blk */
00451           if(tally[idx_op2] == 0L) op2.fp[idx_op2]=mss_val_flt;
00452         } /* end loop over idx_op2 */
00453       } /* end else */
00454     } /* end if */
00455 #endif /* __GNUC__ */
00456     break;
00457   case NC_DOUBLE:
00458 #define FXM_NCO315 1
00459 #ifdef FXM_NCO315
00460     /* ANSI-compliant branch */
00461     if(!has_mss_val){
00462       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00463         const long blk_off=idx_op2*sz_blk;
00464         for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.dp[idx_op2]+=op1.dp[blk_off+idx_blk];
00465         tally[idx_op2]=sz_blk;
00466       } /* end loop over idx_op2 */
00467     }else{
00468       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00469         const long blk_off=idx_op2*sz_blk;
00470         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00471           idx_op1=blk_off+idx_blk;
00472           if(op1.dp[idx_op1] != mss_val_dbl){
00473             op2.dp[idx_op2]+=op1.dp[idx_op1];
00474             tally[idx_op2]++;
00475           } /* end if */
00476         } /* end loop over idx_blk */
00477         if(tally[idx_op2] == 0L) op2.dp[idx_op2]=mss_val_dbl;
00478       } /* end loop over idx_op2 */
00479     } /* end else */
00480 #else /* __GNUC__ */
00481     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00482     if(True){
00483       double op1_2D[sz_op2][sz_blk];
00484       
00485       (void)memcpy((void *)op1_2D,(void *)(op1.dp),sz_op1*nco_typ_lng(type));
00486       
00487       if(!has_mss_val){
00488         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00489           for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.dp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00490           tally[idx_op2]=sz_blk;
00491         } /* end loop over idx_op2 */
00492       }else{
00493         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00494           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00495             if(op1_2D[idx_op2][idx_blk] != mss_val_dbl){
00496               op2.dp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00497               tally[idx_op2]++;
00498             } /* end if */
00499           } /* end loop over idx_blk */
00500           if(tally[idx_op2] == 0L) op2.dp[idx_op2]=mss_val_dbl;
00501         } /* end loop over idx_op2 */
00502       } /* end else */
00503     } /* end if */
00504 #endif /* __GNUC__ */
00505     break;
00506   case NC_INT:
00507 #define FXM_NCO315 1
00508 #ifdef FXM_NCO315
00509     /* ANSI-compliant branch */
00510     if(!has_mss_val){
00511       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00512         const long blk_off=idx_op2*sz_blk;
00513         for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.lp[idx_op2]+=op1.lp[blk_off+idx_blk];
00514         tally[idx_op2]=sz_blk;
00515       } /* end loop over idx_op2 */
00516     }else{
00517       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00518         const long blk_off=idx_op2*sz_blk;
00519         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00520           idx_op1=blk_off+idx_blk;
00521           if(op1.lp[idx_op1] != mss_val_lng){
00522             op2.lp[idx_op2]+=op1.lp[idx_op1];
00523             tally[idx_op2]++;
00524           } /* end if */
00525         } /* end loop over idx_blk */
00526         if(tally[idx_op2] == 0L) op2.lp[idx_op2]=mss_val_lng;
00527       } /* end loop over idx_op2 */
00528     } /* end else */
00529 #else /* __GNUC__ */
00530     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00531     if(True){
00532       long op1_2D[sz_op2][sz_blk];
00533       
00534       (void)memcpy((void *)op1_2D,(void *)(op1.lp),sz_op1*nco_typ_lng(type));
00535       
00536       if(!has_mss_val){
00537         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00538           for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.lp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00539           tally[idx_op2]=sz_blk;
00540         } /* end loop over idx_op2 */
00541       }else{
00542         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00543           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00544             if(op1_2D[idx_op2][idx_blk] != mss_val_lng){
00545               op2.lp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00546               tally[idx_op2]++;
00547             } /* end if */
00548           } /* end loop over idx_blk */
00549           if(tally[idx_op2] == 0L) op2.lp[idx_op2]=mss_val_lng;
00550         } /* end loop over idx_op2 */
00551       } /* end else */
00552     } /* end if */
00553 #endif /* __GNUC__ */
00554     break;
00555   case NC_SHORT:
00556 #define FXM_NCO315 1
00557 #ifdef FXM_NCO315
00558     /* ANSI-compliant branch */
00559     if(!has_mss_val){
00560       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00561         const long blk_off=idx_op2*sz_blk;
00562         for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.sp[idx_op2]+=op1.sp[blk_off+idx_blk];
00563         tally[idx_op2]=sz_blk;
00564       } /* end loop over idx_op2 */
00565     }else{
00566       for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00567         const long blk_off=idx_op2*sz_blk;
00568         for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00569           idx_op1=blk_off+idx_blk;
00570           if(op1.sp[idx_op1] != mss_val_sht){
00571             op2.sp[idx_op2]+=op1.sp[idx_op1];
00572             tally[idx_op2]++;
00573           } /* end if */
00574         } /* end loop over idx_blk */
00575         if(tally[idx_op2] == 0L) op2.sp[idx_op2]=mss_val_sht;
00576       } /* end loop over idx_op2 */
00577     } /* end else */
00578 #else /* __GNUC__ */
00579     /* Compiler supports local automatic arrays. Not ANSI-compliant, but more elegant. */
00580     if(True){
00581       short op1_2D[sz_op2][sz_blk];
00582       
00583       (void)memcpy((void *)op1_2D,(void *)(op1.sp),sz_op1*nco_typ_lng(type));
00584       
00585       if(!has_mss_val){
00586         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00587           for(idx_blk=0;idx_blk<sz_blk;idx_blk++) op2.sp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00588           tally[idx_op2]=sz_blk;
00589         } /* end loop over idx_op2 */
00590       }else{
00591         for(idx_op2=0;idx_op2<sz_op2;idx_op2++){
00592           for(idx_blk=0;idx_blk<sz_blk;idx_blk++){
00593             if(op1_2D[idx_op2][idx_blk] != mss_val_sht){
00594               op2.sp[idx_op2]+=op1_2D[idx_op2][idx_blk];
00595               tally[idx_op2]++;
00596             } /* end if */
00597           } /* end loop over idx_blk */
00598           if(tally[idx_op2] == 0L) op2.sp[idx_op2]=mss_val_sht;
00599         } /* end loop over idx_op2 */
00600       } /* end else */
00601     } /* end if */
00602 #endif /* __GNUC__ */
00603     break;
00604   case NC_CHAR:
00605     /* Do nothing except avoid compiler warnings */
00606     mss_val_chr=mss_val_chr;
00607     break;
00608   case NC_BYTE:
00609     /* Do nothing except avoid compiler warnings */
00610     mss_val_byt=mss_val_byt;
00611     break;
00612   default: nco_dfl_case_nc_type_err(); break;
00613   } /* end switch */
00614   
00615   /* NB: it is not neccessary to un-typecast pointers to values after access 
00616      because we have only operated on local copies of them. */
00617 
00618 } /* end nco_var_avg_reduce_ttl() */


Generated on Thu Mar 16 18:16:31 2006 for nco by  doxygen 1.4.4