#include #include #include #include #include "fregrid_util.h" #include "mpp_io.h" #include "mosaic_util.h" #include "gradient_c2l.h" #define D2R (M_PI/180) #define R2D (180/M_PI) #define EPSLN (1.e-10) 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 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( strstr(filename, ".nc") ) 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; } for(j=0; j EPSLN) 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(opcode & BILINEAR) setup_boundary(mosaic_file, ntiles, grid, bound_C, 1, CORNER); 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; l EPSLN) 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->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); } else { /* for conservative interpolation */ 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 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) { int n, m, i, l, ll, nscalar, nvector, nfield; int ndim, dimsize[4], nz; nc_type type[4]; char cart[4]; char dimname[4][STRING], bndname[4][STRING], errmsg[STRING]; File_config *file = NULL; Field_config *field = NULL; size_t start[4], nread[4]; /* 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; m4) mpp_error("get_input_metadata(fregrid_util.c): ndim should be no less than 2 and no larger than 4"); if(cart[ndim-1] != 'X') mpp_error("get_input_metadata(fregrid_util.c): the last dimension cartesian should be 'X'"); if(cart[ndim-2] != 'Y') mpp_error("get_input_metadata(fregrid_util.c): the second last dimension cartesian should be 'Y'"); if(dimsize[ndim-1] != grid[n].nx) mpp_error("get_input_metadata(fregrid_util.c): x-size in grid file in not the same as in data file"); if(dimsize[ndim-2] != grid[n].ny) mpp_error("get_input_metadata(fregrid_util.c): y-size in grid file in not the same as in data file"); if(cart[0] == 'Z' || cart[1] == 'Z') { field[n].var[ll].has_zaxis = 1; field[n].var[ll].nz = cart[0] == 'Z'? dimsize[0]:dimsize[1]; /* the selected vertical level should be between 1 and nz. */ 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; } } 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); } } } /*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*/ }; /* get_input_metadata */ /******************************************************************************* void set_output_metadata ( Mosaic_config *mosaic) *******************************************************************************/ void set_output_metadata (int ntiles_in, int nfiles, const File_config *file1_in, const File_config *file2_in, const Field_config *scalar_in, const Field_config *u_in, const Field_config *v_in, int ntiles_out, File_config *file1_out, File_config *file2_out, Field_config *scalar_out, Field_config *u_out, Field_config *v_out, const Grid_config *grid_out, const char *history, const char *tagname) { int m, n, ndim, i, l, dims[4]; int dim_bnds, dim_time; int nscalar, nvector; const File_config *file_in = NULL; File_config *file_out = NULL; nscalar = 0; nvector = 0; if( scalar_in) nscalar = scalar_in->nvar; if( u_in) nvector = u_in->nvar; for(n=0; nnvar; for(l=0; l= STRING) mpp_error("setoutput_remap_file(fregrid_util): length of remap_file should be less than STRING"); if( strstr(remap_file, ".nc") ) { 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].nz; for(i=0; i<4; i++) { start[i] = 0; nread[i] = 1; } start[0] = level; /* first read input data for each tile */ for(n=0; nvar[varid].kstart; nread[ndim-3] = nz; } memsize = (nx+2*halo)*(ny+2*halo)*nz; field[n].data = (double *)malloc(memsize*sizeof(double)); if(halo ==0) { mpp_get_var_value_block(*(field[n].fid), field[n].var[varid].vid, start, nread, field[n].data); } else { data = (double *)malloc(nx*ny*nz*sizeof(double)); mpp_get_var_value_block(*(field[n].fid), field[n].var[varid].vid, start, nread, data); init_halo(field[n].data, nx, ny, nz, 1); /* copy the data onto compute domain */ for(k=0; k 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[l].nz; for(i=0; i<4; i++) { start[i] = 0; nwrite[i] = 1; } start[0] = level; 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