#include <stdio.h>#include <stdlib.h>#include <string.h>#include <netcdf.h>#include "nco_netcdf.h"#include "nco.h"#include "nco_ctl.h"#include "nco_lst_utl.h"#include "nco_mmr.h"#include "nco_rth_utl.h"#include "nco_var_utl.h"Include dependency graph for nco_cnf_dmn.h:

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

Go to the source code of this file.
Functions | |
| var_sct * | nco_var_cnf_dmn (const var_sct *const var, var_sct *const wgt, var_sct *wgt_crr, const nco_bool MUST_CONFORM, nco_bool *DO_CONFORM) |
| bool | ncap_var_cnf_dmn (var_sct **var_1, var_sct **var_2) |
| dmn_sct ** | nco_dmn_avg_rdr_prp (dmn_sct **const dmn_in, char **dmn_rdr_lst, const int dmn_rdr_nbr) |
| char * | nco_var_dmn_rdr_mtd (const var_sct *const var_in, var_sct *const var_out, CST_X_PTR_CST_PTR_CST_Y(dmn_sct, dmn_rdr), const int dmn_rdr_nbr, int *const dmn_idx_out_in, const nco_bool *const dmn_rvr_rdr, nco_bool *const dmn_rvr_in) |
| int | nco_var_dmn_rdr_val (const var_sct *const var_in, var_sct *const var_out, const int *const dmn_idx_out_in, const nco_bool *const dmn_rvr_in) |
|
||||||||||||
|
Definition at line 331 of file nco_cnf_dmn.c. References EXIT_FAILURE, var_sct_tag::nbr_dim, nco_bool, nco_exit(), nco_var_cnf_dmn(), nco_var_free(), prg_nm_get(), and True. Referenced by main(), ncap_var_var_add(), ncap_var_var_dvd(), ncap_var_var_mlt(), ncap_var_var_mod(), ncap_var_var_op(), ncap_var_var_pwr(), and ncap_var_var_sub(). 00333 { 00334 /* Purpose: Conform lesser ranked to greater ranked variable, so that 00335 both variables are equal size on return. 00336 If this is possible then return true, otherwise die. 00337 Routine wraps nco_var_cnf_dmn(), which does the hard work 00338 If an input variable is replaced by a broadcast version of itself, 00339 then calling routine must free original version or it will leak. */ 00340 00341 nco_bool DO_CONFORM; /* [flg] Do var_1 and var_2 conform after processing? */ 00342 nco_bool MUST_CONFORM=True; /* [flg] Must var_1 and var_2 conform? */ 00343 var_sct *var_1_org; /* [ptr] Original location of var_1 */ 00344 var_sct *var_2_org; /* [ptr] Original location of var_2 */ 00345 var_sct *var_tmp=NULL; 00346 00347 var_1_org=*var_1; /* [ptr] Original location of var_1 */ 00348 var_2_org=*var_2; /* [ptr] Original location of var_2 */ 00349 00350 if(var_1_org->nbr_dim > var_2_org->nbr_dim){ 00351 var_tmp=nco_var_cnf_dmn(var_1_org,var_2_org,var_tmp,MUST_CONFORM,&DO_CONFORM); 00352 if(var_2_org != var_tmp){ 00353 var_2_org=nco_var_free(var_2_org); 00354 *var_2=var_tmp; 00355 } /* endif replace var_2 */ 00356 }else{ 00357 var_tmp=nco_var_cnf_dmn(var_2_org,var_1_org,var_tmp,MUST_CONFORM,&DO_CONFORM); 00358 if(var_1_org != var_tmp){ 00359 var_1_org=nco_var_free(var_1_org); 00360 *var_1=var_tmp; 00361 } /* endif replace var_1 */ 00362 } /* endif var_1 > var_2 */ 00363 00364 if(!DO_CONFORM){ 00365 (void)fprintf(stderr,"%s: ncap_var_cnf_dmn() reports that variables %s and %s do not have have conforming dimensions. Cannot proceed with operation\n",prg_nm_get(),(*var_1)->nm,(*var_2)->nm); 00366 nco_exit(EXIT_FAILURE); 00367 } /* endif */ 00368 00369 return DO_CONFORM; /* [flg] Do var_1 and var_2 conform after processing? */ 00370 } /* end ncap_var_cnf_dmn() */
|
|
||||||||||||||||
|
|
|
||||||||||||||||||||||||
|
Definition at line 13 of file nco_cnf_dmn.c. References var_sct_tag::cnt, dbg_lvl_get(), var_sct_tag::dim, EXIT_FAILURE, False, var_sct_tag::id, var_sct_tag::nbr_dim, NC_MAX_DIMS, nco_bool, nco_exit(), nco_free(), nco_malloc(), nco_typ_lng(), nco_var_dpl(), nco_var_free(), nco_xrf_var(), var_sct_tag::nm, dmn_sct_tag::nm, prg_nm_get(), var_sct_tag::sz, True, var_sct_tag::type, var_sct_tag::val, vec_set(), and ptr_unn::vp. Referenced by main(), and ncap_var_cnf_dmn(). 00018 { 00019 /* Threads: Routine is thread safe and calls no unsafe routines */ 00020 /* fxm: TODO 226. Is xrf in nco_var_cnf_dmn() really necessary? If not, remove it and make wgt arg const var_sct * const */ 00021 00022 /* Purpose: Stretch second variable to match dimensions of first variable 00023 Dimensions in var which are not in wgt will be present in wgt_out, with values 00024 replicated from existing dimensions in wgt. 00025 By default, wgt's dimensions must be subset of var's dimensions (MUST_CONFORM=true) 00026 Calling routine should set MUST_CONFORM=false if wgt and var need not conform 00027 When wgt and var do not conform then then nco_var_cnf_dmn sets *DO_CONFORM=False and returns copy of var with all values set to 1.0 00028 Calling procedure then decides what to do with unity output 00029 MUST_CONFORM is True for ncbo: Variables of like name to be, e.g., differenced, must be same rank 00030 MUST_CONFORM is False false for ncap, ncflint, ncwa: Some variables to be averaged may not conform to the specified weight, e.g., lon will not conform to gw. This is fine and returned wgt_out may be discarded. */ 00031 00032 /* There are many inelegant ways to accomplish this (without using C++): */ 00033 00034 /* Perhaps most efficient method in general case is to expand weight array until 00035 it is same size as variable array, and then multiply these arrays together 00036 element-by-element in highly vectorized loop (possibly in Fortran or BLAS). 00037 To enhance speed, (enlarged) weight-values array could be static, only re-made 00038 when dimensions of incoming variables change. */ 00039 00040 /* Another general method, though more expensive, is to use C to figure out the 00041 multidimensional indices into the one dimensional hyperslab, a la ncks. 00042 Knowing these indices, routine could loop over the one-dimensional array 00043 element by element, choosing the appropriate index into the weight array from 00044 those same multidimensional indices. 00045 This method can also create a static weight-value array that is only destroyed 00046 when an incoming variable changes dimensions from the previous variable. */ 00047 00048 /* Another method, which is not completely general, but which may be good enough for 00049 governement work, is to create Fortran subroutines which expect variables of 00050 a given number of dimensions as input. 00051 Creating these functions for up to five dimensions would satisfy most situations 00052 C code would determine which branch to call based on number of dimensions 00053 C++ or Fortran9x overloading could construct this interface more elegantly */ 00054 00055 /* An (untested) simplification to some of these methods is to copy the 1-D array 00056 value pointer of variable and cast it to an N-D array pointer 00057 Then C could handle indexing 00058 This method easily produce working, but non-general code 00059 Implementation would require ugly branches or hard-to-understand recursive function calls */ 00060 00061 /* Routine assumes weight will never have more dimensions than variable 00062 (otherwise which hyperslab of weight to use would be ill-defined). 00063 However, weight may (and often will) have fewer dimensions than variable */ 00064 00065 nco_bool CONFORMABLE=False; /* [flg] wgt can be made to conform to var */ 00066 nco_bool USE_DUMMY_WGT=False; /* [flg] Fool NCO into thinking wgt conforms to var */ 00067 00068 int idx; /* [idx] Counting index */ 00069 int idx_dmn; /* [idx] Dimension index */ 00070 int wgt_var_dmn_shr_nbr=0; /* [nbr] Number of dimensions wgt and var share */ 00071 00072 var_sct *wgt_out=NULL; 00073 00074 /* Initialize flag to false. Overwrite by true after successful conformance */ 00075 *DO_CONFORM=False; 00076 00077 /* Does current weight (wgt_crr) conform to variable's dimensions? */ 00078 if(wgt_crr != NULL){ 00079 /* Test rank first because wgt_crr because of 19960218 bug (invalid dmn_id in old wgt_crr leads to match) */ 00080 if(var->nbr_dim == wgt_crr->nbr_dim){ 00081 /* Test whether all wgt and var dimensions match in sequence */ 00082 for(idx=0;idx<var->nbr_dim;idx++){ 00083 if(strcmp(wgt_crr->dim[idx]->nm,var->dim[idx]->nm)) break; 00084 } /* end loop over dimensions */ 00085 if(idx == var->nbr_dim) *DO_CONFORM=True; 00086 } /* end if ranks are equal */ 00087 if(*DO_CONFORM){ 00088 wgt_out=wgt_crr; 00089 }else{ 00090 wgt_crr=nco_var_free(wgt_crr); 00091 wgt_out=NULL; 00092 } /* !*DO_CONFORM */ 00093 } /* wgt_crr == NULL */ 00094 00095 /* Does original weight (wgt) conform to variable's dimensions? */ 00096 if(wgt_out == NULL){ 00097 if(var->nbr_dim > 0){ 00098 /* Test that all dimensions in wgt appear in var */ 00099 for(idx=0;idx<wgt->nbr_dim;idx++){ 00100 for(idx_dmn=0;idx_dmn<var->nbr_dim;idx_dmn++){ 00101 /* Compare names, not dimension IDs */ 00102 if(!strcmp(wgt->dim[idx]->nm,var->dim[idx_dmn]->nm)){ 00103 wgt_var_dmn_shr_nbr++; /* wgt and var share this dimension */ 00104 break; 00105 } /* endif */ 00106 } /* end loop over var dimensions */ 00107 } /* end loop over wgt dimensions */ 00108 /* Decide whether wgt and var dimensions conform, are mutually exclusive, or are partially exclusive (an error) */ 00109 if(wgt_var_dmn_shr_nbr == wgt->nbr_dim){ 00110 /* wgt and var conform */ 00111 CONFORMABLE=True; 00112 }else if(wgt_var_dmn_shr_nbr == 0){ 00113 /* Dimensions in wgt and var are mutually exclusive */ 00114 CONFORMABLE=False; 00115 if(MUST_CONFORM){ 00116 (void)fprintf(stdout,"%s: ERROR %s and template %s share no dimensions\n",prg_nm_get(),wgt->nm,var->nm); 00117 nco_exit(EXIT_FAILURE); 00118 }else{ 00119 if(dbg_lvl_get() > 2) (void)fprintf(stdout,"\n%s: DEBUG %s and template %s share no dimensions: Not broadcasting %s to %s\n",prg_nm_get(),wgt->nm,var->nm,wgt->nm,var->nm); 00120 USE_DUMMY_WGT=True; 00121 } /* endif */ 00122 }else if(wgt->nbr_dim > var->nbr_dim){ 00123 /* wgt is larger rank than var---no possibility of conforming */ 00124 CONFORMABLE=False; 00125 if(MUST_CONFORM){ 00126 (void)fprintf(stdout,"%s: ERROR %s is rank %d but template %s is rank %d: Impossible to broadcast\n",prg_nm_get(),wgt->nm,wgt->nbr_dim,var->nm,var->nbr_dim); 00127 nco_exit(EXIT_FAILURE); 00128 }else{ 00129 if(dbg_lvl_get() > 2) (void)fprintf(stdout,"\n%s: DEBUG %s is rank %d but template %s is rank %d: Not broadcasting %s to %s\n",prg_nm_get(),wgt->nm,wgt->nbr_dim,var->nm,var->nbr_dim,wgt->nm,var->nm); 00130 USE_DUMMY_WGT=True; 00131 } /* endif */ 00132 }else if(wgt_var_dmn_shr_nbr > 0 && wgt_var_dmn_shr_nbr < wgt->nbr_dim){ 00133 /* Some, but not all, of wgt dimensions are in var */ 00134 CONFORMABLE=False; 00135 if(MUST_CONFORM){ 00136 (void)fprintf(stdout,"%s: ERROR %d dimensions of %s belong to template %s but %d dimensions do not\n",prg_nm_get(),wgt_var_dmn_shr_nbr,wgt->nm,var->nm,wgt->nbr_dim-wgt_var_dmn_shr_nbr); 00137 nco_exit(EXIT_FAILURE); 00138 }else{ 00139 if(dbg_lvl_get() > 2) (void)fprintf(stdout,"\n%s: DEBUG %d dimensions of %s belong to template %s but %d dimensions do not: Not broadcasting %s to %s\n",prg_nm_get(),wgt_var_dmn_shr_nbr,wgt->nm,var->nm,wgt->nbr_dim-wgt_var_dmn_shr_nbr,wgt->nm,var->nm); 00140 USE_DUMMY_WGT=True; 00141 } /* endif */ 00142 } /* end if */ 00143 if(USE_DUMMY_WGT){ 00144 /* Variables do not truly conform, but this might be OK, depending on the application, so set DO_CONFORM flag to false and ... */ 00145 *DO_CONFORM=False; 00146 /* ... return a dummy weight of 1.0, which allows program logic to pretend variable is weighted, but does not change answers */ 00147 wgt_out=nco_var_dpl(var); 00148 (void)vec_set(wgt_out->type,wgt_out->sz,wgt_out->val,1.0); 00149 } /* endif */ 00150 if(CONFORMABLE){ 00151 if(var->nbr_dim == wgt->nbr_dim){ 00152 /* var and wgt conform and are same rank */ 00153 /* Test whether all wgt and var dimensions match in sequence */ 00154 for(idx=0;idx<var->nbr_dim;idx++){ 00155 if(strcmp(wgt->dim[idx]->nm,var->dim[idx]->nm)) break; 00156 /* if(wgt->dmn_id[idx] != var->dmn_id[idx]) break;*/ 00157 } /* end loop over dimensions */ 00158 /* If so, take shortcut and copy wgt to wgt_out */ 00159 if(idx == var->nbr_dim) *DO_CONFORM=True; 00160 }else{ 00161 /* var and wgt conform but are not same rank, set flag to proceed to generic conform routine */ 00162 *DO_CONFORM=False; 00163 } /* end else */ 00164 } /* endif CONFORMABLE */ 00165 }else{ 00166 /* var is scalar, if wgt is also then set flag to copy wgt to wgt_out else proceed to generic conform routine */ 00167 if(wgt->nbr_dim == 0) *DO_CONFORM=True; else *DO_CONFORM=False; 00168 } /* end else */ 00169 if(CONFORMABLE && *DO_CONFORM){ 00170 wgt_out=nco_var_dpl(wgt); 00171 (void)nco_xrf_var(wgt,wgt_out); 00172 } /* end if */ 00173 } /* end if */ 00174 00175 if(wgt_out == NULL){ 00176 /* Expand original weight (wgt) to match size of current variable */ 00177 char * restrict wgt_cp; 00178 char * restrict wgt_out_cp; 00179 00180 int idx_wgt_var[NC_MAX_DIMS]; 00181 /* int idx_var_wgt[NC_MAX_DIMS];*/ 00182 int wgt_nbr_dim; 00183 int var_nbr_dmn_m1; 00184 00185 long * restrict var_cnt; 00186 long dmn_ss[NC_MAX_DIMS]; 00187 long dmn_var_map[NC_MAX_DIMS]; 00188 long dmn_wgt_map[NC_MAX_DIMS]; 00189 long var_lmn; 00190 long wgt_lmn; 00191 long var_sz; 00192 00193 size_t wgt_typ_sz; 00194 00195 /* Copy main attributes of variable into ouput weight */ 00196 wgt_out=nco_var_dpl(var); 00197 (void)nco_xrf_var(wgt,wgt_out); 00198 00199 /* wgt_out variable was copied from template var 00200 Modify key fields so its name and type are based on wgt, not var 00201 wgt_out will then be hybrid between wgt and var 00202 Remainder of routine fills wgt_out's var-dimensionality with wgt-values */ 00203 wgt_out->nm=(char *)nco_free(wgt_out->nm); 00204 wgt_out->nm=(char *)strdup(wgt->nm); 00205 wgt_out->id=wgt->id; 00206 wgt_out->type=wgt->type; 00207 wgt_out->val.vp=(void *)nco_free(wgt_out->val.vp); 00208 wgt_out->val.vp=(void *)nco_malloc(wgt_out->sz*nco_typ_lng(wgt_out->type)); 00209 wgt_cp=(char *)wgt->val.vp; 00210 wgt_out_cp=(char *)wgt_out->val.vp; 00211 wgt_typ_sz=nco_typ_lng(wgt_out->type); 00212 00213 if(wgt_out->nbr_dim == 0){ 00214 /* Variable (and weight) are scalars, not arrays */ 00215 (void)memcpy(wgt_out_cp,wgt_cp,wgt_typ_sz); 00216 }else if(wgt->nbr_dim == 0){ 00217 /* Lesser-ranked input variable is scalar 00218 Expansion in this degenerate case needs no index juggling (reverse-mapping) 00219 Code as special case to speed-up important applications of ncap 00220 for synthetic file creation */ 00221 var_sz=var->sz; 00222 for(var_lmn=0;var_lmn<var_sz;var_lmn++){ 00223 (void)memcpy(wgt_out_cp+var_lmn*wgt_typ_sz,wgt_cp,wgt_typ_sz); 00224 } /* end loop over var_lmn */ 00225 }else{ 00226 /* Variable (and therefore wgt_out) are arrays, not scalars */ 00227 00228 /* Create forward and reverse mappings from variable's dimensions to weight's dimensions: 00229 00230 dmn_var_map[i] is number of elements between one value of i_th 00231 dimension of variable and next value of i_th dimension, i.e., 00232 number of elements in memory between indicial increments in i_th dimension. 00233 This is computed as product of one (1) times size of all dimensions (if any) after i_th 00234 dimension in variable. 00235 00236 dmn_wgt_map[i] contains analogous information, except for original weight variable 00237 00238 idx_wgt_var[i] contains index into variable's dimensions of i_th dimension of original weight 00239 idx_var_wgt[i] contains index into original weight's dimensions of i_th dimension of variable 00240 00241 Since weight is a subset of variable, some elements of idx_var_wgt may be "empty", or unused 00242 00243 Since mapping arrays (dmn_var_map and dmn_wgt_map) are ultimately used for a 00244 memcpy() operation, they could (read: should) be computed as byte offsets, not type offsets. 00245 This is why netCDF generic hyperslab routines (ncvarputg(), ncvargetg()) 00246 request imap vector to specify offset (imap) vector in bytes. */ 00247 00248 for(idx=0;idx<wgt->nbr_dim;idx++){ 00249 for(idx_dmn=0;idx_dmn<var->nbr_dim;idx_dmn++){ 00250 /* Compare names, not dimension IDs */ 00251 if(!strcmp(var->dim[idx_dmn]->nm,wgt->dim[idx]->nm)){ 00252 idx_wgt_var[idx]=idx_dmn; 00253 /* idx_var_wgt[idx_dmn]=idx;*/ 00254 break; 00255 } /* end if */ 00256 /* Sanity check */ 00257 if(idx_dmn == var->nbr_dim-1){ 00258 (void)fprintf(stdout,"%s: ERROR wgt %s has dimension %s but var %s does not deep in nco_var_cnf_dmn()\n",prg_nm_get(),wgt->nm,wgt->dim[idx]->nm,var->nm); 00259 nco_exit(EXIT_FAILURE); 00260 } /* end if err */ 00261 } /* end loop over variable dimensions */ 00262 } /* end loop over weight dimensions */ 00263 00264 /* Figure out map for each dimension of variable */ 00265 for(idx=0;idx<var->nbr_dim;idx++) dmn_var_map[idx]=1L; 00266 for(idx=0;idx<var->nbr_dim-1;idx++) 00267 for(idx_dmn=idx+1;idx_dmn<var->nbr_dim;idx_dmn++) 00268 dmn_var_map[idx]*=var->cnt[idx_dmn]; 00269 00270 /* Figure out map for each dimension of weight */ 00271 for(idx=0;idx<wgt->nbr_dim;idx++) dmn_wgt_map[idx]=1L; 00272 for(idx=0;idx<wgt->nbr_dim-1;idx++) 00273 for(idx_dmn=idx+1;idx_dmn<wgt->nbr_dim;idx_dmn++) 00274 dmn_wgt_map[idx]*=wgt->cnt[idx_dmn]; 00275 00276 /* Define convenience variables to avoid repetitive indirect addressing */ 00277 wgt_nbr_dim=wgt->nbr_dim; 00278 var_sz=var->sz; 00279 var_cnt=var->cnt; 00280 var_nbr_dmn_m1=var->nbr_dim-1; 00281 00282 /* var_lmn is offset into 1-D array corresponding to N-D indices dmn_ss */ 00283 for(var_lmn=0;var_lmn<var_sz;var_lmn++){ 00284 /* dmn_ss are corresponding indices (subscripts) into N-D array */ 00285 /* Operations: 1 modulo, 1 pointer offset, 1 user memory fetch 00286 Repetitions: \lmnnbr 00287 Total Counts: \rthnbr=2\lmnnbr, \mmrusrnbr=\lmnnbr 00288 NB: LHS assumed compact and cached, counted RHS offsets and fetches only */ 00289 dmn_ss[var_nbr_dmn_m1]=var_lmn%var_cnt[var_nbr_dmn_m1]; 00290 for(idx=0;idx<var_nbr_dmn_m1;idx++){ 00291 /* Operations: 1 divide, 1 modulo, 2 pointer offset, 2 user memory fetch 00292 Repetitions: \lmnnbr(\dmnnbr-1) 00293 Counts: \rthnbr=4\lmnnbr(\dmnnbr-1), \mmrusrnbr=2\lmnnbr(\dmnnbr-1) 00294 NB: LHS assumed compact and cached, counted RHS offsets and fetches only 00295 NB: Neglected loop arithmetic/compare */ 00296 dmn_ss[idx]=(long)(var_lmn/dmn_var_map[idx]); 00297 dmn_ss[idx]%=var_cnt[idx]; 00298 } /* end loop over dimensions */ 00299 00300 /* Map (shared) N-D array indices into 1-D index into original weight data */ 00301 wgt_lmn=0L; 00302 /* Operations: 1 add, 1 multiply, 3 pointer offset, 3 user memory fetch 00303 Repetitions: \lmnnbr\rnkwgt 00304 Counts: \rthnbr=5\lmnnbr\rnkwgt, \mmrusrnbr=3\lmnnbr\rnkwgt */ 00305 for(idx=0;idx<wgt_nbr_dim;idx++) wgt_lmn+=dmn_ss[idx_wgt_var[idx]]*dmn_wgt_map[idx]; 00306 00307 /* Operations: 2 add, 2 multiply, 0 pointer offset, 1 system memory copy 00308 Repetitions: \lmnnbr 00309 Counts: \rthnbr=4\lmnnbr, \mmrusrnbr=0, \mmrsysnbr=1 */ 00310 (void)memcpy(wgt_out_cp+var_lmn*wgt_typ_sz,wgt_cp+wgt_lmn*wgt_typ_sz,wgt_typ_sz); 00311 00312 } /* end loop over var_lmn */ 00313 00314 } /* end if variable (and weight) are arrays, not scalars */ 00315 00316 *DO_CONFORM=True; 00317 } /* end if we had to stretch weight to fit variable */ 00318 00319 if(*DO_CONFORM == -1){ 00320 (void)fprintf(stdout,"%s: ERROR *DO_CONFORM == -1 on exit from nco_var_cnf_dmn()\n",prg_nm_get()); 00321 nco_exit(EXIT_FAILURE); 00322 } /* endif */ 00323 00324 /* Current weight (wgt_out) now conforms to current variable */ 00325 return wgt_out; 00326 00327 } /* end nco_var_cnf_dmn() */
|
|
||||||||||||||||||||||||||||||||
|
Definition at line 374 of file nco_cnf_dmn.c. References dmn_sct_tag::cnt, dbg_lvl_get(), var_sct_tag::dim, var_sct_tag::dmn_id, dmn_sct_tag::end, EXIT_FAILURE, False, dmn_sct_tag::id, dmn_sct_tag::is_rec_dmn, var_sct_tag::nbr_dim, NC_MAX_DIMS, nco_cmp_int(), nco_exit(), nco_free(), nco_malloc(), NCO_REC_DMN_UNDEFINED, var_sct_tag::nm, dmn_sct_tag::nm, prg_nm_get(), dmn_sct_tag::srd, dmn_sct_tag::srt, and dmn_sct_tag::xrf. Referenced by main(). 00381 { 00382 /* Purpose: Re-order dimensions in a given variable 00383 dmn_rdr contains new dimension order for dimensions 00384 Currently routine allows only dimension permutations, i.e., 00385 re-arranging dimensions without changing their number (variable rank). 00386 00387 Routine keeps track of two variables var_* whose abbreviations are: 00388 in: Input variable (already hyperslabbed) with old dimension ordering 00389 rdr: User-specified re-ordered dimension list. Possibly subset of dmn_in 00390 out: Output (re-ordered) dimensionality specific to each variable 00391 00392 At first it seemed this routine could re-order input variable in place without copying it 00393 Multiple constraints keep this from being practical 00394 Constraints are dictated by the architectural decision to call nco_var_dmn_rdr_mtd() twice 00395 Decision to call nco_var_dmn_rdr_mtd() twice is based on: 00396 1. Want to parallelize loop over variables to increase throughput 00397 Parallel writes to output file only possible if output file is defined in shape, order 00398 Output file only definable once variable shapes, i.e., re-ordered dimensions known 00399 Alternatives to calling nco_var_dmn_rdr_mtd() twice: 00400 A. Each thread enters redefine() mode and adds its variable to output file 00401 Internal data re-copying would be expensive and unnecessary 00402 Hence Alternative A is not viable 00403 B. Perform output file definition and all writes after all variable re-ordering 00404 Memory consumption would increase to O(fl_in_sz) to keep all re-ordered data in memory 00405 Hence Alternative B is not viable 00406 2. The two calls to nco_var_dmn_rdr_mtd() accomplish the following 00407 A. First call: Create var_out->dim for call to nco_var_dfn() 00408 Main thread makes first call in serial mode just prior to nco_var_dfn() 00409 No input data (AOT metadata) have been allocated or read in at this point 00410 Routine exits after modifying var_out metadata for new dimension geometry 00411 B. Second call: Re-order var_in->val data and place in var_out 00412 Although var_out->dmn is retained between calls, intermediate information such as 00413 in_out dimension mapping arrays are lost and must be re-created 00414 Hence second call must re-do most of first call, then begin re-ordering 00415 Routine must access un-touched var_in->dim input structure during both parts of second call 00416 Hence var_in must be unmodified between first and second call 00417 00418 dmn_rdr is user-specified list of dimensions to be re-arranged 00419 User specifies all or only a subset of all dimensions in input file 00420 For example, say user specifies -d lat,lon 00421 This ensures lat precedes lon in all variables in output file 00422 In this case dmn_rdr is (user-specified) list [lat,lon] 00423 Input 0-D variables dimensioned [] output with dmn_out=[] (unaltered) 00424 Input 1-D variables dimensioned [lat] output with dmn_out=[lat] (unaltered) 00425 Input 2-D variables dimensioned [lat,lon] output with dmn_out=[lat,lon] (unaltered) 00426 Input 2-D variables dimensioned [time,lev] output with dmn_out=[time,lev] (unaltered) 00427 Input 2-D variables dimensioned [lon,lat] output with dmn_out=[lon,lat] (transposed) 00428 Input 3-D variables dimensioned [lon,lat,time] output with dmn_out=[lat,lon,time] 00429 Input 3-D variables dimensioned [time,lon,lat] output with dmn_out=[time,lat,lon] 00430 Input 3-D variables dimensioned [lon,lev,lat] output with dmn_out=[lat,lev,lon] 00431 Input 4-D variables dimensioned [lon,lev,lat,time] output with dmn_out=[lat,lev,lon,time] 00432 Hence output dimension dmn_out list depends on each particular variable 00433 Some, or even all, dimensions in dmn_rdr may not be in dmn_in 00434 Re-ordering is only necessary for variables where dmn_in and dmn_rdr share at least two dimensions 00435 00436 Dimension reversal: 00437 Users specify dimension reversal by prefixing dimension name with negative sign 00438 Host routine passes dimension reversing flags in dmn_rvr_rdr 00439 Dimensions may be re-ordered, reversed, or both */ 00440 00441 const char fnc_nm[]="nco_var_dmn_rdr_mtd()"; /* [sng] Function name */ 00442 00443 char *rec_dmn_nm_out=NULL; /* [sng] Name of record dimension, if any, required by re-order */ 00444 00445 dmn_sct **dmn_in=NULL; /* [sct] List of dimension structures in input order */ 00446 dmn_sct **dmn_out; /* [sct] List of dimension structures in output order */ 00447 00448 int dmn_idx_in_shr[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->share Purely diagnostic */ 00449 int dmn_idx_in_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->output */ 00450 int dmn_idx_in_rdr[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->re-order NB: Purely diagnostic */ 00451 int dmn_idx_rdr_in[NC_MAX_DIMS]; /* [idx] Dimension correspondence, re-order->input NB: Purely diagnostic */ 00452 int dmn_idx_shr_rdr[NC_MAX_DIMS]; /* [idx] Dimension correspondence, share->re-order */ 00453 int dmn_idx_shr_in[NC_MAX_DIMS]; /* [idx] Dimension correspondence, share->input */ 00454 int dmn_idx_shr_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, share->output */ 00455 int dmn_idx_rec_out=NCO_REC_DMN_UNDEFINED; /* [idx] Record dimension index in output variable */ 00456 int dmn_shr_nbr=0; /* [nbr] Number of dimensions dmn_in and dmn_rdr share */ 00457 int dmn_in_idx; /* [idx] Counting index for dmn_in */ 00458 int dmn_in_nbr; /* [nbr] Number of dimensions in input variable */ 00459 int dmn_out_idx; /* [idx] Counting index for dmn_out */ 00460 int dmn_out_nbr; /* [nbr] Number of dimensions in output variable */ 00461 int dmn_rdr_idx; /* [idx] Counting index for dmn_rdr */ 00462 int dmn_shr_idx; /* [idx] Counting index for dmn_shr */ 00463 int idx_err=-99999; /* [idx] Invalid index for debugging */ 00464 00465 /* Initialize variables to reduce indirection */ 00466 /* NB: Number of input and output dimensions are equal for pure re-orders 00467 However, keep dimension numbers in separate variables to ease relax this rule in future */ 00468 dmn_in_nbr=var_in->nbr_dim; 00469 dmn_out_nbr=var_out->nbr_dim; 00470 00471 /* Initialize dimension maps to missing_value to aid debugging */ 00472 if(dbg_lvl_get() > 3){ 00473 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++) 00474 dmn_idx_out_in[dmn_out_idx]=idx_err; 00475 for(dmn_rdr_idx=0;dmn_rdr_idx<dmn_rdr_nbr;dmn_rdr_idx++) 00476 dmn_idx_rdr_in[dmn_rdr_idx]=idx_err; 00477 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++){ 00478 dmn_idx_in_shr[dmn_in_idx]=idx_err; 00479 dmn_idx_in_rdr[dmn_in_idx]=idx_err; 00480 dmn_idx_shr_rdr[dmn_in_idx]=idx_err; /* fxm: initialize up to dmn_shr_nbr which is currently unknown */ 00481 dmn_idx_shr_in[dmn_in_idx]=idx_err; /* fxm: initialize up to dmn_shr_nbr which is currently unknown */ 00482 dmn_idx_shr_out[dmn_in_idx]=idx_err; /* fxm: initialize up to dmn_shr_nbr which is currently unknown */ 00483 } /* end loop over dmn_in */ 00484 } /* end if dbg */ 00485 00486 /* Initialize default correspondence and record dimension in case early return desired */ 00487 if(var_out->is_rec_var) rec_dmn_nm_out=var_in->dim[0]->nm; 00488 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++){ 00489 dmn_idx_out_in[dmn_in_idx]=dmn_in_idx; 00490 dmn_rvr_in[dmn_in_idx]=False; 00491 } /* end if */ 00492 00493 /* Scalars are never altered by dimension re-ordering or reversal */ 00494 if(dmn_in_nbr < 1) return rec_dmn_nm_out; 00495 00496 /* On entry to this section of code, we assume: 00497 1. var_out duplicates var_in */ 00498 00499 /* Create complete 1-to-1 ordered list of dimensions in new output variable */ 00500 /* For each dimension in re-ordered dimension list... */ 00501 for(dmn_rdr_idx=0;dmn_rdr_idx<dmn_rdr_nbr;dmn_rdr_idx++){ 00502 /* ...see if re-order dimension exists in dmn_in dimension list... */ 00503 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++){ 00504 /* ...by comparing names, not dimension IDs... */ 00505 if(!strcmp(var_in->dim[dmn_in_idx]->nm,dmn_rdr[dmn_rdr_idx]->nm)){ 00506 dmn_idx_in_rdr[dmn_in_idx]=dmn_rdr_idx; 00507 dmn_idx_rdr_in[dmn_rdr_idx]=dmn_in_idx; 00508 dmn_idx_shr_rdr[dmn_shr_nbr]=dmn_rdr_idx; 00509 dmn_idx_shr_in[dmn_shr_nbr]=dmn_in_idx; 00510 dmn_idx_in_shr[dmn_in_idx]=dmn_shr_nbr; 00511 dmn_shr_nbr++; /* dmn_in and dmn_rdr share this dimension */ 00512 break; 00513 } /* endif */ 00514 } /* end loop over dmn_in */ 00515 } /* end loop over dmn_rdr */ 00516 00517 /* Map permanent list of reversed dimensions to input variable */ 00518 for(dmn_shr_idx=0;dmn_shr_idx<dmn_shr_nbr;dmn_shr_idx++) 00519 dmn_rvr_in[dmn_idx_shr_in[dmn_shr_idx]]=dmn_rvr_rdr[dmn_idx_shr_rdr[dmn_shr_idx]]; 00520 00521 /* No dimension re-ordering is necessary if dmn_in and dmn_rdr share fewer than two dimensions 00522 Dimension reversal must be done with even one shared dimension 00523 Single dimension reversal, however, uses default dimension maps and return values */ 00524 if(dmn_shr_nbr < 2) return rec_dmn_nm_out; 00525 00526 /* dmn_idx_shr_out is sorted version of dmn_idx_shr_in */ 00527 (void)memcpy((void *)(dmn_idx_shr_out),(void *)(dmn_idx_shr_in),dmn_shr_nbr*sizeof(dmn_idx_shr_in[0])); 00528 qsort(dmn_idx_shr_out,(size_t)dmn_shr_nbr,sizeof(dmn_idx_shr_out[0]),nco_cmp_int); 00529 00530 /* Initialize final map to no re-ordering */ 00531 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) 00532 dmn_idx_in_out[dmn_in_idx]=dmn_in_idx; 00533 00534 /* Splice in re-ordered dimension location for each shared dimension */ 00535 for(dmn_shr_idx=0;dmn_shr_idx<dmn_shr_nbr;dmn_shr_idx++) 00536 dmn_idx_in_out[dmn_idx_shr_in[dmn_shr_idx]]=dmn_idx_shr_out[dmn_shr_idx]; 00537 00538 if(dbg_lvl_get() > 3){ 00539 (void)fprintf(stdout,"%s: DEBUG %s variable %s shares %d of its %d dimensions with the %d dimensions in the re-order list\n",prg_nm_get(),fnc_nm,var_in->nm,dmn_shr_nbr,var_in->nbr_dim,dmn_rdr_nbr); 00540 (void)fprintf(stdout,"shr_idx\tshr_rdr\tshr_in\tshr_out\n"); 00541 for(dmn_shr_idx=0;dmn_shr_idx<dmn_shr_nbr;dmn_shr_idx++) 00542 (void)fprintf(stdout,"%d\t%d\t%d\t%d\n",dmn_shr_idx,dmn_idx_shr_rdr[dmn_shr_idx],dmn_idx_shr_in[dmn_shr_idx],dmn_idx_shr_out[dmn_shr_idx]); 00543 (void)fprintf(stdout,"in_idx\tin_shr\tin_rdr\tin_out\trvr_flg\n"); 00544 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) 00545 (void)fprintf(stdout,"%d\t%d\t%d\t%d\t%s\n",dmn_in_idx,dmn_idx_in_shr[dmn_in_idx],dmn_idx_in_rdr[dmn_in_idx],dmn_idx_in_out[dmn_in_idx],(dmn_rvr_in[dmn_in_idx]) ? "true" : "false"); 00546 } /* end if dbg */ 00547 00548 /* Create reverse correspondence */ 00549 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) 00550 dmn_idx_out_in[dmn_idx_in_out[dmn_in_idx]]=dmn_in_idx; 00551 00552 /* Create full dmn_out list */ 00553 dmn_in=var_in->dim; 00554 dmn_out=(dmn_sct **)nco_malloc(dmn_out_nbr*sizeof(dmn_sct *)); 00555 00556 /* Assign dimension structures to new dimension list in correct order 00557 Remember: dmn_in has dimension IDs relative to input file 00558 Copy dmn_in->xrf to get dimension IDs relative to output file (once they are defined) 00559 Oh come on, it only seems like cheating! */ 00560 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++) 00561 dmn_out[dmn_out_idx]=dmn_in[dmn_idx_out_in[dmn_out_idx]]->xrf; 00562 00563 /* Re-ordered output dimension list dmn_out now comprises correctly ordered but 00564 otherwise verbatim copies of dmn_out structures in calling routine */ 00565 00566 /* Free var_out's old dimension list */ 00567 var_out->dim=(dmn_sct **)nco_free(var_out->dim); 00568 /* Replace old with new dimension list */ 00569 var_out->dim=dmn_out; 00570 00571 /* NB: var_out is now in an inconsistent state 00572 var_out->dim refers to re-ordered dimensions 00573 However, var_out->dmn_id,cnt,srt,end,srd refer still duplicate var_in members 00574 They refer to old dimension ordering in input file 00575 nco_cnf_dmn_rdr_mtd() implicitly assumes that only nco_cnf_dmn_rdr_mtd() modifies var_out 00576 The call to nco_cnf_dmn_rdr_val() for this variable performs the actual re-ordering 00577 The interim inconsistent state is required for dimension IDs because 00578 output dimension IDs are not known until nco_dmn_dfn() which cannot (or, at least, should not) 00579 occur until output record dimension is known 00580 Interim modifications of var_out by any other routine are dangerous! */ 00581 00582 /* This is clear at date written (20040727), but memories are short 00583 Hence we modify var_out->dmn_id,cnt,srt,end,srd to contain re-ordered values now 00584 This makes it safer to var_out->dmn_id,cnt,srt,end,srd before second call to nco_cnf_dmn_rdr() 00585 If dmn_out->id does depend on record dimension identity, then this update will do no good 00586 Hence, we must re-update dmn_out->id after nco_dmn_dfn() in nco_cnf_dmn_rdr_val() 00587 Structures should be completely consisten at that point 00588 Not updating these structures (at least dmn_out->id) is equivalent to assuming that 00589 dmn_out->id does not depend on record dimension identity, which is an ASSUMPTION 00590 that may currently be true, but is not guaranteed by the netCDF API to always be true. */ 00591 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++){ 00592 /* NB: Change dmn_id,cnt,srt,end,srd together to minimize chances of forgetting one */ 00593 var_out->dmn_id[dmn_out_idx]=dmn_out[dmn_out_idx]->id; 00594 var_out->cnt[dmn_out_idx]=dmn_out[dmn_out_idx]->cnt; 00595 var_out->srt[dmn_out_idx]=dmn_out[dmn_out_idx]->srt; 00596 var_out->end[dmn_out_idx]=dmn_out[dmn_out_idx]->end; 00597 var_out->srd[dmn_out_idx]=dmn_out[dmn_out_idx]->srd; 00598 } /* end loop over dmn_out */ 00599 00600 if(var_out->is_rec_var){ 00601 /* Which dimension in output dimension list is scheduled to be record dimension? */ 00602 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++) 00603 if(dmn_out[dmn_out_idx]->is_rec_dmn) break; 00604 if(dmn_out_idx != dmn_out_nbr){ 00605 dmn_idx_rec_out=dmn_out_idx; 00606 }else{ 00607 (void)fprintf(stdout,"%s: ERROR %s did not find record dimension in variable %s which claims to be record variable\n",prg_nm_get(),fnc_nm,var_in->nm); 00608 nco_exit(EXIT_FAILURE); 00609 } /* end else */ 00610 /* Request that first dimension be record dimension */ 00611 rec_dmn_nm_out=dmn_out[0]->nm; 00612 if(dmn_idx_rec_out != 0) (void)fprintf(stdout,"%s: INFO %s for variable %s reports old input record dimension %s is now ordinal dimension %d, new record dimension must be %s\n",prg_nm_get(),fnc_nm,var_in->nm,dmn_out[dmn_idx_rec_out]->nm,dmn_idx_rec_out,dmn_out[0]->nm); 00613 } /* endif record variable */ 00614 00615 if(dbg_lvl_get() > 3){ 00616 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) 00617 (void)fprintf(stdout,"%s: DEBUG %s variable %s re-order maps dimension %s from (ordinal,ID)=(%d,%d) to (%d,unknown)\n",prg_nm_get(),fnc_nm,var_in->nm,var_in->dim[dmn_in_idx]->nm,dmn_in_idx,var_in->dmn_id[dmn_in_idx],dmn_idx_in_out[dmn_in_idx]); 00618 } /* endif dbg */ 00619 00620 return rec_dmn_nm_out; 00621 } /* end nco_var_dmn_rdr_mtd() */
|
|
||||||||||||||||||||
|
Definition at line 625 of file nco_cnf_dmn.c. References dmn_sct_tag::cnt, var_sct_tag::cnt, dbg_lvl_get(), var_sct_tag::dim, var_sct_tag::dmn_id, dmn_sct_tag::end, False, var_sct_tag::has_dpl_dmn, dmn_sct_tag::id, var_sct_tag::nbr_dim, NC_MAX_DIMS, nco_bool, nco_typ_lng(), dmn_sct_tag::nm, var_sct_tag::nm, prg_nm_get(), dmn_sct_tag::srd, dmn_sct_tag::srt, var_sct_tag::sz, True, var_sct_tag::val, and ptr_unn::vp. Referenced by main(). 00629 { 00630 /* Purpose: Re-order values in given variable according to supplied dimension map 00631 Description of re-ordering concepts is in nco_var_dmn_rdr_mtd() 00632 Description of actual re-ordering algorithm is in nco_var_dmn_rdr_val() */ 00633 00634 nco_bool IDENTITY_REORDER=False; /* [flg] User requested identity re-ordering */ 00635 00636 char *val_in_cp; /* [ptr] Input data location as char pointer */ 00637 char *val_out_cp; /* [ptr] Output data location as char pointer */ 00638 00639 const char fnc_nm[]="nco_var_dmn_rdr_val()"; /* [sng] Function name */ 00640 00641 dmn_sct **dmn_in=NULL; /* [sct] List of dimension structures in input order */ 00642 dmn_sct **dmn_out; /* [sct] List of dimension structures in output order */ 00643 00644 int *dmn_id_out; /* [id] Contiguous vector of dimension IDs */ 00645 int dmn_idx; /* [idx] Index over dimensions */ 00646 int dmn_in_idx; /* [idx] Counting index for dmn_in */ 00647 int dmn_in_nbr; /* [nbr] Number of dimensions in input variable */ 00648 int dmn_in_nbr_m1; /* [nbr] Number of dimensions in input variable, less one */ 00649 int dmn_out_idx; /* [idx] Counting index for dmn_out */ 00650 int dmn_out_nbr; /* [nbr] Number of dimensions in output variable */ 00651 int rcd=0; /* [rcd] Return code */ 00652 int typ_sz; /* [B] Size of data element in memory */ 00653 00654 long dmn_in_map[NC_MAX_DIMS]; /* [idx] Map for each dimension of input variable */ 00655 long dmn_out_map[NC_MAX_DIMS]; /* [idx] Map for each dimension of output variable */ 00656 long dmn_in_sbs[NC_MAX_DIMS]; /* [idx] Dimension subscripts into N-D input array */ 00657 long var_in_lmn; /* [idx] Offset into 1-D input array */ 00658 long var_out_lmn; /* [idx] Offset into 1-D output array */ 00659 long *var_in_cnt; /* [nbr] Number of valid elements in this dimension (including effects of stride and wrapping) */ 00660 long var_sz; /* [nbr] Number of elements (NOT bytes) in hyperslab (NOT full size of variable in input file!) */ 00661 00662 /* Initialize variables to reduce indirection */ 00663 /* NB: Number of input and output dimensions are equal for pure re-orders 00664 However, keep dimension numbers in separate variables to ease relax this rule in future */ 00665 dmn_in_nbr=var_in->nbr_dim; 00666 dmn_out_nbr=var_out->nbr_dim; 00667 00668 /* On entry to this section of code, we assume: 00669 1. var_out metadata are re-ordered 00670 2. var_out->val buffer has been allocated (calling routine must do this) */ 00671 00672 /* Get ready to re-order */ 00673 dmn_id_out=var_out->dmn_id; 00674 dmn_in_nbr_m1=dmn_in_nbr-1; 00675 dmn_out=var_out->dim; 00676 dmn_in=var_in->dim; 00677 typ_sz=nco_typ_lng(var_out->type); 00678 val_in_cp=(char *)var_in->val.vp; 00679 val_out_cp=(char *)var_out->val.vp; 00680 var_in_cnt=var_in->cnt; 00681 var_sz=var_in->sz; 00682 00683 /* As explained in nco_var_dmn_rdr_mtd(), 00684 "Hence, we must re-update dmn_out->id after nco_dmn_dfn() in nco_cnf_dmn_rdr_val() 00685 Structures should be completely consisten at that point 00686 Not updating these structures (at least dmn_out->id) is equivalent to assuming that 00687 dmn_out->id does not depend on record dimension identity, which is an ASSUMPTION 00688 that may currently be true, but is not guaranteed by the netCDF API to always be true." */ 00689 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++){ 00690 /* NB: Change dmn_id,cnt,srt,end,srd together to minimize chances of forgetting one */ 00691 var_out->dmn_id[dmn_out_idx]=dmn_out[dmn_out_idx]->id; 00692 var_out->cnt[dmn_out_idx]=dmn_out[dmn_out_idx]->cnt; 00693 var_out->srt[dmn_out_idx]=dmn_out[dmn_out_idx]->srt; 00694 var_out->end[dmn_out_idx]=dmn_out[dmn_out_idx]->end; 00695 var_out->srd[dmn_out_idx]=dmn_out[dmn_out_idx]->srd; 00696 } /* end loop over dmn_out */ 00697 00698 /* Report full metadata re-order, if requested */ 00699 if(dbg_lvl_get() > 3){ 00700 int dmn_idx_in_out[NC_MAX_DIMS]; /* [idx] Dimension correspondence, input->output */ 00701 /* Create reverse correspondence */ 00702 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++) 00703 dmn_idx_in_out[dmn_idx_out_in[dmn_out_idx]]=dmn_out_idx; 00704 00705 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) 00706 (void)fprintf(stdout,"%s: DEBUG %s variable %s re-order maps dimension %s from (ordinal,ID)=(%d,%d) to (%d,%d)\n",prg_nm_get(),fnc_nm,var_in->nm,var_in->dim[dmn_in_idx]->nm,dmn_in_idx,var_in->dmn_id[dmn_in_idx],dmn_idx_in_out[dmn_in_idx],var_out->dmn_id[dmn_idx_in_out[dmn_in_idx]]); 00707 } /* endif dbg */ 00708 00709 /* Is identity re-ordering requested? */ 00710 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++) 00711 if(dmn_out_idx != dmn_idx_out_in[dmn_out_idx]) break; 00712 if(dmn_out_idx == dmn_out_nbr) IDENTITY_REORDER=True; 00713 00714 /* Dimension reversal breaks identity re-ordering */ 00715 if(IDENTITY_REORDER){ 00716 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) 00717 if(dmn_rvr_in[dmn_in_idx]) break; 00718 if(dmn_in_idx != dmn_in_nbr) IDENTITY_REORDER=False; 00719 } /* !IDENTITY_REORDER */ 00720 00721 if(IDENTITY_REORDER){ 00722 if(dbg_lvl_get() > 2) (void)fprintf(stdout,"%s: INFO %s reports re-order is identity transformation for variable %s\n",prg_nm_get(),fnc_nm,var_in->nm); 00723 /* Copy in one fell swoop then return */ 00724 (void)memcpy((void *)(var_out->val.vp),(void *)(var_in->val.vp),var_out->sz*nco_typ_lng(var_out->type)); 00725 return rcd; 00726 } /* !IDENTITY_REORDER */ 00727 00728 if(var_in->has_dpl_dmn) (void)fprintf(stdout,"%s: WARNING %s reports non-identity re-order for variable with duplicate dimensions %s.\n%s does not support non-identity re-orders of variables with duplicate dimensions\n",prg_nm_get(),fnc_nm,var_in->nm,prg_nm_get()); 00729 00730 /* Compute map for each dimension of input variable */ 00731 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) dmn_in_map[dmn_in_idx]=1L; 00732 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr-1;dmn_in_idx++) 00733 for(dmn_idx=dmn_in_idx+1;dmn_idx<dmn_in_nbr;dmn_idx++) 00734 dmn_in_map[dmn_in_idx]*=var_in->cnt[dmn_idx]; 00735 00736 /* Compute map for each dimension of output variable */ 00737 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++) dmn_out_map[dmn_out_idx]=1L; 00738 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr-1;dmn_out_idx++) 00739 for(dmn_idx=dmn_out_idx+1;dmn_idx<dmn_out_nbr;dmn_idx++) 00740 dmn_out_map[dmn_out_idx]*=var_out->cnt[dmn_idx]; 00741 00742 /* There is more than one method to re-order dimensions 00743 Output dimensionality is known in advance, unlike nco_var_avg() 00744 Hence outer loop may be over dimensions or over elements 00745 Method 1: Loop over input elements 00746 1a. Loop over 1-D input array offsets 00747 1b. Invert 1-D input array offset to get N-D input subscripts 00748 1c. Turn N-D input subscripts into N-D output subscripts 00749 1d. Map N-D output subscripts to get 1-D output element 00750 1e. Copy input element to output element 00751 This method is simplified from method used in nco_var_avg() 00752 Method 2: Loop over input dimensions 00753 1a. Loop over input dimensions, from slowest to fastest varying 00754 1b. 00755 */ 00756 00757 /* Begin Method 1: Loop over input elements */ 00758 /* var_in_lmn is offset into 1-D array */ 00759 for(var_in_lmn=0;var_in_lmn<var_sz;var_in_lmn++){ 00760 00761 /* dmn_in_sbs are corresponding indices (subscripts) into N-D array */ 00762 dmn_in_sbs[dmn_in_nbr_m1]=var_in_lmn%var_in_cnt[dmn_in_nbr_m1]; 00763 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr_m1;dmn_in_idx++){ 00764 dmn_in_sbs[dmn_in_idx]=(long)(var_in_lmn/dmn_in_map[dmn_in_idx]); 00765 dmn_in_sbs[dmn_in_idx]%=var_in_cnt[dmn_in_idx]; 00766 } /* end loop over dimensions */ 00767 00768 /* Dimension reversal: 00769 Reversing a dimension changes subscripts along that dimension 00770 Consider dimension of size N indexed by [0,1,2,...k-1,k,k+1,...,N-2,N-1] 00771 Reversal maps element k to element N-1-k=N-k-1 00772 Enhance speed by using that all elements along dimension share reversal */ 00773 for(dmn_in_idx=0;dmn_in_idx<dmn_in_nbr;dmn_in_idx++) 00774 if(dmn_rvr_in[dmn_in_idx]) dmn_in_sbs[dmn_in_idx]=var_in_cnt[dmn_in_idx]-dmn_in_sbs[dmn_in_idx]-1; 00775 00776 /* Map variable's N-D array indices to get 1-D index into output data */ 00777 var_out_lmn=0L; 00778 for(dmn_out_idx=0;dmn_out_idx<dmn_out_nbr;dmn_out_idx++) 00779 var_out_lmn+=dmn_in_sbs[dmn_idx_out_in[dmn_out_idx]]*dmn_out_map[dmn_out_idx]; 00780 00781 /* Copy current input element into its slot in output array */ 00782 (void)memcpy(val_out_cp+var_out_lmn*typ_sz,val_in_cp+var_in_lmn*typ_sz,(size_t)typ_sz); 00783 } /* end loop over var_in_lmn */ 00784 /* End Method 1: Loop over input elements */ 00785 00786 /* Begin Method 2: Loop over input dimensions */ 00787 /* End Method 2: Loop over input dimensions */ 00788 00789 return rcd; 00790 } /* end nco_var_dmn_rdr_val() */
|
1.4.4