nco/mpncbo.c File Reference

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "nco_getopt.h"
#include <netcdf.h>
#include "libnco.h"

Include dependency graph for mpncbo.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 84 of file mpncbo.c.


Function Documentation

int main int  argc,
char **  argv
 

Definition at line 88 of file mpncbo.c.

References dmn_sct_tag::cnt, copyright_prn(), var_sct_tag::dim, EXIT_FAILURE, EXIT_SUCCESS, False, FILE, getopt_long, var_sct_tag::has_mss_val, var_sct_tag::id, idx_all_wrk_ass, int_CEWI, lst_prs_2D(), msg_bfr_lng, msg_tag_tkn_wrt_rqs, msg_tag_tkn_wrt_rsp, msg_tag_wrk_rqs, msg_tag_wrk_rsp, var_sct_tag::mss_val, option::name, var_sct_tag::nbr_dim, NC_FORMAT_64BIT, NC_FORMAT_CLASSIC, NC_FORMAT_NETCDF4, NC_GLOBAL, NC_MAX_DIMS, NC_NOERR, NC_NOFILL, NC_NOWRITE, NC_SHARE, NC_WRITE, ncap_var_cnf_dmn(), 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_xrf(), nco_enddef(), nco_err_exit(), nco_exit(), nco_exit_gracefully(), nco_fl_cmp_err_chk(), 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_mpi_att_cat(), nco_mss_val_cnf(), nco_nm_id_lst_free(), nco_op_add, nco_op_dvd, nco_op_mlt, nco_op_nil, nco_op_sbt, nco_op_typ_get(), nco_open(), nco_openmp_ini(), nco_pck_map_nil, nco_pck_plc_nil, nco_put_var1(), nco_put_vara(), nco_set_fill(), nco_sng_lst_free(), nco_spn_lck_brk, nco_spn_lck_us, nco_thr_att_cat(), nco_typ_sng(), nco_usg_prn(), nco_var_add(), nco_var_cnf_typ(), nco_var_dfn(), nco_var_dpl(), nco_var_dvd(), 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_mrg(), nco_var_lst_xcl(), nco_var_mlt(), nco_var_mtd_refresh(), nco_var_sbt(), nco_var_srt_zero(), nco_var_val_cpy(), nco_xrf_dmn(), nco_xrf_var(), no_argument, NULL_CEWI, omp_get_thread_num(), optarg, optind, prg_nm_get(), prg_prs(), required_argument, rnk_mgr, tkn_wrt_rqs_dny, tkn_wrt_rqs_ntv, tkn_wrt_rqs_xcp, True, type, var_sct_tag::type, var_sct_tag::val, option::val, ptr_unn::vp, and wrk_id_bfr_lng.

00089 {
00090   nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */
00091   nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */
00092   nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */
00093   nco_bool FILE_1_RETRIEVED_FROM_REMOTE_LOCATION;
00094   nco_bool FILE_2_RETRIEVED_FROM_REMOTE_LOCATION;
00095   nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */
00096   nco_bool FORCE_APPEND=False; /* Option A */
00097   nco_bool FORCE_OVERWRITE=False; /* Option O */
00098   nco_bool FORTRAN_IDX_CNV=False; /* Option F */
00099   nco_bool HISTORY_APPEND=True; /* Option h */
00100   nco_bool CNV_CCM_CCSM_CF;
00101   nco_bool REMOVE_REMOTE_FILES_AFTER_PROCESSING=True; /* Option R */
00102   
00103   char **fl_lst_abb=NULL; /* Option a */
00104   char **fl_lst_in;
00105   char **var_lst_in=NULL_CEWI;
00106   char *cmd_ln;
00107   char *fl_in_1=NULL; /* fl_in_1 is nco_realloc'd when not NULL */;
00108   char *fl_in_2=NULL; /* fl_in_2 is nco_realloc'd when not NULL */;
00109   char *fl_out=NULL; /* Option o */
00110   char *fl_out_tmp=NULL; /* MPI CEWI */
00111   char *fl_pth=NULL; /* Option p */
00112   char *fl_pth_lcl=NULL; /* Option l */
00113   char *lmt_arg[NC_MAX_DIMS];
00114   char *nco_op_typ_sng=NULL; /* [sng] Operation type */
00115   char *opt_crr=NULL; /* [sng] String representation of current long-option name */
00116   char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */
00117   char *time_bfr_srt;
00118   
00119   const char * const CVS_Id="$Id: mpncbo.c,v 1.48 2006/02/26 07:41:55 zender Exp $"; 
00120   const char * const CVS_Revision="$Revision: 1.48 $";
00121   const char * const opt_sht_lst="4ACcD:d:Fhl:Oo:p:rRSt:v:xy:-:";
00122   
00123   dmn_sct **dim_1;
00124   dmn_sct **dim_2;
00125   dmn_sct **dmn_out;
00126   
00127   extern char *optarg;
00128   extern int optind;
00129   
00130   /* Using naked stdin/stdout/stderr in parallel region generates warning
00131      Copy appropriate filehandle to variable scoped shared in parallel clause */
00132   FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */
00133   FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */
00134   
00135   int *in_id_1_arr;
00136   int *in_id_2_arr;
00137 
00138   int abb_arg_nbr=0;
00139   int fl_idx;
00140   int fl_nbr=0;
00141   int fl_out_fmt=NC_FORMAT_CLASSIC; /* [enm] Output file format */
00142   int fll_md_old; /* [enm] Old fill mode */
00143   int idx;
00144   int in_id_1;  
00145   int in_id_2;  
00146   int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */
00147   int nbr_dmn_fl_1;
00148   int nbr_dmn_fl_2;
00149   int nbr_dmn_xtr_1;
00150   int nbr_dmn_xtr_2;
00151   int nbr_var_fix_1; /* nbr_var_fix_1 gets incremented */
00152   int nbr_var_fix_2; /* nbr_var_fix_2 gets incremented */
00153   int nbr_var_fl_1;
00154   int nbr_var_fl_2;
00155   int nbr_var_prc_1; /* nbr_var_prc_1 gets incremented */
00156   int nbr_var_prc_2; /* nbr_var_prc_2 gets incremented */
00157   int nbr_xtr_1=0; /* nbr_xtr_1 won't otherwise be set for -c with no -v */
00158   int nbr_xtr_2=0; /* nbr_xtr_2 won't otherwise be set for -c with no -v */
00159   int nco_op_typ=nco_op_nil; /* [enm] Operation type */
00160   int opt;
00161   int out_id;  
00162   int rcd=NC_NOERR; /* [rcd] Return code */
00163   int thr_idx; /* [idx] Index of current thread */
00164   int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */
00165   int var_lst_in_nbr=0;
00166   
00167   lmt_sct **lmt;
00168   
00169   nm_id_sct *dmn_lst_1;
00170   nm_id_sct *dmn_lst_2;
00171   nm_id_sct *xtr_lst_1=NULL; /* xtr_lst_1 may be alloc()'d from NULL with -c option */
00172   nm_id_sct *xtr_lst_2=NULL; /* xtr_lst_2 may be alloc()'d from NULL with -c option */
00173   
00174   time_t time_crr_time_t;
00175   
00176   var_sct **var_1;
00177   var_sct **var_2;
00178   var_sct **var_fix_1;
00179   var_sct **var_fix_2;
00180   var_sct **var_fix_out;
00181   var_sct **var_out;
00182   var_sct **var_prc_1;
00183   var_sct **var_prc_2;
00184   var_sct **var_prc_out;
00185   
00186 #ifdef ENABLE_MPI
00187   /* #if defined(ENABLE_MPI) && !defined(ENABLE_NETCDF4) */
00188   /* Declare all MPI-specific variables here */
00189   MPI_Status mpi_stt; /* [enm] Status check to decode msg_tag_typ */
00190   
00191   bool TKN_WRT_FREE=True; /* [flg] Write-access to output file is available */
00192   
00193   int fl_nm_lng; /* [nbr] Output file name length CEWI */
00194   int msg_bfr[msg_bfr_lng]; /* [bfr] Buffer containing var, idx, tkn_wrt_rsp */
00195   int msg_tag_typ; /* [enm] MPI message tag type */
00196   int prc_rnk; /* [idx] Process rank */
00197   int prc_nbr=0; /* [nbr] Number of MPI processes */
00198   int tkn_wrt_rsp; /* [enm] Response to request for write token */
00199   int var_wrt_nbr=0; /* [nbr] Variables written to output file until now */
00200   int rnk_wrk; /* [idx] Worker rank */
00201   int wrk_id_bfr[wrk_id_bfr_lng]; /* [bfr] Buffer for rnk_wrk */
00202 #endif /* !ENABLE_MPI */
00203   
00204   static struct option opt_lng[]=
00205     { /* Structure ordered by short option key if possible */
00206       /* Long options with no argument, no short option counterpart */
00207       /* Long options with argument, no short option counterpart */
00208       {"fl_fmt",required_argument,0,0},
00209       {"file_format",required_argument,0,0},
00210       /* Long options with short counterparts */
00211       {"4",no_argument,0,'4'},
00212       {"64bit",no_argument,0,'4'},
00213       {"netcdf4",no_argument,0,'4'},
00214       {"append",no_argument,0,'A'},
00215       {"coords",no_argument,0,'c'},
00216       {"crd",no_argument,0,'c'},
00217       {"no-coords",no_argument,0,'C'},
00218       {"no-crd",no_argument,0,'C'},
00219       {"debug",required_argument,0,'D'},
00220       {"dbg_lvl",required_argument,0,'D'},
00221       {"dimension",required_argument,0,'d'},
00222       {"dmn",required_argument,0,'d'},
00223       {"fortran",no_argument,0,'F'},
00224       {"ftn",no_argument,0,'F'},
00225       {"history",no_argument,0,'h'},
00226       {"hst",no_argument,0,'h'},
00227       {"local",required_argument,0,'l'},
00228       {"lcl",required_argument,0,'l'},
00229       {"overwrite",no_argument,0,'O'},
00230       {"ovr",no_argument,0,'O'},
00231       {"path",required_argument,0,'p'},
00232       {"retain",no_argument,0,'R'},
00233       {"rtn",no_argument,0,'R'},
00234       {"revision",no_argument,0,'r'},
00235       {"suspend", no_argument,0,'S'},
00236       {"variable",required_argument,0,'v'},
00237       {"version",no_argument,0,'r'},
00238       {"vrs",no_argument,0,'r'},
00239       {"thr_nbr",required_argument,0,'t'},
00240       {"exclude",no_argument,0,'x'},
00241       {"xcl",no_argument,0,'x'},
00242       {"operation",required_argument,0,'y'},
00243       {"op_typ",required_argument,0,'y'},
00244       {"help",no_argument,0,'?'},
00245       {0,0,0,0}
00246     }; /* end opt_lng */
00247   int opt_idx=0; /* Index of current long option into opt_lng array */
00248   
00249 #ifdef ENABLE_MPI 
00250   /* MPI Initialization */
00251   MPI_Init(&argc,&argv);
00252   MPI_Comm_size(MPI_COMM_WORLD,&prc_nbr);
00253   MPI_Comm_rank(MPI_COMM_WORLD,&prc_rnk);
00254 #endif /* !ENABLE_MPI */
00255   
00256   /* Start clock and save command line */ 
00257   cmd_ln=nco_cmd_ln_sng(argc,argv);
00258   time_crr_time_t=time((time_t *)NULL);
00259   time_bfr_srt=ctime(&time_crr_time_t); time_bfr_srt=time_bfr_srt; /* Avoid compiler warning until variable is used for something */
00260   
00261   /* Get program name and set program enum (e.g., prg=ncra) */
00262   prg_nm=prg_prs(argv[0],&prg);
00263   
00264   /* Parse command line arguments */
00265   while(1){
00266     /* getopt_long_only() allows one dash to prefix long options */
00267     opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx);
00268     /* NB: access to opt_crr is only valid when long_opt is detected */
00269     if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */
00270     opt_crr=(char *)strdup(opt_lng[opt_idx].name);
00271 
00272     /* Process long options without short option counterparts */
00273     if(opt == 0){
00274       if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt);
00275     } /* opt != 0 */
00276     /* Process short options */
00277     switch(opt){
00278     case 0: /* Long options have already been processed, return */
00279       break;
00280     case '4': /* [flg] Catch-all to prescribe output storage format */
00281       if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; 
00282       break;
00283     case 'A': /* Toggle FORCE_APPEND */
00284       FORCE_APPEND=!FORCE_APPEND;
00285       break;
00286     case 'C': /* Extract all coordinates associated with extracted variables? */
00287       EXTRACT_ASSOCIATED_COORDINATES=False;
00288       break;
00289     case 'c':
00290       EXTRACT_ALL_COORDINATES=True;
00291       break;
00292     case 'D': /* The debugging level. Default is 0. */
00293       dbg_lvl=(unsigned short)strtol(optarg,(char **)NULL,10);
00294       break;
00295     case 'd': /* Copy argument for later processing */
00296       lmt_arg[lmt_nbr]=(char *)strdup(optarg);
00297       lmt_nbr++;
00298       break;
00299     case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */
00300       FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV;
00301       break;
00302     case 'h': /* Toggle appending to history global attribute */
00303       HISTORY_APPEND=!HISTORY_APPEND;
00304       break;
00305     case 'l': /* Local path prefix for files retrieved from remote file system */
00306       fl_pth_lcl=(char *)strdup(optarg);
00307       break;
00308     case 'O': /* Toggle FORCE_OVERWRITE */
00309       FORCE_OVERWRITE=!FORCE_OVERWRITE;
00310       break;
00311     case 'o': /* Name of output file */
00312       fl_out=(char *)strdup(optarg);
00313       break;
00314     case 'p': /* Common file path */
00315       fl_pth=(char *)strdup(optarg);
00316       break;
00317     case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */
00318       REMOVE_REMOTE_FILES_AFTER_PROCESSING=!REMOVE_REMOTE_FILES_AFTER_PROCESSING;
00319       break;
00320     case 'r': /* Print CVS program information and copyright notice */
00321       (void)copyright_prn(CVS_Id,CVS_Revision);
00322       (void)nco_lbr_vrs_prn();
00323       nco_exit(EXIT_SUCCESS);
00324       break;
00325 #ifdef ENABLE_MPI
00326     case 'S': /* Suspend with signal handler to facilitate debugging */
00327       if(signal(SIGUSR1,nco_cnt_run) == SIG_ERR) (void)fprintf(fp_stdout,"%s: ERROR Could not install suspend handler.\n",prg_nm);
00328       while(!nco_spn_lck_brk) usleep(nco_spn_lck_us); /* Spinlock. fxm: should probably insert a sched_yield */
00329       break;
00330 #endif /* !ENABLE_MPI */
00331     case 't': /* Thread number */
00332       thr_nbr=(int)strtol(optarg,(char **)NULL,10);
00333       break;
00334     case 'v': /* Variables to extract/exclude */
00335       /* Replace commas with hashes when within braces (convert back later) */
00336       optarg_lcl=(char *)strdup(optarg);
00337       (void)nco_lst_comma2hash(optarg_lcl);
00338       var_lst_in=lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr);
00339       optarg_lcl=(char *)nco_free(optarg_lcl);
00340       nbr_xtr_1=nbr_xtr_2=var_lst_in_nbr;
00341       break;
00342     case 'x': /* Exclude rather than extract variables specified with -v */
00343       EXCLUDE_INPUT_LIST=True;
00344       break;
00345     case 'y': /* User-specified operation type overrides invocation default */
00346       nco_op_typ_sng=(char *)strdup(optarg);
00347       nco_op_typ=nco_op_typ_get(nco_op_typ_sng);
00348       break;
00349     case '?': /* Print proper usage */
00350       (void)nco_usg_prn();
00351       nco_exit(EXIT_SUCCESS);
00352       break;
00353     case '-': /* Long options are not allowed */
00354       (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",prg_nm_get());
00355       nco_exit(EXIT_FAILURE);
00356       break;
00357     default: /* Print proper usage */
00358       (void)nco_usg_prn();
00359       nco_exit(EXIT_FAILURE);
00360       break;
00361     } /* end switch */
00362     if(opt_crr != NULL) opt_crr=(char *)nco_free(opt_crr);
00363   } /* end while loop */
00364   
00365   /* Process positional arguments and fill in filenames */
00366   fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN);
00367   
00368   /* Make uniform list of user-specified dimension limits */
00369   lmt=nco_lmt_prs(lmt_nbr,lmt_arg);
00370     
00371   /* Initialize thread information */
00372   thr_nbr=nco_openmp_ini(thr_nbr);
00373   in_id_1_arr=(int *)nco_malloc(thr_nbr*sizeof(int));
00374   in_id_2_arr=(int *)nco_malloc(thr_nbr*sizeof(int));
00375 
00376   /* Parse filenames */
00377   fl_idx=0; /* Input file _1 */
00378   fl_in_1=nco_fl_nm_prs(fl_in_1,fl_idx,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth);
00379   if(dbg_lvl > 0) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in_1);
00380   /* Make sure file is on local system and is readable or die trying */
00381   fl_in_1=nco_fl_mk_lcl(fl_in_1,fl_pth_lcl,&FILE_1_RETRIEVED_FROM_REMOTE_LOCATION);
00382   if(dbg_lvl > 0) (void)fprintf(stderr,"local file %s:\n",fl_in_1);
00383   /* Open file once per thread to improve caching */
00384   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) rcd=nco_open(fl_in_1,NC_NOWRITE,in_id_1_arr+thr_idx);
00385   in_id_1=in_id_1_arr[0];
00386   
00387   fl_idx=1; /* Input file _2 */
00388   fl_in_2=nco_fl_nm_prs(fl_in_2,fl_idx,&fl_nbr,fl_lst_in,abb_arg_nbr,fl_lst_abb,fl_pth);
00389   if(dbg_lvl > 0) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in_2);
00390   /* Make sure file is on local system and is readable or die trying */
00391   fl_in_2=nco_fl_mk_lcl(fl_in_2,fl_pth_lcl,&FILE_2_RETRIEVED_FROM_REMOTE_LOCATION);
00392   if(dbg_lvl > 0) (void)fprintf(stderr,"local file %s:\n",fl_in_2);
00393   /* Open file once per thread to improve caching */
00394   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) rcd=nco_open(fl_in_2,NC_NOWRITE,in_id_2_arr+thr_idx);
00395   in_id_2=in_id_2_arr[0];
00396   
00397   /* Get number of variables and dimensions in file */
00398   (void)nco_inq(in_id_1,&nbr_dmn_fl_1,&nbr_var_fl_1,(int *)NULL,(int *)NULL);
00399   (void)nco_inq(in_id_2,&nbr_dmn_fl_2,&nbr_var_fl_2,(int *)NULL,(int *)NULL);
00400   
00401   /* Form initial extraction list which may include extended regular expressions */
00402   xtr_lst_1=nco_var_lst_mk(in_id_1,nbr_var_fl_1,var_lst_in,EXTRACT_ALL_COORDINATES,&nbr_xtr_1);
00403   xtr_lst_2=nco_var_lst_mk(in_id_2,nbr_var_fl_2,var_lst_in,EXTRACT_ALL_COORDINATES,&nbr_xtr_2);
00404   
00405   /* Change included variables to excluded variables */
00406   if(EXCLUDE_INPUT_LIST) xtr_lst_1=nco_var_lst_xcl(in_id_1,nbr_var_fl_1,xtr_lst_1,&nbr_xtr_1);
00407   if(EXCLUDE_INPUT_LIST) xtr_lst_2=nco_var_lst_xcl(in_id_2,nbr_var_fl_2,xtr_lst_2,&nbr_xtr_2);
00408   
00409   /* Add all coordinate variables to extraction list */
00410   if(EXTRACT_ALL_COORDINATES) xtr_lst_1=nco_var_lst_add_crd(in_id_1,nbr_dmn_fl_1,xtr_lst_1,&nbr_xtr_1);
00411   if(EXTRACT_ALL_COORDINATES) xtr_lst_2=nco_var_lst_add_crd(in_id_2,nbr_dmn_fl_2,xtr_lst_2,&nbr_xtr_2);
00412   
00413   /* Make sure coordinates associated extracted variables are also on extraction list */
00414   if(EXTRACT_ASSOCIATED_COORDINATES) xtr_lst_1=nco_var_lst_ass_crd_add(in_id_1,xtr_lst_1,&nbr_xtr_1);
00415   if(EXTRACT_ASSOCIATED_COORDINATES) xtr_lst_2=nco_var_lst_ass_crd_add(in_id_2,xtr_lst_2,&nbr_xtr_2);
00416   
00417   /* With fully symmetric 1<->2 ordering, may occasionally find nbr_xtr_2 > nbr_xtr_1 
00418      This occurs, e.g., when fl_in_1 contains reduced variables and full coordinates
00419      are only in fl_in_2 and so will not appear xtr_lst_1 */
00420   
00421   /* Sort extraction list by variable ID for fastest I/O */
00422   if(nbr_xtr_1 > 1) xtr_lst_1=nco_lst_srt_nm_id(xtr_lst_1,nbr_xtr_1,False);
00423   if(nbr_xtr_2 > 1) xtr_lst_2=nco_lst_srt_nm_id(xtr_lst_2,nbr_xtr_2,False);
00424   
00425   /* We now have final list of variables to extract. Phew. */
00426   
00427   /* Find coordinate/dimension values associated with user-specified limits
00428      NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */
00429   for(idx=0;idx<lmt_nbr;idx++) (void)nco_lmt_evl(in_id_1,lmt[idx],0L,FORTRAN_IDX_CNV);
00430   
00431   /* Find dimensions associated with variables to be extracted */
00432   dmn_lst_1=nco_dmn_lst_ass_var(in_id_1,xtr_lst_1,nbr_xtr_1,&nbr_dmn_xtr_1);
00433   dmn_lst_2=nco_dmn_lst_ass_var(in_id_2,xtr_lst_2,nbr_xtr_2,&nbr_dmn_xtr_2);
00434   
00435   /* Fill in dimension structure for all extracted dimensions */
00436   dim_1=(dmn_sct **)nco_malloc(nbr_dmn_xtr_1*sizeof(dmn_sct *));
00437   dim_2=(dmn_sct **)nco_malloc(nbr_dmn_xtr_2*sizeof(dmn_sct *));
00438   for(idx=0;idx<nbr_dmn_xtr_1;idx++) dim_1[idx]=nco_dmn_fll(in_id_1,dmn_lst_1[idx].id,dmn_lst_1[idx].nm);
00439   for(idx=0;idx<nbr_dmn_xtr_2;idx++) dim_2[idx]=nco_dmn_fll(in_id_2,dmn_lst_2[idx].id,dmn_lst_2[idx].nm);
00440   /* Dimension lists no longer needed */
00441   dmn_lst_1=nco_nm_id_lst_free(dmn_lst_1,nbr_dmn_xtr_1);
00442   dmn_lst_2=nco_nm_id_lst_free(dmn_lst_2,nbr_dmn_xtr_2);
00443   
00444   /* Merge hyperslab limit information into dimension structures */
00445   if(lmt_nbr > 0) (void)nco_dmn_lmt_mrg(dim_1,nbr_dmn_xtr_1,lmt,lmt_nbr);
00446   if(lmt_nbr > 0) (void)nco_dmn_lmt_mrg(dim_2,nbr_dmn_xtr_2,lmt,lmt_nbr);
00447   
00448   /* Duplicate input dimension structures for output dimension structures */
00449   dmn_out=(dmn_sct **)nco_malloc(nbr_dmn_xtr_1*sizeof(dmn_sct *));
00450   for(idx=0;idx<nbr_dmn_xtr_1;idx++){
00451     dmn_out[idx]=nco_dmn_dpl(dim_1[idx]);
00452     (void)nco_dmn_xrf(dim_1[idx],dmn_out[idx]); 
00453   } /* end loop over idx */
00454   
00455   if(dbg_lvl > 3){
00456     for(idx=0;idx<nbr_xtr_1;idx++) (void)fprintf(stderr,"xtr_lst_1[%d].nm = %s, .id= %d\n",idx,xtr_lst_1[idx].nm,xtr_lst_1[idx].id);
00457   } /* end if */
00458   
00459   /* Is this an CCM/CCSM/CF-format history tape? */
00460   CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(in_id_1);
00461   
00462   /* Fill in variable structure list for all extracted variables */
00463   var_1=(var_sct **)nco_malloc(nbr_xtr_1*sizeof(var_sct *));
00464   var_2=(var_sct **)nco_malloc(nbr_xtr_2*sizeof(var_sct *));
00465   var_out=(var_sct **)nco_malloc(nbr_xtr_1*sizeof(var_sct *));
00466   for(idx=0;idx<nbr_xtr_1;idx++){
00467     var_1[idx]=nco_var_fll(in_id_1,xtr_lst_1[idx].id,xtr_lst_1[idx].nm,dim_1,nbr_dmn_xtr_1);
00468     var_out[idx]=nco_var_dpl(var_1[idx]);
00469     (void)nco_xrf_var(var_1[idx],var_out[idx]);
00470     (void)nco_xrf_dmn(var_out[idx]);
00471   } /* end loop over idx */
00472   for(idx=0;idx<nbr_xtr_2;idx++){
00473     var_2[idx]=nco_var_fll(in_id_2,xtr_lst_2[idx].id,xtr_lst_2[idx].nm,dim_2,nbr_dmn_xtr_2);
00474   } /* end loop over idx */
00475   
00476   /* Extraction lists no longer needed */
00477   xtr_lst_1=nco_nm_id_lst_free(xtr_lst_1,nbr_xtr_1);
00478   xtr_lst_2=nco_nm_id_lst_free(xtr_lst_2,nbr_xtr_2);
00479   
00480   /* Divide variable lists into lists of fixed variables and variables to be processed
00481      Create lists from file_1 last so those values remain in *_out arrays */
00482   (void)nco_var_lst_dvd(var_2,var_out,nbr_xtr_2,CNV_CCM_CCSM_CF,nco_pck_plc_nil,nco_pck_map_nil,(dmn_sct **)NULL,0,&var_fix_2,&var_fix_out,&nbr_var_fix_2,&var_prc_2,&var_prc_out,&nbr_var_prc_2);
00483   /* Avoid double-free() condition */
00484   var_fix_out=(var_sct **)nco_free(var_fix_out);
00485   var_prc_out=(var_sct **)nco_free(var_prc_out);
00486   (void)nco_var_lst_dvd(var_1,var_out,nbr_xtr_1,CNV_CCM_CCSM_CF,nco_pck_plc_nil,nco_pck_map_nil,(dmn_sct **)NULL,0,&var_fix_1,&var_fix_out,&nbr_var_fix_1,&var_prc_1,&var_prc_out,&nbr_var_prc_1);
00487   
00488   /* Die gracefully on unsupported features... */
00489   if(nbr_var_fix_1 < nbr_var_fix_2){
00490     (void)fprintf(fp_stdout,"%s: ERROR First file has fewer fixed variables than second file (%d < %d). This feature is NCO TODO 581.\n",prg_nm,nbr_var_fix_1,nbr_var_fix_2);
00491     nco_exit(EXIT_FAILURE);
00492   } /* endif */
00493   
00494   /* Merge two variable lists into same order */
00495   rcd=nco_var_lst_mrg(&var_prc_1,&var_prc_2,&nbr_var_prc_1,&nbr_var_prc_2); 
00496   
00497   /* Zero start vectors for all output variables */
00498   (void)nco_var_srt_zero(var_out,nbr_xtr_1);
00499   
00500 #ifdef ENABLE_MPI 
00501   if(prc_rnk == rnk_mgr){ /* MPI manager code */
00502 #endif /* !ENABLE_MPI */
00503     /* Open output file */
00504     fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&out_id);
00505     
00506     /* Copy global attributes */
00507     (void)nco_att_cpy(in_id_1,out_id,NC_GLOBAL,NC_GLOBAL,True);
00508     
00509     /* Catenate time-stamped command line to "history" global attribute */
00510     if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln);
00511     
00512     if(thr_nbr > 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr);
00513     
00514 #ifdef ENABLE_MPI 
00515     /* Initialize MPI task information */
00516     if(prc_nbr > 0 && HISTORY_APPEND) (void)nco_mpi_att_cat(out_id,prc_nbr);
00517 #endif /* !ENABLE_MPI */
00518     
00519     /* Define dimensions in output file */
00520     (void)nco_dmn_dfn(fl_out,out_id,dmn_out,nbr_dmn_xtr_1);
00521     
00522     /* fxm: TODO 550 put max_dim_sz/list(var_1,var_2) into var_def(var_out) */
00523     /* Define variables in output file, copy their attributes */
00524     (void)nco_var_dfn(in_id_1,fl_out,out_id,var_out,nbr_xtr_1,(dmn_sct **)NULL,(int)0,nco_pck_plc_nil,nco_pck_map_nil);
00525     
00526     /* Turn off default filling behavior to enhance efficiency */
00527     rcd=nco_set_fill(out_id,NC_NOFILL,&fll_md_old);
00528     
00529     /* Take output file out of define mode */
00530     (void)nco_enddef(out_id);
00531     
00532 #ifdef ENABLE_MPI
00533   } /* prc_rnk != rnk_mgr */
00534   
00535   /* Manager obtains output filename and broadcasts to workers */
00536   if(prc_rnk == rnk_mgr) fl_nm_lng=(int)strlen(fl_out_tmp); 
00537   MPI_Bcast(&fl_nm_lng,1,MPI_INT,rnk_mgr,MPI_COMM_WORLD);
00538   if(prc_rnk != rnk_mgr) fl_out_tmp=(char *)malloc((fl_nm_lng+1)*sizeof(char));
00539   MPI_Bcast(fl_out_tmp,fl_nm_lng+1,MPI_CHAR,rnk_mgr,MPI_COMM_WORLD); 
00540   
00541   if(prc_rnk == rnk_mgr){ /* MPI manager code */
00542     TKN_WRT_FREE=False;
00543 #endif /* !ENABLE_MPI */
00544     /* Copy variable data for non-processed variables */
00545     (void)nco_var_val_cpy(in_id_1,out_id,var_fix_1,nbr_var_fix_1);
00546 #ifdef ENABLE_MPI
00547     /* Close output file so workers can open it */
00548     nco_close(out_id);
00549     TKN_WRT_FREE=True;
00550   } /* prc_rnk != rnk_mgr */
00551 #endif /* !ENABLE_MPI */
00552   
00553   /* ncbo() code has been similar to ncea() (and ncra()) wherever possible
00554      Major differences occur where performance would otherwise suffer
00555      From now on, however, binary-file and binary-operation nature of ncbo()
00556      is too different from ncea() paradigm to justify following ncea() style.
00557      Instead, we adopt symmetric nomenclature (e.g., file_1, file_2), and 
00558      perform differences variable-by-variable so peak memory usage goes as
00559      Order(2*maximum variable size) rather than Order(3*maximum record size) or
00560      Order(3*file size) */
00561   
00562   /* Perform various error-checks on input file */
00563   if(False) (void)nco_fl_cmp_err_chk();
00564   
00565   /* Default operation depends on invocation name */
00566   if(nco_op_typ_sng == NULL) nco_op_typ=nco_op_typ_get(nco_op_typ_sng);
00567   
00568 #ifdef ENABLE_MPI
00569   if(prc_rnk == rnk_mgr){ /* MPI manager code */
00570     /* Compensate for incrementing on each worker's first message */
00571     var_wrt_nbr=-prc_nbr+1;
00572     idx=0;
00573     /* While variables remain to be processed or written... */
00574     while(var_wrt_nbr < nbr_var_prc_1){
00575       /* Receive message from any worker */
00576       MPI_Recv(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&mpi_stt);
00577       /* Obtain MPI message tag type */
00578       msg_tag_typ=mpi_stt.MPI_TAG;
00579       /* Get sender's prc_rnk */ 
00580       rnk_wrk=wrk_id_bfr[0];
00581       
00582       /* Allocate next variable, if any, to worker */
00583       if(msg_tag_typ == msg_tag_wrk_rqs){
00584         var_wrt_nbr++; /* [nbr] Number of variables written */
00585         /* Worker closed output file before sending msg_tag_wrk_rqs */
00586         TKN_WRT_FREE=True;
00587         
00588         if(idx < nbr_var_prc_1){
00589           /* Tell requesting worker to allocate space for next variable */
00590           msg_bfr[0]=idx; /* [idx] Variable to be processed */
00591           msg_bfr[1]=out_id; /* Output file ID */
00592           msg_bfr[2]=var_prc_out[idx]->id; /* [id] Variable ID in output file */
00593           /* Point to next variable on list */
00594           idx++; 
00595         }else{
00596           msg_bfr[0]=idx_all_wrk_ass; /* [enm] All variables already assigned */
00597           msg_bfr[1]=out_id; /* Output file ID */
00598         } /* endif idx */
00599         MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_wrk_rsp,MPI_COMM_WORLD);
00600         /* msg_tag_typ != msg_tag_wrk_rqs */
00601       }else if(msg_tag_typ == msg_tag_tkn_wrt_rqs){ 
00602         /* Allocate token if free, else ask worker to try later */
00603         if(TKN_WRT_FREE){
00604           TKN_WRT_FREE=False;
00605           msg_bfr[0]=tkn_wrt_rqs_xcp; /* Accept request for write token */
00606         }else{
00607           msg_bfr[0]=tkn_wrt_rqs_dny; /* Deny request for write token */
00608         } /* !TKN_WRT_FREE */
00609         MPI_Send(msg_bfr,msg_bfr_lng,MPI_INT,rnk_wrk,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD);
00610       } /* msg_tag_typ != msg_tag_tkn_wrt_rqs */
00611     } /* end while var_wrt_nbr < nbr_var_prc_1 */
00612   }else{ /* prc_rnk != rnk_mgr, end Manager code begin Worker code */
00613     wrk_id_bfr[0]=prc_rnk;
00614     while(1){ /* While work remains... */
00615       /* Send msg_tag_wrk_rqs */
00616       wrk_id_bfr[0]=prc_rnk;
00617       MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_wrk_rqs,MPI_COMM_WORLD);
00618       /* Receive msg_tag_wrk_rsp */
00619       MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,0,msg_tag_wrk_rsp,MPI_COMM_WORLD,&mpi_stt);
00620       idx=msg_bfr[0];
00621       out_id=msg_bfr[1];
00622       if(idx == idx_all_wrk_ass) break;
00623       else{ 
00624         var_prc_out[idx]->id=msg_bfr[2];
00625         /* Process this variable same as UP code */
00626 #else /* !ENABLE_MPI */
00627 #ifdef _OPENMP
00628         /* OpenMP notes:
00629            shared(): msk and wgt are not altered within loop
00630            private(): wgt_avg does not need initialization */
00631 #pragma omp parallel for default(none) private(idx,in_id_1,in_id_2) shared(dbg_lvl,dim_1,fl_in_1,fl_in_2,fl_out,fp_stderr,in_id_1_arr,in_id_2_arr,nbr_dmn_xtr_1,nbr_var_prc_1,nbr_var_prc_2,nco_op_typ,out_id,prg_nm,var_prc_1,var_prc_2,var_prc_out)
00632 #endif /* !_OPENMP */
00633         /* UP and SMP codes main loop over variables */ 
00634         for(idx=0;idx<nbr_var_prc_1;idx++){
00635 #endif /* ENABLE_MPI */
00636           /* Common code for UP, SMP, and MPI */
00637           int has_mss_val=False;
00638           ptr_unn mss_val;
00639 
00640           if(dbg_lvl > 0) (void)fprintf(fp_stderr,"%s, ",var_prc_1[idx]->nm);
00641           if(dbg_lvl > 0) (void)fflush(fp_stderr);
00642           
00643           in_id_1=in_id_1_arr[omp_get_thread_num()];
00644           in_id_2=in_id_2_arr[omp_get_thread_num()];
00645 
00646           (void)nco_var_mtd_refresh(in_id_1,var_prc_1[idx]);
00647           has_mss_val=var_prc_1[idx]->has_mss_val; 
00648           /* NB: nco_var_get() with same nc_id contains OpenMP critical region */
00649           (void)nco_var_get(in_id_1,var_prc_1[idx]);
00650           
00651           /* Find and set variable dmn_nbr, ID, mss_val, type in second file */
00652           (void)nco_var_mtd_refresh(in_id_2,var_prc_2[idx]);
00653           
00654           /* Read hyperslab from second file */
00655           /* NB: nco_var_get() with same nc_id contains OpenMP critical region */
00656           (void)nco_var_get(in_id_2,var_prc_2[idx]);
00657           
00658           /* Determine whether var1 and var2 conform */
00659           if(var_prc_1[idx]->nbr_dim == var_prc_2[idx]->nbr_dim){
00660             int dmn_idx;
00661             /* Do all dimensions match in sequence? */
00662             for(dmn_idx=0;dmn_idx<var_prc_1[idx]->nbr_dim;dmn_idx++){
00663               if(
00664                  strcmp(var_prc_1[idx]->dim[dmn_idx]->nm,var_prc_2[idx]->dim[dmn_idx]->nm) || /* Dimension names do not match */
00665                  (var_prc_1[idx]->dim[dmn_idx]->cnt != var_prc_2[idx]->dim[dmn_idx]->cnt) || /* Dimension sizes do not match */
00666                  False){
00667                 (void)fprintf(fp_stdout,"%s: ERROR Variables do not conform:\nFile %s variable %s dimension %d is %s with size %li and count %li\nFile %s variable %s dimension %d is %s with size %li and count %li\n",prg_nm,fl_in_1,var_prc_1[idx]->nm,dmn_idx,var_prc_1[idx]->dim[dmn_idx]->nm,var_prc_1[idx]->dim[dmn_idx]->sz,var_prc_1[idx]->dim[dmn_idx]->cnt,fl_in_2,var_prc_2[idx]->nm,dmn_idx,var_prc_2[idx]->dim[dmn_idx]->nm,var_prc_2[idx]->dim[dmn_idx]->sz,var_prc_2[idx]->dim[dmn_idx]->cnt);
00668                 if(var_prc_1[idx]->dim[dmn_idx]->cnt == 1 || var_prc_2[idx]->dim[dmn_idx]->cnt == 1) (void)fprintf(fp_stdout,"%s: HINT If a dimension is present in both files, it must be the same size. %s will not attempt to broadcast a degenerate (i.e., size 1) dimension (e.g., a single timestep) to a non-degenerate size. If one of the dimensions is degenerate, try removing it completely (e.g., by averaging over it with ncwa) before invoking %s\n",prg_nm,prg_nm,prg_nm);
00669                 nco_exit(EXIT_FAILURE);
00670               } /* endif */
00671             } /* end loop over dmn_idx */
00672           }else{ /* var_prc_out[idx]->nbr_dim != var_prc_1[idx]->nbr_dim) */
00673             /* Number of dimensions do not match, attempt to broadcast variables 
00674                fxm: broadcasting here leads to memory leak later since var_[1,2] does not know */
00675             
00676             /* Die gracefully on unsupported features... */
00677             if(var_prc_1[idx]->nbr_dim < var_prc_2[idx]->nbr_dim){
00678               (void)fprintf(fp_stdout,"%s: ERROR Variable %s has lesser rank in first file than in second file (%d < %d). This feature is NCO TODO 552.\n",prg_nm,var_prc_1[idx]->nm,var_prc_1[idx]->nbr_dim,var_prc_2[idx]->nbr_dim);
00679               nco_exit(EXIT_FAILURE);
00680             } /* endif */
00681             
00682             (void)ncap_var_cnf_dmn(&var_prc_1[idx],&var_prc_2[idx]);
00683           } /* end else */
00684           
00685           /* var2 now conforms in size to var1, and is in memory */
00686           
00687           /* fxm: TODO 268 allow var1 or var2 to typecast */
00688           /* Make sure var2 conforms to type of var1 */
00689           if(var_prc_1[idx]->type != var_prc_2[idx]->type){
00690             (void)fprintf(fp_stderr,"%s: WARNING Input variables do not conform in type:\nFile 1 = %s variable %s has type %s\nFile 2 = %s variable %s has type %s\nFile 3 = %s variable %s will have type %s\n",prg_nm,fl_in_1,var_prc_1[idx]->nm,nco_typ_sng(var_prc_1[idx]->type),fl_in_2,var_prc_2[idx]->nm,nco_typ_sng(var_prc_2[idx]->type),fl_out,var_prc_1[idx]->nm,nco_typ_sng(var_prc_1[idx]->type));
00691           }  /* endif different type */
00692           var_prc_2[idx]=nco_var_cnf_typ(var_prc_1[idx]->type,var_prc_2[idx]);
00693           
00694           /* Change missing_value of var_prc_2, if any, to missing_value of var_prc_1, if any */
00695           has_mss_val=nco_mss_val_cnf(var_prc_1[idx],var_prc_2[idx]);
00696           
00697           /* mss_val in fl_1, if any, overrides mss_val in fl_2 */
00698           if(has_mss_val) mss_val=var_prc_1[idx]->mss_val;
00699           
00700           /* Perform specified binary operation */
00701           switch(nco_op_typ){
00702           case nco_op_add: /* [enm] Add file_1 to file_2 */
00703             (void)nco_var_add(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break;
00704           case nco_op_mlt: /* [enm] Multiply file_1 by file_2 */
00705             (void)nco_var_mlt(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break;
00706           case nco_op_dvd: /* [enm] Divide file_1 by file_2 */
00707             (void)nco_var_dvd(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break;
00708           case nco_op_sbt: /* [enm] Subtract file_2 from file_1 */
00709             (void)nco_var_sbt(var_prc_1[idx]->type,var_prc_1[idx]->sz,has_mss_val,mss_val,var_prc_2[idx]->val,var_prc_1[idx]->val); break;
00710           default: /* Other defined nco_op_typ values are valid for ncra(), ncrcat(), ncwa(), not ncbo() */
00711             (void)fprintf(fp_stdout,"%s: ERROR Illegal nco_op_typ in binary operation\n",prg_nm);
00712             nco_exit(EXIT_FAILURE);
00713             break;
00714           } /* end case */
00715           
00716           var_prc_2[idx]->val.vp=nco_free(var_prc_2[idx]->val.vp);
00717           
00718 #ifdef ENABLE_MPI
00719           /* Obtain token and prepare to write */
00720           while(1){ /* Send msg_tag_tkn_wrt_rqs repeatedly until token obtained */
00721             wrk_id_bfr[0]=prc_rnk;
00722             MPI_Send(wrk_id_bfr,wrk_id_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rqs,MPI_COMM_WORLD);
00723             MPI_Recv(msg_bfr,msg_bfr_lng,MPI_INT,rnk_mgr,msg_tag_tkn_wrt_rsp,MPI_COMM_WORLD,&mpi_stt);
00724             tkn_wrt_rsp=msg_bfr[0];
00725             /* Wait then re-send request */
00726             if(tkn_wrt_rsp == tkn_wrt_rqs_dny) sleep(tkn_wrt_rqs_ntv); else break;
00727           } /* end while loop waiting for write token */
00728           
00729           /* Worker has token---prepare to write */
00730           if(tkn_wrt_rsp == tkn_wrt_rqs_xcp){
00731             rcd=nco_open(fl_out_tmp,NC_WRITE|NC_SHARE,&out_id);
00732             /* Turn off default filling behavior to enhance efficiency */
00733             rcd=nco_set_fill(out_id,NC_NOFILL,&fll_md_old);
00734 #else /* !ENABLE_MPI */
00735 #ifdef _OPENMP
00736 #pragma omp critical
00737 #endif /* !_OPENMP */ 
00738 #endif /* !ENABLE_MPI */
00739             /* Common code for UP, SMP, and MPI */
00740             { /* begin OpenMP critical */ 
00741               /* Copy result to output file and free workspace buffer */
00742               if(var_prc_1[idx]->nbr_dim == 0){
00743                 (void)nco_put_var1(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_1[idx]->val.vp,var_prc_out[idx]->type);
00744               }else{ /* end if variable is scalar */
00745                 (void)nco_put_vara(out_id,var_prc_out[idx]->id,var_prc_out[idx]->srt,var_prc_out[idx]->cnt,var_prc_1[idx]->val.vp,var_prc_out[idx]->type);
00746               } /* end else */
00747             } /* end OpenMP critical */
00748             var_prc_1[idx]->val.vp=nco_free(var_prc_1[idx]->val.vp);
00749             
00750 #ifdef ENABLE_MPI
00751             /* Close output file and increment written counter */
00752             nco_close(out_id);
00753             var_wrt_nbr++;
00754           } /* endif tkn_wrt_rqs_xcp */
00755         } /* end else !idx_all_wrk_ass */
00756       } /* end while loop requesting work/token */
00757     } /* endif Worker */
00758 #else /* !ENABLE_MPI */
00759   }  /* end (OpenMP parallel for) loop over idx */
00760 #endif /* !ENABLE_MPI */
00761   if(dbg_lvl > 0) (void)fprintf(stderr,"\n");
00762   
00763   /* Close input netCDF files */
00764   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) nco_close(in_id_1_arr[thr_idx]);
00765   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) nco_close(in_id_2_arr[thr_idx]);
00766   
00767 #ifdef ENABLE_MPI 
00768   /* Manager moves output file (closed by workers) from temporary to permanent location */
00769   if(prc_rnk == rnk_mgr) (void)nco_fl_mv(fl_out_tmp,fl_out);
00770 #else /* !ENABLE_MPI */
00771   /* Close output file and move it from temporary to permanent location */
00772   (void)nco_fl_out_cls(fl_out,fl_out_tmp,out_id); 
00773 #endif /* end !ENABLE_MPI */
00774   
00775   /* Remove local copy of file */
00776   if(FILE_1_RETRIEVED_FROM_REMOTE_LOCATION && REMOVE_REMOTE_FILES_AFTER_PROCESSING) (void)nco_fl_rm(fl_in_1);
00777   if(FILE_2_RETRIEVED_FROM_REMOTE_LOCATION && REMOVE_REMOTE_FILES_AFTER_PROCESSING) (void)nco_fl_rm(fl_in_2);
00778   
00779   /* ncbo-unique memory */
00780   if(fl_in_1 != NULL) fl_in_1=(char *)nco_free(fl_in_1);
00781   if(fl_in_2 != NULL) fl_in_2=(char *)nco_free(fl_in_2);
00782   
00783   /* NCO-generic clean-up */
00784   /* Free individual strings/arrays */
00785   if(cmd_ln != NULL) cmd_ln=(char *)nco_free(cmd_ln);
00786   if(fl_out != NULL) fl_out=(char *)nco_free(fl_out);
00787   if(fl_out_tmp != NULL) fl_out_tmp=(char *)nco_free(fl_out_tmp);
00788   if(fl_pth != NULL) fl_pth=(char *)nco_free(fl_pth);
00789   if(fl_pth_lcl != NULL) fl_pth_lcl=(char *)nco_free(fl_pth_lcl);
00790   if(in_id_1_arr != NULL) in_id_1_arr=(int *)nco_free(in_id_1_arr);
00791   if(in_id_2_arr != NULL) in_id_2_arr=(int *)nco_free(in_id_2_arr);
00792   /* Free lists of strings */
00793   if(fl_lst_in != NULL && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); 
00794   if(fl_lst_in != NULL && fl_lst_abb != NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,1);
00795   if(fl_lst_abb != NULL) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr);
00796   if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr);
00797   /* Free limits */
00798   for(idx=0;idx<lmt_nbr;idx++) lmt_arg[idx]=(char *)nco_free(lmt_arg[idx]);
00799   if(lmt_nbr > 0) lmt=nco_lmt_lst_free(lmt,lmt_nbr);
00800   /* Free dimension lists */
00801   if(nbr_dmn_xtr_1 > 0) dim_1=nco_dmn_lst_free(dim_1,nbr_dmn_xtr_1);
00802   if(nbr_dmn_xtr_2 > 0) dim_2=nco_dmn_lst_free(dim_2,nbr_dmn_xtr_2);
00803   if(nbr_dmn_xtr_1 > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr_1);
00804   /* Free variable lists 
00805      Using nco_var_lst_free() to free main var_1 and var_2 lists would fail
00806      if ncap_var_prc_dmn() had to broadcast any variables because pointer
00807      var_1 and var_2 still contain dangling pointer to old variable.
00808      Hence, use nco_var_lst_free() to free prc and fix lists and 
00809      use nco_free() to free main var_1 and var_2 lists.
00810      Dangling pointers in var_1 and var_2 are unsafe: fxm TODO 578 */
00811   if(nbr_var_prc_1 > 0) var_prc_1=nco_var_lst_free(var_prc_1,nbr_var_prc_1);
00812   if(nbr_var_fix_1 > 0) var_fix_1=nco_var_lst_free(var_fix_1,nbr_var_fix_1);
00813   if(nbr_var_prc_2 > 0) var_prc_2=nco_var_lst_free(var_prc_2,nbr_var_prc_2);
00814   if(nbr_var_fix_2 > 0) var_fix_2=nco_var_lst_free(var_fix_2,nbr_var_fix_2);
00815   var_1=(var_sct **)nco_free(var_1);
00816   var_2=(var_sct **)nco_free(var_2);
00817   if(nbr_xtr_1 > 0) var_out=nco_var_lst_free(var_out,nbr_xtr_1);
00818   var_prc_out=(var_sct **)nco_free(var_prc_out);
00819   var_fix_out=(var_sct **)nco_free(var_fix_out);
00820   
00821 #ifdef ENABLE_MPI 
00822   MPI_Finalize();
00823 #endif /* !ENABLE_MPI */
00824   
00825   if(rcd != NC_NOERR) nco_err_exit(rcd,"main");
00826   nco_exit_gracefully();
00827   return EXIT_SUCCESS;
00828 } /* end main() */


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