#include <math.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include "nco_getopt.h"#include <netcdf.h>#include "libnco.h"Include dependency graph for mpncpdq.c:

Go to the source code of this file.
Defines | |
| #define | MAIN_PROGRAM_FILE |
Functions | |
| int | main (int argc, char **argv) |
|
|
|
|
||||||||||||
|
Definition at line 72 of file mpncpdq.c. References aed_sct::att_nm, dmn_sct_tag::cnt, var_sct_tag::cnt, copyright_prn(), var_sct_tag::dim, var_sct_tag::dmn_id, dmn_sct_tag::end, var_sct_tag::end, EXIT_FAILURE, EXIT_SUCCESS, False, FILE, getopt_long, var_sct_tag::has_dpl_dmn, var_sct_tag::id, dmn_sct_tag::id, idx_all_wrk_ass, int_CEWI, dmn_sct_tag::is_rec_dmn, var_sct_tag::is_rec_var, lst_prs_2D(), msg_bfr_lng, msg_tag_tkn_wrt_rqs, msg_tag_tkn_wrt_rsp, msg_tag_wrk_rqs, msg_tag_wrk_rsp, option::name, var_sct_tag::nbr_dim, NC_FORMAT_64BIT, NC_FORMAT_CLASSIC, NC_FORMAT_NETCDF4, NC_GLOBAL, var_sct_tag::nc_id, NC_MAX_DIMS, NC_NOERR, NC_NOFILL, NC_NOWRITE, NC_SHARE, NC_WRITE, nco_aed_prc(), nco_att_cpy(), nco_bool, nco_close(), nco_cmd_ln_sng(), nco_cnt_run(), nco_cnv_ccm_ccsm_cf_inq(), nco_create_mode_prs(), nco_dmn_dfn(), nco_dmn_dpl(), nco_dmn_fll(), nco_dmn_lmt_mrg(), nco_dmn_lst_ass_var(), nco_dmn_lst_free(), nco_dmn_lst_mk(), nco_dmn_xrf(), nco_enddef(), nco_exit(), nco_exit_gracefully(), nco_fl_lst_mk(), nco_fl_mk_lcl(), nco_fl_mv(), nco_fl_nm_prs(), nco_fl_out_cls(), nco_fl_out_open(), nco_fl_rm(), nco_free(), nco_hst_att_cat(), nco_inq(), nco_lbr_vrs_prn(), nco_lmt_evl(), nco_lmt_lst_free(), nco_lmt_prs(), nco_lst_comma2hash(), nco_lst_srt_nm_id(), nco_malloc(), nco_malloc_flg(), nco_mpi_att_cat(), nco_nm_id_lst_free(), nco_open(), nco_openmp_ini(), nco_pck_map_flt_sht, nco_pck_map_get(), nco_pck_map_sng_get(), nco_pck_mtd(), nco_pck_plc_all_new_att, nco_pck_plc_all_xst_att, nco_pck_plc_get(), nco_pck_plc_nil, nco_pck_plc_sng_get(), nco_pck_plc_typ_get(), nco_pck_plc_upk, nco_pck_plc_xst_new_att, nco_pck_val(), nco_put_var1(), nco_put_vara(), nco_realloc(), NCO_REC_DMN_UNDEFINED, nco_redef(), nco_set_fill(), nco_sng_lst_free(), nco_spn_lck_brk, nco_spn_lck_us, nco_thr_att_cat(), nco_typ_lng(), nco_usg_prn(), nco_var_dfn(), nco_var_dmn_rdr_mtd(), nco_var_dmn_rdr_val(), nco_var_dpl(), nco_var_fll(), nco_var_get(), nco_var_lst_add_crd(), nco_var_lst_ass_crd_add(), nco_var_lst_dvd(), nco_var_lst_free(), nco_var_lst_mk(), nco_var_lst_xcl(), nco_var_prc_crr_prn(), nco_var_srt_zero(), nco_var_val_cpy(), nco_xrf_dmn(), nco_xrf_var(), dmn_sct_tag::nm, no_argument, NULL_CEWI, omp_get_thread_num(), optarg, optind, var_sct_tag::pck_ram, prg_nm_get(), prg_prs(), required_argument, rnk_mgr, dmn_sct_tag::srd, var_sct_tag::srd, dmn_sct_tag::srt, var_sct_tag::srt, tkn_wrt_rqs_dny, tkn_wrt_rqs_ntv, tkn_wrt_rqs_xcp, True, var_sct_tag::type, type, option::val, var_sct_tag::val, ptr_unn::vp, and wrk_id_bfr_lng. 00073 { 00074 aed_sct *aed_lst_add_fst=NULL_CEWI; 00075 aed_sct *aed_lst_scl_fct=NULL_CEWI; 00076 00077 nco_bool **dmn_rvr_in=NULL; /* [flg] Reverse dimension */ 00078 nco_bool *dmn_rvr_rdr=NULL; /* [flg] Reverse dimension */ 00079 nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */ 00080 nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */ 00081 nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */ 00082 nco_bool FILE_RETRIEVED_FROM_REMOTE_LOCATION; 00083 nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */ 00084 nco_bool FORCE_APPEND=False; /* Option A */ 00085 nco_bool FORCE_OVERWRITE=False; /* Option O */ 00086 nco_bool FORTRAN_IDX_CNV=False; /* Option F */ 00087 nco_bool HISTORY_APPEND=True; /* Option h */ 00088 nco_bool CNV_CCM_CCSM_CF; 00089 nco_bool REDEFINED_RECORD_DIMENSION=False; /* [flg] Re-defined record dimension */ 00090 nco_bool REMOVE_REMOTE_FILES_AFTER_PROCESSING=True; /* Option R */ 00091 00092 char **dmn_rdr_lst_in=NULL_CEWI; /* Option a */ 00093 char **fl_lst_abb=NULL; /* Option n */ 00094 char **fl_lst_in=NULL_CEWI; 00095 char **var_lst_in=NULL_CEWI; 00096 char *cmd_ln; 00097 char *fl_in=NULL; 00098 char *fl_out=NULL; /* Option o */ 00099 char *fl_out_tmp=NULL_CEWI; 00100 char *fl_pth=NULL; /* Option p */ 00101 char *fl_pth_lcl=NULL; /* Option l */ 00102 char *lmt_arg[NC_MAX_DIMS]; 00103 char *nco_pck_plc_sng=NULL_CEWI; /* [sng] Packing policy Option P */ 00104 char *nco_pck_map_sng=NULL_CEWI; /* [sng] Packing map Option M */ 00105 char *opt_crr=NULL; /* [sng] String representation of current long-option name */ 00106 char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */ 00107 char *rec_dmn_nm_in=NULL; /* [sng] Record dimension name, original */ 00108 char *rec_dmn_nm_out=NULL; /* [sng] Record dimension name, re-ordered */ 00109 char *rec_dmn_nm_out_crr=NULL; /* [sng] Name of record dimension, if any, required by re-order */ 00110 char *time_bfr_srt; 00111 00112 char add_fst_sng[]="add_offset"; /* [sng] Unidata standard string for add offset */ 00113 char scl_fct_sng[]="scale_factor"; /* [sng] Unidata standard string for scale factor */ 00114 00115 const char * const CVS_Id="$Id: mpncpdq.c,v 1.34 2006/02/20 20:59:23 zender Exp $"; 00116 const char * const CVS_Revision="$Revision: 1.34 $"; 00117 const char * const opt_sht_lst="4Aa:CcD:d:Fhl:M:Oo:P:p:RrSt:v:Ux-:"; 00118 00119 dmn_sct **dim=NULL_CEWI; 00120 dmn_sct **dmn_out; 00121 dmn_sct **dmn_rdr=NULL; /* [sct] Dimension structures to be re-ordered */ 00122 00123 extern char *optarg; 00124 extern int optind; 00125 00126 /* Using naked stdin/stdout/stderr in parallel region generates warning 00127 Copy appropriate filehandle to variable scoped shared in parallel clause */ 00128 FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */ 00129 FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */ 00130 00131 int **dmn_idx_out_in=NULL; /* [idx] Dimension correspondence, output->input CEWI */ 00132 00133 int *in_id_arr; 00134 00135 int abb_arg_nbr=0; 00136 int dmn_out_idx; /* [idx] Index over output dimension list */ 00137 int dmn_out_idx_rec_in=NCO_REC_DMN_UNDEFINED; /* [idx] Record dimension index in output dimension list, original */ 00138 int dmn_rdr_nbr=0; /* [nbr] Number of dimension to re-order */ 00139 int dmn_rdr_nbr_in=0; /* [nbr] Original number of dimension to re-order */ 00140 int dmn_rdr_nbr_utl=0; /* [nbr] Number of dimension to re-order, utilized */ 00141 int fl_idx=int_CEWI; 00142 int fl_nbr=0; 00143 int fl_out_fmt=NC_FORMAT_CLASSIC; /* [enm] Output file format */ 00144 int fll_md_old; /* [enm] Old fill mode */ 00145 int idx=int_CEWI; 00146 int idx_rdr=int_CEWI; 00147 int in_id; 00148 int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */ 00149 int nbr_dmn_fl; 00150 int nbr_dmn_out; 00151 int nbr_dmn_xtr; 00152 int nbr_var_fix; /* nbr_var_fix gets incremented */ 00153 int nbr_var_fl; 00154 int nbr_var_prc; /* nbr_var_prc gets incremented */ 00155 int nbr_xtr=0; /* nbr_xtr won't otherwise be set for -c with no -v */ 00156 int nco_pck_map=nco_pck_map_flt_sht; /* [enm] Packing map */ 00157 int nco_pck_plc=nco_pck_plc_nil; /* [enm] Packing policy */ 00158 int opt; 00159 int out_id; 00160 int rcd=NC_NOERR; /* [rcd] Return code */ 00161 int rec_dmn_id_in=NCO_REC_DMN_UNDEFINED; /* [id] Record dimension ID in input file */ 00162 int thr_idx; /* [idx] Index of current thread */ 00163 int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */ 00164 int var_lst_in_nbr=0; 00165 00166 lmt_sct **lmt; 00167 00168 nm_id_sct *dmn_lst; 00169 nm_id_sct *dmn_rdr_lst; 00170 nm_id_sct *xtr_lst=NULL; /* xtr_lst may be alloc()'d from NULL with -c option */ 00171 00172 time_t time_crr_time_t; 00173 00174 var_sct **var; 00175 var_sct **var_fix; 00176 var_sct **var_fix_out; 00177 var_sct **var_out; 00178 var_sct **var_prc; 00179 var_sct **var_prc_out; 00180 00181 #ifdef ENABLE_MPI 00182 /* Declare all MPI-specific variables here */ 00183 MPI_Status mpi_stt; /* [enm] Status check to decode msg_tag_typ */ 00184 00185 nco_bool TKN_WRT_FREE=True; /* [flg] Write-access to output file is available */ 00186 00187 int fl_nm_lng; /* [nbr] Output file name length */ 00188 int msg_bfr[msg_bfr_lng]; /* [bfr] Buffer containing var, idx, tkn_wrt_rsp */ 00189 int jdx=0; /* [idx] For MPI indexing local variables */ 00190 /* csz: fxm why 60? make dynamic? */ 00191 int lcl_idx_lst[60]; /* [arr] Array containing indices of variables processed at each Worker */ 00192 int lcl_nbr_var=0; /* [nbr] Count of variables processes at each Worker */ 00193 int msg_tag_typ; /* [enm] MPI message tag type */ 00194 int prc_rnk; /* [idx] Process rank */ 00195 int prc_nbr=0; /* [nbr] Number of MPI processes */ 00196 int tkn_wrt_rsp; /* [enm] Response to request for write token */ 00197 int var_wrt_nbr=0; /* [nbr] Variables written to output file until now */ 00198 int rnk_wrk; /* [idx] Worker rank */ 00199 int wrk_id_bfr[wrk_id_bfr_lng]; /* [bfr] Buffer for rnk_wrk */ 00200 #endif /* !ENABLE_MPI */ 00201 00202 static struct option opt_lng[]= 00203 { /* Structure ordered by short option key if possible */ 00204 /* Long options with no argument, no short option counterpart */ 00205 /* Long options with argument, no short option counterpart */ 00206 {"fl_fmt",required_argument,0,0}, 00207 {"file_format",required_argument,0,0}, 00208 /* Long options with short counterparts */ 00209 {"4",no_argument,0,'4'}, 00210 {"64bit",no_argument,0,'4'}, 00211 {"netcdf4",no_argument,0,'4'}, 00212 {"append",no_argument,0,'A'}, 00213 {"arrange",required_argument,0,'a'}, 00214 {"permute",required_argument,0,'a'}, 00215 {"reorder",required_argument,0,'a'}, 00216 {"rdr",required_argument,0,'a'}, 00217 {"no-coords",no_argument,0,'C'}, 00218 {"no-crd",no_argument,0,'C'}, 00219 {"coords",no_argument,0,'c'}, 00220 {"crd",no_argument,0,'c'}, 00221 {"debug",required_argument,0,'D'}, 00222 {"dbg_lvl",required_argument,0,'D'}, 00223 {"dimension",required_argument,0,'d'}, 00224 {"dmn",required_argument,0,'d'}, 00225 {"fortran",no_argument,0,'F'}, 00226 {"ftn",no_argument,0,'F'}, 00227 {"history",no_argument,0,'h'}, 00228 {"hst",no_argument,0,'h'}, 00229 {"local",required_argument,0,'l'}, 00230 {"lcl",required_argument,0,'l'}, 00231 {"pck_map",required_argument,0,'M'}, 00232 {"map",required_argument,0,'M'}, 00233 {"overwrite",no_argument,0,'O'}, 00234 {"ovr",no_argument,0,'O'}, 00235 {"output",required_argument,0,'o'}, 00236 {"fl_out",required_argument,0,'o'}, 00237 {"pack_policy",required_argument,0,'P'}, 00238 {"pck_plc",required_argument,0,'P'}, 00239 {"path",required_argument,0,'p'}, 00240 {"retain",no_argument,0,'R'}, 00241 {"rtn",no_argument,0,'R'}, 00242 {"revision",no_argument,0,'r'}, 00243 {"version",no_argument,0,'r'}, 00244 {"vrs",no_argument,0,'r'}, 00245 {"suspend", no_argument,0,'S'}, 00246 {"thr_nbr",required_argument,0,'t'}, 00247 {"threads",required_argument,0,'t'}, 00248 {"omp_num_threads",required_argument,0,'t'}, 00249 {"unpack",no_argument,0,'U'}, 00250 {"upk",no_argument,0,'U'}, 00251 {"variable",required_argument,0,'v'}, 00252 {"exclude",no_argument,0,'x'}, 00253 {"xcl",no_argument,0,'x'}, 00254 {"help",no_argument,0,'?'}, 00255 {0,0,0,0} 00256 }; /* end opt_lng */ 00257 int opt_idx=0; /* Index of current long option into opt_lng array */ 00258 00259 #ifdef ENABLE_MPI 00260 /* MPI Initialization */ 00261 MPI_Init(&argc,&argv); 00262 MPI_Comm_size(MPI_COMM_WORLD,&prc_nbr); 00263 MPI_Comm_rank(MPI_COMM_WORLD,&prc_rnk); 00264 #endif /* !ENABLE_MPI */ 00265 00266 /* Start clock and save command line */ 00267 cmd_ln=nco_cmd_ln_sng(argc,argv); 00268 time_crr_time_t=time((time_t *)NULL); 00269 time_bfr_srt=ctime(&time_crr_time_t); time_bfr_srt=time_bfr_srt; /* Avoid compiler warning until variable is used for something */ 00270 00271 time_bfr_srt=time_bfr_srt; /* CEWI: Avert compiler warning that variable is set but never used */ 00272 00273 /* Get program name and set program enum (e.g., prg=ncra) */ 00274 prg_nm=prg_prs(argv[0],&prg); 00275 00276 /* Parse command line arguments */ 00277 while(1){ 00278 /* getopt_long_only() allows one dash to prefix long options */ 00279 opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx); 00280 /* NB: access to opt_crr is only valid when long_opt is detected */ 00281 if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */ 00282 opt_crr=(char *)strdup(opt_lng[opt_idx].name); 00283 00284 /* Process long options without short option counterparts */ 00285 if(opt == 0){ 00286 if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt); 00287 } /* opt != 0 */ 00288 /* Process short options */ 00289 switch(opt){ 00290 case 0: /* Long options have already been processed, return */ 00291 break; 00292 case '4': /* [flg] Catch-all to prescribe output storage format */ 00293 if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; 00294 break; 00295 case 'A': /* Toggle FORCE_APPEND */ 00296 FORCE_APPEND=!FORCE_APPEND; 00297 break; 00298 case 'a': /* Re-order dimensions */ 00299 dmn_rdr_lst_in=lst_prs_2D(optarg,",",&dmn_rdr_nbr_in); 00300 dmn_rdr_nbr=dmn_rdr_nbr_in; 00301 break; 00302 case 'C': /* Extract all coordinates associated with extracted variables? */ 00303 EXTRACT_ASSOCIATED_COORDINATES=False; 00304 break; 00305 case 'c': 00306 EXTRACT_ALL_COORDINATES=True; 00307 break; 00308 case 'D': /* Debugging level. Default is 0. */ 00309 dbg_lvl=(unsigned short)strtol(optarg,(char **)NULL,10); 00310 break; 00311 case 'd': /* Copy argument for later processing */ 00312 lmt_arg[lmt_nbr]=(char *)strdup(optarg); 00313 lmt_nbr++; 00314 break; 00315 case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */ 00316 FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV; 00317 break; 00318 case 'h': /* Toggle appending to history global attribute */ 00319 HISTORY_APPEND=!HISTORY_APPEND; 00320 break; 00321 case 'l': /* Local path prefix for files retrieved from remote file system */ 00322 fl_pth_lcl=(char *)strdup(optarg); 00323 break; 00324 case 'M': /* Packing map */ 00325 nco_pck_map_sng=(char *)strdup(optarg); 00326 nco_pck_map=nco_pck_map_get(nco_pck_map_sng); 00327 break; 00328 case 'O': /* Toggle FORCE_OVERWRITE */ 00329 FORCE_OVERWRITE=!FORCE_OVERWRITE; 00330 break; 00331 case 'o': /* Name of output file */ 00332 fl_out=(char *)strdup(optarg); 00333 break; 00334 case 'P': /* Packing policy */ 00335 nco_pck_plc_sng=(char *)strdup(optarg); 00336 break; 00337 case 'p': /* Common file path */ 00338 fl_pth=(char *)strdup(optarg); 00339 break; 00340 case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */ 00341 REMOVE_REMOTE_FILES_AFTER_PROCESSING=!REMOVE_REMOTE_FILES_AFTER_PROCESSING; 00342 break; 00343 case 'r': /* Print CVS program information and copyright notice */ 00344 (void)copyright_prn(CVS_Id,CVS_Revision); 00345 (void)nco_lbr_vrs_prn(); 00346 nco_exit(EXIT_SUCCESS); 00347 break; 00348 #ifdef ENABLE_MPI 00349 case 'S': /* Suspend with signal handler to facilitate debugging */ 00350 if(signal(SIGUSR1,nco_cnt_run) == SIG_ERR) (void)fprintf(fp_stdout,"%s: ERROR Could not install suspend handler.\n",prg_nm); 00351 while(!nco_spn_lck_brk) usleep(nco_spn_lck_us); /* Spinlock. fxm: should probably insert a sched_yield */ 00352 break; 00353 #endif /* !ENABLE_MPI */ 00354 case 't': /* Thread number */ 00355 thr_nbr=(int)strtol(optarg,(char **)NULL,10); 00356 break; 00357 case 'U': /* Unpacking switch */ 00358 nco_pck_plc_sng=(char *)strdup("upk"); 00359 break; 00360 case 'v': /* Variables to extract/exclude */ 00361 /* Replace commas with hashes when within braces (convert back later) */ 00362 optarg_lcl=(char *)strdup(optarg); 00363 (void)nco_lst_comma2hash(optarg_lcl); 00364 var_lst_in=lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr); 00365 optarg_lcl=(char *)nco_free(optarg_lcl); 00366 nbr_xtr=var_lst_in_nbr; 00367 break; 00368 case 'x': /* Exclude rather than extract variables specified with -v */ 00369 EXCLUDE_INPUT_LIST=True; 00370 break; 00371 case '?': /* Print proper usage */ 00372 (void)nco_usg_prn(); 00373 nco_exit(EXIT_SUCCESS); 00374 break; 00375 case '-': /* Long options are not allowed */ 00376 (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",prg_nm_get()); 00377 nco_exit(EXIT_FAILURE); 00378 break; 00379 default: /* Print proper usage */ 00380 (void)nco_usg_prn(); 00381 nco_exit(EXIT_FAILURE); 00382 break; 00383 } /* end switch */ 00384 if(opt_crr != NULL) opt_crr=(char *)nco_free(opt_crr); 00385 } /* end while loop */ 00386 00387 /* Process positional arguments and fill in filenames */ 00388 fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN); 00389 00390 /* Make uniform list of user-specified dimension limits */ 00391 lmt=nco_lmt_prs(lmt_nbr,lmt_arg); 00392 00393 /* Initialize thread information */ 00394 thr_nbr=nco_openmp_ini(thr_nbr); 00395 in_id_arr=(int *)nco_malloc(thr_nbr*sizeof(int)); 00396 00397 /* Parse filename */ 00398 fl_in=nco_fl_nm_prs(fl_in,0,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); 00399 /* Make sure file is on local system and is readable or die trying */ 00400 fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FILE_RETRIEVED_FROM_REMOTE_LOCATION); 00401 /* Open file for reading */ 00402 rcd=nco_open(fl_in,NC_NOWRITE,&in_id); 00403 00404 /* Get number of variables, dimensions, and record dimension ID of input file */ 00405 (void)nco_inq(in_id,&nbr_dmn_fl,&nbr_var_fl,(int *)NULL,&rec_dmn_id_in); 00406 00407 /* Form initial extraction list which may include extended regular expressions */ 00408 xtr_lst=nco_var_lst_mk(in_id,nbr_var_fl,var_lst_in,EXTRACT_ALL_COORDINATES,&nbr_xtr); 00409 00410 /* Change included variables to excluded variables */ 00411 if(EXCLUDE_INPUT_LIST) xtr_lst=nco_var_lst_xcl(in_id,nbr_var_fl,xtr_lst,&nbr_xtr); 00412 00413 /* Add all coordinate variables to extraction list */ 00414 if(EXTRACT_ALL_COORDINATES) xtr_lst=nco_var_lst_add_crd(in_id,nbr_dmn_fl,xtr_lst,&nbr_xtr); 00415 00416 /* Make sure coordinates associated extracted variables are also on extraction list */ 00417 if(EXTRACT_ASSOCIATED_COORDINATES) xtr_lst=nco_var_lst_ass_crd_add(in_id,xtr_lst,&nbr_xtr); 00418 00419 /* Sort extraction list by variable ID for fastest I/O */ 00420 if(nbr_xtr > 1) xtr_lst=nco_lst_srt_nm_id(xtr_lst,nbr_xtr,False); 00421 00422 /* Find coordinate/dimension values associated with user-specified limits 00423 NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */ 00424 for(idx=0;idx<lmt_nbr;idx++) (void)nco_lmt_evl(in_id,lmt[idx],0L,FORTRAN_IDX_CNV); 00425 00426 /* Find dimensions associated with variables to be extracted */ 00427 dmn_lst=nco_dmn_lst_ass_var(in_id,xtr_lst,nbr_xtr,&nbr_dmn_xtr); 00428 00429 /* Fill in dimension structure for all extracted dimensions */ 00430 dim=(dmn_sct **)nco_malloc(nbr_dmn_xtr*sizeof(dmn_sct *)); 00431 for(idx=0;idx<nbr_dmn_xtr;idx++) dim[idx]=nco_dmn_fll(in_id,dmn_lst[idx].id,dmn_lst[idx].nm); 00432 /* Dimension list no longer needed */ 00433 dmn_lst=nco_nm_id_lst_free(dmn_lst,nbr_dmn_xtr); 00434 00435 /* Merge hyperslab limit information into dimension structures */ 00436 if(lmt_nbr > 0) (void)nco_dmn_lmt_mrg(dim,nbr_dmn_xtr,lmt,lmt_nbr); 00437 00438 /* Duplicate input dimension structures for output dimension structures */ 00439 nbr_dmn_out=nbr_dmn_xtr; 00440 dmn_out=(dmn_sct **)nco_malloc(nbr_dmn_out*sizeof(dmn_sct *)); 00441 for(idx=0;idx<nbr_dmn_out;idx++){ 00442 dmn_out[idx]=nco_dmn_dpl(dim[idx]); 00443 (void)nco_dmn_xrf(dim[idx],dmn_out[idx]); 00444 } /* end loop over idx */ 00445 00446 /* No re-order dimensions specified implies packing request */ 00447 if(dmn_rdr_nbr == 0){ 00448 if(nco_pck_plc == nco_pck_plc_nil) nco_pck_plc=nco_pck_plc_get(nco_pck_plc_sng); 00449 if(dbg_lvl > 0) (void)fprintf(stderr,"%s: DEBUG Packing map is %s and packing policy is %s\n",prg_nm_get(),nco_pck_map_sng_get(nco_pck_map),nco_pck_plc_sng_get(nco_pck_plc)); 00450 } /* endif */ 00451 00452 /* From this point forward, assume ncpdq operator packs or re-orders, not both */ 00453 if(dmn_rdr_nbr > 0 && nco_pck_plc != nco_pck_plc_nil){ 00454 (void)fprintf(fp_stdout,"%s: ERROR %s does not support simultaneous dimension re-ordering (-a switch) and packing (-P switch).\nHINT: Invoke %s twice, once to re-order (with -a), and once to pack (with -P).\n",prg_nm,prg_nm,prg_nm); 00455 nco_exit(EXIT_FAILURE); 00456 } /* end if */ 00457 00458 if(dmn_rdr_nbr > 0){ 00459 /* NB: Same logic as in ncwa, perhaps combine into single function, nco_dmn_avg_rdr_prp()? */ 00460 /* Make list of user-specified dimension re-orders */ 00461 00462 /* Create reversed dimension list */ 00463 dmn_rvr_rdr=(nco_bool *)nco_malloc(dmn_rdr_nbr*sizeof(nco_bool)); 00464 for(idx_rdr=0;idx_rdr<dmn_rdr_nbr;idx_rdr++){ 00465 if(dmn_rdr_lst_in[idx_rdr][0] == '-'){ 00466 dmn_rvr_rdr[idx_rdr]=True; 00467 /* Copy string to new memory one past negative sign to avoid losing byte */ 00468 optarg_lcl=dmn_rdr_lst_in[idx_rdr]; 00469 dmn_rdr_lst_in[idx_rdr]=(char *)strdup(optarg_lcl+1); 00470 optarg_lcl=(char *)nco_free(optarg_lcl); 00471 }else{ 00472 dmn_rvr_rdr[idx_rdr]=False; 00473 } /* end else */ 00474 } /* end loop over idx_rdr */ 00475 00476 /* Create structured list of re-ordering dimension names and IDs */ 00477 dmn_rdr_lst=nco_dmn_lst_mk(in_id,dmn_rdr_lst_in,dmn_rdr_nbr); 00478 00479 /* Form list of re-ordering dimensions from extracted input dimensions */ 00480 dmn_rdr=(dmn_sct **)nco_malloc(dmn_rdr_nbr*sizeof(dmn_sct *)); 00481 /* Loop over original number of re-order dimensions */ 00482 for(idx_rdr=0;idx_rdr<dmn_rdr_nbr;idx_rdr++){ 00483 for(idx=0;idx<nbr_dmn_xtr;idx++){ 00484 if(!strcmp(dmn_rdr_lst[idx_rdr].nm,dim[idx]->nm)) break; 00485 } /* end loop over idx_rdr */ 00486 if(idx != nbr_dmn_xtr) dmn_rdr[dmn_rdr_nbr_utl++]=dim[idx]; else (void)fprintf(stderr,"%s: WARNING re-ordering dimension \"%s\" is not contained in any variable in extraction list\n",prg_nm,dmn_rdr_lst[idx_rdr].nm); 00487 } /* end loop over idx_rdr */ 00488 dmn_rdr_nbr=dmn_rdr_nbr_utl; 00489 /* Collapse extra dimension structure space to prevent accidentally using it */ 00490 dmn_rdr=(dmn_sct **)nco_realloc(dmn_rdr,dmn_rdr_nbr*sizeof(dmn_sct *)); 00491 /* Dimension list in name-ID format is no longer needed */ 00492 dmn_rdr_lst=nco_nm_id_lst_free(dmn_rdr_lst,dmn_rdr_nbr); 00493 00494 /* Make sure no re-ordering dimension is specified more than once */ 00495 for(idx=0;idx<dmn_rdr_nbr;idx++){ 00496 for(idx_rdr=0;idx_rdr<dmn_rdr_nbr;idx_rdr++){ 00497 if(idx_rdr != idx){ 00498 if(dmn_rdr[idx]->id == dmn_rdr[idx_rdr]->id){ 00499 (void)fprintf(fp_stdout,"%s: ERROR %s specified more than once in reducing list\n",prg_nm,dmn_rdr[idx]->nm); 00500 nco_exit(EXIT_FAILURE); 00501 } /* end if */ 00502 } /* end if */ 00503 } /* end loop over idx_rdr */ 00504 } /* end loop over idx */ 00505 00506 if(dmn_rdr_nbr > nbr_dmn_xtr){ 00507 (void)fprintf(fp_stdout,"%s: ERROR More re-ordering dimensions than extracted dimensions\n",prg_nm); 00508 nco_exit(EXIT_FAILURE); 00509 } /* end if */ 00510 00511 } /* dmn_rdr_nbr <= 0 */ 00512 00513 /* Is this an CCM/CCSM/CF-format history tape? */ 00514 CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(in_id); 00515 00516 /* Fill in variable structure list for all extracted variables */ 00517 var=(var_sct **)nco_malloc(nbr_xtr*sizeof(var_sct *)); 00518 var_out=(var_sct **)nco_malloc(nbr_xtr*sizeof(var_sct *)); 00519 for(idx=0;idx<nbr_xtr;idx++){ 00520 var[idx]=nco_var_fll(in_id,xtr_lst[idx].id,xtr_lst[idx].nm,dim,nbr_dmn_xtr); 00521 var_out[idx]=nco_var_dpl(var[idx]); 00522 (void)nco_xrf_var(var[idx],var_out[idx]); 00523 (void)nco_xrf_dmn(var_out[idx]); 00524 } /* end loop over idx */ 00525 /* Extraction list no longer needed */ 00526 xtr_lst=nco_nm_id_lst_free(xtr_lst,nbr_xtr); 00527 00528 /* Divide variable lists into lists of fixed variables and variables to be processed */ 00529 (void)nco_var_lst_dvd(var,var_out,nbr_xtr,CNV_CCM_CCSM_CF,nco_pck_map,nco_pck_plc,dmn_rdr,dmn_rdr_nbr,&var_fix,&var_fix_out,&nbr_var_fix,&var_prc,&var_prc_out,&nbr_var_prc); 00530 00531 /* We now have final list of variables to extract. Phew. */ 00532 if(dbg_lvl > 2){ 00533 for(idx=0;idx<nbr_xtr;idx++) (void)fprintf(stderr,"var[%d]->nm = %s, ->id=[%d]\n",idx,var[idx]->nm,var[idx]->id); 00534 for(idx=0;idx<nbr_var_fix;idx++) (void)fprintf(stderr,"var_fix[%d]->nm = %s, ->id=[%d]\n",idx,var_fix[idx]->nm,var_fix[idx]->id); 00535 for(idx=0;idx<nbr_var_prc;idx++) (void)fprintf(stderr,"var_prc[%d]->nm = %s, ->id=[%d]\n",idx,var_prc[idx]->nm,var_prc[idx]->id); 00536 } /* end if */ 00537 00538 #ifdef ENABLE_MPI 00539 if(prc_rnk == rnk_mgr){ /* MPI manager code */ 00540 #endif /* !ENABLE_MPI */ 00541 /* Open output file */ 00542 fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&out_id); 00543 if(dbg_lvl > 4) (void)fprintf(stderr,"Input, output file IDs = %d, %d\n",in_id,out_id); 00544 00545 /* Copy global attributes */ 00546 (void)nco_att_cpy(in_id,out_id,NC_GLOBAL,NC_GLOBAL,True); 00547 00548 /* Catenate time-stamped command line to "history" global attribute */ 00549 if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln); 00550 00551 if(thr_nbr > 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr); 00552 00553 #ifdef ENABLE_MPI 00554 /* Initialize MPI task information */ 00555 if(prc_nbr > 0 && HISTORY_APPEND) (void)nco_mpi_att_cat(out_id,prc_nbr); 00556 } /* !prc_rnk == rnk_mgr */ 00557 #endif /* !ENABLE_MPI */ 00558 00559 /* If re-ordering, then in files with record dimension... */ 00560 if(dmn_rdr_nbr > 0 && rec_dmn_id_in != NCO_REC_DMN_UNDEFINED){ 00561 /* ...which, if any, output dimension structure currently holds record dimension? */ 00562 for(dmn_out_idx=0;dmn_out_idx<nbr_dmn_out;dmn_out_idx++) 00563 if(dmn_out[dmn_out_idx]->is_rec_dmn) break; 00564 if(dmn_out_idx != nbr_dmn_out){ 00565 dmn_out_idx_rec_in=dmn_out_idx; 00566 /* Initialize output record dimension to input record dimension */ 00567 rec_dmn_nm_in=rec_dmn_nm_out=dmn_out[dmn_out_idx_rec_in]->nm; 00568 }else{ 00569 dmn_out_idx_rec_in=NCO_REC_DMN_UNDEFINED; 00570 } /* end else */ 00571 } /* end if file contains record dimension */ 00572 00573 /* If re-ordering, determine and set new dimensionality in metadata of each re-ordered variable */ 00574 if(dmn_rdr_nbr > 0){ 00575 dmn_idx_out_in=(int **)nco_malloc(nbr_var_prc*sizeof(int *)); 00576 dmn_rvr_in=(nco_bool **)nco_malloc(nbr_var_prc*sizeof(nco_bool *)); 00577 for(idx=0;idx<nbr_var_prc;idx++){ 00578 dmn_idx_out_in[idx]=(int *)nco_malloc(var_prc[idx]->nbr_dim*sizeof(int)); 00579 dmn_rvr_in[idx]=(nco_bool *)nco_malloc(var_prc[idx]->nbr_dim*sizeof(nco_bool)); 00580 /* nco_var_dmn_rdr_mtd() does re-order heavy lifting */ 00581 rec_dmn_nm_out_crr=nco_var_dmn_rdr_mtd(var_prc[idx],var_prc_out[idx],dmn_rdr,dmn_rdr_nbr,dmn_idx_out_in[idx],dmn_rvr_rdr,dmn_rvr_in[idx]); 00582 /* If record dimension required by current variable re-order... 00583 ...and variable is multi-dimensional (one dimensional arrays 00584 cannot request record dimension changes)... */ 00585 if(rec_dmn_nm_out_crr && var_prc_out[idx]->nbr_dim > 1){ 00586 /* ...differs from input and current output record dimension(s)... */ 00587 if(strcmp(rec_dmn_nm_out_crr,rec_dmn_nm_in) && strcmp(rec_dmn_nm_out_crr,rec_dmn_nm_out)){ 00588 /* ...and current output record dimension already differs from input record dimension... */ 00589 if(REDEFINED_RECORD_DIMENSION){ 00590 /* ...then requested re-order requires multiple record dimensions... */ 00591 (void)fprintf(fp_stdout,"%s: WARNING Re-order requests multiple record dimensions\n. Only first request will be honored (netCDF allows only one record dimension). Record dimensions involved [original,first change request (honored),latest change request (made by variable %s)]=[%s,%s,%s]\n",prg_nm,var_prc[idx]->nm,rec_dmn_nm_in,rec_dmn_nm_out,rec_dmn_nm_out_crr); 00592 break; 00593 }else{ /* !REDEFINED_RECORD_DIMENSION */ 00594 /* ...otherwise, update output record dimension name... */ 00595 rec_dmn_nm_out=rec_dmn_nm_out_crr; 00596 /* ...and set new and un-set old record dimensions... */ 00597 var_prc_out[idx]->dim[0]->is_rec_dmn=True; 00598 dmn_out[dmn_out_idx_rec_in]->is_rec_dmn=False; 00599 /* ...and set flag that record dimension has been re-defined... */ 00600 REDEFINED_RECORD_DIMENSION=True; 00601 } /* !REDEFINED_RECORD_DIMENSION */ 00602 } /* endif new and old record dimensions differ */ 00603 } /* endif current variable is record variable */ 00604 } /* end loop over var_prc */ 00605 } /* endif dmn_rdr_nbr > 0 */ 00606 00607 /* NB: Much of following logic is required by netCDF constraint that only 00608 one record variable is allowed per file. netCDF4 will relax this constraint. 00609 Hence making following logic prettier or funcionalizing is not high priority. 00610 Logic may need to be simplified/re-written once netCDF4 is released. */ 00611 if(REDEFINED_RECORD_DIMENSION){ 00612 (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change record dimension from %s to %s. netCDF allows only one record dimension. Hence %s will make %s record (least rapidly varying) dimension in all variables that contain it.\n",prg_nm,rec_dmn_nm_in,rec_dmn_nm_out,prg_nm,rec_dmn_nm_out); 00613 /* Changing record dimension may invalidate is_rec_var flag 00614 Updating is_rec_var flag to correct value, even if value is ignored, 00615 helps keep user appraised of unexpected dimension re-orders. 00616 is_rec_var may change both for "fixed" and "processed" variables 00617 When is_rec_var changes for processed variables, may also need to change 00618 ancillary information and to check for duplicate dimensions. 00619 Ancillary information (dmn_idx_out_in) is available only for var_prc! 00620 Hence must update is_rec_var flag for var_fix and var_prc separately */ 00621 00622 /* Update is_rec_var flag for var_fix */ 00623 for(idx=0;idx<nbr_var_fix;idx++){ 00624 /* Search all dimensions in variable for new record dimension */ 00625 for(dmn_out_idx=0;dmn_out_idx<var_fix[idx]->nbr_dim;dmn_out_idx++) 00626 if(!strcmp(var_fix[idx]->dim[dmn_out_idx]->nm,rec_dmn_nm_out)) break; 00627 /* ...Will variable be record variable in output file?... */ 00628 if(dmn_out_idx == var_fix[idx]->nbr_dim){ 00629 /* ...No. Variable will be non-record---does this change its status?... */ 00630 if(dbg_lvl > 2) if(var_fix[idx]->is_rec_var == True) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from record to non-record variable\n",prg_nm,var_fix[idx]->nm); 00631 /* Assign record flag dictated by re-order */ 00632 var_fix[idx]->is_rec_var=False; 00633 }else{ /* ...otherwise variable will be record variable... */ 00634 /* ...Yes. Variable will be record... */ 00635 /* ...Will becoming record variable change its status?... */ 00636 if(var_fix[idx]->is_rec_var == False){ 00637 if(dbg_lvl > 2) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from non-record to record variable\n",prg_nm,var_fix[idx]->nm); 00638 /* Change record flag to status dictated by re-order */ 00639 var_fix[idx]->is_rec_var=True; 00640 } /* endif status changing from non-record to record */ 00641 } /* endif variable will be record variable */ 00642 } /* end loop over var_fix */ 00643 00644 /* Update is_rec_var flag for var_prc */ 00645 for(idx=0;idx<nbr_var_prc;idx++){ 00646 /* Search all dimensions in variable for new record dimension */ 00647 for(dmn_out_idx=0;dmn_out_idx<var_prc_out[idx]->nbr_dim;dmn_out_idx++) 00648 if(!strcmp(var_prc_out[idx]->dim[dmn_out_idx]->nm,rec_dmn_nm_out)) break; 00649 /* ...Will variable be record variable in output file?... */ 00650 if(dmn_out_idx == var_prc_out[idx]->nbr_dim){ 00651 /* ...No. Variable will be non-record---does this change its status?... */ 00652 if(dbg_lvl > 2) if(var_prc_out[idx]->is_rec_var == True) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from record to non-record variable\n",prg_nm,var_prc_out[idx]->nm); 00653 /* Assign record flag dictated by re-order */ 00654 var_prc_out[idx]->is_rec_var=False; 00655 }else{ /* ...otherwise variable will be record variable... */ 00656 /* ...Yes. Variable will be record... */ 00657 /* ...must ensure new record dimension is not duplicate dimension... */ 00658 if(var_prc_out[idx]->has_dpl_dmn){ 00659 int dmn_dpl_idx; 00660 for(dmn_dpl_idx=1;dmn_dpl_idx<var_prc_out[idx]->nbr_dim;dmn_dpl_idx++){ /* NB: loop starts from 1 */ 00661 if(var_prc_out[idx]->dmn_id[0] == var_prc_out[idx]->dmn_id[dmn_dpl_idx]){ 00662 (void)fprintf(stdout,"%s: ERROR Requested re-order turns duplicate non-record dimension %s in variable %s into output record dimension. netCDF does not support duplicate record dimensions in a single variable.\n%s: HINT: Exclude variable %s from extraction list with \"-x -v %s\".\n",prg_nm_get(),rec_dmn_nm_out,var_prc_out[idx]->nm,prg_nm_get(),var_prc_out[idx]->nm,var_prc_out[idx]->nm); 00663 nco_exit(EXIT_FAILURE); 00664 } /* endif err */ 00665 } /* end loop over dmn_out */ 00666 } /* endif has_dpl_dmn */ 00667 /* ...Will becoming record variable change its status?... */ 00668 if(var_prc_out[idx]->is_rec_var == False){ 00669 if(dbg_lvl > 2) (void)fprintf(fp_stdout,"%s: INFO Requested re-order will change variable %s from non-record to record variable\n",prg_nm,var_prc_out[idx]->nm); 00670 /* Change record flag to status dictated by re-order */ 00671 var_prc_out[idx]->is_rec_var=True; 00672 /* ...Swap dimension information for multi-dimensional variables... */ 00673 if(var_prc_out[idx]->nbr_dim > 1){ 00674 /* Swap dimension information when turning multi-dimensional 00675 non-record variable into record variable. 00676 Single dimensional non-record variables that turn into 00677 record variables already have correct dimension information */ 00678 dmn_sct *dmn_swp; /* [sct] Dimension structure for swapping */ 00679 int dmn_idx_rec_in; /* [idx] Record dimension index in input variable */ 00680 int dmn_idx_rec_out; /* [idx] Record dimension index in output variable */ 00681 int dmn_idx_swp; /* [idx] Dimension index for swapping */ 00682 /* If necessary, swap new record dimension to first position */ 00683 /* Label indices with standard names */ 00684 dmn_idx_rec_in=dmn_out_idx; 00685 dmn_idx_rec_out=0; 00686 /* Swap indices in map */ 00687 dmn_idx_swp=dmn_idx_out_in[idx][dmn_idx_rec_out]; 00688 dmn_idx_out_in[idx][dmn_idx_rec_out]=dmn_idx_rec_in; 00689 dmn_idx_out_in[idx][dmn_idx_rec_in]=dmn_idx_swp; 00690 /* Swap dimensions in list */ 00691 dmn_swp=var_prc_out[idx]->dim[dmn_idx_rec_out]; 00692 var_prc_out[idx]->dim[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_in]; 00693 var_prc_out[idx]->dim[dmn_idx_rec_in]=dmn_swp; 00694 /* NB: Change dmn_id,cnt,srt,end,srd together to minimize chances of forgetting one */ 00695 /* Correct output variable structure copy of output record dimension information */ 00696 var_prc_out[idx]->dmn_id[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->id; 00697 var_prc_out[idx]->cnt[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->cnt; 00698 var_prc_out[idx]->srt[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->srt; 00699 var_prc_out[idx]->end[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->end; 00700 var_prc_out[idx]->srd[dmn_idx_rec_out]=var_prc_out[idx]->dim[dmn_idx_rec_out]->srd; 00701 /* Correct output variable structure copy of input record dimension information */ 00702 var_prc_out[idx]->dmn_id[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->id; 00703 var_prc_out[idx]->cnt[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->cnt; 00704 var_prc_out[idx]->srt[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->srt; 00705 var_prc_out[idx]->end[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->end; 00706 var_prc_out[idx]->srd[dmn_idx_rec_in]=var_prc_out[idx]->dim[dmn_idx_rec_in]->srd; 00707 } /* endif multi-dimensional */ 00708 } /* endif status changing from non-record to record */ 00709 } /* endif variable will be record variable */ 00710 } /* end loop over var_prc */ 00711 } /* !REDEFINED_RECORD_DIMENSION */ 00712 00713 #ifdef ENABLE_MPI 00714 if(prc_rnk == rnk_mgr){ /* Defining dimension in output file done by Manager alone */ 00715 #endif /* !ENABLE_MPI */ 00716 /* Once new record dimension, if any, is known, define dimensions in output file */ 00717 (void)nco_dmn_dfn(fl_out,out_id,dmn_out,nbr_dmn_out); 00718 #ifdef ENABLE_MPI 00719 } /* prc_rnk != rnk_mgr */ 00720 #endif /* !ENABLE_MPI */ 00721 00722 /* Alter metadata for variables that will be packed */ 00723 if(nco_pck_plc != nco_pck_plc_nil){ 00724 if(nco_pck_plc != nco_pck_plc_upk){ 00725 /* Allocate attribute list container for maximum number of entries */ 00726 aed_lst_add_fst=(aed_sct *)nco_malloc(nbr_var_prc*sizeof(aed_sct)); 00727 aed_lst_scl_fct=(aed_sct *)nco_malloc(nbr_var_prc*sizeof(aed_sct)); 00728 } /* endif packing */ 00729 for(idx=0;idx<nbr_var_prc;idx++){ 00730 nco_pck_mtd(var_prc[idx],var_prc_out[idx],nco_pck_map,nco_pck_plc); 00731 if(nco_pck_plc != nco_pck_plc_upk){ 00732 /* Use same copy of attribute name for all edits */ 00733 aed_lst_add_fst[idx].att_nm=add_fst_sng; 00734 aed_lst_scl_fct[idx].att_nm=scl_fct_sng; 00735 } /* endif packing */ 00736 } /* end loop over var_prc */ 00737 } /* nco_pck_plc == nco_pck_plc_nil */ 00738 00739 #ifdef ENABLE_MPI 00740 if(prc_rnk == rnk_mgr){ /* MPI manager code */ 00741 #endif /* !ENABLE_MPI */ 00742 /* Define variables in output file, copy their attributes */ 00743 (void)nco_var_dfn(in_id,fl_out,out_id,var_out,nbr_xtr,(dmn_sct **)NULL,(int)0,nco_pck_map,nco_pck_plc); 00744 00745 /* Turn off default filling behavior to enhance efficiency */ 00746 rcd=nco_set_fill(out_id,NC_NOFILL,&fll_md_old); 00747 00748 /* Take output file out of define mode */ 00749 (void)nco_enddef(out_id); 00750 #ifdef ENABLE_MPI 00751 } /* prc_rnk != rnk_mgr */ 00752 00753 /* Manager obtains output filename and broadcasts to workers */ 00754 if(prc_rnk == rnk_mgr) fl_nm_lng=(int)strlen(fl_out_tmp); 00755 MPI_Bcast(&fl_nm_lng,1,MPI_INT,0,MPI_COMM_WORLD); 00756 if(prc_rnk != rnk_mgr) fl_out_tmp=(char *)malloc((fl_nm_lng+1)*sizeof(char)); 00757 MPI_Bcast(fl_out_tmp,fl_nm_lng+1,MPI_CHAR,0,MPI_COMM_WORLD); 00758 00759 #endif /* !ENABLE_MPI */ 00760 00761 /* Zero start vectors for all output variables */ 00762 (void)nco_var_srt_zero(var_out,nbr_xtr); 00763 00764 #ifdef ENABLE_MPI 00765 if(prc_rnk == rnk_mgr){ /* MPI manager code */ 00766 TKN_WRT_FREE=False; 00767 #endif /* !ENABLE_MPI */ 00768 /* Copy variable data for non-processed variables */ 00769 (void)nco_var_val_cpy(in_id,out_id,var_fix,nbr_var_fix); 00770 #ifdef ENABLE_MPI 00771 /* Close output file so workers can open it */ 00772 nco_close(out_id); 00773 TKN_WRT_FREE=True; 00774 } /* prc_rnk != rnk_mgr */ 00775 #endif /* !ENABLE_MPI */ 00776 00777 /* Close first input netCDF file */ 00778 nco_close(in_id); 00779 00780 /* Loop over input files (not currently used, fl_nbr == 1) */ 00781 for(fl_idx=0;fl_idx<fl_nbr;fl_idx++){ 00782 /* Parse filename */ 00783 if(fl_idx != 0) fl_in=nco_fl_nm_prs(fl_in,fl_idx,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth); 00784 if(dbg_lvl > 0) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in); 00785 /* Make sure file is on local system and is readable or die trying */ 00786 if(fl_idx != 0) fl_in=nco_fl_mk_lcl(fl_in,fl_pth_lcl,&FILE_RETRIEVED_FROM_REMOTE_LOCATION); 00787 if(dbg_lvl > 0) (void)fprintf(stderr,"local file %s:\n",fl_in); 00788 00789 /* Open file once per thread to improve caching */ 00790 for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) rcd=nco_open(fl_in,NC_NOWRITE,in_id_arr+thr_idx); 00791 00792 #ifdef ENABLE_MPI 00793 if(prc_rnk == rnk_mgr){ /* MPI manager code */ 00794 /* Compensate for incrementing on each worker's first message */ 00795 var_wrt_nbr=-prc_nbr+1; 00796 idx=0; 00797 /* While variables remain to be processed or written... */ 00798 while(var_wrt_nbr < nbr_var_prc){ 00799 /* Receive message from any worker */ 00800 MPI_Recv(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&mpi_stt); 00801 /* Obtain MPI message tag type */ 00802 msg_tag_typ=mpi_stt.MPI_TAG; 00803 /* Get sender's prc_rnk */ 00804 rnk_wrk=wrk_id_bfr[0]; 00805 00806 /* Allocate next variable, if any, to worker */ 00807 if(msg_tag_typ == msg_tag_wrk_rqs){ 00808 var_wrt_nbr++; /* [nbr] Number of variables written */ 00809 /* Worker closed output file before sending msg_tag_wrk_rqs */ 00810 TKN_WRT_FREE=True; 00811 00812 if(idx > nbr_var_prc-1){ 00813 msg_bfr[0]=idx_all_wrk_ass; /* [enm] All variables already assigned */ 00814 msg_bfr[1]=out_id; /* Output file ID */ 00815 }else{ 00816 /* Tell requesting worker to allocate space for next variable */ 00817 msg_bfr[0]=idx; /* [idx] Variable to be processed */ 00818 msg_bfr[1]=out_id; /* Output file ID */ 00819 msg_bfr[2]=var_prc_out[idx]->id; /* [id] Variable ID in output file */ 00820 /* Point to next variable on list */ 00821 idx++; 00822 } /* endif idx */ 00823 MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_wrk_rsp,MPI_COMM_WORLD); 00824 /* msg_tag_typ != msg_tag_wrk_rqs */ 00825 }else if(msg_tag_typ == msg_tag_tkn_wrt_rqs){ 00826 /* Allocate token if free, else ask worker to try later */ 00827 if(TKN_WRT_FREE){ 00828 TKN_WRT_FREE=False; 00829 msg_bfr[0]=tkn_wrt_rqs_xcp; /* Accept request for write token */ 00830 }else{ 00831 msg_bfr[0]=tkn_wrt_rqs_dny; /* Deny request for write token */ 00832 } /* !TKN_WRT_FREE */ 00833 MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); 00834 } /* msg_tag_typ != msg_tag_tkn_wrt_rqs */ 00835 } /* end while var_wrt_nbr < nbr_var_prc */ 00836 }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */ 00837 wrk_id_bfr[0]=prc_rnk; 00838 while(1){ /* While work remains... */ 00839 /* Send msg_tag_wrk_rqs */ 00840 wrk_id_bfr[0]=prc_rnk; 00841 MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rqs,MPI_COMM_WORLD); 00842 /* Receive msg_tag_wrk_rsp */ 00843 MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,0,msg_tag_wrk_rsp,MPI_COMM_WORLD,&mpi_stt); 00844 idx=msg_bfr[0]; 00845 out_id=msg_bfr[1]; 00846 if(idx == idx_all_wrk_ass) break; 00847 else{ 00848 lcl_idx_lst[lcl_nbr_var]=idx; /* storing the indices for subsequent processing by the worker */ 00849 lcl_nbr_var++; 00850 var_prc_out[idx]->id=msg_bfr[2]; 00851 /* Process this variable same as UP code */ 00852 #if 0 00853 /* NB: Immediately preceding MPI else scope confounds Emacs indentation 00854 Fake end scope restores correct indentation, simplifies code-checking */ 00855 } /* fake end else */ 00856 #endif /* !0 */ 00857 #else /* !ENABLE_MPI */ 00858 #ifdef _OPENMP 00859 #pragma omp parallel for default(none) private(idx,in_id) shared(aed_lst_add_fst,aed_lst_scl_fct,dbg_lvl,dmn_idx_out_in,dmn_rdr_nbr,dmn_rvr_in,fp_stderr,fp_stdout,in_id_arr,nbr_var_prc,nco_pck_map,nco_pck_plc,out_id,prg_nm,rcd,var_prc,var_prc_out) 00860 #endif /* !_OPENMP */ 00861 /* UP and SMP codes main loop over variables */ 00862 for(idx=0;idx<nbr_var_prc;idx++){ /* Process all variables in current file */ 00863 #endif /* ENABLE_MPI */ 00864 in_id=in_id_arr[omp_get_thread_num()]; 00865 /* fxm TODO nco638 temporary fix? */ 00866 var_prc[idx]->nc_id=in_id; 00867 if(dbg_lvl > 1) rcd+=nco_var_prc_crr_prn(idx,var_prc[idx]->nm); 00868 if(dbg_lvl > 0) (void)fflush(fp_stderr); 00869 00870 /* Retrieve variable from disk into memory */ 00871 /* NB: nco_var_get() with same nc_id contains OpenMP critical region */ 00872 (void)nco_var_get(in_id,var_prc[idx]); 00873 00874 if(dmn_rdr_nbr > 0){ 00875 if((var_prc_out[idx]->val.vp=(void *)nco_malloc_flg(var_prc_out[idx]->sz*nco_typ_lng(var_prc_out[idx]->type))) == NULL){ 00876 (void)fprintf(fp_stdout,"%s: ERROR Unable to malloc() %ld*%lu bytes for value buffer for variable %s in main()\n",prg_nm_get(),var_prc_out[idx]->sz,(unsigned long)nco_typ_lng(var_prc_out[idx]->type),var_prc_out[idx]->nm); 00877 nco_exit(EXIT_FAILURE); 00878 } /* endif err */ 00879 00880 /* Change dimensionionality of values */ 00881 rcd=nco_var_dmn_rdr_val(var_prc[idx],var_prc_out[idx],dmn_idx_out_in[idx],dmn_rvr_in[idx]); 00882 /* Re-ordering required two value buffers, time to free input buffer */ 00883 var_prc[idx]->val.vp=nco_free(var_prc[idx]->val.vp); 00884 /* Free current dimension correspondence */ 00885 dmn_idx_out_in[idx]=nco_free(dmn_idx_out_in[idx]); 00886 dmn_rvr_in[idx]=nco_free(dmn_rvr_in[idx]); 00887 } /* endif dmn_rdr_nbr > 0 */ 00888 00889 if(nco_pck_plc != nco_pck_plc_nil){ 00890 /* Copy input variable buffer to processed variable buffer */ 00891 /* fxm: this is dangerous and leads to double free()'ing variable buffer */ 00892 var_prc_out[idx]->val=var_prc[idx]->val; 00893 /* (Un-)Pack variable according to packing specification */ 00894 nco_pck_val(var_prc[idx],var_prc_out[idx],nco_pck_map,nco_pck_plc,aed_lst_add_fst+idx,aed_lst_scl_fct+idx); 00895 } /* endif dmn_rdr_nbr > 0 */ 00896 00897 #ifdef ENABLE_MPI 00898 /* Obtain token and prepare to write */ 00899 while(1){ /* Send msg_tag_tkn_wrt_rqs repeatedly until token obtained */ 00900 wrk_id_bfr[0]=prc_rnk; 00901 MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rqs,MPI_COMM_WORLD); 00902 MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); 00903 tkn_wrt_rsp=msg_bfr[0]; 00904 /* Wait then re-send request */ 00905 if(tkn_wrt_rsp == tkn_wrt_rqs_dny) sleep(tkn_wrt_rqs_ntv); else break; 00906 } /* end while loop waiting for write token */ 00907 00908 /* Worker has token---prepare to write */ 00909 if(tkn_wrt_rsp == tkn_wrt_rqs_xcp){ 00910 rcd=nco_open(fl_out_tmp,NC_WRITE|NC_SHARE,&out_id); 00911 /* Turn off default filling behavior to enhance efficiency */ 00912 rcd=nco_set_fill(out_id,NC_NOFILL,&fll_md_old); 00913 #else /* !ENABLE_MPI */ 00914 #ifdef _OPENMP 00915 #pragma omp critical 00916 #endif /* _OPENMP */ 00917 #endif /* !ENABLE_MPI */ 00918 { /* begin OpenMP critical */ 00919 /* Common code for UP, SMP, and MPI */ 00920 /* Copy variable to output file then free value buffer */ 00921 if(var_prc_out[idx]->nbr_dim == 0){ 00922 (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); 00923 }else{ /* end if variable is scalar */ 00924 (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_out[idx]->val.vp,var_prc_out[idx]->type); 00925 } /* end if variable is array */ 00926 } /* end OpenMP critical */ 00927 /* Free current output buffer */ 00928 var_prc_out[idx]->val.vp=nco_free(var_prc_out[idx]->val.vp); 00929 00930 #ifdef ENABLE_MPI 00931 /* Close output file and increment written counter */ 00932 nco_close(out_id); 00933 var_wrt_nbr++; 00934 } /* endif tkn_wrt_rqs_xcp */ 00935 } /* end else !idx_all_wrk_ass */ 00936 } /* end while loop requesting work/token */ 00937 } /* endif Worker */ 00938 #else /* !ENABLE_MPI */ 00939 } /* end (OpenMP parallel for) loop over idx */ 00940 #endif /* !ENABLE_MPI */ 00941 00942 if(dbg_lvl > 0) (void)fprintf(fp_stderr,"\n"); 00943 00944 #ifdef ENABLE_MPI 00945 MPI_Barrier(MPI_COMM_WORLD); 00946 if(prc_rnk == rnk_mgr) { /* Manager only */ 00947 MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk+1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); 00948 } /* ! prc_rnk == rnk_mgr */ 00949 else{ /* Workers */ 00950 MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk-1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); 00951 #endif /* !ENABLE_MPI */ 00952 00953 /* Write/overwrite packing attributes for newly packed and re-packed variables 00954 Logic here should nearly mimic logic in nco_var_dfn() */ 00955 if(nco_pck_plc != nco_pck_plc_nil && nco_pck_plc != nco_pck_plc_upk){ 00956 nco_bool nco_pck_plc_alw; /* [flg] Packing policy allows packing nc_typ_in */ 00957 /* ...put file in define mode to allow metadata writing... */ 00958 rcd=nco_open(fl_out_tmp,NC_WRITE,&out_id); 00959 (void)nco_redef(out_id); 00960 /* ...loop through all variables that may have been packed... */ 00961 #ifdef ENABLE_MPI 00962 for(jdx=0;jdx<lcl_nbr_var;jdx++){ 00963 idx=lcl_idx_lst[jdx]; 00964 #else /* !ENABLE_MPI */ 00965 for(idx=0;idx<nbr_var_prc;idx++){ 00966 #endif /* !ENABLE_MPI */ 00967 /* nco_var_dfn() pre-defined dummy packing attributes in output file 00968 only for input variables considered "packable" */ 00969 if((nco_pck_plc_alw=nco_pck_plc_typ_get(nco_pck_map,var_prc[idx]->typ_upk,(nc_type *)NULL))){ 00970 /* Verify input variable was newly packed by this operator 00971 Writing pre-existing (non-re-packed) attributes here would fail because 00972 nco_pck_dsk_inq() never fills in var->scl_fct.vp and var->add_fst.vp 00973 Logic is same as in nco_var_dfn() (except var_prc[] instead of var[]) 00974 If operator newly packed this particular variable... */ 00975 if( 00976 /* ...either because operator newly packs all variables... */ 00977 (nco_pck_plc == nco_pck_plc_all_new_att) || 00978 /* ...or because operator newly packs un-packed variables like this one... */ 00979 (nco_pck_plc == nco_pck_plc_all_xst_att && !var_prc[idx]->pck_ram) || 00980 /* ...or because operator re-packs packed variables like this one... */ 00981 (nco_pck_plc == nco_pck_plc_xst_new_att && var_prc[idx]->pck_ram) 00982 ){ 00983 /* Replace dummy packing attributes with final values, or delete them */ 00984 if(dbg_lvl >= 5) (void)fprintf(stderr,"%s: main() replacing dummy packing attribute values for variable %s\n",prg_nm,var_prc[idx]->nm); 00985 (void)nco_aed_prc(out_id,aed_lst_add_fst[idx].id,aed_lst_add_fst[idx]); 00986 (void)nco_aed_prc(out_id,aed_lst_scl_fct[idx].id,aed_lst_scl_fct[idx]); 00987 } /* endif variable is newly packed by this operator */ 00988 } /* endif nco_pck_plc_alw */ 00989 } /* end loop over var_prc */ 00990 (void)nco_enddef(out_id); 00991 #ifdef ENABLE_MPI 00992 nco_close(out_id); 00993 #endif /* !ENABLE_MPI */ 00994 } /* nco_pck_plc == nco_pck_plc_nil || nco_pck_plc == nco_pck_plc_upk */ 00995 00996 #ifdef ENABLE_MPI 00997 if(prc_rnk == prc_nbr-1) /* Send Token to Manager */ 00998 MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); 00999 else 01000 MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,prc_rnk+1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD); 01001 } /* !Workers */ 01002 if(prc_rnk == rnk_mgr){ /* Only Manager */ 01003 MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,prc_nbr-1,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt); 01004 } /* prc_rnk != rnk_mgr */ 01005 #endif /* !ENABLE_MPI */ 01006 01007 /* Close input netCDF file */ 01008 for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) nco_close(in_id_arr[thr_idx]); 01009 01010 /* Remove local copy of file */ 01011 if(FILE_RETRIEVED_FROM_REMOTE_LOCATION && REMOVE_REMOTE_FILES_AFTER_PROCESSING) (void)nco_fl_rm(fl_in); 01012 01013 } /* end loop over fl_idx */ 01014 01015 #ifdef ENABLE_MPI 01016 MPI_Barrier(MPI_COMM_WORLD); 01017 /* Manager moves output file (closed by workers) from temporary to permanent location */ 01018 if(prc_rnk == rnk_mgr) (void)nco_fl_mv(fl_out_tmp,fl_out); 01019 #else /* !ENABLE_MPI */ 01020 /* Close output file and move it from temporary to permanent location */ 01021 (void)nco_fl_out_cls(fl_out,fl_out_tmp,out_id); 01022 #endif /* end !ENABLE_MPI */ 01023 01024 /* ncpdq-specific memory cleanup */ 01025 if(dmn_rdr_nbr > 0){ 01026 /* Free dimension correspondence list */ 01027 for(idx=0;idx<nbr_var_prc;idx++){ 01028 dmn_idx_out_in[idx]=(int *)nco_free(dmn_idx_out_in[idx]); 01029 dmn_rvr_in[idx]=(nco_bool *)nco_free(dmn_rvr_in[idx]); 01030 } /* end loop over idx */ 01031 if(dmn_idx_out_in != NULL) dmn_idx_out_in=(int **)nco_free(dmn_idx_out_in); 01032 if(dmn_rvr_in != NULL) dmn_rvr_in=(nco_bool **)nco_free(dmn_rvr_in); 01033 if(dmn_rvr_rdr != NULL) dmn_rvr_rdr=(nco_bool *)nco_free(dmn_rvr_rdr); 01034 if(dmn_rdr_nbr_in > 0) dmn_rdr_lst_in=nco_sng_lst_free(dmn_rdr_lst_in,dmn_rdr_nbr_in); 01035 /* Free dimension list pointers */ 01036 dmn_rdr=(dmn_sct **)nco_free(dmn_rdr); 01037 /* Dimension structures in dmn_rdr are owned by dmn and dmn_out, free'd later */ 01038 } /* endif dmn_rdr_nbr > 0 */ 01039 if(nco_pck_plc != nco_pck_plc_nil){ 01040 if(nco_pck_plc_sng != NULL) nco_pck_plc_sng=(char *)nco_free(nco_pck_plc_sng); 01041 if(nco_pck_map_sng != NULL) nco_pck_map_sng=(char *)nco_free(nco_pck_map_sng); 01042 if(nco_pck_plc != nco_pck_plc_upk){ 01043 /* No need for loop over var_prc variables to free attribute values 01044 Variable structures and attribute edit lists share same attribute values 01045 Free them only once, and do it in nco_var_free() */ 01046 aed_lst_add_fst=(aed_sct *)nco_free(aed_lst_add_fst); 01047 aed_lst_scl_fct=(aed_sct *)nco_free(aed_lst_scl_fct); 01048 } /* nco_pck_plc == nco_pck_plc_upk */ 01049 } /* nco_pck_plc == nco_pck_plc_nil */ 01050 01051 /* NCO-generic clean-up */ 01052 /* Free individual strings/arrays */ 01053 if(cmd_ln != NULL) cmd_ln=(char *)nco_free(cmd_ln); 01054 if(fl_in != NULL) fl_in=(char *)nco_free(fl_in); 01055 if(fl_out != NULL) fl_out=(char *)nco_free(fl_out); 01056 if(fl_out_tmp != NULL) fl_out_tmp=(char *)nco_free(fl_out_tmp); 01057 if(fl_pth != NULL) fl_pth=(char *)nco_free(fl_pth); 01058 if(fl_pth_lcl != NULL) fl_pth_lcl=(char *)nco_free(fl_pth_lcl); 01059 if(in_id_arr != NULL) in_id_arr=(int *)nco_free(in_id_arr); 01060 /* Free lists of strings */ 01061 if(fl_lst_in != NULL && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); 01062 if(fl_lst_in != NULL && fl_lst_abb != NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,1); 01063 if(fl_lst_abb != NULL) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr); 01064 if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr); 01065 /* Free limits */ 01066 for(idx=0;idx<lmt_nbr;idx++) lmt_arg[idx]=(char *)nco_free(lmt_arg[idx]); 01067 if(lmt_nbr > 0) lmt=nco_lmt_lst_free(lmt,lmt_nbr); 01068 /* Free dimension lists */ 01069 if(nbr_dmn_xtr > 0) dim=nco_dmn_lst_free(dim,nbr_dmn_xtr); 01070 if(nbr_dmn_xtr > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr); 01071 /* Free variable lists */ 01072 if(nbr_xtr > 0) var=nco_var_lst_free(var,nbr_xtr); 01073 if(nbr_xtr > 0) var_out=nco_var_lst_free(var_out,nbr_xtr); 01074 var_prc=(var_sct **)nco_free(var_prc); 01075 var_prc_out=(var_sct **)nco_free(var_prc_out); 01076 var_fix=(var_sct **)nco_free(var_fix); 01077 var_fix_out=(var_sct **)nco_free(var_fix_out); 01078 01079 #ifdef ENABLE_MPI 01080 MPI_Finalize(); 01081 #endif /* !ENABLE_MPI */ 01082 01083 nco_exit_gracefully(); 01084 return EXIT_SUCCESS; 01085 } /* end main() */
|
1.4.4