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 <atomic>
9
10 #include "process_int.h"
11 #include "cdo_wtime.h"
12 #include "remap.h"
13 #include "remap_store_link.h"
14 #include "cdo_options.h"
15 #include "progress.h"
16 #include "cimdOmp.h"
17
18 // Interpolation using a distance-weighted average
19
20 // This routine computes the inverse-distance weights for a nearest-neighbor interpolation
21 void
remap_distwgt_weights(size_t numNeighbors,RemapSearch & rsearch,RemapVars & rv)22 remap_distwgt_weights(size_t numNeighbors, RemapSearch &rsearch, RemapVars &rv)
23 {
24 auto src_grid = rsearch.srcGrid;
25 auto tgt_grid = rsearch.tgtGrid;
26
27 if (Options::cdoVerbose) cdo_print("Called %s()", __func__);
28
29 progress::init();
30
31 // Compute mappings from source to target grid
32
33 auto tgt_grid_size = tgt_grid->size;
34
35 std::vector<WeightLinks> weightLinks(tgt_grid_size);
36 weight_links_alloc(numNeighbors, tgt_grid_size, weightLinks);
37
38 std::vector<knnWeightsType> knnWeights;
39 for (int i = 0; i < Threading::ompNumThreads; ++i) knnWeights.push_back(knnWeightsType(numNeighbors));
40
41 const auto start = Options::cdoVerbose ? cdo_get_wtime() : 0.0;
42
43 // Loop over destination grid
44
45 std::atomic<size_t> atomicCount{0};
46
47 #ifdef _OPENMP
48 #pragma omp parallel for default(none) \
49 shared(atomicCount, rsearch, weightLinks, numNeighbors, src_grid, tgt_grid, tgt_grid_size, knnWeights)
50 #endif
51 for (size_t tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add)
52 {
53 const auto ompthID = cdo_omp_get_thread_num();
54
55 atomicCount++;
56 if (ompthID == 0) progress::update(0, 1, (double)atomicCount / tgt_grid_size);
57
58 weightLinks[tgt_cell_add].nlinks = 0;
59
60 if (!tgt_grid->mask[tgt_cell_add]) continue;
61
62 const auto llpoint = remapgrid_get_lonlat(tgt_grid, tgt_cell_add);
63
64 // Find nearest grid points on source grid and distances to each point
65 remap_search_points(rsearch, llpoint, knnWeights[ompthID]);
66
67 // Compute weights based on inverse distance if mask is false, eliminate those points
68 const auto nadds = knnWeights[ompthID].computeWeights(src_grid->mask);
69
70 for (size_t n = 0; n < nadds; ++n)
71 if (knnWeights[ompthID].m_mask[n]) tgt_grid->cell_frac[tgt_cell_add] = 1.0;
72
73 // Store the link
74 store_weightlinks(0, nadds, knnWeights[ompthID].m_addr.data(), knnWeights[ompthID].m_dist.data(), tgt_cell_add, weightLinks);
75 }
76
77 progress::update(0, 1, 1);
78
79 grid_point_search_delete(rsearch.gps);
80
81 weight_links_to_remap_links(0, tgt_grid_size, weightLinks, rv);
82
83 if (numNeighbors == 1) rv.links_per_value = numNeighbors;
84
85 if (Options::cdoVerbose) cdo_print("Point search nearest: %.2f seconds", cdo_get_wtime() - start);
86 } // remap_distwgt_weights
87
88 template <typename T>
89 static void
remap_dist_wgt(size_t numNeighbors,RemapSearch & rsearch,const Varray<T> & src_array,Varray<T> & tgt_array,T missval)90 remap_dist_wgt(size_t numNeighbors, RemapSearch &rsearch, const Varray<T> &src_array, Varray<T> &tgt_array, T missval)
91 {
92 auto src_grid = rsearch.srcGrid;
93 auto tgt_grid = rsearch.tgtGrid;
94
95 if (Options::cdoVerbose) cdo_print("Called %s()", __func__);
96
97 progress::init();
98
99 // Compute mappings from source to target grid
100
101 auto tgt_grid_size = tgt_grid->size;
102 auto src_grid_size = src_grid->size;
103
104 Varray<short> src_grid_mask(src_grid_size);
105 #ifdef _OPENMP
106 #pragma omp parallel for default(none) schedule(static) shared(src_grid_size, src_array, src_grid_mask, missval)
107 #endif
108 for (size_t i = 0; i < src_grid_size; ++i) src_grid_mask[i] = !DBL_IS_EQUAL(src_array[i], missval);
109
110 std::vector<knnWeightsType> knnWeights;
111 for (int i = 0; i < Threading::ompNumThreads; ++i) knnWeights.push_back(knnWeightsType(numNeighbors));
112
113 const auto start = Options::cdoVerbose ? cdo_get_wtime() : 0.0;
114
115 // Loop over destination grid
116
117 std::atomic<size_t> atomicCount{0};
118
119 #ifdef _OPENMP
120 #pragma omp parallel for default(none) shared(atomicCount, rsearch, numNeighbors, src_grid, tgt_grid, tgt_grid_size, src_array, \
121 tgt_array, missval, src_grid_mask, knnWeights)
122 #endif
123 for (size_t tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add)
124 {
125 const auto ompthID = cdo_omp_get_thread_num();
126
127 atomicCount++;
128 if (ompthID == 0) progress::update(0, 1, (double)atomicCount / tgt_grid_size);
129
130 tgt_array[tgt_cell_add] = missval;
131
132 if (!tgt_grid->mask[tgt_cell_add]) continue;
133
134 const auto llpoint = remapgrid_get_lonlat(tgt_grid, tgt_cell_add);
135
136 // Find nearest grid points on source grid and distances to each point
137 remap_search_points(rsearch, llpoint, knnWeights[ompthID]);
138
139 // Compute weights based on inverse distance if mask is false, eliminate those points
140 const auto nadds = knnWeights[ompthID].computeWeights(src_grid_mask);
141 if (nadds) tgt_array[tgt_cell_add] = knnWeights[ompthID].arrayWeightsSum(src_array);
142 }
143
144 progress::update(0, 1, 1);
145
146 if (Options::cdoVerbose) cdo_print("Point search nearest: %.2f seconds", cdo_get_wtime() - start);
147 } // remap_dist_wgt
148
149 void
remap_dist_wgt(size_t numNeighbors,RemapSearch & rsearch,const Field & field1,Field & field2)150 remap_dist_wgt(size_t numNeighbors, RemapSearch &rsearch, const Field &field1, Field &field2)
151 {
152 if (field1.memType == MemType::Float)
153 remap_dist_wgt(numNeighbors, rsearch, field1.vec_f, field2.vec_f, (float) field1.missval);
154 else
155 remap_dist_wgt(numNeighbors, rsearch, field1.vec_d, field2.vec_d, field1.missval);
156 }
157
158 void remapInit(RemapType &remap);
159
160 void
intgriddis(Field & field1,Field & field2,size_t numNeighbors)161 intgriddis(Field &field1, Field &field2, size_t numNeighbors)
162 {
163 auto mapType = RemapMethod::DISTWGT;
164 auto gridID1 = field1.grid;
165 auto gridID2 = field2.grid;
166 auto src_missval = field1.missval;
167 auto tgt_missval = field2.missval;
168 auto src_array = field1.vec_d.data();
169 auto tgt_array = field2.vec_d.data();
170
171 if (Options::cdoVerbose) cdo_print("Called %s()", __func__);
172
173 progress::init();
174
175 // Interpolate from source to target grid
176
177 RemapType remap;
178 remapInit(remap);
179
180 bool remap_extrapolate = false;
181 remap_init_grids(mapType, remap_extrapolate, gridID1, remap.src_grid, gridID2, remap.tgt_grid);
182
183 auto src_grid_size = remap.src_grid.size;
184 auto tgt_grid_size = remap.tgt_grid.size;
185
186 Varray<short> src_mask(src_grid_size);
187 for (size_t i = 0; i < src_grid_size; ++i) src_mask[i] = !DBL_IS_EQUAL(src_array[i], src_missval);
188 // Varray<short> tgt_mask(tgt_grid_size, 1);
189
190 std::vector<knnWeightsType> knnWeights;
191 for (int i = 0; i < Threading::ompNumThreads; ++i) knnWeights.push_back(knnWeightsType(numNeighbors));
192
193 remap_search_init(mapType, remap.search, remap.src_grid, remap.tgt_grid);
194
195 const auto start = Options::cdoVerbose ? cdo_get_wtime() : 0.0;
196
197 // Loop over destination grid
198
199 size_t nmiss = 0;
200 double findex = 0.0;
201
202 for (size_t tgt_cell_add = 0; tgt_cell_add < tgt_grid_size; ++tgt_cell_add)
203 {
204 const auto ompthID = cdo_omp_get_thread_num();
205
206 findex++;
207 if (ompthID == 0) progress::update(0, 1, findex / tgt_grid_size);
208
209 tgt_array[tgt_cell_add] = tgt_missval;
210
211 // if (!tgt_mask[tgt_cell_add]) continue;
212
213 const auto llpoint = remapgrid_get_lonlat(&remap.tgt_grid, tgt_cell_add);
214
215 // Find nearest grid points on source grid and distances to each point
216 remap_search_points(remap.search, llpoint, knnWeights[ompthID]);
217
218 // Compute weights based on inverse distance if mask is false, eliminate those points
219 const auto nadds = knnWeights[ompthID].computeWeights(src_mask);
220 if (nadds)
221 tgt_array[tgt_cell_add] = knnWeights[ompthID].arrayWeightsSum(src_array);
222 else
223 nmiss++;
224 }
225
226 progress::update(0, 1, 1);
227
228 field2.nmiss = nmiss;
229
230 remap_grid_free(remap.src_grid);
231 remap_grid_free(remap.tgt_grid);
232 remap_search_free(remap.search);
233
234 if (Options::cdoVerbose) cdo_print("Point search nearest: %.2f seconds", cdo_get_wtime() - start);
235 } // intgriddis
236