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> // sort
9
10 #include <cdi.h>
11
12 #include "cdo_rlimit.h"
13 #include "process_int.h"
14 #include "cdo_vlist.h"
15 #include "param_conversion.h"
16 #include <mpim_grid.h>
17 #include "util_files.h"
18 #include "cdo_options.h"
19 #include "cdi_lockedIO.h"
20
21 static int globalGridType = CDI_UNDEFID;
22
23 struct GridInfo2
24 {
25 int globalIndicesID;
26 bool needed;
27 };
28
29 struct CollgridInfo
30 {
31 CdoStreamID streamID;
32 int vlistID;
33 VarList varList;
34 Field field;
35 std::vector<std::vector<long>> cellIndex;
36 };
37
38 struct xyinfoType
39 {
40 double x = 0.0, y = 0.0;
41 int id = -1;
42 };
43
44 static bool
cmpx(const xyinfoType & a,const xyinfoType & b)45 cmpx(const xyinfoType &a, const xyinfoType &b)
46 {
47 return (a.x < b.x);
48 }
49
50 static bool
cmpxy_lt(const xyinfoType & a,const xyinfoType & b)51 cmpxy_lt(const xyinfoType &a, const xyinfoType &b)
52 {
53 return (a.y < b.y || (std::fabs(a.y - b.y) <= 0 && a.x < b.x));
54 }
55
56 static bool
cmpxy_gt(const xyinfoType & a,const xyinfoType & b)57 cmpxy_gt(const xyinfoType &a, const xyinfoType &b)
58 {
59 return (a.y > b.y || (std::fabs(a.y - b.y) <= 0 && a.x < b.x));
60 }
61
62 static int
gen_coll_grid(int ngrids,int nfiles,std::vector<CollgridInfo> & collgridInfo,int gindex,long nxblocks)63 gen_coll_grid(int ngrids, int nfiles, std::vector<CollgridInfo> &collgridInfo, int gindex, long nxblocks)
64 {
65 auto lsouthnorth = true;
66 auto lregular = false;
67 auto lcurvilinear = false;
68
69 long nx = (nxblocks != -1) ? nxblocks : -1;
70
71 auto gridID = vlistGrid(collgridInfo[0].vlistID, gindex);
72 const auto gridtype0 = (globalGridType != CDI_UNDEFID) ? globalGridType : gridInqType(gridID);
73 if (ngrids > 1 && gridtype0 == GRID_GENERIC && gridInqXsize(gridID) == 0 && gridInqYsize(gridID) == 0) return -1;
74
75 auto lunstructured = (gridtype0 == GRID_UNSTRUCTURED);
76 const auto nv = lunstructured ? gridInqNvertex(gridID) : 0;
77 const auto lcenter = (globalGridType == CDI_UNDEFID && gridHasCoordinates(gridID));
78 const auto lbounds = (lunstructured && globalGridType == CDI_UNDEFID && gridHasBounds(gridID));
79
80 std::vector<xyinfoType> xyinfo(nfiles);
81 std::vector<long> xsize(nfiles), ysize(nfiles);
82 Varray2D<double> xvals(nfiles), yvals(nfiles);
83 Varray2D<double> xbounds(nfiles), ybounds(nfiles);
84
85 for (int fileID = 0; fileID < nfiles; fileID++)
86 {
87 gridID = vlistGrid(collgridInfo[fileID].vlistID, gindex);
88 const auto gridtype = (globalGridType != CDI_UNDEFID) ? globalGridType : gridInqType(gridID);
89 if (gridtype == GRID_LONLAT || gridtype == GRID_GAUSSIAN || gridtype == GRID_PROJECTION)
90 lregular = true;
91 else if (gridtype == GRID_CURVILINEAR)
92 lcurvilinear = true;
93 else if (gridtype == GRID_UNSTRUCTURED)
94 lunstructured = true;
95 else if (gridtype == GRID_GENERIC /*&& gridInqXsize(gridID) > 0 && gridInqYsize(gridID) > 0*/)
96 ;
97 else
98 cdo_abort("Unsupported grid type: %s!", gridNamePtr(gridtype));
99
100 xsize[fileID] = lunstructured ? gridInqSize(gridID) : gridInqXsize(gridID);
101 ysize[fileID] = lunstructured ? 1 : gridInqYsize(gridID);
102 if (xsize[fileID] == 0) xsize[fileID] = 1;
103 if (ysize[fileID] == 0) ysize[fileID] = 1;
104
105 if (lregular)
106 {
107 xvals[fileID].resize(xsize[fileID]);
108 yvals[fileID].resize(ysize[fileID]);
109 }
110 else if (lcurvilinear || lunstructured)
111 {
112 if (lcenter) xvals[fileID].resize(xsize[fileID] * ysize[fileID]);
113 if (lcenter) yvals[fileID].resize(xsize[fileID] * ysize[fileID]);
114 if (lbounds) xbounds[fileID].resize(nv * xsize[fileID] * ysize[fileID]);
115 if (lbounds) ybounds[fileID].resize(nv * xsize[fileID] * ysize[fileID]);
116 }
117
118 if (lregular || lcurvilinear || lunstructured)
119 {
120 if (lcenter) gridInqXvals(gridID, xvals[fileID].data());
121 if (lcenter) gridInqYvals(gridID, yvals[fileID].data());
122 if (lbounds) gridInqXbounds(gridID, xbounds[fileID].data());
123 if (lbounds) gridInqYbounds(gridID, ybounds[fileID].data());
124 }
125 // printf("fileID %d, gridID %d\n", fileID, gridID);
126
127 xyinfo[fileID].id = fileID;
128 if (lregular)
129 {
130 xyinfo[fileID].x = xvals[fileID][0];
131 xyinfo[fileID].y = yvals[fileID][0];
132 if (ysize[fileID] > 1 && yvals[fileID][0] > yvals[fileID][ysize[fileID] - 1]) lsouthnorth = false;
133 }
134 }
135
136 if (Options::cdoVerbose && lregular)
137 for (int fileID = 0; fileID < nfiles; fileID++) printf("1 %d %g %g \n", xyinfo[fileID].id, xyinfo[fileID].x, xyinfo[fileID].y);
138
139 if (lregular)
140 {
141 std::sort(xyinfo.begin(), xyinfo.end(), cmpx);
142
143 if (Options::cdoVerbose)
144 for (int fileID = 0; fileID < nfiles; fileID++)
145 printf("2 %d %g %g \n", xyinfo[fileID].id, xyinfo[fileID].x, xyinfo[fileID].y);
146
147 auto cmpxy = lsouthnorth ? cmpxy_lt : cmpxy_gt;
148 std::sort(xyinfo.begin(), xyinfo.end(), cmpxy);
149
150 if (Options::cdoVerbose)
151 for (int fileID = 0; fileID < nfiles; fileID++)
152 printf("3 %d %g %g \n", xyinfo[fileID].id, xyinfo[fileID].x, xyinfo[fileID].y);
153
154 if (nx <= 0)
155 {
156 nx = 1;
157 for (int fileID = 1; fileID < nfiles; fileID++)
158 {
159 if (DBL_IS_EQUAL(xyinfo[0].y, xyinfo[fileID].y))
160 nx++;
161 else
162 break;
163 }
164 }
165 }
166 else
167 {
168 if (nx <= 0) nx = nfiles;
169 }
170
171 const long ny = nfiles / nx;
172 if (nx * ny != nfiles) cdo_abort("Number of input files (%ld) and number of blocks (%ldx%ld) differ!", nfiles, nx, ny);
173
174 long xsize2 = 0;
175 for (long i = 0; i < nx; ++i) xsize2 += xsize[xyinfo[i].id];
176 long ysize2 = 0;
177 for (long j = 0; j < ny; ++j) ysize2 += ysize[xyinfo[j * nx].id];
178 if (Options::cdoVerbose) cdo_print("xsize2 %ld ysize2 %ld", xsize2, ysize2);
179
180 { // verify size of data
181 const long xs = xsize[xyinfo[0].id];
182 for (long j = 1; j < ny; ++j)
183 if (xsize[xyinfo[j * nx].id] != xs) cdo_abort("xsize=%ld differ from first file (xsize=%ld)!", xsize[xyinfo[j * nx].id], xs);
184 const long ys = ysize[xyinfo[0].id];
185 for (long i = 1; i < nx; ++i)
186 if (ysize[xyinfo[i].id] != ys) cdo_abort("ysize=%ld differ from first file (ysize=%ld)!", ysize[xyinfo[i].id], ys);
187 }
188
189 Varray<double> xvals2, yvals2;
190 Varray<double> xbounds2, ybounds2;
191 if (lregular)
192 {
193 xvals2.resize(xsize2);
194 yvals2.resize(ysize2);
195 }
196 else if (lcurvilinear || lunstructured)
197 {
198 if (lcenter) xvals2.resize(xsize2 * ysize2);
199 if (lcenter) yvals2.resize(xsize2 * ysize2);
200 if (lbounds) xbounds2.resize(nv * xsize2 * ysize2);
201 if (lbounds) ybounds2.resize(nv * xsize2 * ysize2);
202 }
203
204 std::vector<long> xoff(nx + 1), yoff(ny + 1);
205
206 xoff[0] = 0;
207 for (long i = 0; i < nx; ++i)
208 {
209 const long idx = xyinfo[i].id;
210 if (lregular) array_copy(xsize[idx], xvals[idx].data(), &xvals2[xoff[i]]);
211 xoff[i + 1] = xoff[i] + xsize[idx];
212 }
213
214 yoff[0] = 0;
215 for (long j = 0; j < ny; ++j)
216 {
217 const long idx = xyinfo[j * nx].id;
218 if (lregular) array_copy(ysize[idx], yvals[idx].data(), &yvals2[yoff[j]]);
219 yoff[j + 1] = yoff[j] + ysize[idx];
220 }
221
222 for (int fileID = 0; fileID < nfiles; fileID++)
223 {
224 const long idx = xyinfo[fileID].id;
225 const long iy = fileID / nx;
226 const long ix = fileID - iy * nx;
227
228 const long offset = yoff[iy] * xsize2 + xoff[ix];
229 // printf("fileID %d %d, iy %d, ix %d, offset %d\n", fileID, xyinfo[fileID].id, iy, ix, offset);
230
231 long ij = 0;
232 for (long j = 0; j < ysize[idx]; ++j)
233 for (long i = 0; i < xsize[idx]; ++i)
234 {
235 if (lcurvilinear || lunstructured)
236 {
237 if (lcenter) xvals2[offset + j * xsize2 + i] = xvals[idx][ij];
238 if (lcenter) yvals2[offset + j * xsize2 + i] = yvals[idx][ij];
239 if (lbounds) for (long k = 0; k < nv; ++k) xbounds2[(offset + j * xsize2 + i) * nv + k] = xbounds[idx][ij * nv + k];
240 if (lbounds) for (long k = 0; k < nv; ++k) ybounds2[(offset + j * xsize2 + i) * nv + k] = ybounds[idx][ij * nv + k];
241 }
242 collgridInfo[idx].cellIndex[gindex][ij++] = offset + j * xsize2 + i;
243 }
244 }
245
246 const auto gridID2 = gridCreate(gridtype0, xsize2 * ysize2);
247 if (!lunstructured)
248 {
249 gridDefXsize(gridID2, xsize2);
250 gridDefYsize(gridID2, ysize2);
251 }
252 else if (nv > 0)
253 {
254 gridDefNvertex(gridID2, nv);
255 }
256
257 if (lregular || lcurvilinear || lunstructured)
258 {
259 if (lcenter) gridDefXvals(gridID2, xvals2.data());
260 if (lcenter) gridDefYvals(gridID2, yvals2.data());
261 if (lbounds) gridDefXbounds(gridID2, xbounds2.data());
262 if (lbounds) gridDefYbounds(gridID2, ybounds2.data());
263 }
264
265 gridID = vlistGrid(collgridInfo[0].vlistID, gindex);
266
267 grid_copy_keys(gridID, gridID2);
268
269 if (gridtype0 == GRID_PROJECTION) grid_copy_mapping(gridID, gridID2);
270
271 return gridID2;
272 }
273 /*
274 static void
275 coll_cells_reg2d(const Field &field1, Field &field2, const CollgridInfo &collgridInfo, size_t nlon)
276 {
277 const auto nx = collgridInfo.nx;
278 const auto ny = collgridInfo.ny;
279
280 for (size_t j = 0; j < ny; ++j)
281 {
282 const auto offset1 = j * nx;
283 const auto offset2 = collgridInfo.offset + j * nlon;
284
285 if (field1.memType == MemType::Float)
286 for (size_t i = 0; i < nx; ++i) field2.vec_f[offset2 + i] = field1.vec_f[offset1 + i];
287 else
288 for (size_t i = 0; i < nx; ++i) field2.vec_d[offset2 + i] = field1.vec_d[offset1 + i];
289 }
290 }
291 */
292 static void
collect_cells(const Field & field1,Field & field2,const std::vector<long> & cellIndex)293 collect_cells(const Field &field1, Field &field2, const std::vector<long> &cellIndex)
294 {
295 const auto patchSize = field1.size;
296
297 if (field1.memType == MemType::Float)
298 for (size_t i = 0; i < patchSize; ++i) field2.vec_f[cellIndex[i]] = field1.vec_f[i];
299 else
300 for (size_t i = 0; i < patchSize; ++i) field2.vec_d[cellIndex[i]] = field1.vec_d[i];
301 }
302
303 static std::vector<int>
get_var_gridindex(int vlistID)304 get_var_gridindex(int vlistID)
305 {
306 const auto nvars = vlistNvars(vlistID);
307 const auto ngrids = vlistNgrids(vlistID);
308
309 std::vector<int> varGridIndex(nvars, 0);
310 for (int varID = 0; varID < nvars; ++varID)
311 {
312 const auto gridID = vlistInqVarGrid(vlistID, varID);
313 for (int index = 0; index < ngrids; ++index)
314 {
315 if (gridID == vlistGrid(vlistID, index))
316 {
317 varGridIndex[varID] = index;
318 break;
319 }
320 }
321 }
322
323 return varGridIndex;
324 }
325
326 static std::vector<GridInfo2>
get_gridinfo(int vlistID,const VarList & varlist,const std::vector<int> & varGridIndex,std::vector<bool> & selectedVars)327 get_gridinfo(int vlistID, const VarList &varlist, const std::vector<int> &varGridIndex, std::vector<bool> &selectedVars)
328 {
329 const auto nvars = vlistNvars(vlistID);
330 const auto ngrids = vlistNgrids(vlistID);
331
332 std::vector<GridInfo2> gridInfo(ngrids);
333 for (int index = 0; index < ngrids; ++index)
334 {
335 gridInfo[index].globalIndicesID = -1;
336 gridInfo[index].needed = false;
337 }
338
339 int globalCellIndicesID = -1;
340 int globalVertIndicesID = -1;
341 int globalEdgeIndicesID = -1;
342 for (int varID = 0; varID < nvars; ++varID)
343 {
344 if (strcmp(varlist[varID].name, "global_cell_indices") == 0) globalCellIndicesID = varID;
345 else if (strcmp(varlist[varID].name, "global_vert_indices") == 0) globalVertIndicesID = varID;
346 else if (strcmp(varlist[varID].name, "global_edge_indices") == 0) globalEdgeIndicesID = varID;
347 }
348 if (globalCellIndicesID != -1) selectedVars[globalCellIndicesID] = false;
349 if (globalVertIndicesID != -1) selectedVars[globalVertIndicesID] = false;
350 if (globalEdgeIndicesID != -1) selectedVars[globalEdgeIndicesID] = false;
351
352 if (globalCellIndicesID != -1) gridInfo[varGridIndex[globalCellIndicesID]].globalIndicesID = globalCellIndicesID;
353 if (globalVertIndicesID != -1) gridInfo[varGridIndex[globalVertIndicesID]].globalIndicesID = globalVertIndicesID;
354 if (globalEdgeIndicesID != -1) gridInfo[varGridIndex[globalEdgeIndicesID]].globalIndicesID = globalEdgeIndicesID;
355
356 for (int varID = 0; varID < nvars; ++varID)
357 if (selectedVars[varID]) gridInfo[varGridIndex[varID]].needed = true;
358
359 return gridInfo;
360 }
361
362 static std::vector<bool>
get_selected_vars(int nsel,int noff,int vlistID1,const VarList & varList1)363 get_selected_vars(int nsel, int noff, int vlistID1, const VarList &varList1)
364 {
365 const auto nvars = vlistNvars(vlistID1);
366 std::vector<bool> selectedVars(nvars, false);
367 if (nsel == 0)
368 {
369 for (int varID = 0; varID < nvars; varID++) selectedVars[varID] = true;
370 }
371 else
372 {
373 if (Options::cdoVerbose)
374 for (int i = 0; i < nsel; i++) cdo_print("name %d = %s", i + 1, cdo_operator_argv(noff + i).c_str());
375
376 std::vector<bool> selfound(nsel);
377 for (int i = 0; i < nsel; i++) selfound[i] = false;
378
379 for (int varID = 0; varID < nvars; varID++)
380 {
381 for (int isel = 0; isel < nsel; isel++)
382 {
383 if (cdo_operator_argv(noff + isel) == varList1[varID].name)
384 {
385 selfound[isel] = true;
386 selectedVars[varID] = true;
387 }
388 }
389 }
390
391 int err = 0;
392 for (int isel = 0; isel < nsel; isel++)
393 {
394 if (selfound[isel] == false)
395 {
396 err++;
397 cdo_warning("Variable name %s not found!", cdo_operator_argv(noff + isel).c_str());
398 }
399 }
400 if (err) cdo_abort("Could not find all requested variables: (%d/%d)", nsel - err, nsel);
401 }
402
403 return selectedVars;
404 }
405
406 static void
select_vars(const std::vector<bool> & selectedVars,int vlistID1,const VarList & varList1)407 select_vars(const std::vector<bool> &selectedVars, int vlistID1, const VarList &varList1)
408 {
409 const auto nvars = vlistNvars(vlistID1);
410 int numVars = 0;
411
412 for (int varID = 0; varID < nvars; varID++)
413 {
414 if (selectedVars[varID])
415 {
416 numVars++;
417 const auto nlevels = varList1[varID].nlevels;
418 for (int levID = 0; levID < nlevels; levID++) vlistDefFlag(vlistID1, varID, levID, true);
419 }
420 }
421
422 if (numVars == 0) cdo_abort("No variables selected!");
423 }
424
425 void *
Collgrid(void * process)426 Collgrid(void *process)
427 {
428 int nxblocks = -1;
429
430 cdo_initialize(process);
431
432 const auto nfiles = cdo_stream_cnt() - 1;
433 const auto ofilename = cdo_get_stream_name(nfiles);
434
435 if (!Options::cdoOverwriteMode && FileUtils::file_exists(ofilename) && !FileUtils::user_file_overwrite(ofilename))
436 cdo_abort("Outputfile %s already exists!", ofilename);
437
438 std::vector<CollgridInfo> collgridInfo(nfiles);
439
440 cdo::set_numfiles(nfiles + 8);
441
442 for (int fileID = 0; fileID < nfiles; fileID++)
443 {
444 const auto streamID = cdo_open_read(fileID);
445 const auto vlistID = cdo_stream_inq_vlist(streamID);
446 collgridInfo[fileID].streamID = streamID;
447 collgridInfo[fileID].vlistID = vlistID;
448 varListInit(collgridInfo[fileID].varList, vlistID);
449 }
450
451 const auto &varList1 = collgridInfo[0].varList;
452 const auto vlistID1 = collgridInfo[0].vlistID;
453 vlistClearFlag(vlistID1);
454
455 // check that the contents is always the same
456 for (int fileID = 1; fileID < nfiles; fileID++) vlist_compare(vlistID1, collgridInfo[fileID].vlistID, CMP_NAME | CMP_NLEVEL);
457
458 auto nsel = cdo_operator_argc();
459 int noff = 0;
460
461 if (nsel > 0)
462 {
463 auto argument = cdo_operator_argv(0).c_str();
464 if (strcmp(argument, "gridtype=unstructured") == 0)
465 {
466 nsel--;
467 noff++;
468 globalGridType = GRID_UNSTRUCTURED;
469 }
470 else
471 {
472 auto len = (int) strlen(argument);
473 while (--len >= 0 && isdigit(argument[len]))
474 ;
475
476 if (len == -1)
477 {
478 nsel--;
479 noff++;
480 nxblocks = parameter_to_int(argument);
481 }
482 }
483 }
484
485 auto selectedVars = get_selected_vars(nsel, noff, vlistID1, varList1);
486 const auto varGridIndex = get_var_gridindex(vlistID1);
487 const auto gridInfo = get_gridinfo(vlistID1, varList1, varGridIndex, selectedVars);
488 select_vars(selectedVars, vlistID1, varList1);
489
490 const auto vlistID2 = vlistCreate();
491 cdo_vlist_copy_flag(vlistID2, vlistID1);
492 vlistDefNtsteps(vlistID2, vlistNtsteps(vlistID1));
493
494 const auto taxisID1 = vlistInqTaxis(vlistID1);
495 const auto taxisID2 = taxisDuplicate(taxisID1);
496 vlistDefTaxis(vlistID2, taxisID2);
497
498 // if ( Options::cdoVerbose ) vlistPrint(vlistID1);
499 // if ( Options::cdoVerbose ) vlistPrint(vlistID2);
500
501 const auto ngrids1 = vlistNgrids(vlistID1);
502 const auto ngrids2 = vlistNgrids(vlistID2);
503
504 for (int fileID = 0; fileID < nfiles; fileID++)
505 {
506 collgridInfo[fileID].cellIndex.resize(ngrids1);
507 for (int gindex = 0; gindex < ngrids1; ++gindex)
508 {
509 if (gridInfo[gindex].needed)
510 {
511 const auto patchSize = gridInqSize(vlistGrid(collgridInfo[fileID].vlistID, gindex));
512 collgridInfo[fileID].cellIndex[gindex].resize(patchSize);
513 }
514 }
515 }
516
517 std::vector<int> gridID2s(ngrids2);
518
519 for (int i2 = 0; i2 < ngrids2; ++i2)
520 {
521 int i1;
522 for (i1 = 0; i1 < ngrids1; ++i1)
523 if (vlistGrid(vlistID1, i1) == vlistGrid(vlistID2, i2)) break;
524
525 gridID2s[i2] = gen_coll_grid(ngrids2, nfiles, collgridInfo, i1, nxblocks);
526 }
527
528 for (int i = 0; i < ngrids2; ++i)
529 {
530 if (gridID2s[i] != -1) vlistChangeGridIndex(vlistID2, i, gridID2s[i]);
531 }
532
533 VarList varList2;
534 varListInit(varList2, vlistID2);
535
536 const auto nvars2 = vlistNvars(vlistID2);
537 std::vector<bool> collectVars2(nvars2, false);
538 for (int varID = 0; varID < nvars2; varID++)
539 {
540 const auto gridID = varList2[varID].gridID;
541 for (int i = 0; i < ngrids2; ++i)
542 {
543 if (gridID2s[i] != -1 && gridID == vlistGrid(vlistID2, i))
544 {
545 collectVars2[varID] = true;
546 break;
547 }
548 }
549 }
550
551 const auto streamID2 = cdo_open_write(nfiles);
552 cdo_def_vlist(streamID2, vlistID2);
553
554 Field field2;
555
556 int nrecs0 = 0;
557 int tsID = 0;
558 do
559 {
560 nrecs0 = cdo_stream_inq_timestep(collgridInfo[0].streamID, tsID);
561 for (int fileID = 1; fileID < nfiles; fileID++)
562 {
563 const auto nrecs = cdo_stream_inq_timestep(collgridInfo[fileID].streamID, tsID);
564 if (nrecs != nrecs0)
565 cdo_abort("Number of records at time step %d of %s and %s differ!", tsID + 1, cdo_get_stream_name(0),
566 cdo_get_stream_name(fileID));
567 }
568
569 cdo_taxis_copy_timestep(taxisID2, taxisID1);
570
571 if (nrecs0 > 0) cdo_def_timestep(streamID2, tsID);
572
573 for (int recID = 0; recID < nrecs0; recID++)
574 {
575 int varID = 0, levelID = 0;
576 for (int fileID = nfiles - 1; fileID >= 0; fileID--)
577 cdo_inq_record(collgridInfo[fileID].streamID, &varID, &levelID);
578
579 // if (Options::cdoVerbose && tsID == 0) printf(" tsID, recID, varID, levelID %d %d %d %d\n", tsID, recID, varID, levelID);
580
581 const auto gindex = varGridIndex[varID];
582 if (gridInfo[gindex].needed && gridInfo[gindex].globalIndicesID == varID)
583 {
584 Varray<double> cellIndex;
585 for (int fileID = 0; fileID < nfiles; fileID++)
586 {
587 const auto patchSize = collgridInfo[fileID].varList[varID].gridsize;
588 if (cellIndex.size() < patchSize) cellIndex.resize(patchSize);
589 size_t nmiss;
590 cdo_read_record(collgridInfo[fileID].streamID, cellIndex.data(), &nmiss);
591 for (size_t i = 0; i < patchSize; ++i)
592 collgridInfo[fileID].cellIndex[gindex][i] = std::lround(cellIndex[i]) - 1;
593 }
594 }
595
596 if (vlistInqFlag(vlistID1, varID, levelID) == true)
597 {
598 const auto varID2 = vlistFindVar(vlistID2, varID);
599 const auto levelID2 = vlistFindLevel(vlistID2, varID, levelID);
600 //if (Options::cdoVerbose && tsID == 0) printf("varID %d %d levelID %d %d\n", varID, varID2, levelID, levelID2);
601
602 field2.init(varList2[varID2]);
603
604 const auto gridsize = field2.size;
605 const auto missval = field2.missval;
606 if (field2.memType == MemType::Float)
607 for (size_t i = 0; i < gridsize; i++) field2.vec_f[i] = missval;
608 else
609 for (size_t i = 0; i < gridsize; i++) field2.vec_d[i] = missval;
610
611 #ifdef _OPENMP
612 #pragma omp parallel for default(shared)
613 #endif
614 for (int fileID = 0; fileID < nfiles; fileID++)
615 {
616 auto &field1 = collgridInfo[fileID].field;
617 field1.init(collgridInfo[fileID].varList[varID]);
618 cdo_read_record(collgridInfo[fileID].streamID, field1);
619
620 if (collectVars2[varID2]) collect_cells(field1, field2, collgridInfo[fileID].cellIndex[gindex]);
621 }
622
623 cdo_def_record(streamID2, varID2, levelID2);
624
625 if (collectVars2[varID2])
626 {
627 field_num_mv(field2);
628 cdo_write_record(streamID2, field2);
629 }
630 else
631 {
632 cdo_write_record(streamID2, collgridInfo[0].field);
633 }
634 }
635 }
636
637 tsID++;
638 }
639 while (nrecs0 > 0);
640
641 for (int fileID = 0; fileID < nfiles; fileID++) cdo_stream_close(collgridInfo[fileID].streamID);
642
643 cdo_stream_close(streamID2);
644
645 cdo_finish();
646
647 return nullptr;
648 }
649