chore: remove outdated am4 ci workflow (#1639)
[FMS.git] / horiz_interp / include / horiz_interp_conserve_xgrid.c
blob9b7233ea132050835da10d4075f2cecb4a258bf1
1 /***********************************************************************
2 * GNU Lesser General Public License
4 * This file is part of the GFDL Flexible Modeling System (FMS).
6 * FMS is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or (at
9 * your option) any later version.
11 * FMS is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <math.h>
22 #include "grid_utils.h"
23 #include "tree_utils.h"
24 #include "horiz_interp_conserve_xgrid.h"
25 #include "constant.h"
27 #if defined(_OPENMP)
28 #include <omp.h>
29 #endif
31 /** \file
32 * \ingroup mosaic
33 * \brief Grid creation and calculation functions for use in @ref mosaic_mod
34 * /
36 /*******************************************************************************
37 void create_xgrid_1dx2d_order1
38 This routine generate exchange grids between two grids for the first order
39 conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell
40 and lon_in,lat_in are 1-D grid bounds, lon_out,lat_out are geographic grid location of grid cell bounds.
41 *******************************************************************************/
42 int create_xgrid_1dx2d_order1_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
43 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
44 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out, double *xgrid_area)
46 int nxgrid;
48 nxgrid = create_xgrid_1dx2d_order1(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in,
49 i_in, j_in, i_out, j_out, xgrid_area);
50 return nxgrid;
54 int create_xgrid_1dx2d_order1(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out, const double *lon_in,
55 const double *lat_in, const double *lon_out, const double *lat_out,
56 const double *mask_in, int *i_in, int *j_in, int *i_out,
57 int *j_out, double *xgrid_area)
60 int nx1, ny1, nx2, ny2, nx1p, nx2p;
61 int i1, j1, i2, j2, nxgrid;
62 double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV];
63 double *area_in, *area_out, min_area;
64 double *tmpx, *tmpy;
66 nx1 = *nlon_in;
67 ny1 = *nlat_in;
68 nx2 = *nlon_out;
69 ny2 = *nlat_out;
71 nxgrid = 0;
72 nx1p = nx1 + 1;
73 nx2p = nx2 + 1;
75 area_in = (double *)malloc(nx1*ny1*sizeof(double));
76 area_out = (double *)malloc(nx2*ny2*sizeof(double));
77 tmpx = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double));
78 tmpy = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double));
79 for(j1=0; j1<=ny1; j1++) for(i1=0; i1<=nx1; i1++) {
80 tmpx[j1*nx1p+i1] = lon_in[i1];
81 tmpy[j1*nx1p+i1] = lat_in[j1];
83 /* This is just a temporary fix to solve the issue that there is one point in zonal direction */
84 if(nx1 > 1)
85 get_grid_area(nlon_in, nlat_in, tmpx, tmpy, area_in);
86 else
87 get_grid_area_no_adjust(nlon_in, nlat_in, tmpx, tmpy, area_in);
89 get_grid_area(nlon_out, nlat_out, lon_out, lat_out, area_out);
90 free(tmpx);
91 free(tmpy);
93 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
95 ll_lon = lon_in[i1]; ll_lat = lat_in[j1];
96 ur_lon = lon_in[i1+1]; ur_lat = lat_in[j1+1];
97 for(j2=0; j2<ny2; j2++) for(i2=0; i2<nx2; i2++) {
98 int n_in, n_out;
99 double Xarea;
101 y_in[0] = lat_out[j2*nx2p+i2];
102 y_in[1] = lat_out[j2*nx2p+i2+1];
103 y_in[2] = lat_out[(j2+1)*nx2p+i2+1];
104 y_in[3] = lat_out[(j2+1)*nx2p+i2];
105 if ( (y_in[0]<=ll_lat) && (y_in[1]<=ll_lat)
106 && (y_in[2]<=ll_lat) && (y_in[3]<=ll_lat) ) continue;
107 if ( (y_in[0]>=ur_lat) && (y_in[1]>=ur_lat)
108 && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue;
110 x_in[0] = lon_out[j2*nx2p+i2];
111 x_in[1] = lon_out[j2*nx2p+i2+1];
112 x_in[2] = lon_out[(j2+1)*nx2p+i2+1];
113 x_in[3] = lon_out[(j2+1)*nx2p+i2];
114 n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2);
116 if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) {
117 Xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1];
118 min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]);
119 if( Xarea/min_area > AREA_RATIO_THRESH ) {
120 xgrid_area[nxgrid] = Xarea;
121 i_in[nxgrid] = i1;
122 j_in[nxgrid] = j1;
123 i_out[nxgrid] = i2;
124 j_out[nxgrid] = j2;
125 ++nxgrid;
126 if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID");
132 free(area_in);
133 free(area_out);
135 return nxgrid;
137 } /* create_xgrid_1dx2d_order1 */
140 /*******************************************************************************
141 void create_xgrid_1dx2d_order1_ug
142 This routine generate exchange grids between two grids for the first order
143 conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell
144 and lon_in,lat_in are 1-D grid bounds, lon_out,lat_out are geographic grid location of grid cell bounds.
145 *******************************************************************************/
146 int create_xgrid_1dx2d_order1_ug_(const int *nlon_in, const int *nlat_in, const int *npts_out,
147 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
148 const double *mask_in, int *i_in, int *j_in, int *l_out, double *xgrid_area)
150 int nxgrid;
152 nxgrid = create_xgrid_1dx2d_order1_ug(nlon_in, nlat_in, npts_out, lon_in, lat_in, lon_out, lat_out, mask_in,
153 i_in, j_in, l_out, xgrid_area);
154 return nxgrid;
158 int create_xgrid_1dx2d_order1_ug(const int *nlon_in, const int *nlat_in, const int *npts_out, const double *lon_in,
159 const double *lat_in, const double *lon_out, const double *lat_out,
160 const double *mask_in, int *i_in, int *j_in, int *l_out, double *xgrid_area)
163 int nx1, ny1, nx1p, nv, npts2;
164 int i1, j1, l2, nxgrid;
165 double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV];
166 double *area_in, *area_out, min_area;
167 double *tmpx, *tmpy;
169 nx1 = *nlon_in;
170 ny1 = *nlat_in;
171 nv = 4;
172 npts2 = *npts_out;
174 nxgrid = 0;
175 nx1p = nx1 + 1;
177 area_in = (double *)malloc(nx1*ny1*sizeof(double));
178 area_out = (double *)malloc(npts2*sizeof(double));
179 tmpx = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double));
180 tmpy = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double));
181 for(j1=0; j1<=ny1; j1++) for(i1=0; i1<=nx1; i1++) {
182 tmpx[j1*nx1p+i1] = lon_in[i1];
183 tmpy[j1*nx1p+i1] = lat_in[j1];
185 /* This is just a temporary fix to solve the issue that there is one point in zonal direction */
186 if(nx1 > 1)
187 get_grid_area(nlon_in, nlat_in, tmpx, tmpy, area_in);
188 else
189 get_grid_area_no_adjust(nlon_in, nlat_in, tmpx, tmpy, area_in);
191 get_grid_area_ug(npts_out, lon_out, lat_out, area_out);
192 free(tmpx);
193 free(tmpy);
195 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
197 ll_lon = lon_in[i1]; ll_lat = lat_in[j1];
198 ur_lon = lon_in[i1+1]; ur_lat = lat_in[j1+1];
199 for(l2=0; l2<npts2; l2++) {
200 int n_in, n_out;
201 double Xarea;
203 y_in[0] = lat_out[l2*nv];
204 y_in[1] = lat_out[l2*nv+1];
205 y_in[2] = lat_out[l2*nv+2];
206 y_in[3] = lat_out[l2*nv+3];
207 if ( (y_in[0]<=ll_lat) && (y_in[1]<=ll_lat)
208 && (y_in[2]<=ll_lat) && (y_in[3]<=ll_lat) ) continue;
209 if ( (y_in[0]>=ur_lat) && (y_in[1]>=ur_lat)
210 && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue;
212 x_in[0] = lon_out[l2*nv];
213 x_in[1] = lon_out[l2*nv+1];
214 x_in[2] = lon_out[l2*nv+2];
215 x_in[3] = lon_out[l2*nv+3];
216 n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2);
218 if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) {
219 Xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1];
220 min_area = min(area_in[j1*nx1+i1], area_out[l2]);
221 if( Xarea/min_area > AREA_RATIO_THRESH ) {
222 xgrid_area[nxgrid] = Xarea;
223 i_in[nxgrid] = i1;
224 j_in[nxgrid] = j1;
225 l_out[nxgrid] = l2;
226 ++nxgrid;
227 if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID");
233 free(area_in);
234 free(area_out);
236 return nxgrid;
238 } /* create_xgrid_1dx2d_order1_ug */
240 /********************************************************************************
241 void create_xgrid_1dx2d_order2
242 This routine generate exchange grids between two grids for the second order
243 conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell
244 and lon_in,lat_in are 1-D grid bounds, lon_out,lat_out are geographic grid location of grid cell bounds.
245 ********************************************************************************/
246 int create_xgrid_1dx2d_order2_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
247 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
248 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
249 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
251 int nxgrid;
252 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,
253 j_in, i_out, j_out, xgrid_area, xgrid_clon, xgrid_clat);
254 return nxgrid;
257 int create_xgrid_1dx2d_order2(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
258 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
259 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
260 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
263 int nx1, ny1, nx2, ny2, nx1p, nx2p;
264 int i1, j1, i2, j2, nxgrid;
265 double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV];
266 double *area_in, *area_out, min_area;
267 double *tmpx, *tmpy;
269 nx1 = *nlon_in;
270 ny1 = *nlat_in;
271 nx2 = *nlon_out;
272 ny2 = *nlat_out;
274 nxgrid = 0;
275 nx1p = nx1 + 1;
276 nx2p = nx2 + 1;
278 area_in = (double *)malloc(nx1*ny1*sizeof(double));
279 area_out = (double *)malloc(nx2*ny2*sizeof(double));
280 tmpx = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double));
281 tmpy = (double *)malloc((nx1+1)*(ny1+1)*sizeof(double));
282 for(j1=0; j1<=ny1; j1++) for(i1=0; i1<=nx1; i1++) {
283 tmpx[j1*nx1p+i1] = lon_in[i1];
284 tmpy[j1*nx1p+i1] = lat_in[j1];
286 get_grid_area(nlon_in, nlat_in, tmpx, tmpy, area_in);
287 get_grid_area(nlon_out, nlat_out, lon_out, lat_out, area_out);
288 free(tmpx);
289 free(tmpy);
291 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
293 ll_lon = lon_in[i1]; ll_lat = lat_in[j1];
294 ur_lon = lon_in[i1+1]; ur_lat = lat_in[j1+1];
295 for(j2=0; j2<ny2; j2++) for(i2=0; i2<nx2; i2++) {
296 int n_in, n_out;
297 double xarea, lon_in_avg;
299 y_in[0] = lat_out[j2*nx2p+i2];
300 y_in[1] = lat_out[j2*nx2p+i2+1];
301 y_in[2] = lat_out[(j2+1)*nx2p+i2+1];
302 y_in[3] = lat_out[(j2+1)*nx2p+i2];
303 if ( (y_in[0]<=ll_lat) && (y_in[1]<=ll_lat)
304 && (y_in[2]<=ll_lat) && (y_in[3]<=ll_lat) ) continue;
305 if ( (y_in[0]>=ur_lat) && (y_in[1]>=ur_lat)
306 && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue;
308 x_in[0] = lon_out[j2*nx2p+i2];
309 x_in[1] = lon_out[j2*nx2p+i2+1];
310 x_in[2] = lon_out[(j2+1)*nx2p+i2+1];
311 x_in[3] = lon_out[(j2+1)*nx2p+i2];
312 n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2);
313 lon_in_avg = avgval_double(n_in, x_in);
315 if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) {
316 xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1];
317 min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]);
318 if(xarea/min_area > AREA_RATIO_THRESH ) {
319 xgrid_area[nxgrid] = xarea;
320 xgrid_clon[nxgrid] = poly_ctrlon(x_out, y_out, n_out, lon_in_avg);
321 xgrid_clat[nxgrid] = poly_ctrlat (x_out, y_out, n_out );
322 i_in[nxgrid] = i1;
323 j_in[nxgrid] = j1;
324 i_out[nxgrid] = i2;
325 j_out[nxgrid] = j2;
326 ++nxgrid;
327 if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID");
332 free(area_in);
333 free(area_out);
335 return nxgrid;
337 } /* create_xgrid_1dx2d_order2 */
339 /*******************************************************************************
340 void create_xgrid_2dx1d_order1
341 This routine generate exchange grids between two grids for the first order
342 conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell
343 and lon_out,lat_out are 1-D grid bounds, lon_in,lat_in are geographic grid location of grid cell bounds.
344 mask is on grid lon_in/lat_in.
345 *******************************************************************************/
346 int create_xgrid_2dx1d_order1_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
347 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
348 const double *mask_in, int *i_in, int *j_in, int *i_out,
349 int *j_out, double *xgrid_area)
351 int nxgrid;
353 nxgrid = create_xgrid_2dx1d_order1(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in,
354 i_in, j_in, i_out, j_out, xgrid_area);
355 return nxgrid;
358 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,
359 const double *lat_in, const double *lon_out, const double *lat_out,
360 const double *mask_in, int *i_in, int *j_in, int *i_out,
361 int *j_out, double *xgrid_area)
364 int nx1, ny1, nx2, ny2, nx1p, nx2p;
365 int i1, j1, i2, j2, nxgrid;
366 double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV];
367 double *area_in, *area_out, min_area;
368 double *tmpx, *tmpy;
369 int n_in, n_out;
370 double Xarea;
373 nx1 = *nlon_in;
374 ny1 = *nlat_in;
375 nx2 = *nlon_out;
376 ny2 = *nlat_out;
378 nxgrid = 0;
379 nx1p = nx1 + 1;
380 nx2p = nx2 + 1;
381 area_in = (double *)malloc(nx1*ny1*sizeof(double));
382 area_out = (double *)malloc(nx2*ny2*sizeof(double));
383 tmpx = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double));
384 tmpy = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double));
385 for(j2=0; j2<=ny2; j2++) for(i2=0; i2<=nx2; i2++) {
386 tmpx[j2*nx2p+i2] = lon_out[i2];
387 tmpy[j2*nx2p+i2] = lat_out[j2];
389 get_grid_area(nlon_in, nlat_in, lon_in, lat_in, area_in);
390 get_grid_area(nlon_out, nlat_out, tmpx, tmpy, area_out);
392 free(tmpx);
393 free(tmpy);
395 for(j2=0; j2<ny2; j2++) for(i2=0; i2<nx2; i2++) {
397 ll_lon = lon_out[i2]; ll_lat = lat_out[j2];
398 ur_lon = lon_out[i2+1]; ur_lat = lat_out[j2+1];
399 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
401 y_in[0] = lat_in[j1*nx1p+i1];
402 y_in[1] = lat_in[j1*nx1p+i1+1];
403 y_in[2] = lat_in[(j1+1)*nx1p+i1+1];
404 y_in[3] = lat_in[(j1+1)*nx1p+i1];
405 if ( (y_in[0]<=ll_lat) && (y_in[1]<=ll_lat)
406 && (y_in[2]<=ll_lat) && (y_in[3]<=ll_lat) ) continue;
407 if ( (y_in[0]>=ur_lat) && (y_in[1]>=ur_lat)
408 && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue;
410 x_in[0] = lon_in[j1*nx1p+i1];
411 x_in[1] = lon_in[j1*nx1p+i1+1];
412 x_in[2] = lon_in[(j1+1)*nx1p+i1+1];
413 x_in[3] = lon_in[(j1+1)*nx1p+i1];
415 n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2);
417 if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) {
418 Xarea = poly_area ( x_out, y_out, n_out ) * mask_in[j1*nx1+i1];
419 min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]);
420 if( Xarea/min_area > AREA_RATIO_THRESH ) {
421 xgrid_area[nxgrid] = Xarea;
422 i_in[nxgrid] = i1;
423 j_in[nxgrid] = j1;
424 i_out[nxgrid] = i2;
425 j_out[nxgrid] = j2;
426 ++nxgrid;
427 if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID");
433 free(area_in);
434 free(area_out);
436 return nxgrid;
438 } /* create_xgrid_2dx1d_order1 */
441 /********************************************************************************
442 void create_xgrid_2dx1d_order2
443 This routine generate exchange grids between two grids for the second order
444 conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell
445 and lon_out,lat_out are 1-D grid bounds, lon_in,lat_in are geographic grid location of grid cell bounds.
446 mask is on grid lon_in/lat_in.
447 ********************************************************************************/
448 int create_xgrid_2dx1d_order2_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
449 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
450 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
451 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
453 int nxgrid;
454 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,
455 j_in, i_out, j_out, xgrid_area, xgrid_clon, xgrid_clat);
456 return nxgrid;
460 int create_xgrid_2dx1d_order2(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
461 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
462 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
463 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
466 int nx1, ny1, nx2, ny2, nx1p, nx2p;
467 int i1, j1, i2, j2, nxgrid;
468 double ll_lon, ll_lat, ur_lon, ur_lat, x_in[MV], y_in[MV], x_out[MV], y_out[MV];
469 double *tmpx, *tmpy;
470 double *area_in, *area_out, min_area;
471 double lon_in_avg;
472 int n_in, n_out;
473 double xarea;
476 nx1 = *nlon_in;
477 ny1 = *nlat_in;
478 nx2 = *nlon_out;
479 ny2 = *nlat_out;
481 nxgrid = 0;
482 nx1p = nx1 + 1;
483 nx2p = nx2 + 1;
485 area_in = (double *)malloc(nx1*ny1*sizeof(double));
486 area_out = (double *)malloc(nx2*ny2*sizeof(double));
487 tmpx = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double));
488 tmpy = (double *)malloc((nx2+1)*(ny2+1)*sizeof(double));
489 for(j2=0; j2<=ny2; j2++) for(i2=0; i2<=nx2; i2++) {
490 tmpx[j2*nx2p+i2] = lon_out[i2];
491 tmpy[j2*nx2p+i2] = lat_out[j2];
493 get_grid_area(nlon_in, nlat_in, lon_in, lat_in, area_in);
494 get_grid_area(nlon_out, nlat_out, tmpx, tmpy, area_out);
496 free(tmpx);
497 free(tmpy);
499 for(j2=0; j2<ny2; j2++) for(i2=0; i2<nx2; i2++) {
501 ll_lon = lon_out[i2]; ll_lat = lat_out[j2];
502 ur_lon = lon_out[i2+1]; ur_lat = lat_out[j2+1];
503 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
505 y_in[0] = lat_in[j1*nx1p+i1];
506 y_in[1] = lat_in[j1*nx1p+i1+1];
507 y_in[2] = lat_in[(j1+1)*nx1p+i1+1];
508 y_in[3] = lat_in[(j1+1)*nx1p+i1];
509 if ( (y_in[0]<=ll_lat) && (y_in[1]<=ll_lat)
510 && (y_in[2]<=ll_lat) && (y_in[3]<=ll_lat) ) continue;
511 if ( (y_in[0]>=ur_lat) && (y_in[1]>=ur_lat)
512 && (y_in[2]>=ur_lat) && (y_in[3]>=ur_lat) ) continue;
514 x_in[0] = lon_in[j1*nx1p+i1];
515 x_in[1] = lon_in[j1*nx1p+i1+1];
516 x_in[2] = lon_in[(j1+1)*nx1p+i1+1];
517 x_in[3] = lon_in[(j1+1)*nx1p+i1];
519 n_in = fix_lon(x_in, y_in, 4, (ll_lon+ur_lon)/2);
520 lon_in_avg = avgval_double(n_in, x_in);
522 if ( (n_out = clip ( x_in, y_in, n_in, ll_lon, ll_lat, ur_lon, ur_lat, x_out, y_out )) > 0 ) {
523 xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1];
524 min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]);
525 if(xarea/min_area > AREA_RATIO_THRESH ) {
526 xgrid_area[nxgrid] = xarea;
527 xgrid_clon[nxgrid] = poly_ctrlon(x_out, y_out, n_out, lon_in_avg);
528 xgrid_clat[nxgrid] = poly_ctrlat (x_out, y_out, n_out );
529 i_in[nxgrid] = i1;
530 j_in[nxgrid] = j1;
531 i_out[nxgrid] = i2;
532 j_out[nxgrid] = j2;
533 ++nxgrid;
534 if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID");
540 free(area_in);
541 free(area_out);
543 return nxgrid;
545 } /* create_xgrid_2dx1d_order2 */
547 /*******************************************************************************
548 void create_xgrid_2DX2D_order1
549 This routine generate exchange grids between two grids for the first order
550 conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell
551 and lon_in,lat_in, lon_out,lat_out are geographic grid location of grid cell bounds.
552 mask is on grid lon_in/lat_in.
553 *******************************************************************************/
554 int create_xgrid_2dx2d_order1_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
555 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
556 const double *mask_in, int *i_in, int *j_in, int *i_out,
557 int *j_out, double *xgrid_area)
559 int nxgrid;
561 nxgrid = create_xgrid_2dx2d_order1(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in,
562 i_in, j_in, i_out, j_out, xgrid_area);
563 return nxgrid;
566 int create_xgrid_2dx2d_order1(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
567 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
568 const double *mask_in, int *i_in, int *j_in, int *i_out,
569 int *j_out, double *xgrid_area)
572 int nx1, nx2, ny1, ny2, nx1p, nx2p, nxgrid;
573 double *area_in, *area_out;
574 int nblocks =1;
575 int *istart2=NULL, *iend2=NULL;
576 int npts_left, nblks_left, pos, m, npts_my, ij;
577 double *lon_out_min_list,*lon_out_max_list,*lon_out_avg,*lat_out_min_list,*lat_out_max_list;
578 double *lon_out_list, *lat_out_list;
579 int *pnxgrid=NULL, *pstart;
580 int *pi_in=NULL, *pj_in=NULL, *pi_out=NULL, *pj_out=NULL;
581 double *pxgrid_area=NULL;
582 int *n2_list;
583 int nthreads, nxgrid_block_max;
585 nx1 = *nlon_in;
586 ny1 = *nlat_in;
587 nx2 = *nlon_out;
588 ny2 = *nlat_out;
589 nx1p = nx1 + 1;
590 nx2p = nx2 + 1;
592 area_in = (double *)malloc(nx1*ny1*sizeof(double));
593 area_out = (double *)malloc(nx2*ny2*sizeof(double));
594 get_grid_area(nlon_in, nlat_in, lon_in, lat_in, area_in);
595 get_grid_area(nlon_out, nlat_out, lon_out, lat_out, area_out);
597 nthreads = 1;
598 #if defined(_OPENMP)
599 #pragma omp parallel
600 nthreads = omp_get_num_threads();
601 #endif
603 nblocks = nthreads;
605 istart2 = (int *)malloc(nblocks*sizeof(int));
606 iend2 = (int *)malloc(nblocks*sizeof(int));
608 pstart = (int *)malloc(nblocks*sizeof(int));
609 pnxgrid = (int *)malloc(nblocks*sizeof(int));
611 nxgrid_block_max = MAXXGRID/nblocks;
613 for(m=0; m<nblocks; m++) {
614 pnxgrid[m] = 0;
615 pstart[m] = m*nxgrid_block_max;
618 if(nblocks == 1) {
619 pi_in = i_in;
620 pj_in = j_in;
621 pi_out = i_out;
622 pj_out = j_out;
623 pxgrid_area = xgrid_area;
625 else {
626 pi_in = (int *)malloc(MAXXGRID*sizeof(int));
627 pj_in = (int *)malloc(MAXXGRID*sizeof(int));
628 pi_out = (int *)malloc(MAXXGRID*sizeof(int));
629 pj_out = (int *)malloc(MAXXGRID*sizeof(int));
630 pxgrid_area = (double *)malloc(MAXXGRID*sizeof(double));
633 npts_left = nx2*ny2;
634 nblks_left = nblocks;
635 pos = 0;
636 for(m=0; m<nblocks; m++) {
637 istart2[m] = pos;
638 npts_my = npts_left/nblks_left;
639 iend2[m] = istart2[m] + npts_my - 1;
640 pos = iend2[m] + 1;
641 npts_left -= npts_my;
642 nblks_left--;
645 lon_out_min_list = (double *)malloc(nx2*ny2*sizeof(double));
646 lon_out_max_list = (double *)malloc(nx2*ny2*sizeof(double));
647 lat_out_min_list = (double *)malloc(nx2*ny2*sizeof(double));
648 lat_out_max_list = (double *)malloc(nx2*ny2*sizeof(double));
649 lon_out_avg = (double *)malloc(nx2*ny2*sizeof(double));
650 n2_list = (int *)malloc(nx2*ny2*sizeof(int));
651 lon_out_list = (double *)malloc(MAX_V*nx2*ny2*sizeof(double));
652 lat_out_list = (double *)malloc(MAX_V*nx2*ny2*sizeof(double));
653 #if defined(_OPENMP)
654 #pragma omp parallel for default(none) shared(nx2,ny2,nx2p,lon_out,lat_out,lat_out_min_list, \
655 lat_out_max_list,lon_out_min_list,lon_out_max_list, \
656 lon_out_avg,n2_list,lon_out_list,lat_out_list)
657 #endif
658 for(ij=0; ij<nx2*ny2; ij++){
659 int i2, j2, n, n0, n1, n2, n3, n2_in, l;
660 double x2_in[MV], y2_in[MV];
661 i2 = ij%nx2;
662 j2 = ij/nx2;
663 n = j2*nx2+i2;
664 n0 = j2*nx2p+i2; n1 = j2*nx2p+i2+1;
665 n2 = (j2+1)*nx2p+i2+1; n3 = (j2+1)*nx2p+i2;
666 x2_in[0] = lon_out[n0]; y2_in[0] = lat_out[n0];
667 x2_in[1] = lon_out[n1]; y2_in[1] = lat_out[n1];
668 x2_in[2] = lon_out[n2]; y2_in[2] = lat_out[n2];
669 x2_in[3] = lon_out[n3]; y2_in[3] = lat_out[n3];
671 lat_out_min_list[n] = minval_double(4, y2_in);
672 lat_out_max_list[n] = maxval_double(4, y2_in);
673 n2_in = fix_lon(x2_in, y2_in, 4, M_PI);
674 if(n2_in > MAX_V) error_handler("create_xgrid.c: n2_in is greater than MAX_V");
675 lon_out_min_list[n] = minval_double(n2_in, x2_in);
676 lon_out_max_list[n] = maxval_double(n2_in, x2_in);
677 lon_out_avg[n] = avgval_double(n2_in, x2_in);
678 n2_list[n] = n2_in;
679 for(l=0; l<n2_in; l++) {
680 lon_out_list[n*MAX_V+l] = x2_in[l];
681 lat_out_list[n*MAX_V+l] = y2_in[l];
685 nxgrid = 0;
687 #if defined(_OPENMP)
688 #pragma omp parallel for default(none) shared(nblocks,nx1,ny1,nx1p,mask_in,lon_in,lat_in, \
689 istart2,iend2,nx2,lat_out_min_list,lat_out_max_list, \
690 n2_list,lon_out_list,lat_out_list,lon_out_min_list, \
691 lon_out_max_list,lon_out_avg,area_in,area_out, \
692 pxgrid_area,pnxgrid,pi_in,pj_in,pi_out,pj_out,pstart,nthreads)
693 #endif
694 for(m=0; m<nblocks; m++) {
695 int i1, j1, ij;
696 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
697 int n0, n1, n2, n3, l,n1_in;
698 double lat_in_min,lat_in_max,lon_in_min,lon_in_max,lon_in_avg;
699 double x1_in[MV], y1_in[MV], x_out[MV], y_out[MV];
701 n0 = j1*nx1p+i1; n1 = j1*nx1p+i1+1;
702 n2 = (j1+1)*nx1p+i1+1; n3 = (j1+1)*nx1p+i1;
703 x1_in[0] = lon_in[n0]; y1_in[0] = lat_in[n0];
704 x1_in[1] = lon_in[n1]; y1_in[1] = lat_in[n1];
705 x1_in[2] = lon_in[n2]; y1_in[2] = lat_in[n2];
706 x1_in[3] = lon_in[n3]; y1_in[3] = lat_in[n3];
707 lat_in_min = minval_double(4, y1_in);
708 lat_in_max = maxval_double(4, y1_in);
709 n1_in = fix_lon(x1_in, y1_in, 4, M_PI);
710 lon_in_min = minval_double(n1_in, x1_in);
711 lon_in_max = maxval_double(n1_in, x1_in);
712 lon_in_avg = avgval_double(n1_in, x1_in);
713 for(ij=istart2[m]; ij<=iend2[m]; ij++) {
714 int n_out, i2, j2, n2_in;
715 double xarea, dx, lon_out_min, lon_out_max;
716 double x2_in[MAX_V], y2_in[MAX_V];
718 i2 = ij%nx2;
719 j2 = ij/nx2;
721 if(lat_out_min_list[ij] >= lat_in_max || lat_out_max_list[ij] <= lat_in_min ) continue;
722 /* adjust x2_in according to lon_in_avg*/
723 n2_in = n2_list[ij];
724 for(l=0; l<n2_in; l++) {
725 x2_in[l] = lon_out_list[ij*MAX_V+l];
726 y2_in[l] = lat_out_list[ij*MAX_V+l];
728 lon_out_min = lon_out_min_list[ij];
729 lon_out_max = lon_out_max_list[ij];
730 dx = lon_out_avg[ij] - lon_in_avg;
731 if(dx < -M_PI ) {
732 lon_out_min += TPI;
733 lon_out_max += TPI;
734 for (l=0; l<n2_in; l++) x2_in[l] += TPI;
736 else if (dx > M_PI) {
737 lon_out_min -= TPI;
738 lon_out_max -= TPI;
739 for (l=0; l<n2_in; l++) x2_in[l] -= TPI;
742 /* x2_in should in the same range as x1_in after lon_fix, so no need to
743 consider cyclic condition
745 if(lon_out_min >= lon_in_max || lon_out_max <= lon_in_min ) continue;
746 if ( (n_out = clip_2dx2d( x1_in, y1_in, n1_in, x2_in, y2_in, n2_in, x_out, y_out )) > 0) {
747 double min_area;
748 int nn;
749 xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1];
750 min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]);
751 if( xarea/min_area > AREA_RATIO_THRESH ) {
752 pnxgrid[m]++;
753 if(pnxgrid[m]>= MAXXGRID/nthreads)
754 error_handler("nxgrid is greater than MAXXGRID/nthreads, increase MAXXGRID, decrease nthreads, or increase number of MPI ranks");
755 nn = pstart[m] + pnxgrid[m]-1;
757 pxgrid_area[nn] = xarea;
758 pi_in[nn] = i1;
759 pj_in[nn] = j1;
760 pi_out[nn] = i2;
761 pj_out[nn] = j2;
770 /*copy data if nblocks > 1 */
771 if(nblocks == 1) {
772 nxgrid = pnxgrid[0];
773 pi_in = NULL;
774 pj_in = NULL;
775 pi_out = NULL;
776 pj_out = NULL;
777 pxgrid_area = NULL;
779 else {
780 int nn, i;
781 nxgrid = 0;
782 for(m=0; m<nblocks; m++) {
783 for(i=0; i<pnxgrid[m]; i++) {
784 nn = pstart[m] + i;
785 i_in[nxgrid] = pi_in[nn];
786 j_in[nxgrid] = pj_in[nn];
787 i_out[nxgrid] = pi_out[nn];
788 j_out[nxgrid] = pj_out[nn];
789 xgrid_area[nxgrid] = pxgrid_area[nn];
790 nxgrid++;
793 free(pi_in);
794 free(pj_in);
795 free(pi_out);
796 free(pj_out);
797 free(pxgrid_area);
800 free(area_in);
801 free(area_out);
802 free(lon_out_min_list);
803 free(lon_out_max_list);
804 free(lat_out_min_list);
805 free(lat_out_max_list);
806 free(lon_out_avg);
807 free(n2_list);
808 free(lon_out_list);
809 free(lat_out_list);
811 return nxgrid;
813 }/* get_xgrid_2Dx2D_order1 */
815 /********************************************************************************
816 void create_xgrid_2dx1d_order2
817 This routine generate exchange grids between two grids for the second order
818 conservative interpolation. nlon_in,nlat_in,nlon_out,nlat_out are the size of the grid cell
819 and lon_in,lat_in, lon_out,lat_out are geographic grid location of grid cell bounds.
820 mask is on grid lon_in/lat_in.
821 ********************************************************************************/
822 int create_xgrid_2dx2d_order2_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
823 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
824 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
825 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
827 int nxgrid;
828 nxgrid = create_xgrid_2dx2d_order2(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out, mask_in, i_in,
829 j_in, i_out, j_out, xgrid_area, xgrid_clon, xgrid_clat);
830 return nxgrid;
833 int create_xgrid_2dx2d_order2(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
834 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
835 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
836 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
839 int nx1, nx2, ny1, ny2, nx1p, nx2p, nxgrid;
840 double *area_in, *area_out;
841 int nblocks =1;
842 int *istart2=NULL, *iend2=NULL;
843 int npts_left, nblks_left, pos, m, npts_my, ij;
844 double *lon_out_min_list,*lon_out_max_list,*lon_out_avg,*lat_out_min_list,*lat_out_max_list;
845 double *lon_out_list, *lat_out_list;
846 int *pnxgrid=NULL, *pstart;
847 int *pi_in=NULL, *pj_in=NULL, *pi_out=NULL, *pj_out=NULL;
848 double *pxgrid_area=NULL, *pxgrid_clon=NULL, *pxgrid_clat=NULL;
849 int *n2_list;
850 int nthreads, nxgrid_block_max;
852 nx1 = *nlon_in;
853 ny1 = *nlat_in;
854 nx2 = *nlon_out;
855 ny2 = *nlat_out;
856 nx1p = nx1 + 1;
857 nx2p = nx2 + 1;
859 area_in = (double *)malloc(nx1*ny1*sizeof(double));
860 area_out = (double *)malloc(nx2*ny2*sizeof(double));
861 get_grid_area(nlon_in, nlat_in, lon_in, lat_in, area_in);
862 get_grid_area(nlon_out, nlat_out, lon_out, lat_out, area_out);
864 nthreads = 1;
865 #if defined(_OPENMP)
866 #pragma omp parallel
867 nthreads = omp_get_num_threads();
868 #endif
870 nblocks = nthreads;
872 istart2 = (int *)malloc(nblocks*sizeof(int));
873 iend2 = (int *)malloc(nblocks*sizeof(int));
875 pstart = (int *)malloc(nblocks*sizeof(int));
876 pnxgrid = (int *)malloc(nblocks*sizeof(int));
878 nxgrid_block_max = MAXXGRID/nblocks;
880 for(m=0; m<nblocks; m++) {
881 pnxgrid[m] = 0;
882 pstart[m] = m*nxgrid_block_max;
885 if(nblocks == 1) {
886 pi_in = i_in;
887 pj_in = j_in;
888 pi_out = i_out;
889 pj_out = j_out;
890 pxgrid_area = xgrid_area;
891 pxgrid_clon = xgrid_clon;
892 pxgrid_clat = xgrid_clat;
894 else {
895 pi_in = (int *)malloc(MAXXGRID*sizeof(int));
896 pj_in = (int *)malloc(MAXXGRID*sizeof(int));
897 pi_out = (int *)malloc(MAXXGRID*sizeof(int));
898 pj_out = (int *)malloc(MAXXGRID*sizeof(int));
899 pxgrid_area = (double *)malloc(MAXXGRID*sizeof(double));
900 pxgrid_clon = (double *)malloc(MAXXGRID*sizeof(double));
901 pxgrid_clat = (double *)malloc(MAXXGRID*sizeof(double));
904 npts_left = nx2*ny2;
905 nblks_left = nblocks;
906 pos = 0;
907 for(m=0; m<nblocks; m++) {
908 istart2[m] = pos;
909 npts_my = npts_left/nblks_left;
910 iend2[m] = istart2[m] + npts_my - 1;
911 pos = iend2[m] + 1;
912 npts_left -= npts_my;
913 nblks_left--;
916 lon_out_min_list = (double *)malloc(nx2*ny2*sizeof(double));
917 lon_out_max_list = (double *)malloc(nx2*ny2*sizeof(double));
918 lat_out_min_list = (double *)malloc(nx2*ny2*sizeof(double));
919 lat_out_max_list = (double *)malloc(nx2*ny2*sizeof(double));
920 lon_out_avg = (double *)malloc(nx2*ny2*sizeof(double));
921 n2_list = (int *)malloc(nx2*ny2*sizeof(int));
922 lon_out_list = (double *)malloc(MAX_V*nx2*ny2*sizeof(double));
923 lat_out_list = (double *)malloc(MAX_V*nx2*ny2*sizeof(double));
924 #if defined(_OPENMP)
925 #pragma omp parallel for default(none) shared(nx2,ny2,nx2p,lon_out,lat_out,lat_out_min_list, \
926 lat_out_max_list,lon_out_min_list,lon_out_max_list, \
927 lon_out_avg,n2_list,lon_out_list,lat_out_list)
928 #endif
929 for(ij=0; ij<nx2*ny2; ij++){
930 int i2, j2, n, n0, n1, n2, n3, n2_in, l;
931 double x2_in[MV], y2_in[MV];
932 i2 = ij%nx2;
933 j2 = ij/nx2;
934 n = j2*nx2+i2;
935 n0 = j2*nx2p+i2; n1 = j2*nx2p+i2+1;
936 n2 = (j2+1)*nx2p+i2+1; n3 = (j2+1)*nx2p+i2;
937 x2_in[0] = lon_out[n0]; y2_in[0] = lat_out[n0];
938 x2_in[1] = lon_out[n1]; y2_in[1] = lat_out[n1];
939 x2_in[2] = lon_out[n2]; y2_in[2] = lat_out[n2];
940 x2_in[3] = lon_out[n3]; y2_in[3] = lat_out[n3];
942 lat_out_min_list[n] = minval_double(4, y2_in);
943 lat_out_max_list[n] = maxval_double(4, y2_in);
944 n2_in = fix_lon(x2_in, y2_in, 4, M_PI);
945 if(n2_in > MAX_V) error_handler("create_xgrid.c: n2_in is greater than MAX_V");
946 lon_out_min_list[n] = minval_double(n2_in, x2_in);
947 lon_out_max_list[n] = maxval_double(n2_in, x2_in);
948 lon_out_avg[n] = avgval_double(n2_in, x2_in);
949 n2_list[n] = n2_in;
950 for(l=0; l<n2_in; l++) {
951 lon_out_list[n*MAX_V+l] = x2_in[l];
952 lat_out_list[n*MAX_V+l] = y2_in[l];
956 nxgrid = 0;
958 #if defined(_OPENMP)
959 #pragma omp parallel for default(none) shared(nblocks,nx1,ny1,nx1p,mask_in,lon_in,lat_in, \
960 istart2,iend2,nx2,lat_out_min_list,lat_out_max_list, \
961 n2_list,lon_out_list,lat_out_list,lon_out_min_list, \
962 lon_out_max_list,lon_out_avg,area_in,area_out, \
963 pxgrid_area,pnxgrid,pxgrid_clon,pxgrid_clat,pi_in, \
964 pj_in,pi_out,pj_out,pstart,nthreads)
965 #endif
966 for(m=0; m<nblocks; m++) {
967 int i1, j1, ij;
968 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
969 int n0, n1, n2, n3, l,n1_in;
970 double lat_in_min,lat_in_max,lon_in_min,lon_in_max,lon_in_avg;
971 double x1_in[MV], y1_in[MV], x_out[MV], y_out[MV];
973 n0 = j1*nx1p+i1; n1 = j1*nx1p+i1+1;
974 n2 = (j1+1)*nx1p+i1+1; n3 = (j1+1)*nx1p+i1;
975 x1_in[0] = lon_in[n0]; y1_in[0] = lat_in[n0];
976 x1_in[1] = lon_in[n1]; y1_in[1] = lat_in[n1];
977 x1_in[2] = lon_in[n2]; y1_in[2] = lat_in[n2];
978 x1_in[3] = lon_in[n3]; y1_in[3] = lat_in[n3];
979 lat_in_min = minval_double(4, y1_in);
980 lat_in_max = maxval_double(4, y1_in);
981 n1_in = fix_lon(x1_in, y1_in, 4, M_PI);
982 lon_in_min = minval_double(n1_in, x1_in);
983 lon_in_max = maxval_double(n1_in, x1_in);
984 lon_in_avg = avgval_double(n1_in, x1_in);
985 for(ij=istart2[m]; ij<=iend2[m]; ij++) {
986 int n_out, i2, j2, n2_in;
987 double xarea, dx, lon_out_min, lon_out_max;
988 double x2_in[MAX_V], y2_in[MAX_V];
990 i2 = ij%nx2;
991 j2 = ij/nx2;
993 if(lat_out_min_list[ij] >= lat_in_max || lat_out_max_list[ij] <= lat_in_min ) continue;
994 /* adjust x2_in according to lon_in_avg*/
995 n2_in = n2_list[ij];
996 for(l=0; l<n2_in; l++) {
997 x2_in[l] = lon_out_list[ij*MAX_V+l];
998 y2_in[l] = lat_out_list[ij*MAX_V+l];
1000 lon_out_min = lon_out_min_list[ij];
1001 lon_out_max = lon_out_max_list[ij];
1002 dx = lon_out_avg[ij] - lon_in_avg;
1003 if(dx < -M_PI ) {
1004 lon_out_min += TPI;
1005 lon_out_max += TPI;
1006 for (l=0; l<n2_in; l++) x2_in[l] += TPI;
1008 else if (dx > M_PI) {
1009 lon_out_min -= TPI;
1010 lon_out_max -= TPI;
1011 for (l=0; l<n2_in; l++) x2_in[l] -= TPI;
1014 /* x2_in should in the same range as x1_in after lon_fix, so no need to
1015 consider cyclic condition
1017 if(lon_out_min >= lon_in_max || lon_out_max <= lon_in_min ) continue;
1018 if ( (n_out = clip_2dx2d( x1_in, y1_in, n1_in, x2_in, y2_in, n2_in, x_out, y_out )) > 0) {
1019 double min_area;
1020 int nn;
1021 xarea = poly_area (x_out, y_out, n_out ) * mask_in[j1*nx1+i1];
1022 min_area = min(area_in[j1*nx1+i1], area_out[j2*nx2+i2]);
1023 if( xarea/min_area > AREA_RATIO_THRESH ) {
1024 pnxgrid[m]++;
1025 if(pnxgrid[m]>= MAXXGRID/nthreads)
1026 error_handler("nxgrid is greater than MAXXGRID/nthreads, increase MAXXGRID, decrease nthreads, or increase number of MPI ranks");
1027 nn = pstart[m] + pnxgrid[m]-1;
1028 pxgrid_area[nn] = xarea;
1029 pxgrid_clon[nn] = poly_ctrlon(x_out, y_out, n_out, lon_in_avg);
1030 pxgrid_clat[nn] = poly_ctrlat (x_out, y_out, n_out );
1031 pi_in[nn] = i1;
1032 pj_in[nn] = j1;
1033 pi_out[nn] = i2;
1034 pj_out[nn] = j2;
1041 /*copy data if nblocks > 1 */
1042 if(nblocks == 1) {
1043 nxgrid = pnxgrid[0];
1044 pi_in = NULL;
1045 pj_in = NULL;
1046 pi_out = NULL;
1047 pj_out = NULL;
1048 pxgrid_area = NULL;
1049 pxgrid_clon = NULL;
1050 pxgrid_clat = NULL;
1052 else {
1053 int nn, i;
1054 nxgrid = 0;
1055 for(m=0; m<nblocks; m++) {
1056 for(i=0; i<pnxgrid[m]; i++) {
1057 nn = pstart[m] + i;
1058 i_in[nxgrid] = pi_in[nn];
1059 j_in[nxgrid] = pj_in[nn];
1060 i_out[nxgrid] = pi_out[nn];
1061 j_out[nxgrid] = pj_out[nn];
1062 xgrid_area[nxgrid] = pxgrid_area[nn];
1063 xgrid_clon[nxgrid] = pxgrid_clon[nn];
1064 xgrid_clat[nxgrid] = pxgrid_clat[nn];
1065 nxgrid++;
1068 free(pi_in);
1069 free(pj_in);
1070 free(pi_out);
1071 free(pj_out);
1072 free(pxgrid_area);
1073 free(pxgrid_clon);
1074 free(pxgrid_clat);
1077 free(area_in);
1078 free(area_out);
1079 free(lon_out_min_list);
1080 free(lon_out_max_list);
1081 free(lat_out_min_list);
1082 free(lat_out_max_list);
1083 free(lon_out_avg);
1084 free(n2_list);
1085 free(lon_out_list);
1086 free(lat_out_list);
1088 return nxgrid;
1090 }/* get_xgrid_2Dx2D_order2 */
1092 int create_xgrid_great_circle_(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
1093 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
1094 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
1095 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
1097 int nxgrid;
1098 nxgrid = create_xgrid_great_circle(nlon_in, nlat_in, nlon_out, nlat_out, lon_in, lat_in, lon_out, lat_out,
1099 mask_in, i_in, j_in, i_out, j_out, xgrid_area, xgrid_clon, xgrid_clat);
1101 return nxgrid;
1104 int create_xgrid_great_circle(const int *nlon_in, const int *nlat_in, const int *nlon_out, const int *nlat_out,
1105 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
1106 const double *mask_in, int *i_in, int *j_in, int *i_out, int *j_out,
1107 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
1110 int nx1, nx2, ny1, ny2, nx1p, nx2p, ny1p, ny2p, nxgrid, n1_in, n2_in;
1111 int n0, n1, n2, n3, i1, j1, i2, j2;
1112 double x1_in[MV], y1_in[MV], z1_in[MV];
1113 double x2_in[MV], y2_in[MV], z2_in[MV];
1114 double x_out[MV], y_out[MV], z_out[MV];
1115 double *x1=NULL, *y1=NULL, *z1=NULL;
1116 double *x2=NULL, *y2=NULL, *z2=NULL;
1118 double *area1, *area2, min_area;
1120 nx1 = *nlon_in;
1121 ny1 = *nlat_in;
1122 nx2 = *nlon_out;
1123 ny2 = *nlat_out;
1124 nxgrid = 0;
1125 nx1p = nx1 + 1;
1126 nx2p = nx2 + 1;
1127 ny1p = ny1 + 1;
1128 ny2p = ny2 + 1;
1130 /* first convert lon-lat to cartesian coordinates */
1131 x1 = (double *)malloc(nx1p*ny1p*sizeof(double));
1132 y1 = (double *)malloc(nx1p*ny1p*sizeof(double));
1133 z1 = (double *)malloc(nx1p*ny1p*sizeof(double));
1134 x2 = (double *)malloc(nx2p*ny2p*sizeof(double));
1135 y2 = (double *)malloc(nx2p*ny2p*sizeof(double));
1136 z2 = (double *)malloc(nx2p*ny2p*sizeof(double));
1138 latlon2xyz(nx1p*ny1p, lon_in, lat_in, x1, y1, z1);
1139 latlon2xyz(nx2p*ny2p, lon_out, lat_out, x2, y2, z2);
1141 area1 = (double *)malloc(nx1*ny1*sizeof(double));
1142 area2 = (double *)malloc(nx2*ny2*sizeof(double));
1143 get_grid_great_circle_area(nlon_in, nlat_in, lon_in, lat_in, area1);
1144 get_grid_great_circle_area(nlon_out, nlat_out, lon_out, lat_out, area2);
1145 n1_in = 4;
1146 n2_in = 4;
1148 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
1149 /* clockwise */
1150 n0 = j1*nx1p+i1; n1 = (j1+1)*nx1p+i1;
1151 n2 = (j1+1)*nx1p+i1+1; n3 = j1*nx1p+i1+1;
1152 x1_in[0] = x1[n0]; y1_in[0] = y1[n0]; z1_in[0] = z1[n0];
1153 x1_in[1] = x1[n1]; y1_in[1] = y1[n1]; z1_in[1] = z1[n1];
1154 x1_in[2] = x1[n2]; y1_in[2] = y1[n2]; z1_in[2] = z1[n2];
1155 x1_in[3] = x1[n3]; y1_in[3] = y1[n3]; z1_in[3] = z1[n3];
1157 for(j2=0; j2<ny2; j2++) for(i2=0; i2<nx2; i2++) {
1158 int n_out;
1159 double xarea;
1161 n0 = j2*nx2p+i2; n1 = (j2+1)*nx2p+i2;
1162 n2 = (j2+1)*nx2p+i2+1; n3 = j2*nx2p+i2+1;
1163 x2_in[0] = x2[n0]; y2_in[0] = y2[n0]; z2_in[0] = z2[n0];
1164 x2_in[1] = x2[n1]; y2_in[1] = y2[n1]; z2_in[1] = z2[n1];
1165 x2_in[2] = x2[n2]; y2_in[2] = y2[n2]; z2_in[2] = z2[n2];
1166 x2_in[3] = x2[n3]; y2_in[3] = y2[n3]; z2_in[3] = z2[n3];
1168 if ( (n_out = clip_2dx2d_great_circle( x1_in, y1_in, z1_in, n1_in, x2_in, y2_in, z2_in, n2_in,
1169 x_out, y_out, z_out)) > 0) {
1170 xarea = great_circle_area ( n_out, x_out, y_out, z_out ) * mask_in[j1*nx1+i1];
1171 min_area = min(area1[j1*nx1+i1], area2[j2*nx2+i2]);
1172 if( xarea/min_area > AREA_RATIO_THRESH ) {
1173 xgrid_area[nxgrid] = xarea;
1174 xgrid_clon[nxgrid] = 0; /*z1l: will be developed very soon */
1175 xgrid_clat[nxgrid] = 0;
1176 i_in[nxgrid] = i1;
1177 j_in[nxgrid] = j1;
1178 i_out[nxgrid] = i2;
1179 j_out[nxgrid] = j2;
1180 ++nxgrid;
1181 if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID");
1188 free(area1);
1189 free(area2);
1191 free(x1);
1192 free(y1);
1193 free(z1);
1194 free(x2);
1195 free(y2);
1196 free(z2);
1198 return nxgrid;
1200 }/* create_xgrid_great_circle */
1202 int create_xgrid_great_circle_ug_(const int *nlon_in, const int *nlat_in, const int *npts_out,
1203 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
1204 const double *mask_in, int *i_in, int *j_in, int *l_out,
1205 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
1207 int nxgrid;
1208 nxgrid = create_xgrid_great_circle_ug(nlon_in, nlat_in, npts_out, lon_in, lat_in, lon_out, lat_out,
1209 mask_in, i_in, j_in, l_out, xgrid_area, xgrid_clon, xgrid_clat);
1211 return nxgrid;
1214 int create_xgrid_great_circle_ug(const int *nlon_in, const int *nlat_in, const int *npts_out,
1215 const double *lon_in, const double *lat_in, const double *lon_out, const double *lat_out,
1216 const double *mask_in, int *i_in, int *j_in, int *l_out,
1217 double *xgrid_area, double *xgrid_clon, double *xgrid_clat)
1220 int nx1, ny1, npts2, nx1p, ny1p, nxgrid, n1_in, n2_in, nv;
1221 int n0, n1, n2, n3, i1, j1, l2;
1222 double x1_in[MV], y1_in[MV], z1_in[MV];
1223 double x2_in[MV], y2_in[MV], z2_in[MV];
1224 double x_out[MV], y_out[MV], z_out[MV];
1225 double *x1=NULL, *y1=NULL, *z1=NULL;
1226 double *x2=NULL, *y2=NULL, *z2=NULL;
1228 double *area1, *area2, min_area;
1230 nx1 = *nlon_in;
1231 ny1 = *nlat_in;
1232 nv = 4;
1233 npts2 = *npts_out;
1234 nxgrid = 0;
1235 nx1p = nx1 + 1;
1236 ny1p = ny1 + 1;
1238 /* first convert lon-lat to cartesian coordinates */
1239 x1 = (double *)malloc(nx1p*ny1p*sizeof(double));
1240 y1 = (double *)malloc(nx1p*ny1p*sizeof(double));
1241 z1 = (double *)malloc(nx1p*ny1p*sizeof(double));
1242 x2 = (double *)malloc(npts2*nv*sizeof(double));
1243 y2 = (double *)malloc(npts2*nv*sizeof(double));
1244 z2 = (double *)malloc(npts2*nv*sizeof(double));
1246 latlon2xyz(nx1p*ny1p, lon_in, lat_in, x1, y1, z1);
1247 latlon2xyz(npts2*nv, lon_out, lat_out, x2, y2, z2);
1249 area1 = (double *)malloc(nx1*ny1*sizeof(double));
1250 area2 = (double *)malloc(npts2*sizeof(double));
1251 get_grid_great_circle_area(nlon_in, nlat_in, lon_in, lat_in, area1);
1252 get_grid_great_circle_area_ug(npts_out, lon_out, lat_out, area2);
1253 n1_in = 4;
1254 n2_in = 4;
1256 for(j1=0; j1<ny1; j1++) for(i1=0; i1<nx1; i1++) if( mask_in[j1*nx1+i1] > MASK_THRESH ) {
1257 /* clockwise */
1258 n0 = j1*nx1p+i1; n1 = (j1+1)*nx1p+i1;
1259 n2 = (j1+1)*nx1p+i1+1; n3 = j1*nx1p+i1+1;
1260 x1_in[0] = x1[n0]; y1_in[0] = y1[n0]; z1_in[0] = z1[n0];
1261 x1_in[1] = x1[n1]; y1_in[1] = y1[n1]; z1_in[1] = z1[n1];
1262 x1_in[2] = x1[n2]; y1_in[2] = y1[n2]; z1_in[2] = z1[n2];
1263 x1_in[3] = x1[n3]; y1_in[3] = y1[n3]; z1_in[3] = z1[n3];
1265 for(l2=0; l2<npts2; l2++) {
1266 int n_out;
1267 double xarea;
1269 n0 = l2*nv; n1 = l2*nv+1;
1270 n2 = l2*nv+2; n3 = l2*nv+3;
1271 x2_in[0] = x2[n0]; y2_in[0] = y2[n0]; z2_in[0] = z2[n0];
1272 x2_in[1] = x2[n1]; y2_in[1] = y2[n1]; z2_in[1] = z2[n1];
1273 x2_in[2] = x2[n2]; y2_in[2] = y2[n2]; z2_in[2] = z2[n2];
1274 x2_in[3] = x2[n3]; y2_in[3] = y2[n3]; z2_in[3] = z2[n3];
1276 if ( (n_out = clip_2dx2d_great_circle( x1_in, y1_in, z1_in, n1_in, x2_in, y2_in, z2_in, n2_in,
1277 x_out, y_out, z_out)) > 0) {
1278 xarea = great_circle_area ( n_out, x_out, y_out, z_out ) * mask_in[j1*nx1+i1];
1279 min_area = min(area1[j1*nx1+i1], area2[l2]);
1280 if( xarea/min_area > AREA_RATIO_THRESH ) {
1281 xgrid_area[nxgrid] = xarea;
1282 xgrid_clon[nxgrid] = 0; /*z1l: will be developed very soon */
1283 xgrid_clat[nxgrid] = 0;
1284 i_in[nxgrid] = i1;
1285 j_in[nxgrid] = j1;
1286 l_out[nxgrid] = l2;
1287 ++nxgrid;
1288 if(nxgrid > MAXXGRID) error_handler("nxgrid is greater than MAXXGRID, increase MAXXGRID");
1295 free(area1);
1296 free(area2);
1298 free(x1);
1299 free(y1);
1300 free(z1);
1301 free(x2);
1302 free(y2);
1303 free(z2);
1305 return nxgrid;
1307 }/* create_xgrid_great_circle_ug */
1309 /*******************************************************************************
1310 int get_maxxgrid
1311 return constants MAXXGRID.
1312 *******************************************************************************/
1313 int get_maxxgrid(void)
1315 return MAXXGRID;
1318 int get_maxxgrid_(void)
1320 return get_maxxgrid();