/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! !! GNU General Public License !! !! !! !! This file is part of the Flexible Modeling System (FMS). !! !! !! !! FMS is free software; you can redistribute it and/or modify !! !! it and are expected to follow the terms of the GNU General Public !! !! License as published by the Free Software Foundation. !! !! !! !! FMS is distributed in the hope that it will be useful, !! !! but WITHOUT ANY WARRANTY; without even the implied warranty of !! !! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !! !! GNU General Public License for more details. !! !! !! !! You should have received a copy of the GNU General Public License !! !! along with FMS; if not, write to: !! !! Free Software Foundation, Inc. !! !! 59 Temple Place, Suite 330 !! !! Boston, MA 02111-1307 USA !! !! or see: !! !! http://www.gnu.org/licenses/gpl.txt !! !! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ #include #include #include #include "topog.h" #include "create_xgrid.h" #include "mosaic_util.h" #include "interp.h" #include "mpp_io.h" #include "mpp.h" #define D2R (M_PI/180.) void filter_topo( int nx, int ny, int num_pass, int smooth_topo_allow_deepening, double *depth); void set_depth(int nx, int ny, const double *xbnd, const double *ybnd, double alat1, double slon1, double elon1, double alat2, double slon2, double elon2, double depth_in, double *depth); void enforce_min_depth(int nx, int ny, int round_shallow, int deepen_shallow, int fill_shallow, double min_depth, double *depth); /********************************************************************* void create_rectangular_topog() Constructing a rectangular basin with a flat bottom, basin_depth can be 0 ( all land). ********************************************************************/ void create_rectangular_topog(int nx, int ny, double basin_depth, double *depth) { int i; for(i=0; i= bowl_east || yy <= bowl_south || yy >= bowl_north) bottom = min_depth; else bottom = min_depth + bottom_depth*(1.0-exp(-pow((yy-bowl_south)/2.0,2))) *(1.0-exp(-pow((yy-bowl_north)/2.0,2))) *(1.0-exp(-pow((xx-bowl_west)/4.0,2))) *(1.0-exp(-pow((xx-bowl_east)/4.0,2))); depth[j*nx+i] = bottom; } } }; /* create_bowl_topog */ /********************************************************************* void create_gaussian_topog() Constructing a gaussian bump ********************************************************************/ void create_gaussian_topog(int nx, int ny, const double *x, const double *y, double bottom_depth, double min_depth, double gauss_amp, double gauss_scale, double slope_x, double slope_y, double *depth) { double bump_height, bump_scale, xcent, ycent, arg, bottom; double xe, xw, ys, yn; double *xt, *yt; int i, j, nxp, nyp; xt = (double *)malloc(nx*ny*sizeof(double)); yt = (double *)malloc(nx*ny*sizeof(double)); for(j=0; j 0.0 ) { arg = bottom_depth*(1-0.4*fabs(cos(((j+1)*M_PI)/nyp)*sin(((i+1)*2*M_PI)/nxp))); arg = max(arg, min_depth); depth[j*nx+i] = arg; } } } // add "idealized" ridges arg = 0.666*bottom_depth; set_depth (nx, ny, xbnd, ybnd, -20.0, 360.0-20.0, 360.0-10.0, 30.0, 360.0-45.0, 360.0-35.0, arg, depth); set_depth (nx, ny, xbnd, ybnd, 30.0, 360.0-45.0, 360.0-35.0, 60.0, 360.0-20.0, 360.0-30.0, arg, depth); set_depth (nx, ny, xbnd, ybnd, -60.0,360.0-100.0, 360.0-130.0, 40.0, 360.0-160.0, 180.0, arg, depth); arg = 0.5*bottom_depth; set_depth (nx, ny, xbnd, ybnd, -50.0, 360.0-120.0, 360.0-120.0, 30.0, 190.0, 190.0, arg, depth); free(xbnd); free(ybnd); } /* create_idealized_topog */ /********************************************************************* void set_depth(double alat1, double slon1, double elon1, double alat2, double slon2, double elon2, double depth_in ) set the topography depth "depth[i][j](i,j)" = "depth_in" within the area of the trapezoid bounded by vertices: (alat1,slon1), (alat1,elon1), (alat2,slon2), and (alat2,elon2) inputs: alat1 = southern latitude of trapezoid (degrees) slon1 = starting longitude of southern edge of trapezoid (deg) elon1 = ending longitude of southern edge of trapezoid (deg) alat2 = northern latitude of trapezoid (degrees) slon2 = starting longitude of northern edge of trapezoid (deg) elon2 = ending longitude of northern edge of trapezoid (deg) depth_in = constant depth value ********************************************************************/ void set_depth(int nx, int ny, const double *xbnd, const double *ybnd, double alat1, double slon1, double elon1, double alat2, double slon2, double elon2, double depth_in, double *depth) { double rdj, d; int i, j, i1, i2, j1, j2, is, ie, js, je, is1, ie1, is2, ie2; j1 = nearest_index(alat1, ybnd, ny ); j2 = nearest_index(alat2, ybnd, ny ); js = min(j1,j2); je = max(j1,j2); i1 = nearest_index(slon1, xbnd, nx); i2 = nearest_index(elon1, xbnd, nx); is1 = min(i1,i2); ie1 = max(i1,i2); i1 = nearest_index(slon2, xbnd, nx ); i2 = nearest_index(elon2, xbnd, ny ); is2 = min(i1,i2); ie2 = max(i1,i2); is = is1; ie = ie1; // fill in the area bounded by (js,is1), (js,ie1), (je,is2), (je,ie2) // the nudging of 1.e-5 is to insure that the test case resolution // generates the same topography and geometry on various computers. if (js == je) rdj = 1.0; else rdj = 1.0/(je-js); for(j=js;j<=je;j++){ for(i=is;i<=ie;i++) depth[j*nx+i] = depth_in; d = rdj*((j-js)*is2 + (je-j)*is1) + 1.0e-5; is = ceil(d); if( is - d > 0.5) is = is -1; d = rdj*((j-js)*ie2 + (je-j)*ie1) + 1.0e-5; ie = ceil(d); if( ie - d > 0.5) ie = ie -1; } }; /* set_depth */ /********************************************************************* void create_realistic_topog( ) reading data from source data file topog_file and remap it onto current grid ********************************************************************/ void create_realistic_topog(int nx_dst, int ny_dst, const double *x_dst, const double *y_dst, const char* topog_file, const char* topog_field, double scale_factor, double fill_first_row, int filter_topog, int num_filter_pass, int smooth_topo_allow_deepening, int round_shallow, int fill_shallow, int deepen_shallow, double min_depth, double *depth ) { char xname[128], yname[128]; int nx_src, ny_src, nxp_src, nyp_src, i, j, count, n; double *depth_src, *mask_src, *xt_src, *yt_src, *x_src, *y_src; double *x_out, *y_out; double missing; int fid, vid; /* first read source topography data to get source grid and source topography */ fid = mpp_open(topog_file, MPP_READ); vid = mpp_get_varid(fid, topog_field); mpp_get_var_dimname(fid, vid, 1, xname); mpp_get_var_dimname(fid, vid, 0, yname); nx_src = mpp_get_dimlen( fid, xname ); ny_src = mpp_get_dimlen( fid, yname ); nxp_src = nx_src + 1; nyp_src = ny_src + 1; depth_src = (double *)malloc(nx_src*ny_src*sizeof(double)); mask_src = (double *)malloc(nx_src*ny_src*sizeof(double)); xt_src = (double *)malloc(nx_src*sizeof(double)); yt_src = (double *)malloc(ny_src*sizeof(double)); x_src = (double *)malloc(nxp_src*nyp_src*sizeof(double)); y_src = (double *)malloc(nxp_src*nyp_src*sizeof(double)); mpp_get_var_att(fid, vid, "missing_value", &missing); mpp_get_var_value(fid, vid, depth_src); vid = mpp_get_varid(fid, xname); mpp_get_var_value(fid, vid, xt_src); vid = mpp_get_varid(fid, yname); mpp_get_var_value(fid, vid, yt_src); mpp_close(fid); for(j=0; j 1) mpp_error("topog: at most one of round_shallow/deepen_shallow/fill_shallow can be set to true"); if(count>0) enforce_min_depth(nx_dst, ny_dst, round_shallow, deepen_shallow, fill_shallow, min_depth, depth); free(depth_src); free(mask_src); free(x_src); free(y_src); free(xt_src); free(yt_src); free(x_out); free(y_out); }; /* create_realistic_topog */ /********************************************************************* void filter_topo( int nx, int ny, int num_pass, double *depth) smooth topographic depth "d" with "num_pass" applications of a 2D version of a shapiro filter (weights = 1/4, 1/2, 1/4) . allow filtering to decrease the bottom depth but not increase it. do not allow original geometry to change. note: depth "d" should be on a grid of uniformly constant spacing ********************************************************************/ void filter_topo( int nx, int ny, int num_pass, int smooth_topo_allow_deepening, double *depth) { double *rmask, *s; double f[9], d_old; int n1, n2, i, j, n, m, ip, jp; size_t *dims; rmask = (double *)malloc(nx*ny*sizeof(double)); s = (double *)malloc(nx*ny*sizeof(double)); /* 2D symmetric filter weights */ f[0] = 1.0/16.0; f[1] = 1.0/8.0; f[2] = 1.0/16.0; f[3] = 1.0/8.0; f[4] = 1.0/4.0; f[5] = 1.0/8.0; f[6] = 1.0/16.0; f[7] = 1.0/8.0; f[8] = 1.0/16.0; /* geometry mask */ for(i=0; i d_old) s[j*nx+i] = d_old; } s[j*nx+i] = s[j*nx+i]*rmask[j*nx+i]; } } for(i=0; i= min_depth. ********************************************************************/ void enforce_min_depth(int nx, int ny, int round_shallow, int deepen_shallow, int fill_shallow, double min_depth, double *depth) { int i, j, n, l; if(mpp_pe() == mpp_root_pe() ) printf(" Enforcing the minimum topography depth to be %f\n",min_depth); n = 0; if(round_shallow) { for(j=0;j