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 <algorithm>
9 #include <array>
10 
11 #include "dmemory.h"
12 #include "cdo_options.h"
13 #include "remap.h"
14 #include "remap_store_link.h"
15 
16 static bool
compareAdds(const Addweight & a,const Addweight & b)17 compareAdds(const Addweight &a, const Addweight &b)
18 {
19   return a.add < b.add;
20 }
21 
22 static bool
compareAdds4(const Addweight4 & a,const Addweight4 & b)23 compareAdds4(const Addweight4 &a, const Addweight4 &b)
24 {
25   return a.add < b.add;
26 }
27 
28 static int
qcompareAdds(const void * a,const void * b)29 qcompareAdds(const void *a, const void *b)
30 {
31   const size_t x = ((const Addweight *) a)->add;
32   const size_t y = ((const Addweight *) b)->add;
33   return ((x > y) - (x < y)) * 2 + (x > y) - (x < y);
34 }
35 
36 static int
qcompareAdds4(const void * a,const void * b)37 qcompareAdds4(const void *a, const void *b)
38 {
39   const size_t x = ((const Addweight4 *) a)->add;
40   const size_t y = ((const Addweight4 *) b)->add;
41   return ((x > y) - (x < y)) * 2 + (x > y) - (x < y);
42 }
43 
44 static void
sortAddweights(size_t numWeights,Addweight * addweights)45 sortAddweights(size_t numWeights, Addweight *addweights)
46 {
47   size_t n;
48   for (n = 1; n < numWeights; ++n)
49     if (addweights[n].add < addweights[n - 1].add) break;
50   if (n == numWeights) return;
51 
52   std::qsort(addweights, numWeights, sizeof(Addweight), qcompareAdds);
53 }
54 
55 static void
sortAddweights4(Addweight4 * addweights)56 sortAddweights4(Addweight4 *addweights)
57 {
58   unsigned n;
59   for (n = 1; n < 4; ++n)
60     if (addweights[n].add < addweights[n - 1].add) break;
61   if (n == 4) return;
62 
63   std::qsort(addweights, 4, sizeof(Addweight4), qcompareAdds4);
64 }
65 
66 void
sort_weights_n4(size_t * src_add,double * weights)67 sort_weights_n4(size_t *src_add, double *weights)
68 {
69   constexpr size_t numWeights = 4;
70   size_t n;
71   for (n = 1; n < numWeights; ++n)
72     if (src_add[n] < src_add[n - 1]) break;
73   if (n == numWeights) return;
74 
75   std::array<Addweight, numWeights> addweights;
76 
77   for (n = 0; n < numWeights; ++n)
78     {
79       addweights[n].add = src_add[n];
80       addweights[n].weight = weights[n];
81     }
82 
83   std::sort(addweights.begin(), addweights.end(), compareAdds);
84 
85   for (n = 0; n < numWeights; ++n)
86     {
87       src_add[n] = addweights[n].add;
88       weights[n] = addweights[n].weight;
89     }
90 }
91 
92 void
sort_weights(size_t numWeights,size_t * src_add,double * weights)93 sort_weights(size_t numWeights, size_t *src_add, double *weights)
94 {
95   size_t n;
96   for (n = 1; n < numWeights; ++n)
97     if (src_add[n] < src_add[n - 1]) break;
98   if (n == numWeights) return;
99 
100   if (numWeights > 1)
101     {
102       std::vector<Addweight> addweights(numWeights);
103 
104       for (n = 0; n < numWeights; ++n)
105         {
106           addweights[n].add = src_add[n];
107           addweights[n].weight = weights[n];
108         }
109 
110       std::sort(addweights.begin(), addweights.end(), compareAdds);
111 
112       for (n = 0; n < numWeights; ++n)
113         {
114           src_add[n] = addweights[n].add;
115           weights[n] = addweights[n].weight;
116         }
117     }
118 }
119 
120 void
sort_weights_bicubic(size_t * src_add,double (& weights)[4][4])121 sort_weights_bicubic(size_t *src_add, double (&weights)[4][4])
122 {
123   constexpr size_t numWeights = 4;
124   size_t n;
125   for (n = 1; n < numWeights; ++n)
126     if (src_add[n] < src_add[n - 1]) break;
127   if (n == numWeights) return;
128 
129   std::array<Addweight4, numWeights> addweights;
130 
131   for (n = 0; n < numWeights; ++n)
132     {
133       addweights[n].add = src_add[n];
134       for (unsigned k = 0; k < 4; ++k) addweights[n].weight[k] = weights[n][k];
135     }
136 
137   std::sort(addweights.begin(), addweights.end(), compareAdds4);
138 
139   for (n = 0; n < numWeights; ++n)
140     {
141       src_add[n] = addweights[n].add;
142       for (unsigned k = 0; k < 4; ++k) weights[n][k] = addweights[n].weight[k];
143     }
144 }
145 
146 void
store_weightlinks(int lalloc,size_t numWeights,size_t * srch_add,double * weights,size_t cell_add,std::vector<WeightLinks> & weightLinks)147 store_weightlinks(int lalloc, size_t numWeights, size_t *srch_add, double *weights, size_t cell_add,
148                   std::vector<WeightLinks> &weightLinks)
149 {
150   weightLinks[cell_add].nlinks = 0;
151   weightLinks[cell_add].offset = 0;
152 
153   if (numWeights)
154     {
155       Addweight *addweights = nullptr;
156       if (lalloc)
157         addweights = (Addweight *) Malloc(numWeights * sizeof(Addweight));
158       else
159         addweights = weightLinks[cell_add].addweights;
160 
161       for (size_t n = 0; n < numWeights; ++n)
162         {
163           addweights[n].add = srch_add[n];
164           addweights[n].weight = weights[n];
165         }
166 
167       if (numWeights > 1) sortAddweights(numWeights, addweights);
168 
169       weightLinks[cell_add].nlinks = numWeights;
170 
171       if (lalloc) weightLinks[cell_add].addweights = addweights;
172     }
173 }
174 
175 void
store_weightlinks_bicubic(size_t * srch_add,double (& weights)[4][4],size_t cell_add,std::vector<WeightLinks4> & weightLinks)176 store_weightlinks_bicubic(size_t *srch_add, double (&weights)[4][4], size_t cell_add, std::vector<WeightLinks4> &weightLinks)
177 {
178   weightLinks[cell_add].nlinks = 0;
179   weightLinks[cell_add].offset = 0;
180 
181   Addweight4 *addweights = weightLinks[cell_add].addweights;
182 
183   for (unsigned n = 0; n < 4; ++n)
184     {
185       addweights[n].add = srch_add[n];
186       for (unsigned k = 0; k < 4; ++k) addweights[n].weight[k] = weights[n][k];
187     }
188 
189   sortAddweights4(addweights);
190 
191   weightLinks[cell_add].nlinks = 4;
192 }
193 
194 void
weight_links_to_remap_links(int lalloc,size_t gridSize,std::vector<WeightLinks> & weightLinks,RemapVars & rv)195 weight_links_to_remap_links(int lalloc, size_t gridSize, std::vector<WeightLinks> &weightLinks, RemapVars &rv)
196 {
197   size_t nlinks = 0;
198   for (size_t i = 0; i < gridSize; ++i)
199     {
200       if (weightLinks[i].nlinks)
201         {
202           weightLinks[i].offset = nlinks;
203           nlinks += weightLinks[i].nlinks;
204         }
205     }
206 
207   rv.max_links = nlinks;
208   rv.num_links = nlinks;
209 
210   if (nlinks)
211     {
212       auto num_wts = rv.num_wts;
213       rv.src_cell_add.resize(nlinks);
214       rv.tgt_cell_add.resize(nlinks);
215       rv.wts.resize(nlinks * num_wts);
216       auto &src_cell_adds = rv.src_cell_add;
217       auto &tgt_cell_adds = rv.tgt_cell_add;
218       auto &wts = rv.wts;
219 
220 #ifdef _OPENMP
221 #pragma omp parallel for schedule(static) default(none) shared(src_cell_adds, tgt_cell_adds, wts, weightLinks, gridSize, num_wts)
222 #endif
223       for (size_t i = 0; i < gridSize; ++i)
224         {
225           const auto num_links = weightLinks[i].nlinks;
226           if (num_links)
227             {
228               const auto offset = weightLinks[i].offset;
229               Addweight *addweights = weightLinks[i].addweights;
230               for (size_t ilink = 0; ilink < num_links; ++ilink)
231                 {
232                   src_cell_adds[offset + ilink] = addweights[ilink].add;
233                   tgt_cell_adds[offset + ilink] = i;
234                   wts[(offset + ilink) * num_wts] = addweights[ilink].weight;
235                 }
236             }
237         }
238 
239       if (lalloc)
240         {
241           for (size_t i = 0; i < gridSize; ++i)
242             {
243               const auto num_links = weightLinks[i].nlinks;
244               if (num_links) Free(weightLinks[i].addweights);
245             }
246         }
247       else
248         {
249           Free(weightLinks[0].addweights);
250         }
251     }
252 }
253 
254 void
weight_links_4_to_remap_links(size_t gridSize,std::vector<WeightLinks4> & weightLinks,RemapVars & rv)255 weight_links_4_to_remap_links(size_t gridSize, std::vector<WeightLinks4> &weightLinks, RemapVars &rv)
256 {
257   size_t nlinks = 0;
258   for (size_t i = 0; i < gridSize; ++i)
259     {
260       if (weightLinks[i].nlinks)
261         {
262           weightLinks[i].offset = nlinks;
263           nlinks += weightLinks[i].nlinks;
264         }
265     }
266 
267   rv.max_links = nlinks;
268   rv.num_links = nlinks;
269   if (nlinks)
270     {
271       rv.src_cell_add.resize(nlinks);
272       rv.tgt_cell_add.resize(nlinks);
273       rv.wts.resize(4 * nlinks);
274       auto &src_cell_adds = rv.src_cell_add;
275       auto &tgt_cell_adds = rv.tgt_cell_add;
276       auto &wts = rv.wts;
277 
278 #ifdef _OPENMP
279 #pragma omp parallel for default(none) shared(src_cell_adds, tgt_cell_adds, wts, weightLinks, gridSize)
280 #endif
281       for (size_t i = 0; i < gridSize; ++i)
282         {
283           const auto num_links = weightLinks[i].nlinks;
284           if (num_links)
285             {
286               const auto offset = weightLinks[i].offset;
287               const auto addweights = weightLinks[i].addweights;
288               for (size_t ilink = 0; ilink < num_links; ++ilink)
289                 {
290                   src_cell_adds[offset + ilink] = addweights[ilink].add;
291                   tgt_cell_adds[offset + ilink] = i;
292                   for (size_t k = 0; k < 4; ++k) wts[(offset + ilink) * 4 + k] = addweights[ilink].weight[k];
293                 }
294             }
295         }
296 
297       Free(weightLinks[0].addweights);
298     }
299 }
300 
301 void
weight_links_alloc(size_t numNeighbors,size_t gridSize,std::vector<WeightLinks> & weightLinks)302 weight_links_alloc(size_t numNeighbors, size_t gridSize, std::vector<WeightLinks> &weightLinks)
303 {
304   weightLinks[0].addweights = (Addweight *) Malloc(numNeighbors * gridSize * sizeof(Addweight));
305   for (size_t i = 1; i < gridSize; ++i) weightLinks[i].addweights = weightLinks[0].addweights + numNeighbors * i;
306 }
307 
308 void
weight_links_4_alloc(size_t gridSize,std::vector<WeightLinks4> & weightLinks)309 weight_links_4_alloc(size_t gridSize, std::vector<WeightLinks4> &weightLinks)
310 {
311   weightLinks[0].addweights = (Addweight4 *) Malloc(4 * gridSize * sizeof(Addweight4));
312   for (size_t i = 1; i < gridSize; ++i) weightLinks[i].addweights = weightLinks[0].addweights + 4 * i;
313 }
314