int main(int argc, char* argv[]) { unsigned int opcode = 0; char *mosaic_in=NULL; /* input mosaic file name */ char *mosaic_out=NULL; /* input mosaic file name */ char *dir_in=NULL; /* input file location */ char *dir_out=NULL; /* output file location */ int ntiles_in = 0; /* number of tiles in input mosaic */ int ntiles_out = 0; /* number of tiles in output mosaic */ int nfiles = 0; /* number of input file */ int nfiles_out = 0; /* number of output file */ char input_file [NFILE][STRING]; char output_file[NFILE][STRING]; char scalar_name[NVAR] [STRING]; char u_name [NVAR] [STRING]; char v_name [NVAR] [STRING]; char *test_case = NULL; double test_param = 1; int check_conserve = 0; /* 0 means no check */ double lonbegin = 0, lonend = 360; double latbegin = -90, latend = 90; int nlon = 0, nlat = 0; int kbegin = 0, kend = -1; int lbegin = 0, lend = -1; char *remap_file = NULL; char interp_method[STRING] = "conserve_order1"; int y_at_center = 0; int grid_type = AGRID; int nscalar=0, nvector=0, nvector2=0; int option_index, c, i, n, m, l; char entry[MAXSTRING]; /* should be long enough */ char txt[STRING]; char history[MAXATT]; int fill_missing = 0; unsigned int finer_step = 0; Grid_config *grid_in = NULL; /* store input grid */ Grid_config *grid_out = NULL; /* store output grid */ Field_config *scalar_in = NULL; /* store input scalar data */ Field_config *scalar_out = NULL; /* store output scalar data */ Field_config *u_in = NULL; /* store input vector u-component */ Field_config *v_in = NULL; /* store input vector v-component */ Field_config *u_out = NULL; /* store input vector u-component */ Field_config *v_out = NULL; /* store input vector v-component */ File_config *file_in = NULL; /* store input file information */ File_config *file_out = NULL; /* store output file information */ File_config *file2_in = NULL; /* store input file information */ File_config *file2_out = NULL; /* store output file information */ Bound_config *bound_T = NULL; /* store halo update information for T-cell*/ Interp_config *interp = NULL; /* store remapping information */ int save_weight_only = 0; int errflg = (argc == 1); int fid; static struct option long_options[] = { {"input_mosaic", required_argument, NULL, 'a'}, {"output_mosaic", required_argument, NULL, 'b'}, {"input_dir", required_argument, NULL, 'c'}, {"output_dir", required_argument, NULL, 'd'}, {"input_file", required_argument, NULL, 'e'}, {"output_file", required_argument, NULL, 'f'}, {"remap_file", required_argument, NULL, 'g'}, {"test_case", required_argument, NULL, 'i'}, {"interp_method", required_argument, NULL, 'j'}, {"test_parameter", required_argument, NULL, 'k'}, {"symmetry", no_argument, NULL, 'l'}, {"grid_type", required_argument, NULL, 'm'}, {"target_grid", no_argument, NULL, 'n'}, {"finer_step", required_argument, NULL, 'o'}, {"fill_missing", no_argument, NULL, 'p'}, {"nlon", required_argument, NULL, 'q'}, {"nlat", required_argument, NULL, 'r'}, {"scalar_field", required_argument, NULL, 's'}, {"check_conserve", no_argument, NULL, 't'}, {"u_field", required_argument, NULL, 'u'}, {"v_field", required_argument, NULL, 'v'}, {"center_y", no_argument, NULL, 'y'}, {"lonBegin", required_argument, NULL, 'A'}, {"lonEnd", required_argument, NULL, 'B'}, {"latBegin", required_argument, NULL, 'C'}, {"latEnd", required_argument, NULL, 'D'}, {"KlevelBegin", required_argument, NULL, 'E'}, {"KlevelEnd", required_argument, NULL, 'F'}, {"LstepBegin", required_argument, NULL, 'G'}, {"LstepEnd", required_argument, NULL, 'H'}, {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0}, }; /* start parallel */ mpp_init(&argc, &argv); mpp_domain_init(); while ((c = getopt_long(argc, argv, "", long_options, &option_index)) != -1) { switch (c) { case 'a': mosaic_in = optarg; break; case 'b': mosaic_out = optarg; break; case 'c': dir_in = optarg; break; case 'd': dir_out = optarg; break; case 'e': if(strlen(optarg) >= MAXSTRING) mpp_error("fregrid: the entry is not long for option -e"); strcpy(entry, optarg); tokenize(entry, ",", STRING, NFILE, input_file, &nfiles); break; case 'f': if(strlen(optarg) >= MAXSTRING) mpp_error("fregrid: the entry is not long for option -f"); strcpy(entry, optarg); tokenize(entry, ",", STRING, NFILE, output_file, &nfiles_out); break; case 'g': remap_file = optarg; break; case 's': if(strlen(optarg) >= MAXSTRING) mpp_error("fregrid: the entry is not long for option -s"); strcpy(entry, optarg); tokenize(entry, ",", STRING, NVAR, scalar_name, &nscalar); break; case 'u': if(strlen(optarg) >= MAXSTRING) mpp_error("fregrid: the entry is not long for option -u"); strcpy(entry, optarg); tokenize(entry, ",", STRING, NVAR, u_name, &nvector); break; case 'v': if(strlen(optarg) >= MAXSTRING) mpp_error("fregrid: the entry is not long for option -v"); strcpy(entry, optarg); tokenize(entry, ",", STRING, NVAR, v_name, &nvector2); break; case 'j': strcpy(interp_method, optarg); break; case 'i': test_case = optarg; break; case 'k': test_param = atof(optarg); break; case 'l': opcode |= SYMMETRY; break; case 'm': if(strcmp(optarg, "AGRID") == 0) grid_type = AGRID; else if(strcmp(optarg, "BGRID") == 0) grid_type = BGRID; else mpp_error("fregrid: only AGRID and BGRID vector regridding are implmented, contact developer"); break; case 'n': opcode |= TARGET; break; case 'o': finer_step = atoi(optarg); break; case 'p': fill_missing = 1; break; case 'q': nlon = atoi(optarg); break; case 'r': nlat = atoi(optarg); break; case 't': check_conserve = 1; break; case 'y': y_at_center = 1; break; case 'A': lonbegin = atof(optarg); break; case 'B': lonend = atof(optarg); break; case 'C': latbegin = atof(optarg); break; case 'D': latend = atof(optarg); break; case 'E': kbegin = atoi(optarg); break; case 'F': kend = atoi(optarg); break; case 'G': lbegin = atoi(optarg); break; case 'H': lend = atoi(optarg); break; case '?': errflg++; break; } } if (errflg) { char **u = usage; while (*u) { fprintf(stderr, "%s\n", *u); u++; } exit(2); } /* check the arguments */ if( !mosaic_in ) mpp_error("fregrid: input_mosaic is not specified"); if( !mosaic_out ) { if(nlon == 0 || nlat ==0 ) mpp_error("fregrid: when output_mosaic is not specified, nlon and nlat should be specified"); if(lonend <= lonbegin) mpp_error("fregrid: when output_mosaic is not specified, lonEnd should be larger than lonBegin"); if(latend <= latbegin) mpp_error("fregrid: when output_mosaic is not specified, latEnd should be larger than latBegin"); } else { if(nlon !=0 || nlat != 0) mpp_error("fregrid: when output_mosaic is specified, nlon and nlat should not be specified"); } if( nfiles == 0) { if(nvector > 0 || nscalar > 0 || nvector2 > 0) mpp_error("fregrid: when --input_file is not specified, --scalar_field, --u_field and --v_field should also not be specified"); if(!remap_file) mpp_error("fregrid: when --input_file is not specified, remap_file must be specified to save weight information"); save_weight_only = 1; if(mpp_pe()==mpp_root_pe())printf("NOTE: No input file specified in this run, no data file will be regridded " "and only weight information is calculated.\n"); } else if( nfiles == 1 || nfiles ==2) { if( nvector != nvector2 ) mpp_error("fregrid: number of fields specified in u_field must be the same as specified in v_field"); if( nscalar+nvector==0 ) mpp_error("fregrid: both scalar_field and vector_field are not specified"); /* when nvector =2 and nscalar=0, nfiles can be 2 otherwise nfiles must be 1 */ if( nscalar && nfiles != 1 ) mpp_error("fregrid: when scalar_field is specified, number of files must be 1"); if( nfiles_out == 0 ) { for(i=0; i<nfiles; i++) strcpy(output_file[i], input_file[i]); } else if (nfiles_out != nfiles ) mpp_error("fregrid:number of input file is not equal to number of output file"); } else mpp_error("fregrid: number of input file should be 1 or 2"); if(kbegin != 0 || kend != -1) { /* at least one of kbegin and kend is set */ if(kbegin < 1 || kend < kbegin) mpp_error("fregrid:KlevelBegin should be a positive integer and no larger " "than KlevelEnd when you want pick certain klevel"); } if(lbegin != 0 || lend != -1) { /* at least one of lbegin and lend is set */ if(lbegin < 1 || lend < lbegin) mpp_error("fregrid:LstepBegin should be a positive integer and no larger " "than LstepEnd when you want pick certain Lstep"); } if(nvector > 0) { opcode |= VECTOR; if(grid_type == AGRID) opcode |= AGRID; else if(grid_type == BGRID) opcode |= BGRID; } /* define history to be the history in the grid file */ strcpy(history,argv[0]); for(i=1;i<argc;i++) { strcat(history, " "); if(strlen(argv[i]) > MAXENTRY) { /* limit the size of each entry, here we are assume the only entry that is longer than MAXENTRY= 256 is the option --scalar_field --u_field and v_field */ if(strcmp(argv[i-1], "--scalar_field") && strcmp(argv[i-1], "--u_field") && strcmp(argv[i-1], "--v_field") ) mpp_error("fregrid: the entry ( is not scalar_field, u_field, v_field ) is too long, need to increase parameter MAXENTRY"); strcat(history, "(**please see the field list in this file**)" ); } else strcat(history, argv[i]); } /* get the mosaic information of input and output mosaic*/ fid = mpp_open(mosaic_in, MPP_READ); ntiles_in = mpp_get_dimlen(fid, "ntiles"); mpp_close(fid); if(mosaic_out) { fid = mpp_open(mosaic_out, MPP_READ); ntiles_out = mpp_get_dimlen(fid, "ntiles"); mpp_close(fid); } else ntiles_out = 1; if(!strcmp(interp_method, "conserve_order1") ) { if(mpp_pe() == mpp_root_pe())printf("****fregrid: first order conservative scheme will be used for regridding.\n"); opcode |= CONSERVE_ORDER1; } else if(!strcmp(interp_method, "conserve_order2") ) { if(mpp_pe() == mpp_root_pe())printf("****fregrid: second order conservative scheme will be used for regridding.\n"); opcode |= CONSERVE_ORDER2; } else if(!strcmp(interp_method, "bilinear") ) { if(mpp_pe() == mpp_root_pe())printf("****fregrid: bilinear remapping scheme will be used for regridding.\n"); opcode |= BILINEAR; } else mpp_error("fregrid: interp_method must be 'conserve_order1', 'conserve_order2' or 'bilinear'"); if(test_case) { if(nfiles != 1) mpp_error("fregrid: when test_case is specified, nfiles should be 1"); sprintf(output_file[0], "%s.%s.output", test_case, interp_method); } if(check_conserve) opcode |= CHECK_CONSERVE; if( opcode & BILINEAR ) { int ncontact; ncontact = read_mosaic_ncontacts(mosaic_in); if( nlon == 0 || nlat == 0) mpp_error("fregrid: when interp_method is bilinear, nlon and nlat should be specified"); if(ntiles_in != 6) mpp_error("fregrid: when interp_method is bilinear, the input mosaic should be 6 tile cubic grid"); if(ncontact !=12) mpp_error("fregrid: when interp_method is bilinear, the input mosaic should be 12 contact cubic grid"); if(mpp_npes() > 1) mpp_error("fregrid: parallel is not implemented for bilinear remapping"); } else y_at_center = 1; /* memory allocation for data structure */ grid_in = (Grid_config *)malloc(ntiles_in *sizeof(Grid_config)); grid_out = (Grid_config *)malloc(ntiles_out*sizeof(Grid_config)); bound_T = (Bound_config *)malloc(ntiles_in *sizeof(Bound_config)); interp = (Interp_config *)malloc(ntiles_out*sizeof(Interp_config)); get_input_grid( ntiles_in, grid_in, bound_T, mosaic_in, opcode ); if(mosaic_out) get_output_grid_from_mosaic( ntiles_out, grid_out, mosaic_out, opcode ); else get_output_grid_by_size(ntiles_out, grid_out, lonbegin, lonend, latbegin, latend, nlon, nlat, finer_step, y_at_center, opcode); if(remap_file) set_remap_file(ntiles_out, mosaic_out, remap_file, interp, &opcode, save_weight_only); if(!save_weight_only) { file_in = (File_config *)malloc(ntiles_in *sizeof(File_config)); file_out = (File_config *)malloc(ntiles_out*sizeof(File_config)); if(nfiles == 2) { file2_in = (File_config *)malloc(ntiles_in *sizeof(File_config)); file2_out = (File_config *)malloc(ntiles_out*sizeof(File_config)); } if(nscalar > 0) { scalar_in = (Field_config *)malloc(ntiles_in *sizeof(Field_config)); scalar_out = (Field_config *)malloc(ntiles_out *sizeof(Field_config)); } if(nvector > 0) { u_in = (Field_config *)malloc(ntiles_in *sizeof(Field_config)); u_out = (Field_config *)malloc(ntiles_out *sizeof(Field_config)); v_in = (Field_config *)malloc(ntiles_in *sizeof(Field_config)); v_out = (Field_config *)malloc(ntiles_out *sizeof(Field_config)); } set_mosaic_data_file(ntiles_in, mosaic_in, dir_in, file_in, input_file[0]); set_mosaic_data_file(ntiles_out, mosaic_out, dir_out, file_out, output_file[0]); if(nfiles == 2) { set_mosaic_data_file(ntiles_in, mosaic_in, dir_in, file2_in, input_file[1]); set_mosaic_data_file(ntiles_out, mosaic_out, dir_out, file2_out, output_file[1]); } for(n=0; n<ntiles_in; n++) file_in[n].fid = mpp_open(file_in[n].name, MPP_READ); set_field_struct ( ntiles_in, scalar_in, nscalar, scalar_name[0], file_in); set_field_struct ( ntiles_out, scalar_out, nscalar, scalar_name[0], file_out); set_field_struct ( ntiles_in, u_in, nvector, u_name[0], file_in); set_field_struct ( ntiles_out, u_out, nvector, u_name[0], file_out); if(nfiles == 1) { set_field_struct ( ntiles_in, v_in, nvector, v_name[0], file_in); set_field_struct ( ntiles_out, v_out, nvector, v_name[0], file_out); } else { set_field_struct ( ntiles_in, v_in, nvector, v_name[0], file2_in); set_field_struct ( ntiles_out, v_out, nvector, v_name[0], file2_out); } get_input_metadata(ntiles_in, nfiles, file_in, file2_in, scalar_in, u_in, v_in, grid_in, kbegin, kend, lbegin, lend, opcode); set_output_metadata(ntiles_in, nfiles, file_in, file2_in, scalar_in, u_in, v_in, ntiles_out, file_out, file2_out, scalar_out, u_out, v_out, grid_out, history, tagname); /* when the interp_method specified through command line is CONSERVE_ORDER1, but the interp_method in the source file field attribute is CONSERVE_ORDER2, need to modify the interp_method value */ if(opcode & CONSERVE_ORDER1) { for(l=0; l<nscalar; l++) { if(scalar_out->var[l].interp_method == CONSERVE_ORDER2) { if(mpp_pe() == mpp_root_pe())printf("NOTE from fregrid: even though the interp_method specified through command line is " "conserve_order1, the interp_method is reset to conserve_order2 because some fields in " "the source data have interp_method attribute value conserve_order2"); opcode = opcode & ~CONSERVE_ORDER1; opcode |= CONSERVE_ORDER2; break; } } } if(opcode & CONSERVE_ORDER1) { for(l=0; l<nvector; l++) { if(u_out->var[l].interp_method == CONSERVE_ORDER2) { if(mpp_pe() == mpp_root_pe())printf("NOTE from fregrid: even though the interp_method specified through command line is " "conserve_order1, the interp_method is reset to conserve_order2 because some fields in " "the source data have interp_method attribute value conserve_order2"); opcode = opcode & ~CONSERVE_ORDER1; opcode |= CONSERVE_ORDER2; break; } } } } /* preparing for the interpolation, if remapping information exist, read it from remap_file, otherwise create the remapping information and write it to remap_file */ if( opcode & BILINEAR ) /* bilinear interpolation from cubic to lalon */ setup_bilinear_interp(ntiles_in, grid_in, ntiles_out, grid_out, interp, opcode ); else setup_conserve_interp(ntiles_in, grid_in, ntiles_out, grid_out, interp, opcode); if(save_weight_only) { if(mpp_pe() == mpp_root_pe() ) { printf("NOTE: Successfully running fregrid and the following files which store weight information are generated.\n"); for(n=0; n<ntiles_out; n++) { printf("****%s\n", interp[n].remap_file); } } mpp_end(); return 0; } if(nscalar > 0) { get_field_attribute(ntiles_in, scalar_in); copy_field_attribute(ntiles_out, scalar_in, scalar_out); } if(nvector > 0) { get_field_attribute(ntiles_in, u_in); get_field_attribute(ntiles_in, v_in); copy_field_attribute(ntiles_out, u_in, u_out); copy_field_attribute(ntiles_out, v_in, v_out); } /* set time step to 1, only test scalar field now, nz need to be 1 */ if(test_case) { if(nscalar != 1 || nvector != 0) mpp_error("fregrid: when test_case is specified, nscalar must be 1 and nvector must be 0"); if(scalar_in->var->nz != 1) mpp_error("fregrid: when test_case is specified, number of vertical level must be 1"); file_in->nt = 1; file_out->nt = 1; } /* Then doing the regridding */ for(m=0; m<file_in->nt; m++) { int memsize, level_z, level_n, level_t; write_output_time(ntiles_out, file_out, m); if(nfiles > 1) write_output_time(ntiles_out, file2_out, m); /* first interp scalar variable */ for(l=0; l<nscalar; l++) { if( !scalar_in->var[l].has_taxis && m>0) continue; level_t = m + scalar_in->var[l].lstart; /*--- to reduce memory usage, we are only do remapping for on horizontal level one time */ for(level_n =0; level_n < scalar_in->var[l].nn; level_n++) for(level_z=scalar_in->var[l].kstart; level_z <= scalar_in->var[l].kend; level_z++) { if(test_case) get_test_input_data(test_case, test_param, ntiles_in, scalar_in, grid_in, bound_T, opcode); else get_input_data(ntiles_in, scalar_in, grid_in, bound_T, l, level_z, level_n, level_t); allocate_field_data(ntiles_out, scalar_out, grid_out); if( opcode & BILINEAR ) do_scalar_bilinear_interp(interp, l, ntiles_in, grid_in, grid_out, scalar_in, scalar_out, finer_step, fill_missing); else do_scalar_conserve_interp(interp, l, ntiles_in, grid_in, ntiles_out, grid_out, scalar_in, scalar_out, opcode); write_field_data(ntiles_out, scalar_out, grid_out, l, level_z, level_n, m); if(scalar_out->var[l].interp_method == CONSERVE_ORDER2) { for(n=0; n<ntiles_in; n++) { free(scalar_in[n].grad_x); free(scalar_in[n].grad_y); if(scalar_in[n].var[l].has_missing) free(scalar_in[n].grad_mask); } } for(n=0; n<ntiles_in; n++) free(scalar_in[n].data); for(n=0; n<ntiles_out; n++) free(scalar_out[n].data); } } /* then interp vector field */ for(l=0; l<nvector; l++) { if( !u_in[n].var[l].has_taxis && m>0) continue; level_t = m + u_in->var[l].lstart; get_input_data(ntiles_in, u_in, grid_in, bound_T, l, level_z, level_n, level_t); get_input_data(ntiles_in, v_in, grid_in, bound_T, l, level_z, level_n, level_t); allocate_field_data(ntiles_out, u_out, grid_out); allocate_field_data(ntiles_out, v_out, grid_out); if( opcode & BILINEAR ) do_vector_bilinear_interp(interp, l, ntiles_in, grid_in, ntiles_out, grid_out, u_in, v_in, u_out, v_out, finer_step, fill_missing); else do_vector_conserve_interp(interp, l, ntiles_in, grid_in, ntiles_out, grid_out, u_in, v_in, u_out, v_out, opcode); write_field_data(ntiles_out, u_out, grid_out, l, level_z, level_n, m); write_field_data(ntiles_out, v_out, grid_out, l, level_z, level_n, m); for(n=0; n<ntiles_in; n++) { free(u_in[n].data); free(v_in[n].data); } for(n=0; n<ntiles_out; n++) { free(u_out[n].data); free(v_out[n].data); } } } if(mpp_pe() == mpp_root_pe() ) { printf("Successfully running fregrid and the following output file are generated.\n"); for(n=0; n<ntiles_out; n++) { mpp_close(file_out[n].fid); printf("****%s\n", file_out[n].name); if( nfiles > 1 ) { mpp_close(file2_out[n].fid); printf("****%s\n", file2_out[n].name); } } } mpp_end(); return 0; } /* end of main */
int read_mosaic_ncontacts_(const char *mosaic_file) { return read_mosaic_ncontacts(mosaic_file); }