#include #include #include #include #include "fregrid_util.h" #include "mpp.h" #include "mpp_io.h" #include "tool_util.h" #include "mosaic_util.h" #include "read_mosaic.h" #include "gradient_c2l.h" #include "globals.h" #include "interp.h" #define D2R (M_PI/180) #define R2D (180/M_PI) #define EPSLN10 (1.e-10) #define REL_COEF ( 0.9 ) #define MAX_ITER 4000 void init_halo(double *var, int nx, int ny, int nz, int halo); void update_halo(int nx, int ny, int nz, double *data, Bound_config *bound, Data_holder *dHold); void setup_boundary(const char *mosaic_file, int ntiles, Grid_config *grid, Bound_config *bound, int halo, int position); void delete_bound_memory(int ntiles, Bound_config *bound); void copy_var_config(const Var_config *var_in, Var_config *var_out); void init_var_config(Var_config *var, int interp_method); void fill_boundaries(int ni, int nj, double *data, int is_cyclic); int parse_string(const char *str1, const char *str2, char *strOut, char *errmsg); void do_extrapolate (int ni, int nj, int nk, const double *lon, const double *lat, const double *data_in, double *data_out, int is_cyclic, double missing_value, double stop_crit); /******************************************************************************* void setup_tile_data_file(Mosaic_config mosaic, const char *filename) This routine will setup the data file name for each tile. *******************************************************************************/ void set_mosaic_data_file(int ntiles, const char *mosaic_file, const char *dir, File_config *file, const char *filename) { char str1[STRING]="", str2[STRING]="", tilename[STRING]=""; int i, n, len, fid, vid; size_t start[4], nread[4]; len = strlen(filename); if( strcmp(filename+len-3, ".nc") ==0 ) strncpy(str1, filename, len-3); else strcpy(str1, filename); if(dir) { if(strlen(dir)+strlen(str1) >= STRING)mpp_error("set_mosaic_data_file(fregrid_util): length of str1 + " "length of dir should be no greater than STRING"); sprintf(str2, "%s/%s", dir, str1); } else strcpy(str2, str1); for(i=0; i<4; i++) { start[i] = 0; nread[i] = 1; } nread[1] = STRING; if(ntiles > 1) { if(!mosaic_file) mpp_error("fregrid_util: when ntiles is greater than 1, mosaic_file should be defined"); fid = mpp_open(mosaic_file, MPP_READ); vid = mpp_get_varid(fid, "gridtiles"); } for(i = 0; i < ntiles; i++) { start[0] = i; if(ntiles > 1) { mpp_get_var_value_block(fid, vid, start, nread, tilename); if(strlen(str2) + strlen(tilename) > STRING -5) mpp_error("set_mosaic_data_file(fregrid_util): length of str2 + " "length of tilename should be no greater than STRING-5"); sprintf(file[i].name, "%s.%s.nc", str2, tilename); } else sprintf(file[i].name, "%s.nc", str2); } }; /* setup_data_file */ /******************************************************************************* void set_scalar_var() *******************************************************************************/ void set_field_struct(int ntiles, Field_config *field, int nvar, char * varname, File_config *file) { int n, i; if(nvar == 0) return; for(n=0; n0) { init_halo(grid[n].lonc, nx[n]+1, ny[n]+1, 1, halo); init_halo(grid[n].latc, nx[n]+1, ny[n]+1, 1, halo); } for(j=0; j<=ny[n]; j++) for(i=0; i<=nx[n]; i++) { ind1 = (j+halo)*(nx[n]+1+2*halo)+i+halo; ind2 = 2*j*(2*nx[n]+1)+2*i; grid[n].lonc[ind1] = x[ind2]*D2R; grid[n].latc[ind1] = y[ind2]*D2R; } if(read_tgrid) { grid[n].lont = (double *) malloc((nx[n]+2)*(ny[n]+2)*sizeof(double)); grid[n].latt = (double *) malloc((nx[n]+2)*(ny[n]+2)*sizeof(double)); for(j=0; j EPSLN10) grid[n].rotate = 1; } free(angle); } } free(x); free(y); mpp_close(g_fid); } mpp_close(m_fid); /* get the boundary condition */ setup_boundary(mosaic_file, ntiles, grid, bound_T, 1, CENTER); if(read_tgrid) { for(n=0; n 0 ) { dHold = (Data_holder *)malloc(nbound*sizeof(Data_holder)); for(l=0; l 0) { dHold = (Data_holder *)malloc(nbound*sizeof(Data_holder)); for(l=0; lhalo; for(n=0; n 2) { sprintf(errmsg, "fregrid_util.c: " "number of contacts should be no larger than 2 in file %s",mosaic_file ); mpp_error(errmsg); } read_mosaic_contact( mosaic_file, tile1, tile2, istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2 ); for(m=0; mis_tripolar = 1; } } } m_fid = mpp_open(mosaic_file, MPP_READ); get_file_path(mosaic_file, dir); for(n=0; n EPSLN10) grid[n].rotate = 1; } free(angle); } } mpp_close(g_fid); } mpp_close(m_fid); free(nx); free(ny); }; /* get_output_grid_from_mosaic*/ /******************************************************************************* void get_output_grid_by_size(Mosaic_config *mosaic, int nlon, int nlat, int finer_steps, unsigned int opcode) calculate output grid based on nlon, nlat and finer steps. *******************************************************************************/ void get_output_grid_by_size(int ntiles, Grid_config *grid, double lonbegin, double lonend, double latbegin, double latend, int nlon, int nlat, int finer_steps, int center_y, unsigned int opcode) { double dlon, dlat, lon_fine, lat_fine, lon_range, lat_range; int nx_fine, ny_fine, i, j, layout[2]; int nxc, nyc, ii, jj; if(ntiles !=1) mpp_error("fregrid_utils: ntiles of output mosaic must be 1 for bilinear interpolation"); if(finer_steps && !(opcode&BILINEAR)) mpp_error("fregrid_util: finer_steps must be 0 when interp_method is not bilinear"); grid->nx = nlon; grid->ny = nlat; grid->nx_fine = pow(2,finer_steps)*nlon; grid->ny_fine = pow(2,finer_steps)*(nlat-1)+1; nx_fine = grid->nx_fine; ny_fine = grid->ny_fine; lon_range = lonend - lonbegin; lat_range = latend - latbegin; grid->is_tripolar = 0; grid->lont1D = (double *)malloc(nlon*sizeof(double)); grid->latt1D = (double *)malloc(nlat*sizeof(double)); grid->lonc1D = (double *)malloc((nlon+1)*sizeof(double)); grid->latc1D = (double *)malloc((nlat+1)*sizeof(double)); dlon=lon_range/nlon; for(i=0; ilont1D[i] = (lonbegin + (i + 0.5)*dlon)*D2R; for(i=0; i<=nlon; i++) grid->lonc1D[i] = (lonbegin + i*dlon)*D2R; layout[0] = 1; layout[1] = mpp_npes(); mpp_define_domain2d(grid->nx, grid->ny, layout, 0, 0, &(grid->domain)); mpp_get_compute_domain2d(grid->domain, &(grid->isc), &(grid->iec), &(grid->jsc), &(grid->jec)); grid->nxc = grid->iec - grid->isc + 1; grid->nyc = grid->jec - grid->jsc + 1; nxc = grid->nxc; nyc = grid->nyc; if(center_y) { dlat=lat_range/nlat; for(j=0; jlatt1D[j] = (latbegin+(j+0.5)*dlat)*D2R; for(j=0; j<=nlat; j++) grid->latc1D[j] = (latbegin+j*dlat)*D2R; } else { dlat=lat_range/(nlat-1); for(j=0; jlatt1D[j] = (latbegin+j*dlat)*D2R; for(j=0; j<=nlat; j++) grid->latc1D[j] = (latbegin+(j-0.5)*dlat)*D2R; } if(opcode & BILINEAR) { grid->latt1D_fine = (double *)malloc(ny_fine*sizeof(double)); grid->lont = (double *)malloc(nx_fine*ny_fine*sizeof(double)); grid->latt = (double *)malloc(nx_fine*ny_fine*sizeof(double)); grid->xt = (double *)malloc(nx_fine*ny_fine*sizeof(double)); grid->yt = (double *)malloc(nx_fine*ny_fine*sizeof(double)); grid->zt = (double *)malloc(nx_fine*ny_fine*sizeof(double)); grid->vlon_t = (double *)malloc(3*nx_fine*ny_fine*sizeof(double)); grid->vlat_t = (double *)malloc(3*nx_fine*ny_fine*sizeof(double)); dlon = lon_range/nx_fine; for(i=0; ilont[j*nx_fine+i] = lon_fine; } if(center_y) { dlat=lat_range/ny_fine; for(j=0; jlatt1D_fine[j] = (latbegin+(j+0.5)*dlat)*D2R; } else { dlat = lat_range/(ny_fine-1); for(j=0; jlatt1D_fine[j] = (latbegin+j*dlat)*D2R; } for(j=0; jlatt[j*nx_fine+i] = grid->latt1D_fine[j]; } /* get the cartesian coordinates */ latlon2xyz(nx_fine*ny_fine, grid->lont, grid->latt, grid->xt, grid->yt, grid->zt); unit_vect_latlon(nx_fine*ny_fine, grid->lont, grid->latt, grid->vlon_t, grid->vlat_t); } grid->lonc = (double *) malloc((nxc+1)*(nyc+1)*sizeof(double)); grid->latc = (double *) malloc((nxc+1)*(nyc+1)*sizeof(double)); for(j=0; j<=nyc; j++) { jj = j + grid->jsc; for(i=0; i<=nxc; i++) { ii = i + grid->isc; grid->lonc[j*(nxc+1)+i] = grid->lonc1D[ii]; grid->latc[j*(nxc+1)+i] = grid->latc1D[jj]; } } if(opcode & VECTOR) { /* no rotation is needed for regular lat-lon grid. */ grid->rotate = 0; } }; /* get_output_grid_by_size */ /******************************************************************************* void init_var_config(Var_config *var) *******************************************************************************/ void init_var_config(Var_config *var, int interp_method) { var->nz = 1; var->nn = 1; var->has_naxis = 0; var->has_zaxis = 0; var->has_taxis = 0; var->kstart = 0; var->kend = 0; var->lstart = 0; var->lend = 0; var->ndim = 0; var->interp_method = interp_method; } /******************************************************************************* void copy_var_config(Var_config *var) *******************************************************************************/ void copy_var_config(const Var_config *var_in, Var_config *var_out) { int i; var_out->nz = var_in->nz; var_out->nn = var_in->nn; var_out->has_naxis = var_in->has_naxis; var_out->has_zaxis = var_in->has_zaxis; var_out->has_taxis = var_in->has_taxis; var_out->kstart = var_in->kstart; var_out->kend = var_in->kend ; var_out->lstart = var_in->lstart; var_out->lend = var_in->lend; var_out->ndim = var_in->ndim; var_out->interp_method = var_in->interp_method; for(i=0; indim; i++) var_out->index[i] = var_in->index[i]; } /* We assume all the tiles have the same vgrid */ void get_output_vgrid( VGrid_config *vgrid, const char *vgrid_file ) { int fid, nz, vid, k; double *z=NULL; /* first get number of levels */ fid = mpp_open(vgrid_file, MPP_READ); nz = mpp_get_dimlen(fid, "nzv"); if((nz-1)%2) mpp_error("fregrid_util: size of dimension nzv should be 2*nlev+1"); z = (double *)malloc(nz*sizeof(double)); vid = mpp_get_varid(fid, "zeta"); mpp_get_var_value(fid, vid, z); mpp_close(fid); nz = (nz-1)/2; vgrid->nz = nz; vgrid->z = (double *)malloc(nz*sizeof(double)); vgrid->zb = (double *)malloc((nz+1)*sizeof(double)); for(k=0; kz[k] = z[2*k+1]; for(k=0; k<=nz; k++) vgrid->zb[k] = z[2*k]; free(z); } void get_input_vgrid( VGrid_config *vgrid, const char *vgrid_file, const char *field ) { int fid, vid, vid2, ndim, i, nz; char dimname[32]; char cart; /* first get number of levels */ fid = mpp_open(vgrid_file, MPP_READ); vid = mpp_get_varid(fid, field); ndim = mpp_get_var_ndim(fid, vid); nz = 0; for(i=0; inz = nz; vgrid->z = (double *)malloc(nz*sizeof(double)); mpp_get_var_value(fid, vid2, vgrid->z); } } mpp_close(fid); if(nz == 0) mpp_error("fregrid_util: no vertical levels found in the input file"); } void setup_vertical_interp(VGrid_config *vgrid_in, VGrid_config *vgrid_out) { int nk1, nk2, kstart, kend, k; nk1 = vgrid_in->nz; nk2 = vgrid_out->nz; for(kstart=0; kstartz[kstart] >= vgrid_in->z[0]) break; } for(kend=nk2-1; kend>=0; kend--) { if(vgrid_out->z[kend] <= vgrid_in->z[nk1-1]) break; } if(kstart >0 && mpp_pe()==mpp_root_pe()) { printf("NOTE from fregrid_util: the value from level 0 to level %d will be set to the value at the shallowest source levle.\n", kstart-1); } if(kend kstart = kstart; vgrid_out->kend = kend; vgrid_out->need_interp = 1; if(nk1 == nk2 ){ for(k=0; kz[k]-vgrid_in->z[k]) > EPSLN10 ) break; } if(k==nk1) vgrid_out->need_interp = 0; } } void do_vertical_interp(VGrid_config *vgrid_in, VGrid_config *vgrid_out, Grid_config *grid_out, Field_config *field, int varid) { int nk1, nk2, nx, ny, kstart, kend, i, k; double *tmp; if(vgrid_out->need_interp && field->var[varid].has_zaxis ) { nk1 = vgrid_in->nz; nk2 = vgrid_out->nz; nx = grid_out->nx; ny = grid_out->ny; tmp = (double *)malloc(nx*ny*nk1*sizeof(double)); for(i=0; idata[i]; if(nk1 != nk2 ) { free(field->data); field->data = (double *)malloc(nx*ny*nk2*sizeof(double)); } kstart = vgrid_out->kstart; kend = vgrid_out->kend; for(k=0; kdata[k*nx*ny+i] = tmp[i]; } for(k=kend; kdata[k*nx*ny+i] = tmp[(nk1-1)*nx*ny+i]; } nk2 = kend - kstart + 1; linear_vertical_interp(nx, ny, nk1, nk2, vgrid_in->z, vgrid_out->z+kstart, tmp, field->data+kstart*nx*ny); free(tmp); } } /******************************************************************************* void get_input_metadata(Mosaic_config, *mosaic) *******************************************************************************/ void get_input_metadata(int ntiles, int nfiles, File_config *file1, File_config *file2, Field_config *scalar, Field_config *u_comp, Field_config *v_comp, const Grid_config *grid, int kbegin, int kend, int lbegin, int lend, unsigned int opcode, char *associated_file_dir) { int n, m, i, l, ll, nscalar, nvector, nfield; int ndim, dimsize[5], nz; nc_type type[5]; char cart[5]; char dimname[5][STRING], bndname[5][STRING], errmsg[STRING]; File_config *file = NULL; Field_config *field = NULL; size_t start[4], nread[4]; int interp_method, use_bilinear, use_conserve; int len, found; use_bilinear = 0; use_conserve = 0; if(opcode & CONSERVE_ORDER1) { use_conserve = 1; interp_method = CONSERVE_ORDER1; } else if(opcode & CONSERVE_ORDER2) { use_conserve = 1; interp_method = CONSERVE_ORDER2; } else if(opcode & BILINEAR) { use_bilinear = 1; interp_method = BILINEAR; } /* First find out how many fields in file and file2. */ nscalar = 0; nvector = 0; if( scalar) nscalar = scalar->nvar; if( u_comp) nvector = u_comp->nvar; for(n=0; n<4; n++) { start[n] = 0; nread[n] = 1; } for(m=0; m= MAXLIST)mpp_error("fregrid_util(get_input_metadata): nfile_list > MAXLIST"); strcpy(file_list[i], associated_file); file_id[i] = field[n].var[ll].area_fid; nfile_list++; } } } /* get the vid of area_name and check if area_name is time dependent or not */ field[n].var[ll].area_vid = mpp_get_varid(field[n].var[ll].area_fid, field[n].var[ll].area_name); ndim = mpp_get_var_ndim(field[n].var[ll].area_fid, field[n].var[ll].area_vid); /* check if it has T-axis */ mpp_get_var_dimname(field[n].var[ll].area_fid, field[n].var[ll].area_vid, 0, dimname); vid2 = mpp_get_varid(field[n].var[ll].area_fid, dimname); cart = mpp_get_var_cart(field[n].var[ll].area_fid, vid2); if( cart == 'T' ) { if(ndim <=2) { sprintf(errmsg, "fregrid_util(get_input_metadata): number of dimension of field %s in file %s has t-axis and <3" , field[n].var[ll].area_name, associated_file ); mpp_error(errmsg); } field[n].var[ll].area_has_taxis = 1; } else { field[n].var[ll].area_has_taxis = 0; } /* check if has n-axis (diurnal data). */ field[n].var[ll].area_has_naxis = 0; if(ndim>2) { if(field[n].var[ll].area_has_taxis) mpp_get_var_dimname(field[n].var[ll].area_fid, field[n].var[ll].area_vid, 1, dimname); else mpp_get_var_dimname(field[n].var[ll].area_fid, field[n].var[ll].area_vid, 0, dimname); vid2 = mpp_get_varid(field[n].var[ll].area_fid, dimname); cart = mpp_get_var_cart(field[n].var[ll].area_fid, vid2); if(cart == 'N') { field[n].var[ll].area_has_naxis = 1; if(ndim==3 && field[n].var[ll].area_has_taxis) { sprintf(errmsg, "fregrid_util(get_input_metadata): ndim=3, has_taxis=T and hax_naxis=T for field %s in file %s", field[n].var[ll].area_name, associated_file ); } else if(ndim==4 && !field[n].var[ll].area_has_taxis) { sprintf(errmsg, "fregrid_util(get_input_metadata): ndim=4, has_taxis=F for field %s in file %s", field[n].var[ll].area_name, associated_file ); } } } if(ndim>4) { sprintf(errmsg, "fregrid_util(get_input_metadata): number of dimension of field %s in file %s > 4" , field[n].var[ll].area_name, associated_file ); mpp_error(errmsg); } if( mpp_var_att_exist(field[n].var[ll].area_fid, field[n].var[ll].area_vid, "missing_value") ) { mpp_get_var_att_double(field[n].var[ll].area_fid, field[n].var[ll].area_vid, "missing_value", &(field[n].var[ll].area_missing)); } else if( mpp_var_att_exist(field[n].var[ll].area_fid, field[n].var[ll].area_vid, "_FillValue") ) { mpp_get_var_att_double(field[n].var[ll].area_fid, field[n].var[ll].area_vid, "_FillValue", &(field[n].var[ll].area_missing)); } else field[n].var[ll].area_missing = 0; } } else { field[n].var[ll].cell_measures=0; field[n].var[ll].area_missing = 0; field[n].var[ll].area_has_taxis = 0; } /* get the interp_method from the field attribute if existing when interp_method is not conserve_order2_monotonic */ if( !(opcode & MONOTONIC) ) { if(mpp_var_att_exist(file[n].fid, field[n].var[ll].vid, "interp_method")) { char remap_method[STRING] = ""; mpp_get_var_att(file[n].fid, field[n].var[ll].vid, "interp_method", remap_method); if(!strcmp(remap_method, "conserve_order1") ) { use_conserve = 1; field[n].var[ll].interp_method = CONSERVE_ORDER1; } else if(!strcmp(remap_method, "conserve_order2") ) { use_conserve = 1; field[n].var[ll].interp_method = CONSERVE_ORDER2; } else if(!strcmp(remap_method, "bilinear") ) { use_bilinear = 1; field[n].var[ll].interp_method = BILINEAR; } else { sprintf(errmsg, "get_input_metadata(fregrid_util.c): in file %s, attribute interp_method of field %s has value = %s" "is not suitable, it should be conserve_order1, conserve_order2 or bilinear", file[n].name, field[n].var[ll].name, remap_method); mpp_error(errmsg); } } } ndim = mpp_get_var_ndim(file[n].fid, field[n].var[ll].vid); if(ndim <2 || ndim>5) mpp_error("get_input_metadata(fregrid_util.c): ndim should be no less than 2 and no larger than 5"); for(i=0; i 2) { if(cart[ndim-3] == 'Z') { field[n].var[ll].has_zaxis = 1; field[n].var[ll].nz = dimsize[ndim-3]; if(kend > field[n].var[ll].nz) { sprintf(errmsg, "get_input_metadata(fregrid_util.c): KlevelEnd should be no larger than " "number of vertical levels of field %s in file %s.", field[n].var[ll].name, file[n].name); mpp_error(errmsg); } if(kbegin>0) { field[n].var[ll].kstart = kbegin - 1; field[n].var[ll].kend = kend - 1; field[n].var[ll].nz = kend - kbegin + 1; } else { field[n].var[ll].kstart = 0; field[n].var[ll].kend = field[n].var[ll].nz - 1; } } else if(cart[ndim-3] == 'N') { field[n].var[ll].has_naxis = 1; field[n].var[ll].nn = dimsize[ndim-3]; } } if(ndim > 3) { if(cart[ndim-4] == 'Z') { mpp_error("get_input_metadata(fregrid_util.c): the Z-axis must be the third dimension"); } if(cart[ndim-4] == 'N') { field[n].var[ll].has_naxis = 1; field[n].var[ll].nn = dimsize[ndim-4]; } } if(cart[0] == 'T') { field[n].var[ll].has_taxis = 1; if(lend > dimsize[0]) { sprintf(errmsg, "get_input_metadata(fregrid_util.c): LstepEnd should be no larger than " "number of time levels of field %s in file %s.", field[n].var[ll].name, file[n].name); mpp_error(errmsg); } if(lbegin>0) { field[n].var[ll].lstart = lbegin - 1; field[n].var[ll].lend = lend - 1; file[n].nt = lend - lbegin + 1; } else { field[n].var[ll].lstart = 0; field[n].var[ll].lend = dimsize[0] - 1; file[n].nt = dimsize[0]; } } for(i=0; i MAXDIM) mpp_error("get_input_metadata(fregrid_util.c):ndim is greater than MAXDIM"); file[n].axis[j].cart = cart[i]; file[n].axis[j].type = type[i]; strcpy(file[n].axis[j].name, dimname[i]); strcpy(file[n].axis[j].bndname, bndname[i]); file[n].axis[j].vid = mpp_get_varid(file[n].fid, dimname[i]); if(cart[i] == 'T') { start[0] = field[n].var[ll].lstart; file[n].axis[j].size = file[n].nt; } else if(cart[i] == 'Z') { start[0] = field[n].var[ll].kstart; file[n].axis[j].size = field[n].var[ll].nz; } else { start[0] = 0; file[n].axis[j].size = dimsize[i]; } file[n].axis[j].data = (double *)malloc(file[n].axis[j].size*sizeof(double)); nread[0] = file[n].axis[j].size; mpp_get_var_value_block(file[n].fid, file[n].axis[j].vid, start, nread, file[n].axis[j].data); file[n].axis[j].bndtype = 0; if(strcmp(bndname[i], "none") ) { file[n].axis[j].bndid = mpp_get_varid(file[n].fid, bndname[i]); if(mpp_get_var_ndim(file[n].fid,file[n].axis[j].bndid) == 1) { file[n].axis[j].bndtype = 1; file[n].axis[j].bnddata = (double *)malloc((file[n].axis[j].size+1)*sizeof(double)); nread[0] = file[n].axis[j].size+1; } else { file[n].axis[j].bndtype = 2; file[n].axis[j].bnddata = (double *)malloc(2*file[n].axis[j].size*sizeof(double)); nread[0] = file[n].axis[j].size; nread[1] = 2; } mpp_get_var_value_block(file[n].fid, file[n].axis[j].bndid, start, nread, file[n].axis[j].bnddata); } else if( cart[i] == 'X' || cart[i] == 'Y' ) { sprintf(file[n].axis[j].bndname, "%s_bnds", file[n].axis[j].name); } } } /*ndim*/ } /* nvar */ } /* ntile */ /* make sure the consistency between tiles */ for(n=1; n 0) start[0] = lbegin-1; else start[0] = 0; nread[0] = file[n].nt; nread[1] = 1; mpp_get_var_value_block(file[n].fid, file[n].id_t1, start, nread, file[n].t1); mpp_get_var_value_block(file[n].fid, file[n].id_t2, start, nread, file[n].t2); mpp_get_var_value_block(file[n].fid, file[n].id_dt, start, nread, file[n].dt); } } } /*nfile*/ /* make sure bilinear and conservative interpolation do not co-exist. */ if(use_bilinear && use_conserve) mpp_error("get_input_metadata(fregrid_util.c): bilinear interpolation and conservative " "interpolation can not co-exist, check you option interp_method in command " "line and field attribute interp_method in source file"); }; /* get_input_metadata */ /* get the string after str2 in str1 and save it into strOut return 1 if the string is found, return 0 if not, return -1 if error found */ int parse_string(const char *str1, const char *str2, char *strOut, char *errmsg) { char *str=NULL; int len2, len, istart, attlen, i; len2 = strlen(str2); str = strstr(str1, str2); if( str ) { /* str2 is found */ str = str+len2; len = strlen(str); /* find the start position */ istart = len; for(i=0; invar; if( u_in) nvector = u_in->nvar; for(n=0; nnz > 0) scalar_out[n].var[l].nz = vgrid_out->nz; } for(l=0; lnz >0 ) file_out[n].axis[i].size = vgrid_out->nz; else file_out[n].axis[i].size = file_in[0].axis[i].size; if(file_out[n].axis[i].cart == 'X') file_out[n].axis[i].size = grid_out[n].nx; if(file_out[n].axis[i].cart == 'Y') file_out[n].axis[i].size = grid_out[n].ny; file_out[n].axis[i].type = file_in[0].axis[i].type; file_out[n].axis[i].bndtype = file_in[0].axis[i].bndtype; if(standard_dimension && (file_out[n].axis[i].cart == 'X' || file_out[n].axis[i].cart == 'Y') ) file_out[n].axis[i].bndtype = 3; if(file_out[n].axis[i].bndtype ==0 && (file_out[n].axis[i].cart == 'X' || file_out[n].axis[i].cart == 'Y') && dst_is_latlon) file_out[n].axis[i].bndtype = 3; strcpy(file_out[n].axis[i].name, file_in[0].axis[i].name); strcpy(file_out[n].axis[i].bndname, file_in[0].axis[i].bndname); } for(i=0; inz > 0 ) { /* z-axis */ for(l=0; lz[l]; } else { for(l=0; lnz > 0) { for(l=0; l<=file_out[n].axis[i].size; l++) file_out[n].axis[i].bnddata[l ] = vgrid_out->zb[l]; } else{ for(l=0; l<=file_out[n].axis[i].size; l++) file_out[n].axis[i].bnddata[l] = file_in[0].axis[i].bnddata[l]; } break; case 2: file_out[n].axis[i].bnddata = (double *)malloc(2*file_out[n].axis[i].size*sizeof(double)); if( file_out[n].axis[i].cart == 'X' ) { /* x-axis */ for(l=0; lnz > 0) { for(l=0; lzb[l]; file_out[n].axis[i].bnddata[2*l+1] = vgrid_out->zb[l+1]; } } else { for(l=0; l 0 ) mpp_put_var_value(file_out[n].fid, file_out[n].axis[i].bndid, file_out[n].axis[i].bnddata); } } } } }; /* set_output_metadata */ /******************************************************************************* void get_field_attribute( ) *******************************************************************************/ void get_field_attribute( int ntiles, Field_config *field) { int n, l, nfield; char str[128]; nfield = field->nvar; for(l=0; lnvar; l++) { field_out[n].var[l].missing = field_in->var[l].missing; field_out[n].var[l].scale = field_in->var[l].scale; field_out[n].var[l].offset = field_in->var[l].offset; } } /******************************************************************************* void set_remap_file( ) *******************************************************************************/ void set_remap_file( int ntiles, const char *mosaic_file, const char *remap_file, Interp_config *interp, unsigned int *opcode, int save_weight_only) { int i, len, m, fid, vid; size_t start[4], nread[4]; char str1[STRING], tilename[STRING]; int file_exist; if(!remap_file) return; for(i=0; i<4; i++) { start[i] = 0; nread[i] = 1; } nread[1] = STRING; len = strlen(remap_file); if(len >= STRING) mpp_error("setoutput_remap_file(fregrid_util): length of remap_file should be less than STRING"); if( strcmp(remap_file+len-3, ".nc")==0 ) { strncpy(str1, remap_file, len-3); str1[len-3] = 0; } else strcpy(str1, remap_file); (*opcode) |= WRITE; if(ntiles>1) { fid = mpp_open(mosaic_file, MPP_READ); vid = mpp_get_varid(fid, "gridtiles"); } for(m=0; m 1) { start[0] = m; mpp_get_var_value_block(fid, vid, start, nread, tilename); if(strlen(str1) + strlen(tilename) > STRING -5) mpp_error("set_output_remap_file(fregrid_util): length of str1 + " "length of tilename should be no greater than STRING-5"); sprintf(interp[m].remap_file, "%s.%s.nc", str1, tilename); } else sprintf(interp[m].remap_file, "%s.nc", str1); /* check xgrid file to be read (=1) or write ( = 2) */ if(!save_weight_only && mpp_file_exist(interp[m].remap_file)) { (*opcode) |= READ; interp[m].file_exist = 1; } } if(ntiles>1) mpp_close(fid); };/* set_remap_file */ /*---------------------------------------------------------------------- void write_output_axis_data( ) write out time axis data of the output data file --------------------------------------------------------------------*/ void write_output_time(int ntiles, File_config *file, int level) { int i, n; size_t start[4], nwrite[4]; for(i=0; i<4; i++) { start[i] = 0; nwrite[i] = 1; } start[0] = level; if( mpp_pe() == mpp_root_pe()) { for(n=0; nvar[varid].missing; interp_method = field->var[varid].interp_method; if(interp_method == CONSERVE_ORDER1) halo = 0; else halo = 1; nz = 1; if( level_z < 0 ) nz = field->var[varid].nz; ndim = field->var[varid].ndim; if(ndim < 2) mpp_error("fregrid_util(get_input_data): ndim must be no less than 2"); nread = (size_t *)malloc(ndim*sizeof(size_t)); start = (size_t *)malloc(ndim*sizeof(size_t)); for(i=0; ivar[varid].has_taxis) start[pos++] = level_t; if(field->var[varid].has_naxis) start[pos++] = level_n; if(field->var[varid].has_zaxis) { if( level_z <0 ) { nread[pos] = field->var[varid].nz; start[pos++] = field->var[varid].kstart; } else start[pos++] = level_z; } if(ndim != pos + 2) mpp_error("fregrid_util(get_input_data): mimstch between ndim and has_taxis/has_zaxis/has_naxis"); /* first read input data for each tile */ for(n=0; n 0 */ if(halo > 0) { for(n=0; n 0) { dHold = (Data_holder *)malloc(nbound*sizeof(Data_holder)); for(l=0; l 0 */ if(halo > 0) { for(n=0; n 0) { dHold = (Data_holder *)malloc(nbound*sizeof(Data_holder)); for(l=0; lvar[varid].ndim; if(ndim < 2) mpp_error("fregrid_util(write_field_data): ndim must be no less than 2"); nwrite = (size_t *)malloc(ndim*sizeof(size_t)); start = (size_t *)malloc(ndim*sizeof(size_t)); nz = 1; if(level_z<0) nz = field->var[varid].nz; for(i=0; ivar[varid].missing; pos = 0; if(field->var[varid].has_taxis) start[pos++] = level_t; if(field->var[varid].has_naxis) start[pos++] = level_n; if(field->var[varid].has_zaxis) { if(level_z < 0) nwrite[pos++] = nz; else start[pos++] = level_z; } if(ndim != pos + 2) mpp_error("fregrid_util(write_field_data): mimstch between ndim and has_taxis/has_zaxis/has_naxis"); for(n=0; n 0) { bound[n].is1 = (int *)malloc(nbound*sizeof(int)); bound[n].ie1 = (int *)malloc(nbound*sizeof(int)); bound[n].js1 = (int *)malloc(nbound*sizeof(int)); bound[n].je1 = (int *)malloc(nbound*sizeof(int)); bound[n].is2 = (int *)malloc(nbound*sizeof(int)); bound[n].ie2 = (int *)malloc(nbound*sizeof(int)); bound[n].js2 = (int *)malloc(nbound*sizeof(int)); bound[n].je2 = (int *)malloc(nbound*sizeof(int)); bound[n].rotate = (int *)malloc(nbound*sizeof(int)); bound[n].tile2 = (int *)malloc(nbound*sizeof(int)); nb = 0; for(l=0; l<2*ncontacts; l++) { if(tile[l] != n) continue; switch(dir[l]) { case WEST: bound[n].is1[nb] = 0; bound[n].ie1[nb] = halo-1; bound[n].js1[nb] = min(jstart[l],jend[l])+halo; bound[n].je1[nb] = max(jstart[l],jend[l])+halo+shift; break; case EAST: bound[n].is1[nb] = nx+shift+halo; bound[n].ie1[nb] = nx+shift+halo+halo-1; bound[n].js1[nb] = min(jstart[l],jend[l])+halo; bound[n].je1[nb] = max(jstart[l],jend[l])+halo+shift; break; case SOUTH: bound[n].is1[nb] = min(istart[l],iend[l])+halo; bound[n].ie1[nb] = max(istart[l],iend[l])+halo+shift; bound[n].js1[nb] = 0; bound[n].je1[nb] = halo-1; break; case NORTH: bound[n].is1[nb] = min(istart[l],iend[l])+halo; bound[n].ie1[nb] = max(istart[l],iend[l])+halo+shift; bound[n].js1[nb] = ny+shift+halo; bound[n].je1[nb] = ny+shift+halo+halo-1; break; } l2 = (l+ncontacts)%(2*ncontacts); bound[n].tile2[nb] = tile[l2]; switch(dir[l2]) { case WEST: bound[n].is2[nb] = halo+shift; bound[n].ie2[nb] = halo+shift+halo-1; bound[n].js2[nb] = min(jstart[l2],jend[l2])+halo; bound[n].je2[nb] = max(jstart[l2],jend[l2])+halo+shift; break; case EAST: bound[n].is2[nb] = nx-halo+1; bound[n].ie2[nb] = nx; bound[n].js2[nb] = min(jstart[l2],jend[l2])+halo; bound[n].je2[nb] = max(jstart[l2],jend[l2])+halo+shift; break; case SOUTH: bound[n].is2[nb] = min(istart[l2],iend[l2])+halo; bound[n].ie2[nb] = max(istart[l2],iend[l2])+halo+shift; bound[n].js2[nb] = halo+shift; bound[n].je2[nb] = halo+shift+halo-1; break; case NORTH: bound[n].is2[nb] = min(istart[l2],iend[l2])+halo; bound[n].ie2[nb] = max(istart[l2],iend[l2])+halo+shift; bound[n].js2[nb] = ny-halo+1; bound[n].je2[nb] = ny; break; } bound[n].rotate[nb] = ZERO; if(dir[l] == WEST && dir[l2] == NORTH) bound[n].rotate[nb] = NINETY; if(dir[l] == EAST && dir[l2] == SOUTH) bound[n].rotate[nb]= NINETY; if(dir[l] == SOUTH && dir[l2] == EAST) bound[n].rotate[nb] = MINUS_NINETY; if(dir[l] == NORTH && dir[l2] == WEST) bound[n].rotate[nb] = MINUS_NINETY; if(dir[l] == NORTH && dir[l2] == NORTH) bound[n].rotate[nb] = ONE_HUNDRED_EIGHTY; /* make sure the size match at the boundary */ if( (bound[n].ie2[nb]-bound[n].is2[nb]+1)*(bound[n].je2[nb]-bound[n].js2[nb]+1) != (bound[n].ie1[nb]-bound[n].is1[nb]+1)*(bound[n].je1[nb]-bound[n].js1[nb]+1) ) mpp_error("fregrid_util: size mismatch between the boundary"); nb++; } } } }; /* setup_boundary */ void delete_bound_memory(int ntiles, Bound_config *bound) { int n; for(n=0; n 0) { free(bound[n].is1); free(bound[n].ie1); free(bound[n].js1); free(bound[n].je1); free(bound[n].is2); free(bound[n].ie2); free(bound[n].js2); free(bound[n].je2); free(bound[n].tile2); free(bound[n].rotate); } } } /*----------------------------------------------------------------------------- void init_halo(double *var, int nx, int ny, int nz, int halo) initialze the halo data to be zero. ---------------------------------------------------------------------------*/ void init_halo(double *var, int nx, int ny, int nz, int halo) { int i, j, k; int nxd, nyd, nall; nxd = nx+2*halo; nyd = ny+2*halo; nall = nxd*nyd; for(k=0; knbound; size1 = nx*ny; for(n=0; nis1[n]; ie1 = bound->ie1[n]; js1 = bound->js1[n]; je1 = bound->je1[n]; is2 = bound->is2[n]; ie2 = bound->ie2[n]; js2 = bound->js2[n]; je2 = bound->je2[n]; nx2 = dHold[n].nx; ny2 = dHold[n].ny; size2 = nx2*ny2; bufsize = nz*(ie2-is2+1)*(je2-js2+1); buffer = (double *)malloc(bufsize*sizeof(double)); /* fill the buffer */ l = 0; switch(bound->rotate[n]) { case ZERO: for(k=0; k=is2; i--) for(j=js2; j<=je2; j++) buffer[l++] = dHold[n].data[k*size2+j*nx2+i]; break; case MINUS_NINETY: for(k=0; k=js2; j--) buffer[l++] = dHold[n].data[k*size2+j*nx2+i]; break; case ONE_HUNDRED_EIGHTY: for(k=0; k=js2; j--) for(i=ie2; i>=is2; i--) buffer[l++] = dHold[n].data[k*size2+j*nx2+i]; break; } l = 0; for(k=0; k