/*********************************************************************** * GNU Lesser General Public License * * This file is part of the GFDL Flexible Modeling System (FMS). * * FMS is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * 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 Lesser General Public * License along with FMS. If not, see . **********************************************************************/ #include #include #include #include "mosaic_util.h" #include "create_xgrid.h" #include "constant.h" #if defined(_OPENMP) #include #endif #define AREA_RATIO_THRESH (1.e-6) #define MASK_THRESH (0.5) #define EPSLN8 (1.e-8) #define EPSLN30 (1.0e-30) #define EPSLN10 (1.0e-10) #define R2D (180/M_PI) #define TPI (2.0*M_PI) /******************************************************************************* int get_maxxgrid return constants MAXXGRID. *******************************************************************************/ int get_maxxgrid(void) { return MAXXGRID; } int get_maxxgrid_(void) { return get_maxxgrid(); } /******************************************************************************* void get_grid_area(const int *nlon, const int *nlat, const double *lon, const double *lat, const double *area) return the grid area. *******************************************************************************/ #ifndef __AIX void get_grid_area_(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area) { get_grid_area(nlon, nlat, lon, lat, area); } #endif void get_grid_area(const int *nlon, const int *nlat, const double *lon, const double *lat, double *area) { int nx, ny, nxp, i, j, n_in; double x_in[20], y_in[20]; nx = *nlon; ny = *nlat; nxp = nx + 1; for(j=0; j 1) get_grid_area(nlon_in, nlat_in, tmpx, tmpy, area_in); else get_grid_area_no_adjust(nlon_in, nlat_in, tmpx, tmpy, area_in); get_grid_area(nlon_out, nlat_out, lon_out, lat_out, area_out); free(tmpx); free(tmpy); for(j1=0; j1 MASK_THRESH ) { ll_lon = lon_in[i1]; ll_lat = lat_in[j1]; ur_lon = lon_in[i1+1]; ur_lat = lat_in[j1+1]; for(j2=0; j2=ur_lat) && (y_in[1]>=ur_lat) && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue; x_in[0] = lon_out[j2*nx2p+i2]; x_in[1] = lon_out[j2*nx2p+i2+1]; x_in[2] = lon_out[(j2+1)*nx2p+i2+1]; x_in[3] = lon_out[(j2+1)*nx2p+i2]; n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2); if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) { Xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1]; min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]); if( Xarea/min_area > AREA_RATIO_THRESH ) { xgrid_area[nxgrid] = Xarea; i_in[nxgrid] = i1; j_in[nxgrid] = j1; i_out[nxgrid] = i2; j_out[nxgrid] = j2; ++nxgrid; if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID"); } } } } free(area_in); free(area_out); return nxgrid; } /* create_xgrid_1dx2d_order1 */ /******************************************************************************* void create_xgrid_1dx2d_order1_ug This routine generate exchange grids between two grids for the first order conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell and lon_in,lat_in are 1-D grid bounds, lon_out,lat_out are geographic grid location of grid cell bounds. *******************************************************************************/ int create_xgrid_1dx2d_order1_ug_(const int *nlon_in, const int *nlat_in, const int *npts_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *l_out, double *xgrid_area) { int nxgrid; nxgrid = create_xgrid_1dx2d_order1_ug(nlon_in, nlat_in, npts_out, lon_in, lat_in, lon_out, lat_out, mask_in, i_in, j_in, l_out, xgrid_area); return nxgrid; } int create_xgrid_1dx2d_order1_ug(const int *nlon_in, const int *nlat_in, const int *npts_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *l_out, double *xgrid_area) { int nx1, ny1, nx1p, nv, npts2; int i1, j1, l2, nxgrid; double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV]; double *area_in, *area_out, min_area; double *tmpx, *tmpy; nx1 = *nlon_in; ny1 = *nlat_in; nv = 4; npts2 = *npts_out; nxgrid = 0; nx1p = nx1 + 1; area_in = (double *)malloc(nx1*ny1*sizeof(double)); area_out = (double *)malloc(npts2*sizeof(double)); tmpx = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double)); tmpy = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double)); for(j1=0; j1<=ny1; j1++) for(i1=0; i1<=nx1; i1++) { tmpx[j1*nx1p+i1] = lon_in[i1]; tmpy[j1*nx1p+i1] = lat_in[j1]; } /* This is just a temporary fix to solve the issue that there is one point in zonal direction */ if(nx1 > 1) get_grid_area(nlon_in, nlat_in, tmpx, tmpy, area_in); else get_grid_area_no_adjust(nlon_in, nlat_in, tmpx, tmpy, area_in); get_grid_area_ug(npts_out, lon_out, lat_out, area_out); free(tmpx); free(tmpy); for(j1=0; j1 MASK_THRESH ) { ll_lon = lon_in[i1]; ll_lat = lat_in[j1]; ur_lon = lon_in[i1+1]; ur_lat = lat_in[j1+1]; for(l2=0; l2=ur_lat) && (y_in[1]>=ur_lat) && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue; x_in[0] = lon_out[l2*nv]; x_in[1] = lon_out[l2*nv+1]; x_in[2] = lon_out[l2*nv+2]; x_in[3] = lon_out[l2*nv+3]; n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2); if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) { Xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1]; min_area = min(area_in[j1*nx1+i1], area_out[l2]); if( Xarea/min_area > AREA_RATIO_THRESH ) { xgrid_area[nxgrid] = Xarea; i_in[nxgrid] = i1; j_in[nxgrid] = j1; l_out[nxgrid] = l2; ++nxgrid; if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID"); } } } } free(area_in); free(area_out); return nxgrid; } /* create_xgrid_1dx2d_order1_ug */ /******************************************************************************** void create_xgrid_1dx2d_order2 This routine generate exchange grids between two grids for the second order conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell and lon_in,lat_in are 1-D grid bounds, lon_out,lat_out are geographic grid location of grid cell bounds. ********************************************************************************/ int create_xgrid_1dx2d_order2_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area, double *xgrid_clon, double *xgrid_clat) { int nxgrid; nxgrid = create_xgrid_1dx2d_order2(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in, i_in, j_in, i_out, j_out, xgrid_area, xgrid_clon, xgrid_clat); return nxgrid; } int create_xgrid_1dx2d_order2(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area, double *xgrid_clon, double *xgrid_clat) { int nx1, ny1, nx2, ny2, nx1p, nx2p; int i1, j1, i2, j2, nxgrid, n; double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV]; double *area_in, *area_out, min_area; double *tmpx, *tmpy; nx1 = *nlon_in; ny1 = *nlat_in; nx2 = *nlon_out; ny2 = *nlat_out; nxgrid = 0; nx1p = nx1 + 1; nx2p = nx2 + 1; area_in = (double *)malloc(nx1*ny1*sizeof(double)); area_out = (double *)malloc(nx2*ny2*sizeof(double)); tmpx = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double)); tmpy = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double)); for(j1=0; j1<=ny1; j1++) for(i1=0; i1<=nx1; i1++) { tmpx[j1*nx1p+i1] = lon_in[i1]; tmpy[j1*nx1p+i1] = lat_in[j1]; } get_grid_area(nlon_in, nlat_in, tmpx, tmpy, area_in); get_grid_area(nlon_out, nlat_out, lon_out, lat_out, area_out); free(tmpx); free(tmpy); for(j1=0; j1 MASK_THRESH ) { ll_lon = lon_in[i1]; ll_lat = lat_in[j1]; ur_lon = lon_in[i1+1]; ur_lat = lat_in[j1+1]; for(j2=0; j2=ur_lat) && (y_in[1]>=ur_lat) && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue; x_in[0] = lon_out[j2*nx2p+i2]; x_in[1] = lon_out[j2*nx2p+i2+1]; x_in[2] = lon_out[(j2+1)*nx2p+i2+1]; x_in[3] = lon_out[(j2+1)*nx2p+i2]; n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2); lon_in_avg = avgval_double(n_in, x_in); if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) { xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1]; min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]); if(xarea/min_area > AREA_RATIO_THRESH ) { xgrid_area[nxgrid] = xarea; xgrid_clon[nxgrid] = poly_ctrlon(x_out, y_out, n_out, lon_in_avg); xgrid_clat[nxgrid] = poly_ctrlat (x_out, y_out, n_out ); i_in[nxgrid] = i1; j_in[nxgrid] = j1; i_out[nxgrid] = i2; j_out[nxgrid] = j2; ++nxgrid; if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID"); } } } } free(area_in); free(area_out); return nxgrid; } /* create_xgrid_1dx2d_order2 */ /******************************************************************************* void create_xgrid_2dx1d_order1 This routine generate exchange grids between two grids for the first order conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell and lon_out,lat_out are 1-D grid bounds, lon_in,lat_in are geographic grid location of grid cell bounds. mask is on grid lon_in/lat_in. *******************************************************************************/ int create_xgrid_2dx1d_order1_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area) { int nxgrid; nxgrid = create_xgrid_2dx1d_order1(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in, i_in, j_in, i_out, j_out, xgrid_area); return nxgrid; } int create_xgrid_2dx1d_order1(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area) { int nx1, ny1, nx2, ny2, nx1p, nx2p; int i1, j1, i2, j2, nxgrid; double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV]; double *area_in, *area_out, min_area; double *tmpx, *tmpy; int n_in, n_out; double Xarea; nx1 = *nlon_in; ny1 = *nlat_in; nx2 = *nlon_out; ny2 = *nlat_out; nxgrid = 0; nx1p = nx1 + 1; nx2p = nx2 + 1; area_in = (double *)malloc(nx1*ny1*sizeof(double)); area_out = (double *)malloc(nx2*ny2*sizeof(double)); tmpx = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double)); tmpy = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double)); for(j2=0; j2<=ny2; j2++) for(i2=0; i2<=nx2; i2++) { tmpx[j2*nx2p+i2] = lon_out[i2]; tmpy[j2*nx2p+i2] = lat_out[j2]; } get_grid_area(nlon_in, nlat_in, lon_in, lat_in, area_in); get_grid_area(nlon_out, nlat_out, tmpx, tmpy, area_out); free(tmpx); free(tmpy); for(j2=0; j2 MASK_THRESH ) { y_in[0] = lat_in[j1*nx1p+i1]; y_in[1] = lat_in[j1*nx1p+i1+1]; y_in[2] = lat_in[(j1+1)*nx1p+i1+1]; y_in[3] = lat_in[(j1+1)*nx1p+i1]; if ( (y_in[0]<=ll_lat) && (y_in[1]<=ll_lat) && (y_in[2]<=ll_lat) && (y_in[3]<=ll_lat) ) continue; if ( (y_in[0]>=ur_lat) && (y_in[1]>=ur_lat) && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue; x_in[0] = lon_in[j1*nx1p+i1]; x_in[1] = lon_in[j1*nx1p+i1+1]; x_in[2] = lon_in[(j1+1)*nx1p+i1+1]; x_in[3] = lon_in[(j1+1)*nx1p+i1]; n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2); if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) { Xarea = poly_area ( x_out, y_out, n_out ) * mask_in[j1*nx1+i1]; min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]); if( Xarea/min_area > AREA_RATIO_THRESH ) { xgrid_area[nxgrid] = Xarea; i_in[nxgrid] = i1; j_in[nxgrid] = j1; i_out[nxgrid] = i2; j_out[nxgrid] = j2; ++nxgrid; if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID"); } } } } free(area_in); free(area_out); return nxgrid; } /* create_xgrid_2dx1d_order1 */ /******************************************************************************** void create_xgrid_2dx1d_order2 This routine generate exchange grids between two grids for the second order conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell and lon_out,lat_out are 1-D grid bounds, lon_in,lat_in are geographic grid location of grid cell bounds. mask is on grid lon_in/lat_in. ********************************************************************************/ int create_xgrid_2dx1d_order2_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area, double *xgrid_clon, double *xgrid_clat) { int nxgrid; nxgrid = create_xgrid_2dx1d_order2(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in, i_in, j_in, i_out, j_out, xgrid_area, xgrid_clon, xgrid_clat); return nxgrid; } int create_xgrid_2dx1d_order2(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area, double *xgrid_clon, double *xgrid_clat) { int nx1, ny1, nx2, ny2, nx1p, nx2p; int i1, j1, i2, j2, nxgrid, n; double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV]; double *tmpx, *tmpy; double *area_in, *area_out, min_area; double lon_in_avg; int n_in, n_out; double xarea; nx1 = *nlon_in; ny1 = *nlat_in; nx2 = *nlon_out; ny2 = *nlat_out; nxgrid = 0; nx1p = nx1 + 1; nx2p = nx2 + 1; area_in = (double *)malloc(nx1*ny1*sizeof(double)); area_out = (double *)malloc(nx2*ny2*sizeof(double)); tmpx = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double)); tmpy = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double)); for(j2=0; j2<=ny2; j2++) for(i2=0; i2<=nx2; i2++) { tmpx[j2*nx2p+i2] = lon_out[i2]; tmpy[j2*nx2p+i2] = lat_out[j2]; } get_grid_area(nlon_in, nlat_in, lon_in, lat_in, area_in); get_grid_area(nlon_out, nlat_out, tmpx, tmpy, area_out); free(tmpx); free(tmpy); for(j2=0; j2 MASK_THRESH ) { y_in[0] = lat_in[j1*nx1p+i1]; y_in[1] = lat_in[j1*nx1p+i1+1]; y_in[2] = lat_in[(j1+1)*nx1p+i1+1]; y_in[3] = lat_in[(j1+1)*nx1p+i1]; if ( (y_in[0]<=ll_lat) && (y_in[1]<=ll_lat) && (y_in[2]<=ll_lat) && (y_in[3]<=ll_lat) ) continue; if ( (y_in[0]>=ur_lat) && (y_in[1]>=ur_lat) && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue; x_in[0] = lon_in[j1*nx1p+i1]; x_in[1] = lon_in[j1*nx1p+i1+1]; x_in[2] = lon_in[(j1+1)*nx1p+i1+1]; x_in[3] = lon_in[(j1+1)*nx1p+i1]; n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2); lon_in_avg = avgval_double(n_in, x_in); if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) { xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1]; min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]); if(xarea/min_area > AREA_RATIO_THRESH ) { xgrid_area[nxgrid] = xarea; xgrid_clon[nxgrid] = poly_ctrlon(x_out, y_out, n_out, lon_in_avg); xgrid_clat[nxgrid] = poly_ctrlat (x_out, y_out, n_out ); i_in[nxgrid] = i1; j_in[nxgrid] = j1; i_out[nxgrid] = i2; j_out[nxgrid] = j2; ++nxgrid; if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID"); } } } } free(area_in); free(area_out); return nxgrid; } /* create_xgrid_2dx1d_order2 */ /******************************************************************************* void create_xgrid_2DX2D_order1 This routine generate exchange grids between two grids for the first order conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell and lon_in,lat_in, lon_out,lat_out are geographic grid location of grid cell bounds. mask is on grid lon_in/lat_in. *******************************************************************************/ #ifndef __AIX int create_xgrid_2dx2d_order1_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area) { int nxgrid; nxgrid = create_xgrid_2dx2d_order1(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in, i_in, j_in, i_out, j_out, xgrid_area); return nxgrid; } #endif int create_xgrid_2dx2d_order1(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area) { #define MAX_V 8 int nx1, nx2, ny1, ny2, nx1p, nx2p, nxgrid; double *area_in, *area_out; int nblocks =1; int *istart2=NULL, *iend2=NULL; int npts_left, nblks_left, pos, m, npts_my, ij; double *lon_out_min_list,*lon_out_max_list,*lon_out_avg,*lat_out_min_list,*lat_out_max_list; double *lon_out_list, *lat_out_list; int *pnxgrid=NULL, *pstart; int *pi_in=NULL, *pj_in=NULL, *pi_out=NULL, *pj_out=NULL; double *pxgrid_area=NULL; int *n2_list; int nthreads, nxgrid_block_max; nx1 = *nlon_in; ny1 = *nlat_in; nx2 = *nlon_out; ny2 = *nlat_out; nx1p = nx1 + 1; nx2p = nx2 + 1; area_in = (double *)malloc(nx1*ny1*sizeof(double)); area_out = (double *)malloc(nx2*ny2*sizeof(double)); get_grid_area(nlon_in, nlat_in, lon_in, lat_in, area_in); get_grid_area(nlon_out, nlat_out, lon_out, lat_out, area_out); nthreads = 1; #if defined(_OPENMP) #pragma omp parallel nthreads = omp_get_num_threads(); #endif nblocks = nthreads; istart2 = (int *)malloc(nblocks*sizeof(int)); iend2 = (int *)malloc(nblocks*sizeof(int)); pstart = (int *)malloc(nblocks*sizeof(int)); pnxgrid = (int *)malloc(nblocks*sizeof(int)); nxgrid_block_max = MAXXGRID/nblocks; for(m=0; m MAX_V) error_handler("create_xgrid.c: n2_in is greater than MAX_V"); lon_out_min_list[n] = minval_double(n2_in, x2_in); lon_out_max_list[n] = maxval_double(n2_in, x2_in); lon_out_avg[n] = avgval_double(n2_in, x2_in); n2_list[n] = n2_in; for(l=0; l MASK_THRESH ) { int n0, n1, n2, n3, l,n1_in; double lat_in_min,lat_in_max,lon_in_min,lon_in_max,lon_in_avg; double x1_in[MV], y1_in[MV], x_out[MV], y_out[MV]; n0 = j1*nx1p+i1; n1 = j1*nx1p+i1+1; n2 = (j1+1)*nx1p+i1+1; n3 = (j1+1)*nx1p+i1; x1_in[0] = lon_in[n0]; y1_in[0] = lat_in[n0]; x1_in[1] = lon_in[n1]; y1_in[1] = lat_in[n1]; x1_in[2] = lon_in[n2]; y1_in[2] = lat_in[n2]; x1_in[3] = lon_in[n3]; y1_in[3] = lat_in[n3]; lat_in_min = minval_double(4, y1_in); lat_in_max = maxval_double(4, y1_in); n1_in = fix_lon(x1_in, y1_in, 4, M_PI); lon_in_min = minval_double(n1_in, x1_in); lon_in_max = maxval_double(n1_in, x1_in); lon_in_avg = avgval_double(n1_in, x1_in); for(ij=istart2[m]; ij<=iend2[m]; ij++) { int n_in, n_out, i2, j2, n2_in; double xarea, dx, lon_out_min, lon_out_max; double x2_in[MAX_V], y2_in[MAX_V]; i2 = ij%nx2; j2 = ij/nx2; if(lat_out_min_list[ij] >= lat_in_max || lat_out_max_list[ij] <= lat_in_min ) continue; /* adjust x2_in according to lon_in_avg*/ n2_in = n2_list[ij]; for(l=0; l M_PI) { lon_out_min -= TPI; lon_out_max -= TPI; for (l=0; l= lon_in_max || lon_out_max <= lon_in_min ) continue; if ( (n_out = clip_2dx2d( x1_in, y1_in, n1_in, x2_in, y2_in, n2_in, x_out, y_out )) > 0) { double min_area; int nn; xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1]; min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]); if( xarea/min_area > AREA_RATIO_THRESH ) { pnxgrid[m]++; if(pnxgrid[m]>= MAXXGRID/nthreads) error_handler("nxgrid is greater than MAXXGRID/nthreads, increase MAXXGRID, decrease nthreads, or increase number of MPI ranks"); nn = pstart[m] + pnxgrid[m]-1; pxgrid_area[nn] = xarea; pi_in[nn] = i1; pj_in[nn] = j1; pi_out[nn] = i2; pj_out[nn] = j2; } } } } } /*copy data if nblocks > 1 */ if(nblocks == 1) { nxgrid = pnxgrid[0]; pi_in = NULL; pj_in = NULL; pi_out = NULL; pj_out = NULL; pxgrid_area = NULL; } else { int nn, i; nxgrid = 0; for(m=0; m MAX_V) error_handler("create_xgrid.c: n2_in is greater than MAX_V"); lon_out_min_list[n] = minval_double(n2_in, x2_in); lon_out_max_list[n] = maxval_double(n2_in, x2_in); lon_out_avg[n] = avgval_double(n2_in, x2_in); n2_list[n] = n2_in; for(l=0; l MASK_THRESH ) { int n0, n1, n2, n3, l,n1_in; double lat_in_min,lat_in_max,lon_in_min,lon_in_max,lon_in_avg; double x1_in[MV], y1_in[MV], x_out[MV], y_out[MV]; n0 = j1*nx1p+i1; n1 = j1*nx1p+i1+1; n2 = (j1+1)*nx1p+i1+1; n3 = (j1+1)*nx1p+i1; x1_in[0] = lon_in[n0]; y1_in[0] = lat_in[n0]; x1_in[1] = lon_in[n1]; y1_in[1] = lat_in[n1]; x1_in[2] = lon_in[n2]; y1_in[2] = lat_in[n2]; x1_in[3] = lon_in[n3]; y1_in[3] = lat_in[n3]; lat_in_min = minval_double(4, y1_in); lat_in_max = maxval_double(4, y1_in); n1_in = fix_lon(x1_in, y1_in, 4, M_PI); lon_in_min = minval_double(n1_in, x1_in); lon_in_max = maxval_double(n1_in, x1_in); lon_in_avg = avgval_double(n1_in, x1_in); for(ij=istart2[m]; ij<=iend2[m]; ij++) { int n_in, n_out, i2, j2, n2_in; double xarea, dx, lon_out_min, lon_out_max; double x2_in[MAX_V], y2_in[MAX_V]; i2 = ij%nx2; j2 = ij/nx2; if(lat_out_min_list[ij] >= lat_in_max || lat_out_max_list[ij] <= lat_in_min ) continue; /* adjust x2_in according to lon_in_avg*/ n2_in = n2_list[ij]; for(l=0; l M_PI) { lon_out_min -= TPI; lon_out_max -= TPI; for (l=0; l= lon_in_max || lon_out_max <= lon_in_min ) continue; if ( (n_out = clip_2dx2d( x1_in, y1_in, n1_in, x2_in, y2_in, n2_in, x_out, y_out )) > 0) { double min_area; int nn; xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1]; min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]); if( xarea/min_area > AREA_RATIO_THRESH ) { pnxgrid[m]++; if(pnxgrid[m]>= MAXXGRID/nthreads) error_handler("nxgrid is greater than MAXXGRID/nthreads, increase MAXXGRID, decrease nthreads, or increase number of MPI ranks"); nn = pstart[m] + pnxgrid[m]-1; pxgrid_area[nn] = xarea; pxgrid_clon[nn] = poly_ctrlon(x_out, y_out, n_out, lon_in_avg); pxgrid_clat[nn] = poly_ctrlat (x_out, y_out, n_out ); pi_in[nn] = i1; pj_in[nn] = j1; pi_out[nn] = i2; pj_out[nn] = j2; } } } } } /*copy data if nblocks > 1 */ if(nblocks == 1) { nxgrid = pnxgrid[0]; pi_in = NULL; pj_in = NULL; pi_out = NULL; pj_out = NULL; pxgrid_area = NULL; pxgrid_clon = NULL; pxgrid_clat = NULL; } else { int nn, i; nxgrid = 0; for(m=0; m= ll_lon); for (i_in=0,i_out=0;i_in= ll_lon))!=inside_last) { x_tmp[i_out] = ll_lon; y_tmp[i_out++] = y_last + (ll_lon - x_last) * (lat_in[i_in] - y_last) / (lon_in[i_in] - x_last); } /* if "to" point is right of LEFT boundary, output it */ if (inside) { x_tmp[i_out] = lon_in[i_in]; y_tmp[i_out++] = lat_in[i_in]; } x_last = lon_in[i_in]; y_last = lat_in[i_in]; inside_last = inside; } if (!(n_out=i_out)) return(0); /* clip polygon with RIGHT boundary - clip V_TMP to V_OUT */ x_last = x_tmp[n_out-1]; y_last = y_tmp[n_out-1]; inside_last = (x_last <= ur_lon); for (i_in=0,i_out=0;i_in= ll_lat); for (i_in=0,i_out=0;i_in= ll_lat))!=inside_last) { y_tmp[i_out] = ll_lat; x_tmp[i_out++] = x_last + (ll_lat - y_last) * (lon_out[i_in] - x_last) / (lat_out[i_in] - y_last); } /* if "to" point is above BOTTOM boundary, output it */ if (inside) { x_tmp[i_out] = lon_out[i_in]; y_tmp[i_out++] = lat_out[i_in]; } x_last = lon_out[i_in]; y_last = lat_out[i_in]; inside_last = inside; } if (!(n_out=i_out)) return(0); /* clip polygon with TOP boundary - clip V_TMP to V_OUT */ x_last = x_tmp[n_out-1]; y_last = y_tmp[n_out-1]; inside_last = (y_last <= ur_lat); for (i_in=0,i_out=0;i_in and should not parallel to the line between and may need to consider truncation error */ dy1 = y1_1-y1_0; dy2 = y2_1-y2_0; dx1 = x1_1-x1_0; dx2 = x2_1-x2_0; ds1 = y1_0*x1_1 - y1_1*x1_0; ds2 = y2_0*x2_1 - y2_1*x2_0; determ = dy2*dx1 - dy1*dx2; if(fabs(determ) < EPSLN30) { error_handler("the line between and should not parallel to " "the line between and "); } lon_out[i_out] = (dx2*ds1 - dx1*ds2)/determ; lat_out[i_out++] = (dy2*ds1 - dy1*ds2)/determ; } if(inside) { lon_out[i_out] = x1_1; lat_out[i_out++] = y1_1; } x1_0 = x1_1; y1_0 = y1_1; inside_last = inside; } if(!(n_out=i_out)) return 0; for(i1=0; i1 MASK_THRESH ) { /* clockwise */ n0 = j1*nx1p+i1; n1 = (j1+1)*nx1p+i1; n2 = (j1+1)*nx1p+i1+1; n3 = j1*nx1p+i1+1; x1_in[0] = x1[n0]; y1_in[0] = y1[n0]; z1_in[0] = z1[n0]; x1_in[1] = x1[n1]; y1_in[1] = y1[n1]; z1_in[1] = z1[n1]; x1_in[2] = x1[n2]; y1_in[2] = y1[n2]; z1_in[2] = z1[n2]; x1_in[3] = x1[n3]; y1_in[3] = y1[n3]; z1_in[3] = z1[n3]; for(j2=0; j2 0) { xarea = great_circle_area ( n_out, x_out, y_out, z_out ) * mask_in[j1*nx1+i1]; min_area = min(area1[j1*nx1+i1], area2[j2*nx2+i2]); if( xarea/min_area > AREA_RATIO_THRESH ) { #ifdef debug_test_create_xgrid printf("(i2,j2)=(%d,%d), (i1,j1)=(%d,%d), xarea=%g\n", i2, j2, i1, j1, xarea); #endif xgrid_area[nxgrid] = xarea; xgrid_clon[nxgrid] = 0; /*z1l: will be developed very soon */ xgrid_clat[nxgrid] = 0; i_in[nxgrid] = i1; j_in[nxgrid] = j1; i_out[nxgrid] = i2; j_out[nxgrid] = j2; ++nxgrid; if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID"); } } } } free(area1); free(area2); free(x1); free(y1); free(z1); free(x2); free(y2); free(z2); return nxgrid; }/* create_xgrid_great_circle */ #ifndef __AIX int create_xgrid_great_circle_ug_(const int *nlon_in, const int *nlat_in, const int *npts_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *l_out, double *xgrid_area, double *xgrid_clon, double *xgrid_clat) { int nxgrid; nxgrid = create_xgrid_great_circle_ug(nlon_in, nlat_in, npts_out, lon_in, lat_in, lon_out, lat_out, mask_in, i_in, j_in, l_out, xgrid_area, xgrid_clon, xgrid_clat); return nxgrid; } #endif int create_xgrid_great_circle_ug(const int *nlon_in, const int *nlat_in, const int *npts_out, const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out, const double *mask_in, int *i_in, int *j_in, int *l_out, double *xgrid_area, double *xgrid_clon, double *xgrid_clat) { int nx1, ny1, npts2, nx1p, ny1p, nxgrid, n1_in, n2_in, nv; int n0, n1, n2, n3, i1, j1, l2; double x1_in[MV], y1_in[MV], z1_in[MV]; double x2_in[MV], y2_in[MV], z2_in[MV]; double x_out[MV], y_out[MV], z_out[MV]; double *x1=NULL, *y1=NULL, *z1=NULL; double *x2=NULL, *y2=NULL, *z2=NULL; double xctrlon, xctrlat; double *area1, *area2, min_area; nx1 = *nlon_in; ny1 = *nlat_in; nv = 4; npts2 = *npts_out; nxgrid = 0; nx1p = nx1 + 1; ny1p = ny1 + 1; /* first convert lon-lat to cartesian coordinates */ x1 = (double *)malloc(nx1p*ny1p*sizeof(double)); y1 = (double *)malloc(nx1p*ny1p*sizeof(double)); z1 = (double *)malloc(nx1p*ny1p*sizeof(double)); x2 = (double *)malloc(npts2*nv*sizeof(double)); y2 = (double *)malloc(npts2*nv*sizeof(double)); z2 = (double *)malloc(npts2*nv*sizeof(double)); latlon2xyz(nx1p*ny1p, lon_in, lat_in, x1, y1, z1); latlon2xyz(npts2*nv, lon_out, lat_out, x2, y2, z2); area1 = (double *)malloc(nx1*ny1*sizeof(double)); area2 = (double *)malloc(npts2*sizeof(double)); get_grid_great_circle_area(nlon_in, nlat_in, lon_in, lat_in, area1); get_grid_great_circle_area_ug(npts_out, lon_out, lat_out, area2); n1_in = 4; n2_in = 4; for(j1=0; j1 MASK_THRESH ) { /* clockwise */ n0 = j1*nx1p+i1; n1 = (j1+1)*nx1p+i1; n2 = (j1+1)*nx1p+i1+1; n3 = j1*nx1p+i1+1; x1_in[0] = x1[n0]; y1_in[0] = y1[n0]; z1_in[0] = z1[n0]; x1_in[1] = x1[n1]; y1_in[1] = y1[n1]; z1_in[1] = z1[n1]; x1_in[2] = x1[n2]; y1_in[2] = y1[n2]; z1_in[2] = z1[n2]; x1_in[3] = x1[n3]; y1_in[3] = y1[n3]; z1_in[3] = z1[n3]; for(l2=0; l2 0) { xarea = great_circle_area ( n_out, x_out, y_out, z_out ) * mask_in[j1*nx1+i1]; min_area = min(area1[j1*nx1+i1], area2[l2]); if( xarea/min_area > AREA_RATIO_THRESH ) { #ifdef debug_test_create_xgrid printf("(l2)=(%d,%d), (i1,j1)=(%d,%d), xarea=%g\n", l2, i1, j1, xarea); #endif xgrid_area[nxgrid] = xarea; xgrid_clon[nxgrid] = 0; /*z1l: will be developed very soon */ xgrid_clat[nxgrid] = 0; i_in[nxgrid] = i1; j_in[nxgrid] = j1; l_out[nxgrid] = l2; ++nxgrid; if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID"); } } } } free(area1); free(area2); free(x1); free(y1); free(z1); free(x2); free(y2); free(z2); return nxgrid; }/* create_xgrid_great_circle_ug */ /******************************************************************************* Revise Sutherland-Hodgeman algorithm to find the vertices of the overlapping between any two grid boxes. It return the number of vertices for the exchange grid. Each edge of grid box is a part of great circle. All the points are cartesian coordinates. Here we are assuming each polygon is convex. RANGE_CHECK_CRITERIA is used to determine if the two grid boxes are possible to be overlap. The size should be between 0 and 0.5. The larger the range_check_criteria, the more expensive of the computatioin. When the value is close to 0, some small exchange grid might be lost. Suggest to use value 0.05 for C48. *******************************************************************************/ int clip_2dx2d_great_circle(const double x1_in[], const double y1_in[], const double z1_in[], int n1_in, const double x2_in[], const double y2_in[], const double z2_in [], int n2_in, double x_out[], double y_out[], double z_out[]) { struct Node *subjList=NULL; struct Node *clipList=NULL; struct Node *grid1List=NULL; struct Node *grid2List=NULL; struct Node *intersectList=NULL; struct Node *polyList=NULL; struct Node *curList=NULL; struct Node *firstIntersect=NULL, *curIntersect=NULL; struct Node *temp1=NULL, *temp2=NULL, *temp=NULL; int i1, i2, i1p, i2p, i2p2, npts1, npts2; int nintersect, n_out; int maxiter1, maxiter2, iter1, iter2; int found1, found2, curListNum; int has_inbound, inbound; double pt1[MV][3], pt2[MV][3]; double *p1_0=NULL, *p1_1=NULL; double *p2_0=NULL, *p2_1=NULL, *p2_2=NULL; double intersect[3]; double u1, u2; double min_x1, max_x1, min_y1, max_y1, min_z1, max_z1; double min_x2, max_x2, min_y2, max_y2, min_z2, max_z2; static int first_call=1; /* first check the min and max of (x1_in, y1_in, z1_in) with (x2_in, y2_in, z2_in) */ min_x1 = minval_double(n1_in, x1_in); max_x2 = maxval_double(n2_in, x2_in); if(min_x1 >= max_x2+RANGE_CHECK_CRITERIA) return 0; max_x1 = maxval_double(n1_in, x1_in); min_x2 = minval_double(n2_in, x2_in); if(min_x2 >= max_x1+RANGE_CHECK_CRITERIA) return 0; min_y1 = minval_double(n1_in, y1_in); max_y2 = maxval_double(n2_in, y2_in); if(min_y1 >= max_y2+RANGE_CHECK_CRITERIA) return 0; max_y1 = maxval_double(n1_in, y1_in); min_y2 = minval_double(n2_in, y2_in); if(min_y2 >= max_y1+RANGE_CHECK_CRITERIA) return 0; min_z1 = minval_double(n1_in, z1_in); max_z2 = maxval_double(n2_in, z2_in); if(min_z1 >= max_z2+RANGE_CHECK_CRITERIA) return 0; max_z1 = maxval_double(n1_in, z1_in); min_z2 = minval_double(n2_in, z2_in); if(min_z2 >= max_z1+RANGE_CHECK_CRITERIA) return 0; rewindList(); grid1List = getNext(); grid2List = getNext(); intersectList = getNext(); polyList = getNext(); /* insert points into SubjList and ClipList */ for(i1=0; i1isInside = 1; else temp->isInside = 0; temp = getNextNode(temp); } #ifdef debug_test_create_xgrid printf("\nNOTE from clip_2dx2d_great_circle: begin to set inside value of grid2List\n"); #endif /* check if grid2List is inside grid1List */ temp = grid2List; while(temp) { if(insidePolygon(temp, grid1List)) temp->isInside = 1; else temp->isInside = 0; temp = getNextNode(temp); } /* make sure the grid box is clockwise */ /*make sure each polygon is convex, which is equivalent that the great_circle_area is positive */ if( gridArea(grid1List) <= 0 ) error_handler("create_xgrid.c(clip_2dx2d_great_circle): grid box 1 is not convex"); if( gridArea(grid2List) <= 0 ) error_handler("create_xgrid.c(clip_2dx2d_great_circle): grid box 2 is not convex"); #ifdef debug_test_create_xgrid printNode(grid1List, "grid1List"); printNode(grid2List, "grid2List"); #endif /* get the coordinates from grid1List and grid2List. Please not npts1 might not equal n1_in, npts2 might not equal n2_in because of pole */ temp = grid1List; for(i1=0; i1Next; } temp = grid2List; for(i2=0; i2Next; } firstIntersect=getNext(); curIntersect = getNext(); #ifdef debug_test_create_xgrid printf("\n\n************************ Start line_intersect_2D_3D ******************************\n"); #endif /* first find all the intersection points */ nintersect = 0; for(i1=0; i1 1) { getFirstInbound(intersectList, firstIntersect); if(firstIntersect->initialized) { has_inbound = 1; } } /* when has_inbound == 0, get the grid1List and grid2List */ if( !has_inbound && nintersect > 1) { setInbound(intersectList, grid1List); getFirstInbound(intersectList, firstIntersect); if(firstIntersect->initialized) has_inbound = 1; } /* if has_inbound = 1, find the overlapping */ n_out = 0; if(has_inbound) { maxiter1 = nintersect; #ifdef debug_test_create_xgrid printf("\nNOTE from clip_2dx2d_great_circle: number of intersect is %d\n", nintersect); printf("\n size of grid2List is %d, size of grid1List is %d\n", length(grid2List), length(grid1List)); printNode(intersectList, "beginning intersection list"); printNode(grid2List, "beginning clip list"); printNode(grid1List, "beginning subj list"); printf("\n************************ End line_intersect_2D_3D **********************************\n\n"); #endif temp1 = getNode(grid1List, *firstIntersect); if( temp1 == NULL) { double lon[10], lat[10]; int i; xyz2latlon(n1_in, x1_in, y1_in, z1_in, lon, lat); for(i=0; i< n1_in; i++) printf("lon1 = %g, lat1 = %g\n", lon[i]*R2D, lat[i]*R2D); printf("\n"); xyz2latlon(n2_in, x2_in, y2_in, z2_in, lon, lat); for(i=0; i< n2_in; i++) printf("lon2 = %g, lat2 = %g\n", lon[i]*R2D, lat[i]*R2D); printf("\n"); error_handler("firstIntersect is not in the grid1List"); } addNode(polyList, *firstIntersect); nintersect--; #ifdef debug_test_create_xgrid printNode(polyList, "polyList at stage 1"); #endif /* Loop over the grid1List and grid2List to find again the firstIntersect */ curList = grid1List; curListNum = 0; /* Loop through curList to find the next intersection, the loop will end when come back to firstIntersect */ copyNode(curIntersect, *firstIntersect); iter1 = 0; found1 = 0; while( iter1 < maxiter1 ) { #ifdef debug_test_create_xgrid printf("\n----------- At iteration = %d\n\n", iter1+1 ); printNode(curIntersect, "curIntersect at the begining of iter1"); #endif /* find the curIntersect in curList and get the next intersection points */ temp1 = getNode(curList, *curIntersect); temp2 = temp1->Next; if( temp2 == NULL ) temp2 = curList; maxiter2 = length(curList); found2 = 0; iter2 = 0; /* Loop until find the next intersection */ while( iter2 < maxiter2 ) { int temp2IsIntersect; temp2IsIntersect = 0; if( isIntersect( *temp2 ) ) { /* copy the point and switch to the grid2List */ struct Node *temp3; /* first check if temp2 is the firstIntersect */ if( sameNode( *temp2, *firstIntersect) ) { found1 = 1; break; } temp3 = temp2->Next; if( temp3 == NULL) temp3 = curList; if( temp3 == NULL) error_handler("creat_xgrid.c: temp3 can not be NULL"); found2 = 1; /* if next node is inside or an intersection, need to keep on curList */ temp2IsIntersect = 1; if( isIntersect(*temp3) || (temp3->isInside == 1) ) found2 = 0; } if(found2) { copyNode(curIntersect, *temp2); break; } else { addNode(polyList, *temp2); #ifdef debug_test_create_xgrid printNode(polyList, "polyList at stage 2"); #endif if(temp2IsIntersect) { nintersect--; } } temp2 = temp2->Next; if( temp2 == NULL ) temp2 = curList; iter2 ++; } if(found1) break; if( !found2 ) error_handler(" not found the next intersection "); /* if find the first intersection, the poly found */ if( sameNode( *curIntersect, *firstIntersect) ) { found1 = 1; break; } /* add curIntersect to polyList and remove it from intersectList and curList */ addNode(polyList, *curIntersect); #ifdef debug_test_create_xgrid printNode(polyList, "polyList at stage 3"); #endif nintersect--; /* switch curList */ if( curListNum == 0) { curList = grid2List; curListNum = 1; } else { curList = grid1List; curListNum = 0; } iter1++; } if(!found1) error_handler("not return back to the first intersection"); /* currently we are only clipping convex polygon to convex polygon */ if( nintersect > 0) error_handler("After clipping, nintersect should be 0"); /* copy the polygon to x_out, y_out, z_out */ temp1 = polyList; while (temp1 != NULL) { getCoordinate(*temp1, x_out+n_out, y_out+n_out, z_out+n_out); temp1 = temp1->Next; n_out++; } /* if(n_out < 3) error_handler(" The clipped region has < 3 vertices"); */ if( n_out < 3) n_out = 0; #ifdef debug_test_create_xgrid printNode(polyList, "polyList after clipping"); #endif } /* check if grid1 is inside grid2 */ if(n_out==0){ /* first check number of points in grid1 is inside grid2 */ int n, n1in2; /* One possible is that grid1List is inside grid2List */ #ifdef debug_test_create_xgrid printf("\nNOTE from clip_2dx2d_great_circle: check if grid1 is inside grid2\n"); #endif n1in2 = 0; temp = grid1List; while(temp) { if(temp->intersect != 1) { #ifdef debug_test_create_xgrid printf("grid1->isInside = %d\n", temp->isInside); #endif if( temp->isInside == 1) n1in2++; } temp = getNextNode(temp); } if(npts1==n1in2) { /* grid1 is inside grid2 */ n_out = npts1; n = 0; temp = grid1List; while( temp ) { getCoordinate(*temp, &x_out[n], &y_out[n], &z_out[n]); n++; temp = getNextNode(temp); } } if(n_out>0) return n_out; } /* check if grid2List is inside grid1List */ if(n_out ==0){ int n, n2in1; #ifdef debug_test_create_xgrid printf("\nNOTE from clip_2dx2d_great_circle: check if grid2 is inside grid1\n"); #endif temp = grid2List; n2in1 = 0; while(temp) { if(temp->intersect != 1) { #ifdef debug_test_create_xgrid printf("grid2->isInside = %d\n", temp->isInside); #endif if( temp->isInside == 1) n2in1++; } temp = getNextNode(temp); } if(npts2==n2in1) { /* grid2 is inside grid1 */ n_out = npts2; n = 0; temp = grid2List; while( temp ) { getCoordinate(*temp, &x_out[n], &y_out[n], &z_out[n]); n++; temp = getNextNode(temp); } } } return n_out; } /* Intersects between the line a and the seqment s where both line and segment are great circle lines on the sphere represented by 3D cartesian points. [sin sout] are the ends of a line segment returns true if the lines could be intersected, false otherwise. inbound means the direction of (a1,a2) go inside or outside of (q1,q2,q3) */ int line_intersect_2D_3D(double *a1, double *a2, double *q1, double *q2, double *q3, double *intersect, double *u_a, double *u_q, int *inbound){ /* Do this intersection by reprsenting the line a1 to a2 as a plane through the two line points and the origin of the sphere (0,0,0). This is the definition of a great circle arc. */ double plane[9]; double plane_p[2]; double u; double p1[3], v1[3], v2[3]; double c1[3], c2[3], c3[3]; double coincident, sense, norm; int i; int is_inter1, is_inter2; *inbound = 0; /* first check if any vertices are the same */ if(samePoint(a1[0], a1[1], a1[2], q1[0], q1[1], q1[2])) { *u_a = 0; *u_q = 0; intersect[0] = a1[0]; intersect[1] = a1[1]; intersect[2] = a1[2]; #ifdef debug_test_create_xgrid printf("\nNOTE from line_intersect_2D_3D: u_a = %19.15f, u_q=%19.15f, inbound=%d\n", *u_a, *u_q, *inbound); #endif return 1; } else if (samePoint(a1[0], a1[1], a1[2], q2[0], q2[1], q2[2])) { *u_a = 0; *u_q = 1; intersect[0] = a1[0]; intersect[1] = a1[1]; intersect[2] = a1[2]; #ifdef debug_test_create_xgrid printf("\nNOTE from line_intersect_2D_3D: u_a = %19.15f, u_q=%19.15f, inbound=%d\n", *u_a, *u_q, *inbound); #endif return 1; } else if(samePoint(a2[0], a2[1], a2[2], q1[0], q1[1], q1[2])) { #ifdef debug_test_create_xgrid printf("\nNOTE from line_intersect_2D_3D: u_a = %19.15f, u_q=%19.15f, inbound=%d\n", *u_a, *u_q, *inbound); #endif *u_a = 1; *u_q = 0; intersect[0] = a2[0]; intersect[1] = a2[1]; intersect[2] = a2[2]; return 1; } else if (samePoint(a2[0], a2[1], a2[2], q2[0], q2[1], q2[2])) { #ifdef debug_test_create_xgrid printf("\nNOTE from line_intersect_2D_3D: u_a = %19.15f, u_q=%19.15f, inbound=%d\n", *u_a, *u_q, *inbound); #endif *u_a = 1; *u_q = 1; intersect[0] = a2[0]; intersect[1] = a2[1]; intersect[2] = a2[2]; return 1; } /* Load points defining plane into variable (these are supposed to be in counterclockwise order) */ plane[0]=q1[0]; plane[1]=q1[1]; plane[2]=q1[2]; plane[3]=q2[0]; plane[4]=q2[1]; plane[5]=q2[2]; plane[6]=0.0; plane[7]=0.0; plane[8]=0.0; /* Intersect the segment with the plane */ is_inter1 = intersect_tri_with_line(plane, a1, a2, plane_p, u_a); if(!is_inter1) return 0; if(fabs(*u_a) < EPSLN8) *u_a = 0; if(fabs(*u_a-1) < EPSLN8) *u_a = 1; #ifdef debug_test_create_xgrid printf("\nNOTE from line_intersect_2D_3D: u_a = %19.15f\n", *u_a); #endif if( (*u_a < 0) || (*u_a > 1) ) return 0; /* Load points defining plane into variable (these are supposed to be in counterclockwise order) */ plane[0]=a1[0]; plane[1]=a1[1]; plane[2]=a1[2]; plane[3]=a2[0]; plane[4]=a2[1]; plane[5]=a2[2]; plane[6]=0.0; plane[7]=0.0; plane[8]=0.0; /* Intersect the segment with the plane */ is_inter2 = intersect_tri_with_line(plane, q1, q2, plane_p, u_q); if(!is_inter2) return 0; if(fabs(*u_q) < EPSLN8) *u_q = 0; if(fabs(*u_q-1) < EPSLN8) *u_q = 1; #ifdef debug_test_create_xgrid printf("\nNOTE from line_intersect_2D_3D: u_q = %19.15f\n", *u_q); #endif if( (*u_q < 0) || (*u_q > 1) ) return 0; u =*u_a; /* The two planes are coincidental */ vect_cross(a1, a2, c1); vect_cross(q1, q2, c2); vect_cross(c1, c2, c3); coincident = metric(c3); if(fabs(coincident) < EPSLN30) return 0; /* Calculate point of intersection */ intersect[0]=a1[0] + u*(a2[0]-a1[0]); intersect[1]=a1[1] + u*(a2[1]-a1[1]); intersect[2]=a1[2] + u*(a2[2]-a1[2]); norm = metric( intersect ); for(i = 0; i < 3; i ++) intersect[i] /= norm; /* when u_q =0 or u_q =1, the following could not decide the inbound value */ if(*u_q != 0 && *u_q != 1){ p1[0] = a2[0]-a1[0]; p1[1] = a2[1]-a1[1]; p1[2] = a2[2]-a1[2]; v1[0] = q2[0]-q1[0]; v1[1] = q2[1]-q1[1]; v1[2] = q2[2]-q1[2]; v2[0] = q3[0]-q2[0]; v2[1] = q3[1]-q2[1]; v2[2] = q3[2]-q2[2]; vect_cross(v1, v2, c1); vect_cross(v1, p1, c2); sense = dot(c1, c2); *inbound = 1; if(sense > 0) *inbound = 2; /* v1 going into v2 in CCW sense */ } #ifdef debug_test_create_xgrid printf("\nNOTE from line_intersect_2D_3D: inbound=%d\n", *inbound); #endif return 1; } /*------------------------------------------------------------------------------ double poly_ctrlat(const double x[], const double y[], int n) This routine is used to calculate the latitude of the centroid ---------------------------------------------------------------------------*/ double poly_ctrlat(const double x[], const double y[], int n) { double ctrlat = 0.0; int i; for (i=0;i M_PI) dx = dx - 2.0*M_PI; if(dx < -M_PI) dx = dx + 2.0*M_PI; if ( fabs(hdy)< SMALL_VALUE ) /* cheap area calculation along latitude */ ctrlat -= dx*(2*cos(avg_y) + lat2*sin(avg_y) - cos(lat1) ); else ctrlat -= dx*( (sin(hdy)/hdy)*(2*cos(avg_y) + lat2*sin(avg_y)) - cos(lat1) ); } return (ctrlat*RADIUS*RADIUS); } /* poly_ctrlat */ /*------------------------------------------------------------------------------ double poly_ctrlon(const double x[], const double y[], int n, double clon) This routine is used to calculate the lontitude of the centroid. ---------------------------------------------------------------------------*/ double poly_ctrlon(const double x[], const double y[], int n, double clon) { double ctrlon = 0.0; int i; clon = clon; for (i=0;i M_PI) dphi = dphi - 2.0*M_PI; if(dphi < -M_PI) dphi = dphi + 2.0*M_PI; dphi1 = phi1 - clon; if( dphi1 > M_PI) dphi1 -= 2.0*M_PI; if( dphi1 <-M_PI) dphi1 += 2.0*M_PI; dphi2 = phi2 -clon; if( dphi2 > M_PI) dphi2 -= 2.0*M_PI; if( dphi2 <-M_PI) dphi2 += 2.0*M_PI; if(abs(dphi2 -dphi1) < M_PI) { ctrlon -= dphi * (dphi1*f1+dphi2*f2)/2.0; } else { if(dphi1 > 0.0) fac = M_PI; else fac = -M_PI; fint = f1 + (f2-f1)*(fac-dphi1)/abs(dphi); ctrlon -= 0.5*dphi1*(dphi1-fac)*f1 - 0.5*dphi2*(dphi2+fac)*f2 + 0.5*fac*(dphi1+dphi2)*fint; } } return (ctrlon*RADIUS*RADIUS); } /* poly_ctrlon */ /* ----------------------------------------------------------------------------- double box_ctrlat(double ll_lon, double ll_lat, double ur_lon, double ur_lat) This routine is used to calculate the latitude of the centroid. ---------------------------------------------------------------------------*/ double box_ctrlat(double ll_lon, double ll_lat, double ur_lon, double ur_lat) { double dphi = ur_lon-ll_lon; double ctrlat; if(dphi > M_PI) dphi = dphi - 2.0*M_PI; if(dphi < -M_PI) dphi = dphi + 2.0*M_PI; ctrlat = dphi*(cos(ur_lat) + ur_lat*sin(ur_lat)-(cos(ll_lat) + ll_lat*sin(ll_lat))); return (ctrlat*RADIUS*RADIUS); } /* box_ctrlat */ /*------------------------------------------------------------------------------ double box_ctrlon(double ll_lon, double ll_lat, double ur_lon, double ur_lat, double clon) This routine is used to calculate the lontitude of the centroid ----------------------------------------------------------------------------*/ double box_ctrlon(double ll_lon, double ll_lat, double ur_lon, double ur_lat, double clon) { double phi1, phi2, dphi, lat1, lat2, dphi1, dphi2; double f1, f2, fac, fint; double ctrlon = 0.0; int i; clon = clon; for( i =0; i<2; i++) { if(i == 0) { phi1 = ur_lon; phi2 = ll_lon; lat1 = lat2 = ll_lat; } else { phi1 = ll_lon; phi2 = ur_lon; lat1 = lat2 = ur_lat; } dphi = phi1 - phi2; f1 = 0.5*(cos(lat1)*sin(lat1)+lat1); f2 = 0.5*(cos(lat2)*sin(lat2)+lat2); if(dphi > M_PI) dphi = dphi - 2.0*M_PI; if(dphi < -M_PI) dphi = dphi + 2.0*M_PI; /* make sure the center is in the same grid box. */ dphi1 = phi1 - clon; if( dphi1 > M_PI) dphi1 -= 2.0*M_PI; if( dphi1 <-M_PI) dphi1 += 2.0*M_PI; dphi2 = phi2 -clon; if( dphi2 > M_PI) dphi2 -= 2.0*M_PI; if( dphi2 <-M_PI) dphi2 += 2.0*M_PI; if(fabs(dphi2 -dphi1) < M_PI) { ctrlon -= dphi * (dphi1*f1+dphi2*f2)/2.0; } else { if(dphi1 > 0.0) fac = M_PI; else fac = -M_PI; fint = f1 + (f2-f1)*(fac-dphi1)/fabs(dphi); ctrlon -= 0.5*dphi1*(dphi1-fac)*f1 - 0.5*dphi2*(dphi2+fac)*f2 + 0.5*fac*(dphi1+dphi2)*fint; } } return (ctrlon*RADIUS*RADIUS); } /* box_ctrlon */ /******************************************************************************* double grid_box_radius(double *x, double *y, double *z, int n); Find the radius of the grid box, the radius is defined the maximum distance between any two vertices *******************************************************************************/ double grid_box_radius(const double *x, const double *y, const double *z, int n) { double radius; int i, j; radius = 0; for(i=0; i is the outward edge normal from vertex to . is the vector from to . if Inner produce * > 0, outside, otherwise inside. inner product value = 0 also treate as inside. *******************************************************************************/ int inside_edge(double x0, double y0, double x1, double y1, double x, double y) { const double SMALL = 1.e-12; double product; product = ( x-x0 )*(y1-y0) + (x0-x1)*(y-y0); return (product<=SMALL) ? 1:0; } /* inside_edge */ /* The following is a test program to test subroutines in create_xgrid.c */ #ifdef test_create_xgrid #include "create_xgrid.h" #include #define D2R (M_PI/180) #define R2D (180/M_PI) #define MAXPOINT 1000 int main(int argc, char* argv[]) { double lon1_in[MAXPOINT], lat1_in[MAXPOINT]; double lon2_in[MAXPOINT], lat2_in[MAXPOINT]; double x1_in[MAXPOINT], y1_in[MAXPOINT], z1_in[MAXPOINT]; double x2_in[MAXPOINT], y2_in[MAXPOINT], z2_in[MAXPOINT]; double lon_out[20], lat_out[20]; double x_out[20], y_out[20], z_out[20]; int n1_in, n2_in, n_out, i, j; int nlon1=0, nlat1=0, nlon2=0, nlat2=0; int n; int ntest = 11; for(n=11; n<=ntest; n++) { switch (n) { case 1: /**************************************************************** test clip_2dx2d_great_cirle case 1: box 1: (20,10), (20,12), (22,12), (22,10) box 2: (21,11), (21,14), (24,14), (24,11) out : (21, 12.0018), (22, 12), (22, 11.0033), (21, 11) ****************************************************************/ n1_in = 4; n2_in = 4; /* first a simple lat-lon grid box to clip another lat-lon grid box */ lon1_in[0] = 20; lat1_in[0] = 10; lon1_in[1] = 20; lat1_in[1] = 12; lon1_in[2] = 22; lat1_in[2] = 12; lon1_in[3] = 22; lat1_in[3] = 10; lon2_in[0] = 21; lat2_in[0] = 11; lon2_in[1] = 21; lat2_in[1] = 14; lon2_in[2] = 24; lat2_in[2] = 14; lon2_in[3] = 24; lat2_in[3] = 11; break; case 2: /**************************************************************** test clip_2dx2d_great_cirle case 2: two identical box box 1: (20,10), (20,12), (22,12), (22,10) box 2: (20,10), (20,12), (22,12), (22,10) out : (20,10), (20,12), (22,12), (22,10) ****************************************************************/ lon1_in[0] = 20; lat1_in[0] = 10; lon1_in[1] = 20; lat1_in[1] = 12; lon1_in[2] = 22; lat1_in[2] = 12; lon1_in[3] = 22; lat1_in[3] = 10; for(i=0; i 10 ) { int nxgrid; int *i1, *j1, *i2, *j2; double *xarea, *xclon, *xclat, *mask1; mask1 = (double *)malloc(nlon1*nlat1*sizeof(double)); i1 = (int *)malloc(MAXXGRID*sizeof(int)); j1 = (int *)malloc(MAXXGRID*sizeof(int)); i2 = (int *)malloc(MAXXGRID*sizeof(int)); j2 = (int *)malloc(MAXXGRID*sizeof(int)); xarea = (double *)malloc(MAXXGRID*sizeof(double)); xclon = (double *)malloc(MAXXGRID*sizeof(double)); xclat = (double *)malloc(MAXXGRID*sizeof(double)); for(i=0; i