1 #include "NCHelperHOMME.hpp"
2 #include "moab/ReadUtilIface.hpp"
3 #include "moab/FileOptions.hpp"
4 #include "moab/SpectralMeshTool.hpp"
5
6 #include <cmath>
7
8 namespace moab {
9
NCHelperHOMME(ReadNC * readNC,int fileId,const FileOptions & opts,EntityHandle fileSet)10 NCHelperHOMME::NCHelperHOMME(ReadNC* readNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
11 : UcdNCHelper(readNC, fileId, opts, fileSet),
12 _spectralOrder(-1), connectId(-1), isConnFile(false)
13 {
14 // Calculate spectral order
15 std::map<std::string, ReadNC::AttData>::iterator attIt = readNC->globalAtts.find("np");
16 if (attIt != readNC->globalAtts.end()) {
17 int success = NCFUNC(get_att_int)(readNC->fileId, attIt->second.attVarId, attIt->second.attName.c_str(), &_spectralOrder);
18 if (0 == success)
19 _spectralOrder--; // Spectral order is one less than np
20 }
21 else {
22 // As can_read_file() returns true and there is no global attribute "np", it should be a connectivity file
23 isConnFile = true;
24 _spectralOrder = 3; // Assume np is 4
25 }
26 }
27
can_read_file(ReadNC * readNC,int fileId)28 bool NCHelperHOMME::can_read_file(ReadNC* readNC, int fileId)
29 {
30 // If global attribute "np" exists then it should be the HOMME grid
31 if (readNC->globalAtts.find("np") != readNC->globalAtts.end()) {
32 // Make sure it is CAM grid
33 std::map<std::string, ReadNC::AttData>::iterator attIt = readNC->globalAtts.find("source");
34 if (attIt == readNC->globalAtts.end())
35 return false;
36 unsigned int sz = attIt->second.attLen;
37 std::string att_data;
38 att_data.resize(sz + 1);
39 att_data[sz] = '\000';
40 int success = NCFUNC(get_att_text)(fileId, attIt->second.attVarId, attIt->second.attName.c_str(), &att_data[0]);
41 if (success)
42 return false;
43 if (att_data.find("CAM") == std::string::npos)
44 return false;
45
46 return true;
47 }
48 else {
49 // If dimension names "ncol" AND "ncorners" AND "ncells" exist, then it should be the HOMME connectivity file
50 // In this case, the mesh can still be created
51 std::vector<std::string>& dimNames = readNC->dimNames;
52 if ((std::find(dimNames.begin(), dimNames.end(), std::string("ncol")) != dimNames.end()) &&
53 (std::find(dimNames.begin(), dimNames.end(), std::string("ncorners")) != dimNames.end()) &&
54 (std::find(dimNames.begin(), dimNames.end(), std::string("ncells")) != dimNames.end()))
55 return true;
56 }
57
58 return false;
59 }
60
init_mesh_vals()61 ErrorCode NCHelperHOMME::init_mesh_vals()
62 {
63 std::vector<std::string>& dimNames = _readNC->dimNames;
64 std::vector<int>& dimLens = _readNC->dimLens;
65 std::map<std::string, ReadNC::VarData>& varInfo = _readNC->varInfo;
66
67 ErrorCode rval;
68 unsigned int idx;
69 std::vector<std::string>::iterator vit;
70
71 // Look for time dimension
72 if (isConnFile) {
73 // Connectivity file might not have time dimension
74 }
75 else {
76 if ((vit = std::find(dimNames.begin(), dimNames.end(), "time")) != dimNames.end())
77 idx = vit - dimNames.begin();
78 else if ((vit = std::find(dimNames.begin(), dimNames.end(), "t")) != dimNames.end())
79 idx = vit - dimNames.begin();
80 else {
81 MB_SET_ERR(MB_FAILURE, "Couldn't find 'time' or 't' dimension");
82 }
83 tDim = idx;
84 nTimeSteps = dimLens[idx];
85 }
86
87 // Get number of vertices (labeled as number of columns)
88 if ((vit = std::find(dimNames.begin(), dimNames.end(), "ncol")) != dimNames.end())
89 idx = vit - dimNames.begin();
90 else {
91 MB_SET_ERR(MB_FAILURE, "Couldn't find 'ncol' dimension");
92 }
93 vDim = idx;
94 nVertices = dimLens[idx];
95
96 // Set number of cells
97 nCells = nVertices - 2;
98
99 // Get number of levels
100 if (isConnFile) {
101 // Connectivity file might not have level dimension
102 }
103 else {
104 if ((vit = std::find(dimNames.begin(), dimNames.end(), "lev")) != dimNames.end())
105 idx = vit - dimNames.begin();
106 else if ((vit = std::find(dimNames.begin(), dimNames.end(), "ilev")) != dimNames.end())
107 idx = vit - dimNames.begin();
108 else {
109 MB_SET_ERR(MB_FAILURE, "Couldn't find 'lev' or 'ilev' dimension");
110 }
111 levDim = idx;
112 nLevels = dimLens[idx];
113 }
114
115 // Store lon values in xVertVals
116 std::map<std::string, ReadNC::VarData>::iterator vmit;
117 if ((vmit = varInfo.find("lon")) != varInfo.end() && (*vmit).second.varDims.size() == 1) {
118 rval = read_coordinate("lon", 0, nVertices - 1, xVertVals);MB_CHK_SET_ERR(rval, "Trouble reading 'lon' variable");
119 }
120 else {
121 MB_SET_ERR(MB_FAILURE, "Couldn't find 'lon' variable");
122 }
123
124 // Store lat values in yVertVals
125 if ((vmit = varInfo.find("lat")) != varInfo.end() && (*vmit).second.varDims.size() == 1) {
126 rval = read_coordinate("lat", 0, nVertices - 1, yVertVals);MB_CHK_SET_ERR(rval, "Trouble reading 'lat' variable");
127 }
128 else {
129 MB_SET_ERR(MB_FAILURE, "Couldn't find 'lat' variable");
130 }
131
132 // Store lev values in levVals
133 if (isConnFile) {
134 // Connectivity file might not have level variable
135 }
136 else {
137 if ((vmit = varInfo.find("lev")) != varInfo.end() && (*vmit).second.varDims.size() == 1) {
138 rval = read_coordinate("lev", 0, nLevels - 1, levVals);MB_CHK_SET_ERR(rval, "Trouble reading 'lev' variable");
139
140 // Decide whether down is positive
141 char posval[10] = {0};
142 int success = NCFUNC(get_att_text)(_fileId, (*vmit).second.varId, "positive", posval);
143 if (0 == success && !strcmp(posval, "down")) {
144 for (std::vector<double>::iterator dvit = levVals.begin(); dvit != levVals.end(); ++dvit)
145 (*dvit) *= -1.0;
146 }
147 }
148 else {
149 MB_SET_ERR(MB_FAILURE, "Couldn't find 'lev' variable");
150 }
151 }
152
153 // Store time coordinate values in tVals
154 if (isConnFile) {
155 // Connectivity file might not have time variable
156 }
157 else {
158 if ((vmit = varInfo.find("time")) != varInfo.end() && (*vmit).second.varDims.size() == 1) {
159 rval = read_coordinate("time", 0, nTimeSteps - 1, tVals);MB_CHK_SET_ERR(rval, "Trouble reading 'time' variable");
160 }
161 else if ((vmit = varInfo.find("t")) != varInfo.end() && (*vmit).second.varDims.size() == 1) {
162 rval = read_coordinate("t", 0, nTimeSteps - 1, tVals);MB_CHK_SET_ERR(rval, "Trouble reading 't' variable");
163 }
164 else {
165 // If expected time variable does not exist, set dummy values to tVals
166 for (int t = 0; t < nTimeSteps; t++)
167 tVals.push_back((double)t);
168 }
169 }
170
171 // For each variable, determine the entity location type and number of levels
172 std::map<std::string, ReadNC::VarData>::iterator mit;
173 for (mit = varInfo.begin(); mit != varInfo.end(); ++mit) {
174 ReadNC::VarData& vd = (*mit).second;
175
176 // Default entLoc is ENTLOCSET
177 if (std::find(vd.varDims.begin(), vd.varDims.end(), tDim) != vd.varDims.end()) {
178 if (std::find(vd.varDims.begin(), vd.varDims.end(), vDim) != vd.varDims.end())
179 vd.entLoc = ReadNC::ENTLOCVERT;
180 }
181
182 // Default numLev is 0
183 if (std::find(vd.varDims.begin(), vd.varDims.end(), levDim) != vd.varDims.end())
184 vd.numLev = nLevels;
185 }
186
187 // Hack: create dummy variables for dimensions (like ncol) with no corresponding coordinate variables
188 rval = create_dummy_variables();MB_CHK_SET_ERR(rval, "Failed to create dummy variables");
189
190 return MB_SUCCESS;
191 }
192
193 // When noMesh option is used on this read, the old ReadNC class instance for last read can get out
194 // of scope (and deleted). The old instance initialized localGidVerts properly when the mesh was
195 // created, but it is now lost. The new instance (will not create the mesh with noMesh option) has
196 // to restore it based on the existing mesh from last read
check_existing_mesh()197 ErrorCode NCHelperHOMME::check_existing_mesh()
198 {
199 Interface*& mbImpl = _readNC->mbImpl;
200 Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
201 bool& noMesh = _readNC->noMesh;
202
203 if (noMesh && localGidVerts.empty()) {
204 // We need to populate localGidVerts range with the gids of vertices from current file set
205 // localGidVerts is important in reading the variable data into the nodes
206 // Also, for our purposes, localGidVerts is truly the GLOBAL_ID tag data, not other
207 // file_id tags that could get passed around in other scenarios for parallel reading
208
209 // Get all vertices from current file set (it is the input set in no_mesh scenario)
210 Range local_verts;
211 ErrorCode rval = mbImpl->get_entities_by_dimension(_fileSet, 0, local_verts);MB_CHK_SET_ERR(rval, "Trouble getting local vertices in current file set");
212
213 if (!local_verts.empty()) {
214 std::vector<int> gids(local_verts.size());
215
216 // !IMPORTANT : this has to be the GLOBAL_ID tag
217 rval = mbImpl->tag_get_data(mGlobalIdTag, local_verts, &gids[0]);MB_CHK_SET_ERR(rval, "Trouble getting local gid values of vertices");
218
219 // Restore localGidVerts
220 std::copy(gids.rbegin(), gids.rend(), range_inserter(localGidVerts));
221 nLocalVertices = localGidVerts.size();
222 }
223 }
224
225 return MB_SUCCESS;
226 }
227
create_mesh(Range & faces)228 ErrorCode NCHelperHOMME::create_mesh(Range& faces)
229 {
230 Interface*& mbImpl = _readNC->mbImpl;
231 std::string& fileName = _readNC->fileName;
232 Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
233 const Tag*& mpFileIdTag = _readNC->mpFileIdTag;
234 DebugOutput& dbgOut = _readNC->dbgOut;
235 bool& spectralMesh = _readNC->spectralMesh;
236 int& gatherSetRank = _readNC->gatherSetRank;
237 int& trivialPartitionShift = _readNC->trivialPartitionShift;
238
239 int rank = 0;
240 int procs = 1;
241 #ifdef MOAB_HAVE_MPI
242 bool& isParallel = _readNC->isParallel;
243 if (isParallel) {
244 ParallelComm*& myPcomm = _readNC->myPcomm;
245 rank = myPcomm->proc_config().proc_rank();
246 procs = myPcomm->proc_config().proc_size();
247 }
248 #endif
249
250 ErrorCode rval;
251 int success = 0;
252
253 // Need to get/read connectivity data before creating elements
254 std::string conn_fname;
255
256 if (isConnFile) {
257 // Connectivity file has already been read
258 connectId = _readNC->fileId;
259 }
260 else {
261 // Try to open the connectivity file through CONN option, if used
262 rval = _opts.get_str_option("CONN", conn_fname);
263 if (MB_SUCCESS != rval) {
264 // Default convention for reading HOMME is a file HommeMapping.nc in same dir as data file
265 conn_fname = std::string(fileName);
266 size_t idx = conn_fname.find_last_of("/");
267 if (idx != std::string::npos)
268 conn_fname = conn_fname.substr(0, idx).append("/HommeMapping.nc");
269 else
270 conn_fname = "HommeMapping.nc";
271 }
272 #ifdef MOAB_HAVE_PNETCDF
273 #ifdef MOAB_HAVE_MPI
274 if (isParallel) {
275 ParallelComm*& myPcomm = _readNC->myPcomm;
276 success = NCFUNC(open)(myPcomm->proc_config().proc_comm(), conn_fname.c_str(), 0, MPI_INFO_NULL, &connectId);
277 }
278 else
279 success = NCFUNC(open)(MPI_COMM_SELF, conn_fname.c_str(), 0, MPI_INFO_NULL, &connectId);
280 #endif
281 #else
282 success = NCFUNC(open)(conn_fname.c_str(), 0, &connectId);
283 #endif
284 if (success)
285 MB_SET_ERR(MB_FAILURE, "Failed on open");
286 }
287
288 std::vector<std::string> conn_names;
289 std::vector<int> conn_vals;
290 rval = _readNC->get_dimensions(connectId, conn_names, conn_vals);MB_CHK_SET_ERR(rval, "Failed to get dimensions for connectivity");
291
292 // Read connectivity into temporary variable
293 int num_fine_quads = 0;
294 int num_coarse_quads = 0;
295 int start_idx = 0;
296 std::vector<std::string>::iterator vit;
297 int idx = 0;
298 if ((vit = std::find(conn_names.begin(), conn_names.end(), "ncells")) != conn_names.end())
299 idx = vit - conn_names.begin();
300 else if ((vit = std::find(conn_names.begin(), conn_names.end(), "ncenters")) != conn_names.end())
301 idx = vit - conn_names.begin();
302 else {
303 MB_SET_ERR(MB_FAILURE, "Failed to get number of quads");
304 }
305 int num_quads = conn_vals[idx];
306 if (!isConnFile && num_quads != nCells) {
307 dbgOut.tprintf(1, "Warning: number of quads from %s and cells from %s are inconsistent; num_quads = %d, nCells = %d.\n",
308 conn_fname.c_str(), fileName.c_str(), num_quads, nCells);
309 }
310
311 // Get the connectivity into tmp_conn2 and permute into tmp_conn
312 int cornerVarId;
313 success = NCFUNC(inq_varid)(connectId, "element_corners", &cornerVarId);
314 if (success)
315 MB_SET_ERR(MB_FAILURE, "Failed to get variable id of 'element_corners'");
316 NCDF_SIZE tmp_starts[2] = {0, 0};
317 NCDF_SIZE tmp_counts[2] = {4, static_cast<NCDF_SIZE>(num_quads)};
318 std::vector<int> tmp_conn(4 * num_quads), tmp_conn2(4 * num_quads);
319 success = NCFUNCAG(_vara_int)(connectId, cornerVarId, tmp_starts, tmp_counts, &tmp_conn2[0]);
320 if (success)
321 MB_SET_ERR(MB_FAILURE, "Failed to get temporary connectivity");
322 if (isConnFile) {
323 // This data/connectivity file will be closed later in ReadNC::load_file()
324 }
325 else {
326 success = NCFUNC(close)(connectId);
327 if (success)
328 MB_SET_ERR(MB_FAILURE, "Failed on close");
329 }
330 // Permute the connectivity
331 for (int i = 0; i < num_quads; i++) {
332 tmp_conn[4 * i] = tmp_conn2[i];
333 tmp_conn[4 * i + 1] = tmp_conn2[i + 1 * num_quads];
334 tmp_conn[4 * i + 2] = tmp_conn2[i + 2 * num_quads];
335 tmp_conn[4 * i + 3] = tmp_conn2[i + 3 * num_quads];
336 }
337
338 // Need to know whether we'll be creating gather mesh later, to make sure
339 // we allocate enough space in one shot
340 bool create_gathers = false;
341 if (rank == gatherSetRank)
342 create_gathers = true;
343
344 // Shift rank to obtain a rotated trivial partition
345 int shifted_rank = rank;
346 if (procs >= 2 && trivialPartitionShift > 0)
347 shifted_rank = (rank + trivialPartitionShift) % procs;
348
349 // Compute the number of local quads, accounting for coarse or fine representation
350 // spectral_unit is the # fine quads per coarse quad, or spectralOrder^2
351 int spectral_unit = (spectralMesh ? _spectralOrder * _spectralOrder : 1);
352 // num_coarse_quads is the number of quads instantiated in MOAB; if !spectralMesh, num_coarse_quads = num_fine_quads
353 num_coarse_quads = int(std::floor(1.0 * num_quads / (spectral_unit * procs)));
354 // start_idx is the starting index in the HommeMapping connectivity list for this proc, before converting to coarse quad representation
355 start_idx = 4 * shifted_rank * num_coarse_quads * spectral_unit;
356 // iextra = # coarse quads extra after equal split over procs
357 int iextra = num_quads % (procs * spectral_unit);
358 if (shifted_rank < iextra)
359 num_coarse_quads++;
360 start_idx += 4 * spectral_unit * std::min(shifted_rank, iextra);
361 // num_fine_quads is the number of quads in the connectivity list in HommeMapping file assigned to this proc
362 num_fine_quads = spectral_unit * num_coarse_quads;
363
364 // Now create num_coarse_quads
365 EntityHandle* conn_arr;
366 EntityHandle start_vertex;
367 Range tmp_range;
368
369 // Read connectivity into that space
370 EntityHandle* sv_ptr = NULL;
371 EntityHandle start_quad;
372 SpectralMeshTool smt(mbImpl, _spectralOrder);
373 if (!spectralMesh) {
374 rval = _readNC->readMeshIface->get_element_connect(num_coarse_quads, 4,
375 MBQUAD, 0, start_quad, conn_arr,
376 // Might have to create gather mesh later
377 (create_gathers ? num_coarse_quads + num_quads : num_coarse_quads));MB_CHK_SET_ERR(rval, "Failed to create local quads");
378 tmp_range.insert(start_quad, start_quad + num_coarse_quads - 1);
379 int* tmp_conn_end = (&tmp_conn[start_idx + 4 * num_fine_quads-1])+1;
380 std::copy(&tmp_conn[start_idx], tmp_conn_end, conn_arr);
381 std::copy(conn_arr, conn_arr + 4 * num_fine_quads, range_inserter(localGidVerts));
382 }
383 else {
384 rval = smt.create_spectral_elems(&tmp_conn[0], num_fine_quads, 2, tmp_range, start_idx, &localGidVerts);MB_CHK_SET_ERR(rval, "Failed to create spectral elements");
385 int count, v_per_e;
386 rval = mbImpl->connect_iterate(tmp_range.begin(), tmp_range.end(), conn_arr, v_per_e, count);MB_CHK_SET_ERR(rval, "Failed to get connectivity of spectral elements");
387 rval = mbImpl->tag_iterate(smt.spectral_vertices_tag(true), tmp_range.begin(), tmp_range.end(),
388 count, (void*&)sv_ptr);MB_CHK_SET_ERR(rval, "Failed to get fine connectivity of spectral elements");
389 }
390
391 // Create vertices
392 nLocalVertices = localGidVerts.size();
393 std::vector<double*> arrays;
394 rval = _readNC->readMeshIface->get_node_coords(3, nLocalVertices, 0, start_vertex, arrays,
395 // Might have to create gather mesh later
396 (create_gathers ? nLocalVertices + nVertices : nLocalVertices));MB_CHK_SET_ERR(rval, "Failed to create local vertices");
397
398 // Set vertex coordinates
399 Range::iterator rit;
400 double* xptr = arrays[0];
401 double* yptr = arrays[1];
402 double* zptr = arrays[2];
403 int i;
404 for (i = 0, rit = localGidVerts.begin(); i < nLocalVertices; i++, ++rit) {
405 assert(*rit < xVertVals.size() + 1);
406 xptr[i] = xVertVals[(*rit) - 1]; // lon
407 yptr[i] = yVertVals[(*rit) - 1]; // lat
408 }
409
410 // Convert lon/lat/rad to x/y/z
411 const double pideg = acos(-1.0) / 180.0;
412 double rad = (isConnFile) ? 8000.0 : 8000.0 + levVals[0];
413 for (i = 0; i < nLocalVertices; i++) {
414 double cosphi = cos(pideg * yptr[i]);
415 double zmult = sin(pideg * yptr[i]);
416 double xmult = cosphi * cos(xptr[i] * pideg);
417 double ymult = cosphi * sin(xptr[i] * pideg);
418 xptr[i] = rad * xmult;
419 yptr[i] = rad * ymult;
420 zptr[i] = rad * zmult;
421 }
422
423 // Get ptr to gid memory for vertices
424 Range vert_range(start_vertex, start_vertex + nLocalVertices - 1);
425 void* data;
426 int count;
427 rval = mbImpl->tag_iterate(mGlobalIdTag, vert_range.begin(), vert_range.end(),
428 count, data);MB_CHK_SET_ERR(rval, "Failed to iterate global id tag on local vertices");
429 assert(count == nLocalVertices);
430 int* gid_data = (int*) data;
431 std::copy(localGidVerts.begin(), localGidVerts.end(), gid_data);
432
433 // Duplicate global id data, which will be used to resolve sharing
434 if (mpFileIdTag) {
435 rval = mbImpl->tag_iterate(*mpFileIdTag, vert_range.begin(), vert_range.end(),
436 count, data);MB_CHK_SET_ERR(rval, "Failed to iterate file id tag on local vertices");
437 assert(count == nLocalVertices);
438 int bytes_per_tag = 4;
439 rval = mbImpl->tag_get_bytes(*mpFileIdTag, bytes_per_tag);MB_CHK_SET_ERR(rval, "Can't get number of bytes for file id tag");
440 if (4 == bytes_per_tag) {
441 gid_data = (int*) data;
442 std::copy(localGidVerts.begin(), localGidVerts.end(), gid_data);
443 }
444 else if (8 == bytes_per_tag) { // Should be a handle tag on 64 bit machine?
445 long* handle_tag_data = (long*)data;
446 std::copy(localGidVerts.begin(), localGidVerts.end(), handle_tag_data);
447 }
448 }
449
450 // Create map from file ids to vertex handles, used later to set connectivity
451 std::map<EntityHandle, EntityHandle> vert_handles;
452 for (rit = localGidVerts.begin(), i = 0; rit != localGidVerts.end(); ++rit, i++)
453 vert_handles[*rit] = start_vertex + i;
454
455 // Compute proper handles in connectivity using offset
456 for (int q = 0; q < 4 * num_coarse_quads; q++) {
457 conn_arr[q] = vert_handles[conn_arr[q]];
458 assert(conn_arr[q]);
459 }
460 if (spectralMesh) {
461 int verts_per_quad = (_spectralOrder + 1) * (_spectralOrder + 1);
462 for (int q = 0; q < verts_per_quad * num_coarse_quads; q++) {
463 sv_ptr[q] = vert_handles[sv_ptr[q]];
464 assert(sv_ptr[q]);
465 }
466 }
467
468 // Add new vertices and quads to current file set
469 faces.merge(tmp_range);
470 tmp_range.insert(start_vertex, start_vertex + nLocalVertices - 1);
471 rval = mbImpl->add_entities(_fileSet, tmp_range);MB_CHK_SET_ERR(rval, "Failed to add new vertices and quads to current file set");
472
473 // Mark the set with the spectral order
474 Tag sporder;
475 rval = mbImpl->tag_get_handle("SPECTRAL_ORDER", 1, MB_TYPE_INTEGER, sporder,
476 MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating SPECTRAL_ORDER tag");
477 rval = mbImpl->tag_set_data(sporder, &_fileSet, 1, &_spectralOrder);MB_CHK_SET_ERR(rval, "Trouble setting data to SPECTRAL_ORDER tag");
478
479 if (create_gathers) {
480 EntityHandle gather_set;
481 rval = _readNC->readMeshIface->create_gather_set(gather_set);MB_CHK_SET_ERR(rval, "Failed to create gather set");
482
483 // Create vertices
484 arrays.clear();
485 // Don't need to specify allocation number here, because we know enough verts were created before
486 rval = _readNC->readMeshIface->get_node_coords(3, nVertices, 0, start_vertex, arrays);MB_CHK_SET_ERR(rval, "Failed to create gather set vertices");
487
488 xptr = arrays[0];
489 yptr = arrays[1];
490 zptr = arrays[2];
491 for (i = 0; i < nVertices; i++) {
492 double cosphi = cos(pideg * yVertVals[i]);
493 double zmult = sin(pideg * yVertVals[i]);
494 double xmult = cosphi * cos(xVertVals[i] * pideg);
495 double ymult = cosphi * sin(xVertVals[i] * pideg);
496 xptr[i] = rad * xmult;
497 yptr[i] = rad * ymult;
498 zptr[i] = rad * zmult;
499 }
500
501 // Get ptr to gid memory for vertices
502 Range gather_set_verts_range(start_vertex, start_vertex + nVertices - 1);
503 rval = mbImpl->tag_iterate(mGlobalIdTag, gather_set_verts_range.begin(), gather_set_verts_range.end(),
504 count, data);MB_CHK_SET_ERR(rval, "Failed to iterate global id tag on gather set vertices");
505 assert(count == nVertices);
506 gid_data = (int*) data;
507 for (int j = 1; j <= nVertices; j++)
508 gid_data[j - 1] = j;
509 // Set the file id tag too, it should be bigger something not interfering with global id
510 if (mpFileIdTag) {
511 rval = mbImpl->tag_iterate(*mpFileIdTag, gather_set_verts_range.begin(), gather_set_verts_range.end(),
512 count, data);MB_CHK_SET_ERR(rval, "Failed to iterate file id tag on gather set vertices");
513 assert(count == nVertices);
514 int bytes_per_tag = 4;
515 rval = mbImpl->tag_get_bytes(*mpFileIdTag, bytes_per_tag);MB_CHK_SET_ERR(rval, "Can't get number of bytes for file id tag");
516 if (4 == bytes_per_tag) {
517 gid_data = (int*)data;
518 for (int j = 1; j <= nVertices; j++)
519 gid_data[j - 1] = nVertices + j; // Bigger than global id tag
520 }
521 else if (8 == bytes_per_tag) { // Should be a handle tag on 64 bit machine?
522 long* handle_tag_data = (long*)data;
523 for (int j = 1; j <= nVertices; j++)
524 handle_tag_data[j - 1] = nVertices + j; // Bigger than global id tag
525 }
526 }
527
528 rval = mbImpl->add_entities(gather_set, gather_set_verts_range);MB_CHK_SET_ERR(rval, "Failed to add vertices to the gather set");
529
530 // Create quads
531 Range gather_set_quads_range;
532 // Don't need to specify allocation number here, because we know enough quads were created before
533 rval = _readNC->readMeshIface->get_element_connect(num_quads, 4, MBQUAD, 0,
534 start_quad, conn_arr);MB_CHK_SET_ERR(rval, "Failed to create gather set quads");
535 gather_set_quads_range.insert(start_quad, start_quad + num_quads - 1);
536 int* tmp_conn_end = (&tmp_conn[4 * num_quads-1]) + 1;
537 std::copy(&tmp_conn[0], tmp_conn_end, conn_arr);
538 for (i = 0; i != 4 * num_quads; i++)
539 conn_arr[i] += start_vertex - 1; // Connectivity array is shifted by where the gather verts start
540 rval = mbImpl->add_entities(gather_set, gather_set_quads_range);MB_CHK_SET_ERR(rval, "Failed to add quads to the gather set");
541 }
542
543 return MB_SUCCESS;
544 }
545
read_ucd_variables_to_nonset_allocate(std::vector<ReadNC::VarData> & vdatas,std::vector<int> & tstep_nums)546 ErrorCode NCHelperHOMME::read_ucd_variables_to_nonset_allocate(std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
547 {
548 Interface*& mbImpl = _readNC->mbImpl;
549 std::vector<int>& dimLens = _readNC->dimLens;
550 DebugOutput& dbgOut = _readNC->dbgOut;
551
552 Range* range = NULL;
553
554 // Get vertices
555 Range verts;
556 ErrorCode rval = mbImpl->get_entities_by_dimension(_fileSet, 0, verts);MB_CHK_SET_ERR(rval, "Trouble getting vertices in current file set");
557 assert("Should only have a single vertex subrange, since they were read in one shot" && verts.psize() == 1);
558
559 for (unsigned int i = 0; i < vdatas.size(); i++) {
560 // Support non-set variables with 3 dimensions like (time, lev, ncol)
561 assert(3 == vdatas[i].varDims.size());
562
563 // For a non-set variable, time should be the first dimension
564 assert(tDim == vdatas[i].varDims[0]);
565
566 // Set up readStarts and readCounts
567 vdatas[i].readStarts.resize(3);
568 vdatas[i].readCounts.resize(3);
569
570 // First: time
571 vdatas[i].readStarts[0] = 0; // This value is timestep dependent, will be set later
572 vdatas[i].readCounts[0] = 1;
573
574 // Next: lev
575 vdatas[i].readStarts[1] = 0;
576 vdatas[i].readCounts[1] = vdatas[i].numLev;
577
578 // Finally: ncol
579 switch (vdatas[i].entLoc) {
580 case ReadNC::ENTLOCVERT:
581 // Vertices
582 // Start from the first localGidVerts
583 // Actually, this will be reset later on in a loop
584 vdatas[i].readStarts[2] = localGidVerts[0] - 1;
585 vdatas[i].readCounts[2] = nLocalVertices;
586 range = &verts;
587 break;
588 default:
589 MB_SET_ERR(MB_FAILURE, "Unexpected entity location type for variable " << vdatas[i].varName);
590 }
591
592 // Get variable size
593 vdatas[i].sz = 1;
594 for (std::size_t idx = 0; idx != 3; idx++)
595 vdatas[i].sz *= vdatas[i].readCounts[idx];
596
597 for (unsigned int t = 0; t < tstep_nums.size(); t++) {
598 dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].varName.c_str(), tstep_nums[t]);
599
600 if (tstep_nums[t] >= dimLens[tDim]) {
601 MB_SET_ERR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number " << tstep_nums[t]);
602 }
603
604 // Get the tag to read into
605 if (!vdatas[i].varTags[t]) {
606 rval = get_tag_to_nonset(vdatas[i], tstep_nums[t], vdatas[i].varTags[t], vdatas[i].numLev);MB_CHK_SET_ERR(rval, "Trouble getting tag for variable " << vdatas[i].varName);
607 }
608
609 // Get ptr to tag space
610 void* data;
611 int count;
612 rval = mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), range->end(), count, data);MB_CHK_SET_ERR(rval, "Failed to iterate tag for variable " << vdatas[i].varName);
613 assert((unsigned)count == range->size());
614 vdatas[i].varDatas[t] = data;
615 }
616 }
617
618 return rval;
619 }
620
621 #ifdef MOAB_HAVE_PNETCDF
read_ucd_variables_to_nonset_async(std::vector<ReadNC::VarData> & vdatas,std::vector<int> & tstep_nums)622 ErrorCode NCHelperHOMME::read_ucd_variables_to_nonset_async(std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
623 {
624 DebugOutput& dbgOut = _readNC->dbgOut;
625
626 ErrorCode rval = read_ucd_variables_to_nonset_allocate(vdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble allocating space to read non-set variables");
627
628 // Finally, read into that space
629 int success;
630
631 for (unsigned int i = 0; i < vdatas.size(); i++) {
632 std::size_t sz = vdatas[i].sz;
633
634 // A typical supported variable: float T(time, lev, ncol)
635 // For tag values, need transpose (lev, ncol) to (ncol, lev)
636 size_t ni = vdatas[i].readCounts[2]; // ncol
637 size_t nj = 1; // Here we should just set nj to 1
638 size_t nk = vdatas[i].readCounts[1]; // lev
639
640 for (unsigned int t = 0; t < tstep_nums.size(); t++) {
641 // We will synchronize all these reads with the other processors,
642 // so the wait will be inside this double loop; is it too much?
643 size_t nb_reads = localGidVerts.psize();
644 std::vector<int> requests(nb_reads), statuss(nb_reads);
645 size_t idxReq = 0;
646
647 // Tag data for this timestep
648 void* data = vdatas[i].varDatas[t];
649
650 // Set readStart for each timestep along time dimension
651 vdatas[i].readStarts[0] = tstep_nums[t];
652
653 switch (vdatas[i].varDataType) {
654 case NC_FLOAT:
655 case NC_DOUBLE: {
656 // Read float as double
657 std::vector<double> tmpdoubledata(sz);
658
659 // In the case of ucd mesh, and on multiple proc,
660 // we need to read as many times as subranges we have in the
661 // localGidVerts range;
662 // basically, we have to give a different point
663 // for data to start, for every subrange :(
664 size_t indexInDoubleArray = 0;
665 size_t ic = 0;
666 for (Range::pair_iterator pair_iter = localGidVerts.pair_begin();
667 pair_iter != localGidVerts.pair_end();
668 ++pair_iter, ic++) {
669 EntityHandle starth = pair_iter->first;
670 EntityHandle endh = pair_iter->second; // Inclusive
671 vdatas[i].readStarts[2] = (NCDF_SIZE) (starth - 1);
672 vdatas[i].readCounts[2] = (NCDF_SIZE) (endh - starth + 1);
673
674 // Do a partial read, in each subrange
675 // Wait outside this loop
676 success = NCFUNCREQG(_vara_double)(_fileId, vdatas[i].varId,
677 &(vdatas[i].readStarts[0]), &(vdatas[i].readCounts[0]),
678 &(tmpdoubledata[indexInDoubleArray]), &requests[idxReq++]);
679 if (success)
680 MB_SET_ERR(MB_FAILURE, "Failed to read double data in a loop for variable " << vdatas[i].varName);
681 // We need to increment the index in double array for the
682 // next subrange
683 indexInDoubleArray += (endh - starth + 1) * 1 * vdatas[i].numLev;
684 }
685 assert(ic == localGidVerts.psize());
686
687 success = ncmpi_wait_all(_fileId, requests.size(), &requests[0], &statuss[0]);
688 if (success)
689 MB_SET_ERR(MB_FAILURE, "Failed on wait_all");
690
691 if (vdatas[i].numLev > 1)
692 // Transpose (lev, ncol) to (ncol, lev)
693 kji_to_jik_stride(ni, nj, nk, data, &tmpdoubledata[0], localGidVerts);
694 else {
695 for (std::size_t idx = 0; idx != tmpdoubledata.size(); idx++)
696 ((double*) data)[idx] = tmpdoubledata[idx];
697 }
698
699 break;
700 }
701 default:
702 MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName);
703 }
704 }
705 }
706
707 // Debug output, if requested
708 if (1 == dbgOut.get_verbosity()) {
709 dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str());
710 for (unsigned int i = 1; i < vdatas.size(); i++)
711 dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
712 dbgOut.tprintf(1, "\n");
713 }
714
715 return rval;
716 }
717 #else
read_ucd_variables_to_nonset(std::vector<ReadNC::VarData> & vdatas,std::vector<int> & tstep_nums)718 ErrorCode NCHelperHOMME::read_ucd_variables_to_nonset(std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
719 {
720 DebugOutput& dbgOut = _readNC->dbgOut;
721
722 ErrorCode rval = read_ucd_variables_to_nonset_allocate(vdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble allocating space to read non-set variables");
723
724 // Finally, read into that space
725 int success;
726 for (unsigned int i = 0; i < vdatas.size(); i++) {
727 std::size_t sz = vdatas[i].sz;
728
729 // A typical supported variable: float T(time, lev, ncol)
730 // For tag values, need transpose (lev, ncol) to (ncol, lev)
731 size_t ni = vdatas[i].readCounts[2]; // ncol
732 size_t nj = 1; // Here we should just set nj to 1
733 size_t nk = vdatas[i].readCounts[1]; // lev
734
735 for (unsigned int t = 0; t < tstep_nums.size(); t++) {
736 // Tag data for this timestep
737 void* data = vdatas[i].varDatas[t];
738
739 // Set readStart for each timestep along time dimension
740 vdatas[i].readStarts[0] = tstep_nums[t];
741
742 switch (vdatas[i].varDataType) {
743 case NC_FLOAT:
744 case NC_DOUBLE: {
745 // Read float as double
746 std::vector<double> tmpdoubledata(sz);
747
748 // In the case of ucd mesh, and on multiple proc,
749 // we need to read as many times as subranges we have in the
750 // localGidVerts range;
751 // basically, we have to give a different point
752 // for data to start, for every subrange :(
753 size_t indexInDoubleArray = 0;
754 size_t ic = 0;
755 for (Range::pair_iterator pair_iter = localGidVerts.pair_begin();
756 pair_iter != localGidVerts.pair_end();
757 ++pair_iter, ic++) {
758 EntityHandle starth = pair_iter->first;
759 EntityHandle endh = pair_iter->second; // Inclusive
760 vdatas[i].readStarts[2] = (NCDF_SIZE) (starth - 1);
761 vdatas[i].readCounts[2] = (NCDF_SIZE) (endh - starth + 1);
762
763 success = NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId,
764 &(vdatas[i].readStarts[0]), &(vdatas[i].readCounts[0]),
765 &(tmpdoubledata[indexInDoubleArray]));
766 if (success)
767 MB_SET_ERR(MB_FAILURE, "Failed to read double data in a loop for variable " << vdatas[i].varName);
768 // We need to increment the index in double array for the
769 // next subrange
770 indexInDoubleArray += (endh - starth + 1) * 1 * vdatas[i].numLev;
771 }
772 assert(ic == localGidVerts.psize());
773
774 if (vdatas[i].numLev > 1)
775 // Transpose (lev, ncol) to (ncol, lev)
776 kji_to_jik_stride(ni, nj, nk, data, &tmpdoubledata[0], localGidVerts);
777 else {
778 for (std::size_t idx = 0; idx != tmpdoubledata.size(); idx++)
779 ((double*) data)[idx] = tmpdoubledata[idx];
780 }
781
782 break;
783 }
784 default:
785 MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName);
786 }
787 }
788 }
789
790 // Debug output, if requested
791 if (1 == dbgOut.get_verbosity()) {
792 dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str());
793 for (unsigned int i = 1; i < vdatas.size(); i++)
794 dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
795 dbgOut.tprintf(1, "\n");
796 }
797
798 return rval;
799 }
800 #endif
801
802 } // namespace moab
803