nco/mpncpdq.c File Reference

#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)


Define Documentation

#define MAIN_PROGRAM_FILE
 

Definition at line 68 of file mpncpdq.c.


Function Documentation

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() */


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