nco/ncbo.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 ncbo.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 79 of file ncbo.c.


Function Documentation

int main int  argc,
char **  argv
 

Definition at line 83 of file ncbo.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, int_CEWI, lst_prs_2D(), 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, ncap_var_cnf_dmn(), nco_att_cpy(), nco_bool, nco_close(), nco_cmd_ln_sng(), 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_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_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_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, True, type, var_sct_tag::type, var_sct_tag::val, option::val, and ptr_unn::vp.

00084 {
00085   nco_bool EXCLUDE_INPUT_LIST=False; /* Option c */
00086   nco_bool EXTRACT_ALL_COORDINATES=False; /* Option c */
00087   nco_bool EXTRACT_ASSOCIATED_COORDINATES=True; /* Option C */
00088   nco_bool FILE_1_RETRIEVED_FROM_REMOTE_LOCATION;
00089   nco_bool FILE_2_RETRIEVED_FROM_REMOTE_LOCATION;
00090   nco_bool FL_LST_IN_FROM_STDIN=False; /* [flg] fl_lst_in comes from stdin */
00091   nco_bool FORCE_APPEND=False; /* Option A */
00092   nco_bool FORCE_OVERWRITE=False; /* Option O */
00093   nco_bool FORTRAN_IDX_CNV=False; /* Option F */
00094   nco_bool HISTORY_APPEND=True; /* Option h */
00095   nco_bool CNV_CCM_CCSM_CF;
00096   nco_bool REMOVE_REMOTE_FILES_AFTER_PROCESSING=True; /* Option R */
00097   
00098   char **fl_lst_abb=NULL; /* Option a */
00099   char **fl_lst_in;
00100   char **var_lst_in=NULL_CEWI;
00101   char *cmd_ln;
00102   char *fl_in_1=NULL; /* fl_in_1 is nco_realloc'd when not NULL */;
00103   char *fl_in_2=NULL; /* fl_in_2 is nco_realloc'd when not NULL */;
00104   char *fl_out=NULL; /* Option o */
00105   char *fl_out_tmp;
00106   char *fl_pth=NULL; /* Option p */
00107   char *fl_pth_lcl=NULL; /* Option l */
00108   char *lmt_arg[NC_MAX_DIMS];
00109   char *nco_op_typ_sng=NULL; /* [sng] Operation type */
00110   char *opt_crr=NULL; /* [sng] String representation of current long-option name */
00111   char *optarg_lcl=NULL; /* [sng] Local copy of system optarg */
00112   char *time_bfr_srt;
00113   
00114   const char * const CVS_Id="$Id: ncbo.c,v 1.79 2006/02/26 07:41:55 zender Exp $"; 
00115   const char * const CVS_Revision="$Revision: 1.79 $";
00116   const char * const opt_sht_lst="4ACcD:d:Fhl:Oo:p:rRt:v:xy:-:";
00117   
00118   dmn_sct **dim_1;
00119   dmn_sct **dim_2;
00120   dmn_sct **dmn_out;
00121   
00122   extern char *optarg;
00123   extern int optind;
00124   
00125   /* Using naked stdin/stdout/stderr in parallel region generates warning
00126      Copy appropriate filehandle to variable scoped shared in parallel clause */
00127   FILE * const fp_stderr=stderr; /* [fl] stderr filehandle CEWI */
00128   FILE * const fp_stdout=stdout; /* [fl] stdout filehandle CEWI */
00129 
00130   int *in_id_1_arr;
00131   int *in_id_2_arr;
00132 
00133   int abb_arg_nbr=0;
00134   int fl_idx;
00135   int fl_nbr=0;
00136   int fl_out_fmt=NC_FORMAT_CLASSIC; /* [enm] Output file format */
00137   int fll_md_old; /* [enm] Old fill mode */
00138   int idx;
00139   int in_id_1;  
00140   int in_id_2;  
00141   int lmt_nbr=0; /* Option d. NB: lmt_nbr gets incremented */
00142   int nbr_dmn_fl_1;
00143   int nbr_dmn_fl_2;
00144   int nbr_dmn_xtr_1;
00145   int nbr_dmn_xtr_2;
00146   int nbr_var_fix_1; /* nbr_var_fix_1 gets incremented */
00147   int nbr_var_fix_2; /* nbr_var_fix_2 gets incremented */
00148   int nbr_var_fl_1;
00149   int nbr_var_fl_2;
00150   int nbr_var_prc_1; /* nbr_var_prc_1 gets incremented */
00151   int nbr_var_prc_2; /* nbr_var_prc_2 gets incremented */
00152   int nbr_xtr_1=0; /* nbr_xtr_1 won't otherwise be set for -c with no -v */
00153   int nbr_xtr_2=0; /* nbr_xtr_2 won't otherwise be set for -c with no -v */
00154   int nco_op_typ=nco_op_nil; /* [enm] Operation type */
00155   int opt;
00156   int out_id;  
00157   int rcd=NC_NOERR; /* [rcd] Return code */
00158   int thr_idx; /* [idx] Index of current thread */
00159   int thr_nbr=int_CEWI; /* [nbr] Thread number Option t */
00160   int var_lst_in_nbr=0;
00161   
00162   lmt_sct **lmt;
00163   
00164   nm_id_sct *dmn_lst_1;
00165   nm_id_sct *dmn_lst_2;
00166   nm_id_sct *xtr_lst_1=NULL; /* xtr_lst_1 may be alloc()'d from NULL with -c option */
00167   nm_id_sct *xtr_lst_2=NULL; /* xtr_lst_2 may be alloc()'d from NULL with -c option */
00168   
00169   time_t time_crr_time_t;
00170   
00171   var_sct **var_1;
00172   var_sct **var_2;
00173   var_sct **var_fix_1;
00174   var_sct **var_fix_2;
00175   var_sct **var_fix_out;
00176   var_sct **var_out;
00177   var_sct **var_prc_1;
00178   var_sct **var_prc_2;
00179   var_sct **var_prc_out;
00180   
00181   static struct option opt_lng[]=
00182     { /* Structure ordered by short option key if possible */
00183       /* Long options with no argument, no short option counterpart */
00184       /* Long options with argument, no short option counterpart */
00185       {"fl_fmt",required_argument,0,0},
00186       {"file_format",required_argument,0,0},
00187       /* Long options with short counterparts */
00188       {"4",no_argument,0,'4'},
00189       {"64bit",no_argument,0,'4'},
00190       {"netcdf4",no_argument,0,'4'},
00191       {"append",no_argument,0,'A'},
00192       {"coords",no_argument,0,'c'},
00193       {"crd",no_argument,0,'c'},
00194       {"no-coords",no_argument,0,'C'},
00195       {"no-crd",no_argument,0,'C'},
00196       {"debug",required_argument,0,'D'},
00197       {"dbg_lvl",required_argument,0,'D'},
00198       {"dimension",required_argument,0,'d'},
00199       {"dmn",required_argument,0,'d'},
00200       {"fortran",no_argument,0,'F'},
00201       {"ftn",no_argument,0,'F'},
00202       {"history",no_argument,0,'h'},
00203       {"hst",no_argument,0,'h'},
00204       {"local",required_argument,0,'l'},
00205       {"lcl",required_argument,0,'l'},
00206       {"overwrite",no_argument,0,'O'},
00207       {"ovr",no_argument,0,'O'},
00208       {"path",required_argument,0,'p'},
00209       {"retain",no_argument,0,'R'},
00210       {"rtn",no_argument,0,'R'},
00211       {"revision",no_argument,0,'r'},
00212       {"variable",required_argument,0,'v'},
00213       {"version",no_argument,0,'r'},
00214       {"vrs",no_argument,0,'r'},
00215       {"thr_nbr",required_argument,0,'t'},
00216       {"exclude",no_argument,0,'x'},
00217       {"xcl",no_argument,0,'x'},
00218       {"operation",required_argument,0,'y'},
00219       {"op_typ",required_argument,0,'y'},
00220       {"help",no_argument,0,'?'},
00221       {0,0,0,0}
00222     }; /* end opt_lng */
00223   int opt_idx=0; /* Index of current long option into opt_lng array */
00224   
00225   /* Start clock and save command line */ 
00226   cmd_ln=nco_cmd_ln_sng(argc,argv);
00227   time_crr_time_t=time((time_t *)NULL);
00228   time_bfr_srt=ctime(&time_crr_time_t); time_bfr_srt=time_bfr_srt; /* Avoid compiler warning until variable is used for something */
00229   
00230   /* Get program name and set program enum (e.g., prg=ncra) */
00231   prg_nm=prg_prs(argv[0],&prg);
00232   
00233   /* Parse command line arguments */
00234   while(1){
00235     /* getopt_long_only() allows one dash to prefix long options */
00236     opt=getopt_long(argc,argv,opt_sht_lst,opt_lng,&opt_idx);
00237     /* NB: access to opt_crr is only valid when long_opt is detected */
00238     if(opt == EOF) break; /* Parse positional arguments once getopt_long() returns EOF */
00239     opt_crr=(char *)strdup(opt_lng[opt_idx].name);
00240 
00241     /* Process long options without short option counterparts */
00242     if(opt == 0){
00243       if(!strcmp(opt_crr,"fl_fmt") || !strcmp(opt_crr,"file_format")) rcd=nco_create_mode_prs(optarg,&fl_out_fmt);
00244     } /* opt != 0 */
00245     /* Process short options */
00246     switch(opt){
00247     case 0: /* Long options have already been processed, return */
00248       break;
00249     case '4': /* [flg] Catch-all to prescribe output storage format */
00250       if(!strcmp(opt_crr,"64bit")) fl_out_fmt=NC_FORMAT_64BIT; else fl_out_fmt=NC_FORMAT_NETCDF4; 
00251       break;
00252     case 'A': /* Toggle FORCE_APPEND */
00253       FORCE_APPEND=!FORCE_APPEND;
00254       break;
00255     case 'C': /* Extract all coordinates associated with extracted variables? */
00256       EXTRACT_ASSOCIATED_COORDINATES=False;
00257       break;
00258     case 'c':
00259       EXTRACT_ALL_COORDINATES=True;
00260       break;
00261     case 'D': /* The debugging level. Default is 0. */
00262       dbg_lvl=(unsigned short)strtol(optarg,(char **)NULL,10);
00263       break;
00264     case 'd': /* Copy argument for later processing */
00265       lmt_arg[lmt_nbr]=(char *)strdup(optarg);
00266       lmt_nbr++;
00267       break;
00268     case 'F': /* Toggle index convention. Default is 0-based arrays (C-style). */
00269       FORTRAN_IDX_CNV=!FORTRAN_IDX_CNV;
00270       break;
00271     case 'h': /* Toggle appending to history global attribute */
00272       HISTORY_APPEND=!HISTORY_APPEND;
00273       break;
00274     case 'l': /* Local path prefix for files retrieved from remote file system */
00275       fl_pth_lcl=(char *)strdup(optarg);
00276       break;
00277     case 'O': /* Toggle FORCE_OVERWRITE */
00278       FORCE_OVERWRITE=!FORCE_OVERWRITE;
00279       break;
00280     case 'o': /* Name of output file */
00281       fl_out=(char *)strdup(optarg);
00282       break;
00283     case 'p': /* Common file path */
00284       fl_pth=(char *)strdup(optarg);
00285       break;
00286     case 'R': /* Toggle removal of remotely-retrieved-files. Default is True. */
00287       REMOVE_REMOTE_FILES_AFTER_PROCESSING=!REMOVE_REMOTE_FILES_AFTER_PROCESSING;
00288       break;
00289     case 'r': /* Print CVS program information and copyright notice */
00290       (void)copyright_prn(CVS_Id,CVS_Revision);
00291       (void)nco_lbr_vrs_prn();
00292       nco_exit(EXIT_SUCCESS);
00293       break;
00294     case 't': /* Thread number */
00295       thr_nbr=(int)strtol(optarg,(char **)NULL,10);
00296       break;
00297     case 'v': /* Variables to extract/exclude */
00298       /* Replace commas with hashes when within braces (convert back later) */
00299       optarg_lcl=(char *)strdup(optarg);
00300       (void)nco_lst_comma2hash(optarg_lcl);
00301       var_lst_in=lst_prs_2D(optarg_lcl,",",&var_lst_in_nbr);
00302       optarg_lcl=(char *)nco_free(optarg_lcl);
00303       nbr_xtr_1=nbr_xtr_2=var_lst_in_nbr;
00304       break;
00305     case 'x': /* Exclude rather than extract variables specified with -v */
00306       EXCLUDE_INPUT_LIST=True;
00307       break;
00308     case 'y': /* User-specified operation type overrides invocation default */
00309       nco_op_typ_sng=(char *)strdup(optarg);
00310       nco_op_typ=nco_op_typ_get(nco_op_typ_sng);
00311       break;
00312     case '?': /* Print proper usage */
00313       (void)nco_usg_prn();
00314       nco_exit(EXIT_SUCCESS);
00315       break;
00316     case '-': /* Long options are not allowed */
00317       (void)fprintf(stderr,"%s: ERROR Long options are not available in this build. Use single letter options instead.\n",prg_nm_get());
00318       nco_exit(EXIT_FAILURE);
00319       break;
00320     default: /* Print proper usage */
00321       (void)nco_usg_prn();
00322       nco_exit(EXIT_FAILURE);
00323       break;
00324     } /* end switch */
00325     if(opt_crr != NULL) opt_crr=(char *)nco_free(opt_crr);
00326   } /* end while loop */
00327   
00328   /* Process positional arguments and fill in filenames */
00329   fl_lst_in=nco_fl_lst_mk(argv,argc,optind,&fl_nbr,&fl_out,&FL_LST_IN_FROM_STDIN);
00330   
00331   /* Make uniform list of user-specified dimension limits */
00332   lmt=nco_lmt_prs(lmt_nbr,lmt_arg);
00333     
00334   /* Initialize thread information */
00335   thr_nbr=nco_openmp_ini(thr_nbr);
00336   in_id_1_arr=(int *)nco_malloc(thr_nbr*sizeof(int));
00337   in_id_2_arr=(int *)nco_malloc(thr_nbr*sizeof(int));
00338 
00339   /* Parse filenames */
00340   fl_idx=0; /* Input file _1 */
00341   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);
00342   if(dbg_lvl > 0) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in_1);
00343   /* Make sure file is on local system and is readable or die trying */
00344   fl_in_1=nco_fl_mk_lcl(fl_in_1,fl_pth_lcl,&FILE_1_RETRIEVED_FROM_REMOTE_LOCATION);
00345   if(dbg_lvl > 0) (void)fprintf(stderr,"local file %s:\n",fl_in_1);
00346   /* Open file once per thread to improve caching */
00347   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) rcd=nco_open(fl_in_1,NC_NOWRITE,in_id_1_arr+thr_idx);
00348   in_id_1=in_id_1_arr[0];
00349 
00350   fl_idx=1; /* Input file _2 */
00351   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);
00352   if(dbg_lvl > 0) (void)fprintf(stderr,"\nInput file %d is %s; ",fl_idx,fl_in_2);
00353   /* Make sure file is on local system and is readable or die trying */
00354   fl_in_2=nco_fl_mk_lcl(fl_in_2,fl_pth_lcl,&FILE_2_RETRIEVED_FROM_REMOTE_LOCATION);
00355   if(dbg_lvl > 0) (void)fprintf(stderr,"local file %s:\n",fl_in_2);
00356   /* Open file once per thread to improve caching */
00357   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) rcd=nco_open(fl_in_2,NC_NOWRITE,in_id_2_arr+thr_idx);
00358   in_id_2=in_id_2_arr[0];
00359   
00360   /* Get number of variables and dimensions in file */
00361   (void)nco_inq(in_id_1,&nbr_dmn_fl_1,&nbr_var_fl_1,(int *)NULL,(int *)NULL);
00362   (void)nco_inq(in_id_2,&nbr_dmn_fl_2,&nbr_var_fl_2,(int *)NULL,(int *)NULL);
00363   
00364   /* Form initial extraction list which may include extended regular expressions */
00365   xtr_lst_1=nco_var_lst_mk(in_id_1,nbr_var_fl_1,var_lst_in,EXTRACT_ALL_COORDINATES,&nbr_xtr_1);
00366   xtr_lst_2=nco_var_lst_mk(in_id_2,nbr_var_fl_2,var_lst_in,EXTRACT_ALL_COORDINATES,&nbr_xtr_2);
00367   
00368   /* Change included variables to excluded variables */
00369   if(EXCLUDE_INPUT_LIST) xtr_lst_1=nco_var_lst_xcl(in_id_1,nbr_var_fl_1,xtr_lst_1,&nbr_xtr_1);
00370   if(EXCLUDE_INPUT_LIST) xtr_lst_2=nco_var_lst_xcl(in_id_2,nbr_var_fl_2,xtr_lst_2,&nbr_xtr_2);
00371   
00372   /* Add all coordinate variables to extraction list */
00373   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);
00374   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);
00375   
00376   /* Make sure coordinates associated extracted variables are also on extraction list */
00377   if(EXTRACT_ASSOCIATED_COORDINATES) xtr_lst_1=nco_var_lst_ass_crd_add(in_id_1,xtr_lst_1,&nbr_xtr_1);
00378   if(EXTRACT_ASSOCIATED_COORDINATES) xtr_lst_2=nco_var_lst_ass_crd_add(in_id_2,xtr_lst_2,&nbr_xtr_2);
00379   
00380   /* With fully symmetric 1<->2 ordering, may occasionally find nbr_xtr_2 > nbr_xtr_1 
00381      This occurs, e.g., when fl_in_1 contains reduced variables and full coordinates
00382      are only in fl_in_2 and so will not appear xtr_lst_1 */
00383   
00384   /* Sort extraction list by variable ID for fastest I/O */
00385   if(nbr_xtr_1 > 1) xtr_lst_1=nco_lst_srt_nm_id(xtr_lst_1,nbr_xtr_1,False);
00386   if(nbr_xtr_2 > 1) xtr_lst_2=nco_lst_srt_nm_id(xtr_lst_2,nbr_xtr_2,False);
00387   
00388   /* We now have final list of variables to extract. Phew. */
00389   
00390   /* Find coordinate/dimension values associated with user-specified limits
00391      NB: nco_lmt_evl() with same nc_id contains OpenMP critical region */
00392   for(idx=0;idx<lmt_nbr;idx++) (void)nco_lmt_evl(in_id_1,lmt[idx],0L,FORTRAN_IDX_CNV);
00393 
00394   /* Find dimensions associated with variables to be extracted */
00395   dmn_lst_1=nco_dmn_lst_ass_var(in_id_1,xtr_lst_1,nbr_xtr_1,&nbr_dmn_xtr_1);
00396   dmn_lst_2=nco_dmn_lst_ass_var(in_id_2,xtr_lst_2,nbr_xtr_2,&nbr_dmn_xtr_2);
00397   
00398   /* Fill in dimension structure for all extracted dimensions */
00399   dim_1=(dmn_sct **)nco_malloc(nbr_dmn_xtr_1*sizeof(dmn_sct *));
00400   dim_2=(dmn_sct **)nco_malloc(nbr_dmn_xtr_2*sizeof(dmn_sct *));
00401   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);
00402   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);
00403   /* Dimension lists no longer needed */
00404   dmn_lst_1=nco_nm_id_lst_free(dmn_lst_1,nbr_dmn_xtr_1);
00405   dmn_lst_2=nco_nm_id_lst_free(dmn_lst_2,nbr_dmn_xtr_2);
00406   
00407   /* Merge hyperslab limit information into dimension structures */
00408   if(lmt_nbr > 0) (void)nco_dmn_lmt_mrg(dim_1,nbr_dmn_xtr_1,lmt,lmt_nbr);
00409   if(lmt_nbr > 0) (void)nco_dmn_lmt_mrg(dim_2,nbr_dmn_xtr_2,lmt,lmt_nbr);
00410   
00411   /* Duplicate input dimension structures for output dimension structures */
00412   dmn_out=(dmn_sct **)nco_malloc(nbr_dmn_xtr_1*sizeof(dmn_sct *));
00413   for(idx=0;idx<nbr_dmn_xtr_1;idx++){
00414     dmn_out[idx]=nco_dmn_dpl(dim_1[idx]);
00415     (void)nco_dmn_xrf(dim_1[idx],dmn_out[idx]); 
00416   } /* end loop over idx */
00417   
00418   if(dbg_lvl > 3){
00419     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);
00420   } /* end if */
00421   
00422   /* Is this an CCM/CCSM/CF-format history tape? */
00423   CNV_CCM_CCSM_CF=nco_cnv_ccm_ccsm_cf_inq(in_id_1);
00424   
00425   /* Fill in variable structure list for all extracted variables */
00426   var_1=(var_sct **)nco_malloc(nbr_xtr_1*sizeof(var_sct *));
00427   var_2=(var_sct **)nco_malloc(nbr_xtr_2*sizeof(var_sct *));
00428   var_out=(var_sct **)nco_malloc(nbr_xtr_1*sizeof(var_sct *));
00429   for(idx=0;idx<nbr_xtr_1;idx++){
00430     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);
00431     var_out[idx]=nco_var_dpl(var_1[idx]);
00432     (void)nco_xrf_var(var_1[idx],var_out[idx]);
00433     (void)nco_xrf_dmn(var_out[idx]);
00434   } /* end loop over idx */
00435   for(idx=0;idx<nbr_xtr_2;idx++){
00436     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);
00437   } /* end loop over idx */
00438 
00439   /* Extraction lists no longer needed */
00440   xtr_lst_1=nco_nm_id_lst_free(xtr_lst_1,nbr_xtr_1);
00441   xtr_lst_2=nco_nm_id_lst_free(xtr_lst_2,nbr_xtr_2);
00442   
00443   /* Divide variable lists into lists of fixed variables and variables to be processed
00444      Create lists from file_1 last so those values remain in *_out arrays */
00445   (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);
00446   /* Avoid double-free() condition */
00447   var_fix_out=(var_sct **)nco_free(var_fix_out);
00448   var_prc_out=(var_sct **)nco_free(var_prc_out);
00449   (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);
00450 
00451   /* Die gracefully on unsupported features... */
00452   if(nbr_var_fix_1 < nbr_var_fix_2){
00453     (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);
00454       nco_exit(EXIT_FAILURE);
00455   } /* endif */
00456 
00457   /* Merge two variable lists into same order */
00458   rcd=nco_var_lst_mrg(&var_prc_1,&var_prc_2,&nbr_var_prc_1,&nbr_var_prc_2); 
00459 
00460   /* Open output file */
00461   fl_out_tmp=nco_fl_out_open(fl_out,FORCE_APPEND,FORCE_OVERWRITE,fl_out_fmt,&out_id);
00462   
00463   /* Copy global attributes */
00464   (void)nco_att_cpy(in_id_1,out_id,NC_GLOBAL,NC_GLOBAL,True);
00465   
00466   /* Catenate time-stamped command line to "history" global attribute */
00467   if(HISTORY_APPEND) (void)nco_hst_att_cat(out_id,cmd_ln);
00468   
00469   if(thr_nbr > 0 && HISTORY_APPEND) (void)nco_thr_att_cat(out_id,thr_nbr);
00470   
00471   /* Define dimensions in output file */
00472   (void)nco_dmn_dfn(fl_out,out_id,dmn_out,nbr_dmn_xtr_1);
00473   
00474   /* fxm: TODO 550 put max_dim_sz/list(var_1,var_2) into var_def(var_out) */
00475   /* Define variables in output file, copy their attributes */
00476   (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);
00477   
00478   /* Turn off default filling behavior to enhance efficiency */
00479   rcd=nco_set_fill(out_id,NC_NOFILL,&fll_md_old);
00480   
00481   /* Take output file out of define mode */
00482   (void)nco_enddef(out_id);
00483   
00484   /* Zero start vectors for all output variables */
00485   (void)nco_var_srt_zero(var_out,nbr_xtr_1);
00486   
00487   /* Copy variable data for non-processed variables */
00488   (void)nco_var_val_cpy(in_id_1,out_id,var_fix_1,nbr_var_fix_1);
00489   
00490   /* ncbo() code has been similar to ncea() (and ncra()) wherever possible
00491      Major differences occur where performance would otherwise suffer
00492      From now on, however, binary-file and binary-operation nature of ncbo()
00493      is too different from ncea() paradigm to justify following ncea() style.
00494      Instead, we adopt symmetric nomenclature (e.g., file_1, file_2), and 
00495      perform differences variable-by-variable so peak memory usage goes as
00496      Order(2*maximum variable size) rather than Order(3*maximum record size) or
00497      Order(3*file size) */
00498      
00499   /* Perform various error-checks on input file */
00500   if(False) (void)nco_fl_cmp_err_chk();
00501   
00502   /* Default operation depends on invocation name */
00503   if(nco_op_typ_sng == NULL) nco_op_typ=nco_op_typ_get(nco_op_typ_sng);
00504     
00505   /* Loop over variables */
00506 #ifdef _OPENMP
00507   /* OpenMP notes:
00508      shared(): msk and wgt are not altered within loop
00509      private(): wgt_avg does not need initialization */
00510 #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)
00511 #endif /* !_OPENMP */
00512   for(idx=0;idx<nbr_var_prc_1;idx++){
00513     int has_mss_val=False;
00514     ptr_unn mss_val;
00515 
00516     if(dbg_lvl > 0) (void)fprintf(fp_stderr,"%s, ",var_prc_1[idx]->nm);
00517     if(dbg_lvl > 0) (void)fflush(fp_stderr);
00518     
00519     in_id_1=in_id_1_arr[omp_get_thread_num()];
00520     in_id_2=in_id_2_arr[omp_get_thread_num()];
00521 
00522     (void)nco_var_mtd_refresh(in_id_1,var_prc_1[idx]);
00523     has_mss_val=var_prc_1[idx]->has_mss_val; 
00524     (void)nco_var_get(in_id_1,var_prc_1[idx]);
00525     
00526     /* Find and set variable dmn_nbr, ID, mss_val, type in second file */
00527     (void)nco_var_mtd_refresh(in_id_2,var_prc_2[idx]);
00528     
00529     /* Read hyperslab from second file */
00530     (void)nco_var_get(in_id_2,var_prc_2[idx]);
00531 
00532     /* Determine whether var1 and var2 conform */
00533     if(var_prc_1[idx]->nbr_dim == var_prc_2[idx]->nbr_dim){
00534       int dmn_idx;
00535       /* Do all dimensions match in sequence? */
00536       for(dmn_idx=0;dmn_idx<var_prc_1[idx]->nbr_dim;dmn_idx++){
00537         if(
00538            strcmp(var_prc_1[idx]->dim[dmn_idx]->nm,var_prc_2[idx]->dim[dmn_idx]->nm) || /* Dimension names do not match */
00539            (var_prc_1[idx]->dim[dmn_idx]->cnt != var_prc_2[idx]->dim[dmn_idx]->cnt) || /* Dimension sizes do not match */
00540            False){
00541           (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);
00542           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);
00543           nco_exit(EXIT_FAILURE);
00544         } /* endif */
00545       } /* end loop over dmn_idx */
00546     }else{ /* var_prc_out[idx]->nbr_dim != var_prc_1[idx]->nbr_dim) */
00547       /* Number of dimensions do not match, attempt to broadcast variables 
00548          fxm: broadcasting here leads to memory leak later since var_[1,2] does not know */
00549 
00550       /* Die gracefully on unsupported features... */
00551       if(var_prc_1[idx]->nbr_dim < var_prc_2[idx]->nbr_dim){
00552         (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);
00553         nco_exit(EXIT_FAILURE);
00554       } /* endif */
00555 
00556       (void)ncap_var_cnf_dmn(&var_prc_1[idx],&var_prc_2[idx]);
00557     } /* end else */
00558     
00559     /* var2 now conforms in size to var1, and is in memory */
00560     
00561     /* fxm: TODO 268 allow var1 or var2 to typecast */
00562     /* Make sure var2 conforms to type of var1 */
00563     if(var_prc_1[idx]->type != var_prc_2[idx]->type){
00564       (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));
00565     }  /* endif different type */
00566     var_prc_2[idx]=nco_var_cnf_typ(var_prc_1[idx]->type,var_prc_2[idx]);
00567     
00568     /* Change missing_value of var_prc_2, if any, to missing_value of var_prc_1, if any */
00569     has_mss_val=nco_mss_val_cnf(var_prc_1[idx],var_prc_2[idx]);
00570     
00571     /* mss_val in fl_1, if any, overrides mss_val in fl_2 */
00572     if(has_mss_val) mss_val=var_prc_1[idx]->mss_val;
00573     
00574     /* Perform specified binary operation */
00575     switch(nco_op_typ){
00576     case nco_op_add: /* [enm] Add file_1 to file_2 */
00577       (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;
00578     case nco_op_mlt: /* [enm] Multiply file_1 by file_2 */
00579       (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;
00580     case nco_op_dvd: /* [enm] Divide file_1 by file_2 */
00581       (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;
00582     case nco_op_sbt: /* [enm] Subtract file_2 from file_1 */
00583       (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;
00584     default: /* Other defined nco_op_typ values are valid for ncra(), ncrcat(), ncwa(), not ncbo() */
00585       (void)fprintf(fp_stdout,"%s: ERROR Illegal nco_op_typ in binary operation\n",prg_nm);
00586       nco_exit(EXIT_FAILURE);
00587       break;
00588     } /* end case */
00589     
00590     var_prc_2[idx]->val.vp=nco_free(var_prc_2[idx]->val.vp);
00591 
00592 #ifdef _OPENMP
00593 #pragma omp critical
00594 #endif /* _OPENMP */
00595     { /* begin OpenMP critical */
00596       /* Copy result to output file and free workspace buffer */
00597       if(var_prc_1[idx]->nbr_dim == 0){
00598         (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);
00599       }else{ /* end if variable is scalar */
00600         (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);
00601       } /* end else */
00602     } /* end OpenMP critical */
00603     var_prc_1[idx]->val.vp=nco_free(var_prc_1[idx]->val.vp);
00604     
00605   } /* end (OpenMP parallel for) loop over idx */
00606   if(dbg_lvl > 0) (void)fprintf(stderr,"\n");
00607   
00608   /* Close input netCDF files */
00609   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) nco_close(in_id_1_arr[thr_idx]);
00610   for(thr_idx=0;thr_idx<thr_nbr;thr_idx++) nco_close(in_id_2_arr[thr_idx]);
00611   
00612   /* Close output file and move it from temporary to permanent location */
00613   (void)nco_fl_out_cls(fl_out,fl_out_tmp,out_id);
00614   
00615   /* Remove local copy of file */
00616   if(FILE_1_RETRIEVED_FROM_REMOTE_LOCATION && REMOVE_REMOTE_FILES_AFTER_PROCESSING) (void)nco_fl_rm(fl_in_1);
00617   if(FILE_2_RETRIEVED_FROM_REMOTE_LOCATION && REMOVE_REMOTE_FILES_AFTER_PROCESSING) (void)nco_fl_rm(fl_in_2);
00618   
00619   /* ncbo-unique memory */
00620   if(fl_in_1 != NULL) fl_in_1=(char *)nco_free(fl_in_1);
00621   if(fl_in_2 != NULL) fl_in_2=(char *)nco_free(fl_in_2);
00622 
00623   /* NCO-generic clean-up */
00624   /* Free individual strings/arrays */
00625   if(cmd_ln != NULL) cmd_ln=(char *)nco_free(cmd_ln);
00626   if(fl_out != NULL) fl_out=(char *)nco_free(fl_out);
00627   if(fl_out_tmp != NULL) fl_out_tmp=(char *)nco_free(fl_out_tmp);
00628   if(fl_pth != NULL) fl_pth=(char *)nco_free(fl_pth);
00629   if(fl_pth_lcl != NULL) fl_pth_lcl=(char *)nco_free(fl_pth_lcl);
00630   if(in_id_1_arr != NULL) in_id_1_arr=(int *)nco_free(in_id_1_arr);
00631   if(in_id_2_arr != NULL) in_id_2_arr=(int *)nco_free(in_id_2_arr);
00632   /* Free lists of strings */
00633   if(fl_lst_in != NULL && fl_lst_abb == NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,fl_nbr); 
00634   if(fl_lst_in != NULL && fl_lst_abb != NULL) fl_lst_in=nco_sng_lst_free(fl_lst_in,1);
00635   if(fl_lst_abb != NULL) fl_lst_abb=nco_sng_lst_free(fl_lst_abb,abb_arg_nbr);
00636   if(var_lst_in_nbr > 0) var_lst_in=nco_sng_lst_free(var_lst_in,var_lst_in_nbr);
00637   /* Free limits */
00638   for(idx=0;idx<lmt_nbr;idx++) lmt_arg[idx]=(char *)nco_free(lmt_arg[idx]);
00639   if(lmt_nbr > 0) lmt=nco_lmt_lst_free(lmt,lmt_nbr);
00640   /* Free dimension lists */
00641   if(nbr_dmn_xtr_1 > 0) dim_1=nco_dmn_lst_free(dim_1,nbr_dmn_xtr_1);
00642   if(nbr_dmn_xtr_2 > 0) dim_2=nco_dmn_lst_free(dim_2,nbr_dmn_xtr_2);
00643   if(nbr_dmn_xtr_1 > 0) dmn_out=nco_dmn_lst_free(dmn_out,nbr_dmn_xtr_1);
00644   /* Free variable lists 
00645      Using nco_var_lst_free() to free main var_1 and var_2 lists would fail
00646      if ncap_var_prc_dmn() had to broadcast any variables because pointer
00647      var_1 and var_2 still contain dangling pointer to old variable.
00648      Hence, use nco_var_lst_free() to free prc and fix lists and 
00649      use nco_free() to free main var_1 and var_2 lists.
00650      Dangling pointers in var_1 and var_2 are unsafe: fxm TODO 578 */
00651   if(nbr_var_prc_1 > 0) var_prc_1=nco_var_lst_free(var_prc_1,nbr_var_prc_1);
00652   if(nbr_var_fix_1 > 0) var_fix_1=nco_var_lst_free(var_fix_1,nbr_var_fix_1);
00653   if(nbr_var_prc_2 > 0) var_prc_2=nco_var_lst_free(var_prc_2,nbr_var_prc_2);
00654   if(nbr_var_fix_2 > 0) var_fix_2=nco_var_lst_free(var_fix_2,nbr_var_fix_2);
00655   var_1=(var_sct **)nco_free(var_1);
00656   var_2=(var_sct **)nco_free(var_2);
00657   if(nbr_xtr_1 > 0) var_out=nco_var_lst_free(var_out,nbr_xtr_1);
00658   var_prc_out=(var_sct **)nco_free(var_prc_out);
00659   var_fix_out=(var_sct **)nco_free(var_fix_out);
00660 
00661   if(rcd != NC_NOERR) nco_err_exit(rcd,"main");
00662   nco_exit_gracefully();
00663   return EXIT_SUCCESS;
00664 } /* end main() */


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