1 /*
2 This file is part of CDO. CDO is a collection of Operators to manipulate and analyse Climate model Data.
3
4 Author: Uwe Schulzweida
5
6 */
7
8 #include "remap_grid_cell_search.h"
9 #include "cdo_output.h"
10 #include "compare.h"
11 #include "varray.h"
12 #include "cdo_options.h"
13 #include "cimdOmp.h"
14 #include <mpim_grid.h>
15
16 extern "C"
17 {
18 #include "lib/yac/sphere_part.h"
19 }
20
21 CellSearchMethod cellSearchMethod(CellSearchMethod::spherepart);
22
23 void
set_cell_search_method(const char * methodstr)24 set_cell_search_method(const char *methodstr)
25 {
26 // clang-format off
27 if (cdo_cmpstr(methodstr, "spherepart")) cellSearchMethod = CellSearchMethod::spherepart;
28 else if (cdo_cmpstr(methodstr, "latbins")) cellSearchMethod = CellSearchMethod::latbins;
29 else cdo_abort("Grid cell search method %s not available!", methodstr);
30 // clang-format on
31 }
32
33 static void
gridBoundboxReg2d(size_t nx,size_t ny,const Varray<double> & reg2d_corner_lon,const Varray<double> & reg2d_corner_lat,double * grid_bound_box)34 gridBoundboxReg2d(size_t nx, size_t ny, const Varray<double> ®2d_corner_lon, const Varray<double> ®2d_corner_lat,
35 double *grid_bound_box)
36 {
37 grid_bound_box[0] = reg2d_corner_lat[0];
38 grid_bound_box[1] = reg2d_corner_lat[ny];
39 if (grid_bound_box[0] > grid_bound_box[1])
40 {
41 grid_bound_box[0] = reg2d_corner_lat[ny];
42 grid_bound_box[1] = reg2d_corner_lat[0];
43 }
44 grid_bound_box[2] = reg2d_corner_lon[0];
45 grid_bound_box[3] = reg2d_corner_lon[nx];
46 }
47
48 void
grid_cell_search_create_reg_2d(GridCellSearch & gcs,size_t dims[2],const Varray<double> & reg2d_corner_lon,const Varray<double> & reg2d_corner_lat)49 grid_cell_search_create_reg_2d(GridCellSearch &gcs, size_t dims[2], const Varray<double> ®2d_corner_lon,
50 const Varray<double> ®2d_corner_lat)
51 {
52 gcs.is_reg2d = true;
53 gcs.dims[0] = dims[0];
54 gcs.dims[1] = dims[1];
55 const auto nx = dims[0];
56 const auto ny = dims[1];
57 const auto nxp1 = nx + 1;
58 const auto nyp1 = ny + 1;
59
60 gcs.reg2d_corner_lon.resize(nxp1);
61 gcs.reg2d_corner_lat.resize(nyp1);
62
63 varray_copy(nxp1, reg2d_corner_lon, gcs.reg2d_corner_lon);
64 varray_copy(nyp1, reg2d_corner_lat, gcs.reg2d_corner_lat);
65
66 gridBoundboxReg2d(nx, ny, gcs.reg2d_corner_lon, gcs.reg2d_corner_lat, gcs.gridBoundboxReg2d);
67
68 gcs.in_use = true;
69 }
70
71 void
grid_cell_search_create(GridCellSearch & gcs,size_t numCells,size_t numCellCorners,Varray<double> & cellCornerLon,Varray<double> & cellCornerLat)72 grid_cell_search_create(GridCellSearch &gcs, size_t numCells, size_t numCellCorners, Varray<double> &cellCornerLon,
73 Varray<double> &cellCornerLat)
74 {
75 gcs.method = cellSearchMethod;
76
77 std::vector<struct grid_cell> cells(Threading::ompNumThreads);
78 for (int i = 0; i < Threading::ompNumThreads; ++i)
79 {
80 cells[i].coordinates_xyz = (double(*)[3]) malloc(numCellCorners * sizeof(*(cells[i].coordinates_xyz)));
81 cells[i].edge_type = (enum yac_edge_type *) malloc(numCellCorners * sizeof(*(cells[i].edge_type)));
82 cells[i].num_corners = numCellCorners;
83 cells[i].array_size = numCellCorners;
84 for (size_t k = 0; k < numCellCorners; ++k) cells[i].edge_type[k] = GREAT_CIRCLE;
85 }
86
87 struct bounding_circle *bnd_circles = (struct bounding_circle *) malloc(numCells * sizeof(struct bounding_circle));
88
89 #ifdef _OPENMP
90 #pragma omp parallel for default(shared)
91 #endif
92 for (size_t i = 0; i < numCells; ++i)
93 {
94 const auto ompthID = cdo_omp_get_thread_num();
95 auto &cell = cells[ompthID];
96 auto xyz = cell.coordinates_xyz;
97
98 for (size_t k = 0; k < numCellCorners; ++k)
99 gcLLtoXYZ(cellCornerLon[i * numCellCorners + k], cellCornerLat[i * numCellCorners + k], xyz[k]);
100
101 if (numCellCorners == 3)
102 yac_get_cell_bounding_circle_unstruct_triangle(xyz[0], xyz[1], xyz[2], &bnd_circles[i]);
103 else
104 yac_get_cell_bounding_circle(cell, &bnd_circles[i]);
105 }
106
107 gcs.yacSearch = yac_bnd_sphere_part_search_new(bnd_circles, numCells);
108 gcs.yacBndCircles = bnd_circles;
109
110 for (int i = 0; i < Threading::ompNumThreads; ++i)
111 {
112 free(cells[i].edge_type);
113 free(cells[i].coordinates_xyz);
114 }
115
116 gcs.in_use = true;
117 }
118
119 void
grid_cell_search_delete(GridCellSearch & gcs)120 grid_cell_search_delete(GridCellSearch &gcs)
121 {
122 if (gcs.in_use)
123 {
124 varray_free(gcs.reg2d_corner_lon);
125 varray_free(gcs.reg2d_corner_lat);
126
127 if (gcs.yacSearch) yac_bnd_sphere_part_search_delete((bnd_sphere_part_search *) gcs.yacSearch);
128 if (gcs.yacBndCircles) free(gcs.yacBndCircles);
129
130 gcs.in_use = false;
131 }
132 }
133
134 static size_t
doGridCellSearchYac(bnd_sphere_part_search * yacSearch,bounding_circle * yacBndCircles,bool isReg2dCell,const grid_cell & gridCell,Varray<size_t> & srchAddr)135 doGridCellSearchYac(bnd_sphere_part_search *yacSearch, bounding_circle *yacBndCircles, bool isReg2dCell, const grid_cell &gridCell,
136 Varray<size_t> &srchAddr)
137 {
138 size_t numCellCorners = gridCell.num_corners;
139 bounding_circle bndCircle;
140 double(*xyz)[3] = gridCell.coordinates_xyz;
141
142 if (numCellCorners == 4 && isReg2dCell)
143 yac_get_cell_bounding_circle_reg_quad(xyz[0], xyz[1], xyz[2], &bndCircle);
144 else if (numCellCorners == 3)
145 yac_get_cell_bounding_circle_unstruct_triangle(xyz[0], xyz[1], xyz[2], &bndCircle);
146 else
147 yac_get_cell_bounding_circle(gridCell, &bndCircle);
148
149 size_t numSrchCells;
150 size_t *currNeighs;
151 yac_bnd_sphere_part_search_do_bnd_circle_search(yacSearch, &bndCircle, 1, &currNeighs, &numSrchCells);
152
153 if (srchAddr.size() < numSrchCells) srchAddr.resize(numSrchCells);
154
155 size_t k = 0;
156 // for (size_t i = 0; i < numSrchCells; ++i) srchAddr[i] = currNeighs[i];
157 for (size_t i = 0; i < numSrchCells; ++i)
158 {
159 if (yac_extents_overlap(&bndCircle, &yacBndCircles[currNeighs[i]])) srchAddr[k++] = currNeighs[i];
160 }
161 numSrchCells = k;
162 free(currNeighs);
163
164 return numSrchCells;
165 }
166
167 size_t
do_grid_cell_search(GridCellSearch & gcs,bool isReg2dCell,grid_cell & gridCell,Varray<size_t> & srchAddr)168 do_grid_cell_search(GridCellSearch &gcs, bool isReg2dCell, grid_cell &gridCell, Varray<size_t> &srchAddr)
169 {
170 if (gcs.in_use)
171 {
172 // clang-format off
173 if (gcs.method == CellSearchMethod::spherepart)
174 return doGridCellSearchYac((bnd_sphere_part_search*)gcs.yacSearch, (bounding_circle *)gcs.yacBndCircles,
175 isReg2dCell, gridCell, srchAddr);
176 else
177 cdo_abort("%s::method undefined!", __func__);
178 // clang-format on
179 }
180
181 return 0;
182 }
183