1 /*
2 * NCWriteHelper.cpp
3 *
4 * Created on: Mar 28, 2014
5 * Author: iulian
6 */
7
8 #include "NCWriteHelper.hpp"
9 #include "NCWriteEuler.hpp"
10 #include "NCWriteFV.hpp"
11 #include "NCWriteHOMME.hpp"
12 #include "NCWriteMPAS.hpp"
13 #include "NCWriteGCRM.hpp"
14
15 #include "moab/WriteUtilIface.hpp"
16 #include "MBTagConventions.hpp"
17
18 #include <sstream>
19
20 #ifdef WIN32
21 #ifdef size_t
22 #undef size_t
23 #endif
24 #endif
25
26 namespace moab {
27
28 //! Get appropriate helper instance for WriteNC class; based on some info in the file set
get_nc_helper(WriteNC * writeNC,int fileId,const FileOptions & opts,EntityHandle fileSet)29 NCWriteHelper* NCWriteHelper::get_nc_helper(WriteNC* writeNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
30 {
31 std::string& grid_type = writeNC->grid_type;
32 if (grid_type == "CAM_EUL")
33 return new (std::nothrow) NCWriteEuler(writeNC, fileId, opts, fileSet);
34 else if (grid_type == "CAM_FV")
35 return new (std::nothrow) NCWriteFV(writeNC, fileId, opts, fileSet);
36 else if (grid_type == "CAM_SE")
37 return new (std::nothrow) NCWriteHOMME(writeNC, fileId, opts, fileSet);
38 else if (grid_type == "MPAS")
39 return new (std::nothrow) NCWriteMPAS(writeNC, fileId, opts, fileSet);
40 else if (grid_type == "GCRM")
41 return new (std::nothrow) NCWriteGCRM(writeNC, fileId, opts, fileSet);
42
43 // Unknown NetCDF grid
44 return NULL;
45 }
46
collect_variable_data(std::vector<std::string> & var_names,std::vector<int> & tstep_nums)47 ErrorCode NCWriteHelper::collect_variable_data(std::vector<std::string>& var_names, std::vector<int>& tstep_nums)
48 {
49 Interface*& mbImpl = _writeNC->mbImpl;
50 std::vector<std::string>& dimNames = _writeNC->dimNames;
51 std::vector<int>& dimLens = _writeNC->dimLens;
52 std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
53 std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
54 std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
55 DebugOutput& dbgOut = _writeNC->dbgOut;
56
57 ErrorCode rval;
58
59 usedCoordinates.clear();
60
61 if (tstep_nums.empty() && nTimeSteps > 0) {
62 // No timesteps input, get them all
63 for (int i = 0; i < nTimeSteps; i++)
64 tstep_nums.push_back(i);
65 }
66
67 for (size_t i = 0; i < var_names.size(); i++) {
68 std::string varname = var_names[i];
69 std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(varname);
70 if (vit == varInfo.end())
71 MB_SET_ERR(MB_FAILURE, "Can't find variable " << varname);
72
73 WriteNC::VarData& currentVarData = vit->second;
74
75 dbgOut.tprintf(2, " for variable %s varDims.size %d \n", varname.c_str(), (int)currentVarData.varDims.size());
76 for (size_t j = 0; j < currentVarData.varDims.size(); j++) {
77 std::string dimName = dimNames[currentVarData.varDims[j]];
78 vit = varInfo.find(dimName);
79 if (vit == varInfo.end())
80 MB_SET_ERR(MB_FAILURE, "Can't find coordinate variable " << dimName);
81
82 usedCoordinates.insert(dimName); // Collect those used, we will need to write them to the file
83 dbgOut.tprintf(2, " for variable %s need dimension %s with length %d\n", varname.c_str(), dimName.c_str(), dimLens[currentVarData.varDims[j]]);
84 }
85
86 // Process coordinate variables later
87 if (usedCoordinates.find(varname) != usedCoordinates.end())
88 continue;
89
90 // Default has_tsteps is false
91 if (std::find(currentVarData.varDims.begin(), currentVarData.varDims.end(), tDim) != currentVarData.varDims.end())
92 currentVarData.has_tsteps = true;
93
94 // Default numLev is 0
95 if ((std::find(currentVarData.varDims.begin(), currentVarData.varDims.end(), levDim) != currentVarData.varDims.end()))
96 currentVarData.numLev = nLevels;
97
98 // Process set variables
99 if (WriteNC::ENTLOCSET == currentVarData.entLoc) {
100 if (currentVarData.has_tsteps) {
101 // Set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen)
102 // TBD
103 MB_SET_ERR(MB_NOT_IMPLEMENTED, "Writing set variables with timesteps is not implemented yet");
104 }
105 else {
106 // Get the tag with varname
107 Tag tag = 0;
108 rval = mbImpl->tag_get_handle(varname.c_str(), tag);MB_CHK_SET_ERR(rval, "Can't find tag " << varname);
109 currentVarData.varTags.push_back(tag); // Really, only one for these
110 const void* data;
111 int size;
112 rval = mbImpl->tag_get_by_ptr(tag, &_fileSet, 1, &data, &size);MB_CHK_SET_ERR(rval, "Can't get data of tag " << varname);
113
114 // Find the type of tag, and use it
115 DataType type;
116 rval = mbImpl->tag_get_data_type(tag, type);MB_CHK_SET_ERR(rval, "Can't get data type of tag " << varname);
117
118 currentVarData.varDataType = NC_DOUBLE;
119 if (MB_TYPE_INTEGER == type)
120 currentVarData.varDataType = NC_INT;
121
122 assert(0 == currentVarData.memoryHogs.size()); // Nothing so far
123 currentVarData.memoryHogs.push_back((void*)data);
124
125 if (currentVarData.varDims.empty()) {
126 // Scalar variable
127 currentVarData.writeStarts.push_back(0);
128 currentVarData.writeCounts.push_back(1);
129 }
130 else {
131 for (size_t j = 0; j < currentVarData.varDims.size(); j++) {
132 currentVarData.writeStarts.push_back(0);
133 currentVarData.writeCounts.push_back(dimLens[currentVarData.varDims[j]]);
134 }
135 }
136
137 // Get variable size
138 currentVarData.sz = 1;
139 for (std::size_t idx = 0; idx != currentVarData.writeCounts.size(); idx++)
140 currentVarData.sz *= currentVarData.writeCounts[idx];
141 }
142 } // if (WriteNC::ENTLOCSET == currentVarData.entLoc)
143 // Process non-set variables
144 else {
145 Tag indexedTag = 0;
146
147 if (currentVarData.has_tsteps) {
148 for (unsigned int t = 0; t < tstep_nums.size(); t++) {
149 std::stringstream ssTagNameWithIndex;
150 ssTagNameWithIndex << varname << tstep_nums[t];
151 rval = mbImpl->tag_get_handle(ssTagNameWithIndex.str().c_str(), indexedTag);MB_CHK_SET_ERR(rval, "Can't find tag " << ssTagNameWithIndex.str());
152 dbgOut.tprintf(2, " found indexed tag %d with name %s\n", tstep_nums[t], ssTagNameWithIndex.str().c_str());
153 currentVarData.varTags.push_back(indexedTag);
154 }
155 }
156 else {
157 // This should be a user-created non-set variable without timesteps
158 // Treat it like having one, 0th, timestep
159 std::stringstream ssTagNameWithIndex;
160 ssTagNameWithIndex << varname << 0;
161 rval = mbImpl->tag_get_handle(ssTagNameWithIndex.str().c_str(), indexedTag);MB_CHK_SET_ERR(rval, "Can't find tag " << ssTagNameWithIndex.str() << " for a user-created variable");
162 dbgOut.tprintf(2, " found indexed tag 0 with name %s\n", ssTagNameWithIndex.str().c_str());
163 currentVarData.varTags.push_back(indexedTag);
164 }
165
166 // The type of the tag is fixed though
167 DataType type;
168 rval = mbImpl->tag_get_data_type(indexedTag, type);MB_CHK_SET_ERR(rval, "Can't get data type of tag " << varname);
169
170 currentVarData.varDataType = NC_DOUBLE;
171 if (MB_TYPE_INTEGER == type)
172 currentVarData.varDataType = NC_INT;
173 }
174 } // for (size_t i = 0; i < var_names.size(); i++)
175
176 // Process coordinate variables here
177 // Check that for used coordinates we have found the tags
178 for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
179 setIt != usedCoordinates.end(); ++setIt) {
180 const std::string& coordName = *setIt;
181
182 std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(coordName);
183 if (vit == varInfo.end())
184 MB_SET_ERR(MB_FAILURE, "Can't find coordinate variable " << coordName);
185
186 WriteNC::VarData& varCoordData = vit->second;
187 Tag coordTag = 0;
188 rval = mbImpl->tag_get_handle(coordName.c_str(), coordTag);MB_CHK_SET_ERR(rval, "Can't find tag " << coordName);
189 varCoordData.varTags.push_back(coordTag); // Really, only one for these
190
191 const void* data;
192 int sizeCoordinate;
193 rval = mbImpl->tag_get_by_ptr(coordTag, &_fileSet, 1, &data, &sizeCoordinate);MB_CHK_SET_ERR(rval, "Can't get coordinate values of " << coordName);
194 dbgOut.tprintf(2, " found coordinate tag with name %s and length %d\n", coordName.c_str(),
195 sizeCoordinate);
196
197 // Find the type of tag, and use it
198 DataType type;
199 rval = mbImpl->tag_get_data_type(coordTag, type);MB_CHK_SET_ERR(rval, "Can't get data type of tag " << coordName);
200 varCoordData.varDataType = NC_DOUBLE;
201 if (MB_TYPE_INTEGER == type)
202 varCoordData.varDataType = NC_INT;
203
204 // Get dimension length (the only dimension of this coordinate variable, with the same name)
205 assert(1 == varCoordData.varDims.size());
206 int coordDimLen = dimLens[varCoordData.varDims[0]];
207
208 if (dummyVarNames.find(coordName) != dummyVarNames.end()) {
209 // For a dummy coordinate variable, the tag size is always 1
210 // The number of coordinates should be set to dimension length, instead of 1
211 assert(1 == sizeCoordinate);
212 sizeCoordinate = coordDimLen;
213
214 // No variable data to write
215 data = NULL;
216 }
217 else {
218 // The number of coordinates should be exactly the same as dimension length
219 // However, if timesteps spread across files and time tag has been updated,
220 // sizeCoordinate will be larger
221 if (varCoordData.varDims[0] != tDim)
222 assert(sizeCoordinate == coordDimLen);
223 }
224
225 // For time, the actual output size and values are determined by tstep_nums
226 if (varCoordData.varDims[0] == tDim) {
227 // Does not apply to dummy time tag (e.g. 'Time' tag of MPAS), when timesteps
228 // spread across files
229 if (NULL != data)
230 assert(tstep_nums.size() > 0 && tstep_nums.size() <= (size_t)sizeCoordinate);
231
232 sizeCoordinate = tstep_nums.size();
233
234 if (NULL != data) {
235 assert(NC_DOUBLE == varCoordData.varDataType);
236 timeStepVals.resize(sizeCoordinate);
237 for (unsigned int t = 0; t < tstep_nums.size(); t++)
238 timeStepVals[t] = ((double*)data)[tstep_nums[t]];
239
240 data = &timeStepVals[0];
241 }
242 }
243
244 // This is the length
245 varCoordData.sz = sizeCoordinate;
246 varCoordData.writeStarts.resize(1);
247 varCoordData.writeStarts[0] = 0;
248 varCoordData.writeCounts.resize(1);
249 varCoordData.writeCounts[0] = sizeCoordinate;
250
251 assert(0 == varCoordData.memoryHogs.size()); // Nothing so far
252 varCoordData.memoryHogs.push_back((void*)data);
253 } // for (std::set<std::string>::iterator setIt ...
254
255 return MB_SUCCESS;
256 }
257
init_file(std::vector<std::string> & var_names,std::vector<std::string> & desired_names,bool append)258 ErrorCode NCWriteHelper::init_file(std::vector<std::string>& var_names, std::vector<std::string>& desired_names, bool append)
259 {
260 std::vector<std::string>& dimNames = _writeNC->dimNames;
261 std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
262 std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
263 std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
264 std::map<std::string, WriteNC::AttData>& globalAtts = _writeNC->globalAtts;
265 DebugOutput& dbgOut = _writeNC->dbgOut;
266
267 int tDim_in_dimNames = tDim;
268 int levDim_in_dimNames = levDim;
269
270 // If append mode, make sure we are in define mode; a simple open will not allow creation of new variables
271 if (append) {
272 int errcode = NCFUNC(redef)(_fileId);
273 if (errcode != NC_NOERR)
274 MB_SET_ERR(MB_FAILURE, "Can't open file in redefine mode");
275 }
276
277 // First initialize all coordinates, then fill VarData for actual variables (and dimensions)
278 // Check that for used coordinates we have found the tags
279 for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
280 setIt != usedCoordinates.end(); ++setIt) {
281 const std::string& coordName = *setIt;
282
283 std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(coordName);
284 if (vit == varInfo.end())
285 MB_SET_ERR(MB_FAILURE, "Can't find coordinate variable " << coordName);
286
287 WriteNC::VarData& varCoordData = vit->second;
288 varCoordData.varDims.resize(1);
289
290 // If not append, create it for sure
291 // If append, we might already have it, including the tag / variable with the same name
292 /*
293 * int ncmpi_inq_dimid(int ncid, const char *name, int *idp);
294 */
295 if (append) {
296 int dimId;
297 if (NCFUNC(inq_dimid)(_fileId, coordName.c_str(), &dimId) == NC_NOERR) { // If not found, create it later
298 varCoordData.varDims[0] = dimId;
299 dbgOut.tprintf(2, " file already has coordName %s dim id is %d \n", coordName.c_str(), (int)varCoordData.varDims[0]);
300
301 // Update tDim and levDim to actual dimension id
302 if (coordName == dimNames[tDim_in_dimNames])
303 tDim = varCoordData.varDims[0];
304 else if (coordName == dimNames[levDim_in_dimNames])
305 levDim = varCoordData.varDims[0];
306
307 // Skip dummy coordinate variables (e.g. ncol)
308 if (dummyVarNames.find(coordName) != dummyVarNames.end())
309 continue;
310
311 // Check that the coordinate is a variable too
312 // Inquire for a variable with the same name
313 int varId;
314 if (NCFUNC(inq_varid)(_fileId, coordName.c_str(), &varId) != NC_NOERR)
315 MB_SET_ERR(MB_FAILURE, "We do not have a variable with the same name " << coordName);
316 // We should also check that this variable has one dimension, and it is dimId
317 varCoordData.varId = varId;
318 dbgOut.tprintf(2, " file already has coordinate %s and varId is %d \n", coordName.c_str(), varId);
319
320 continue; // Maybe more checks are needed here
321 }
322 }
323
324 /* int nc_def_dim (int ncid, const char *name, size_t len, int *dimidp);
325 * example: status = nc_def_dim(fileId, "lat", 18L, &latid);
326 */
327
328 // Actually define a dimension
329 if (NCFUNC(def_dim)(_fileId, coordName.c_str(), (size_t)varCoordData.sz,
330 &varCoordData.varDims[0]) != NC_NOERR)
331 MB_SET_ERR(MB_FAILURE, "Failed to generate dimension " << coordName);
332 dbgOut.tprintf(2, " for coordName %s dim id is %d \n", coordName.c_str(), (int)varCoordData.varDims[0]);
333
334 // Update tDim and levDim to actual dimension id
335 if (coordName == dimNames[tDim_in_dimNames])
336 tDim = varCoordData.varDims[0];
337 else if (coordName == dimNames[levDim_in_dimNames])
338 levDim = varCoordData.varDims[0];
339
340 // Create a variable with the same name, and its only dimension the one we just defined
341 /*
342 * int nc_def_var (int ncid, const char *name, nc_type xtype,
343 int ndims, const int dimids[], int *varidp);
344 example: http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c/nc_005fdef_005fvar.html#nc_005fdef_005fvar
345 */
346
347 // Skip dummy coordinate variables (e.g. ncol)
348 if (dummyVarNames.find(coordName) != dummyVarNames.end())
349 continue;
350
351 // Define a coordinate variable
352 if (NCFUNC(def_var)(_fileId, coordName.c_str(), varCoordData.varDataType,
353 1, &(varCoordData.varDims[0]), &varCoordData.varId) != NC_NOERR)
354 MB_SET_ERR(MB_FAILURE, "Failed to create coordinate variable " << coordName);
355
356 dbgOut.tprintf(2, " for coordName %s variable id is %d \n", coordName.c_str(), varCoordData.varId);
357 }
358
359 // Now look at requested variables, and update from the index in dimNames to the actual dimension id
360 for (size_t i = 0; i < var_names.size(); i++) {
361 std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(var_names[i]);
362 if (vit == varInfo.end())
363 MB_SET_ERR(MB_FAILURE, "Can't find requested variable " << var_names[i]);
364
365 // Skip coordinate variables
366 if (usedCoordinates.find(var_names[i]) != usedCoordinates.end())
367 continue;
368
369 WriteNC::VarData& variableData = vit->second;
370
371 // The index is for dimNames; we need to find out the actual dimension id (from above)
372 int numDims = (int)variableData.varDims.size();
373 for (int j = 0; j < numDims; j++) {
374 std::string dimName = dimNames[variableData.varDims[j]];
375 std::map<std::string, WriteNC::VarData>::iterator vit2 = varInfo.find(dimName);
376 if (vit2 == varInfo.end())
377 MB_SET_ERR(MB_FAILURE, "Can't find requested coordinate variable " << dimName);
378
379 WriteNC::VarData& coordData = vit2->second;
380 // Index in dimNames to actual dimension id
381 variableData.varDims[j] = coordData.varDims[0]; // This one, being a coordinate, is the only one
382 dbgOut.tprintf(2, " dimension with index %d name %s has ID %d \n",
383 j, dimName.c_str(), variableData.varDims[j]);
384 }
385
386 // Define the variable now:
387 int errCode = NCFUNC(def_var)(_fileId, desired_names[i].c_str(), variableData.varDataType,
388 (int)variableData.varDims.size(), &(variableData.varDims[0]),
389 &variableData.varId);
390 if (errCode != NC_NOERR)
391 MB_SET_ERR(MB_FAILURE, "Failed to create requested variable " << desired_names[i]);
392
393 dbgOut.tprintf(2, " for variable %s with desired name %s variable id is %d \n", var_names[i].c_str(),
394 desired_names[i].c_str(), variableData.varId);
395 // Now define the variable, with all dimensions
396 }
397
398 // Define global attributes (exactly copied from the original file for the time being)
399 // Should we modify some of them (e.g. revision_Id) later?
400 std::map<std::string, WriteNC::AttData>::iterator attIt;
401 for (attIt = globalAtts.begin(); attIt != globalAtts.end(); ++attIt) {
402 const std::string& attName = attIt->first;
403 WriteNC::AttData& attData = attIt->second;
404 NCDF_SIZE& attLen = attData.attLen;
405 nc_type& attDataType = attData.attDataType;
406 const std::string& attValue = attData.attValue;
407
408 switch (attDataType) {
409 case NC_BYTE:
410 case NC_CHAR:
411 if (NC_NOERR != NCFUNC(put_att_text)(_fileId, NC_GLOBAL, attName.c_str(), attLen, attValue.c_str()))
412 MB_SET_ERR(MB_FAILURE, "Failed to define text type attribute");
413 break;
414 case NC_DOUBLE:
415 if (NC_NOERR != NCFUNC(put_att_double)(_fileId, NC_GLOBAL, attName.c_str(), NC_DOUBLE, 1, (double*)attValue.c_str()))
416 MB_SET_ERR(MB_FAILURE, "Failed to define double type attribute");
417 break;
418 case NC_FLOAT:
419 if (NC_NOERR != NCFUNC(put_att_float)(_fileId, NC_GLOBAL, attName.c_str(), NC_FLOAT, 1, (float*)attValue.c_str()))
420 MB_SET_ERR(MB_FAILURE, "Failed to define float type attribute");
421 break;
422 case NC_INT:
423 if (NC_NOERR != NCFUNC(put_att_int)(_fileId, NC_GLOBAL, attName.c_str(), NC_INT, 1, (int*)attValue.c_str()))
424 MB_SET_ERR(MB_FAILURE, "Failed to define int type attribute");
425 break;
426 case NC_SHORT:
427 if (NC_NOERR != NCFUNC(put_att_short)(_fileId, NC_GLOBAL, attName.c_str(), NC_SHORT, 1, (short*)attValue.c_str()))
428 MB_SET_ERR(MB_FAILURE, "Failed to define short type attribute");
429 break;
430 default:
431 MB_SET_ERR(MB_FAILURE, "Unknown attribute data type");
432 }
433 }
434
435 // Take it out of define mode
436 if (NC_NOERR != NCFUNC(enddef)(_fileId))
437 MB_SET_ERR(MB_FAILURE, "Failed to close define mode");
438
439 return MB_SUCCESS;
440 }
441
write_values(std::vector<std::string> & var_names,std::vector<int> & tstep_nums)442 ErrorCode NCWriteHelper::write_values(std::vector<std::string>& var_names, std::vector<int>& tstep_nums)
443 {
444 std::set<std::string>& usedCoordinates = _writeNC->usedCoordinates;
445 std::set<std::string>& dummyVarNames = _writeNC->dummyVarNames;
446 std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
447
448 std::vector<WriteNC::VarData> vdatas;
449 std::vector<WriteNC::VarData> vsetdatas;
450
451 // For set variables, include coordinates used by requested var_names
452 for (std::set<std::string>::iterator setIt = usedCoordinates.begin();
453 setIt != usedCoordinates.end(); ++setIt) {
454 const std::string& coordName = *setIt;
455
456 // Skip dummy coordinate variables (if any)
457 if (dummyVarNames.find(coordName) != dummyVarNames.end())
458 continue;
459
460 std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(coordName);
461 if (vit == varInfo.end()) {
462 MB_SET_ERR(MB_FAILURE, "Can't find coordinate variable " << coordName);
463 }
464
465 vsetdatas.push_back(vit->second);
466 }
467
468 // Collect non-set and set variables from requested var_names
469 for (unsigned int i = 0; i < var_names.size(); i++) {
470 std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(var_names[i]);
471 if (vit == varInfo.end()) {
472 MB_SET_ERR(MB_FAILURE, "Can't find requested variable " << var_names[i]);
473 }
474
475 WriteNC::VarData& variableData = vit->second;
476 if (WriteNC::ENTLOCSET == variableData.entLoc) {
477 // Used coordinates has all ready been included
478 if (usedCoordinates.find(var_names[i]) != usedCoordinates.end())
479 continue;
480
481 vsetdatas.push_back(variableData);
482 }
483 else
484 vdatas.push_back(variableData);
485 }
486
487 // Assume that the data ranges do not overlap across processors
488 // While overlapped writing might still work, we should better not take that risk
489 write_nonset_variables(vdatas, tstep_nums);
490
491 // Use independent I/O mode put, since this write is only for the root processor
492 write_set_variables(vsetdatas, tstep_nums);
493
494 return MB_SUCCESS;
495 }
496
write_set_variables(std::vector<WriteNC::VarData> & vsetdatas,std::vector<int> &)497 ErrorCode NCWriteHelper::write_set_variables(std::vector<WriteNC::VarData>& vsetdatas, std::vector<int>& /* tstep_nums */)
498 {
499 int success;
500
501 // CAUTION: if the NetCDF ID is from a previous call to ncmpi_create rather than ncmpi_open,
502 // all processors need to call ncmpi_begin_indep_data(). If only the root processor does so,
503 // ncmpi_begin_indep_data() call will be blocked forever :(
504 #ifdef MOAB_HAVE_PNETCDF
505 // Enter independent I/O mode
506 success = NCFUNC(begin_indep_data)(_fileId);
507 if (success)
508 MB_SET_ERR(MB_FAILURE, "Failed to begin independent I/O mode");
509 #endif
510
511 int rank = 0;
512 #ifdef MOAB_HAVE_MPI
513 bool& isParallel = _writeNC->isParallel;
514 if (isParallel) {
515 ParallelComm*& myPcomm = _writeNC->myPcomm;
516 rank = myPcomm->proc_config().proc_rank();
517 }
518 #endif
519 if (0 == rank) {
520 for (unsigned int i = 0; i < vsetdatas.size(); i++) {
521 WriteNC::VarData& variableData = vsetdatas[i];
522
523 // Set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen)
524 if (variableData.has_tsteps) {
525 MB_SET_ERR(MB_NOT_IMPLEMENTED, "Writing set variables with timesteps is not implemented yet");
526 }
527
528 switch (variableData.varDataType) {
529 case NC_DOUBLE:
530 // Independent I/O mode put
531 success = NCFUNCP(_vara_double)(_fileId, variableData.varId, &variableData.writeStarts[0],
532 &variableData.writeCounts[0], (double*)(variableData.memoryHogs[0]));
533 if (success)
534 MB_SET_ERR(MB_FAILURE, "Failed to write double data for variable " << variableData.varName);
535 break;
536 case NC_INT:
537 // Independent I/O mode put
538 success = NCFUNCP(_vara_int)(_fileId, variableData.varId, &variableData.writeStarts[0],
539 &variableData.writeCounts[0], (int*)(variableData.memoryHogs[0]));
540 if (success)
541 MB_SET_ERR(MB_FAILURE, "Failed to write int data for variable " << variableData.varName);
542 break;
543 default:
544 MB_SET_ERR(MB_NOT_IMPLEMENTED, "Writing non-double or non-int data is not implemented yet");
545 }
546 }
547 }
548
549 #ifdef MOAB_HAVE_PNETCDF
550 // End independent I/O mode
551 success = NCFUNC(end_indep_data)(_fileId);
552 if (success)
553 MB_SET_ERR(MB_FAILURE, "Failed to end independent I/O mode");
554 #endif
555
556 return MB_SUCCESS;
557 }
558
collect_mesh_info()559 ErrorCode ScdNCWriteHelper::collect_mesh_info()
560 {
561 Interface*& mbImpl = _writeNC->mbImpl;
562 std::vector<std::string>& dimNames = _writeNC->dimNames;
563 std::vector<int>& dimLens = _writeNC->dimLens;
564
565 ErrorCode rval;
566
567 // Look for time dimension
568 std::vector<std::string>::iterator vecIt;
569 if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "time")) != dimNames.end())
570 tDim = vecIt - dimNames.begin();
571 else if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "t")) != dimNames.end())
572 tDim = vecIt - dimNames.begin();
573 else {
574 MB_SET_ERR(MB_FAILURE, "Couldn't find 'time' or 't' dimension");
575 }
576 nTimeSteps = dimLens[tDim];
577
578 // Get number of levels
579 if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "lev")) != dimNames.end())
580 levDim = vecIt - dimNames.begin();
581 else if ((vecIt = std::find(dimNames.begin(), dimNames.end(), "ilev")) != dimNames.end())
582 levDim = vecIt - dimNames.begin();
583 else {
584 MB_SET_ERR(MB_FAILURE, "Couldn't find 'lev' or 'ilev' dimension");
585 }
586 nLevels = dimLens[levDim];
587
588 // __<dim_name>_LOC_MINMAX (for slon, slat, lon and lat)
589 Tag convTag = 0;
590 rval = mbImpl->tag_get_handle("__slon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag,
591 MB_TAG_ANY);MB_CHK_SET_ERR(rval, "Trouble getting conventional tag __slon_LOC_MINMAX");
592 int val[2];
593 rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);MB_CHK_SET_ERR(rval, "Trouble getting data of conventional tag __slon_LOC_MINMAX");
594 lDims[0] = val[0];
595 lDims[3] = val[1];
596
597 rval = mbImpl->tag_get_handle("__slat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag,
598 MB_TAG_ANY);MB_CHK_SET_ERR(rval, "Trouble getting conventional tag __slat_LOC_MINMAX");
599 rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);MB_CHK_SET_ERR(rval, "Trouble getting data of conventional tag __slat_LOC_MINMAX");
600 lDims[1] = val[0];
601 lDims[4] = val[1];
602
603 rval = mbImpl->tag_get_handle("__lon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag,
604 MB_TAG_ANY);MB_CHK_SET_ERR(rval, "Trouble getting conventional tag __lon_LOC_MINMAX");
605 rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);MB_CHK_SET_ERR(rval, "Trouble getting data of conventional tag __lon_LOC_MINMAX");
606 lCDims[0] = val[0];
607 lCDims[3] = val[1];
608
609 rval = mbImpl->tag_get_handle("__lat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag,
610 MB_TAG_ANY);MB_CHK_SET_ERR(rval, "Trouble getting conventional tag __lat_LOC_MINMAX");
611 rval = mbImpl->tag_get_data(convTag, &_fileSet, 1, val);MB_CHK_SET_ERR(rval, "Trouble getting data of conventional tag __lat_LOC_MINMAX");
612 lCDims[1] = val[0];
613 lCDims[4] = val[1];
614
615 // Get local faces
616 rval = mbImpl->get_entities_by_dimension(_fileSet, 2, localCellsOwned);MB_CHK_SET_ERR(rval, "Trouble getting local faces in current file set");
617 assert(!localCellsOwned.empty());
618
619 #ifdef MOAB_HAVE_MPI
620 bool& isParallel = _writeNC->isParallel;
621 if (isParallel) {
622 ParallelComm*& myPcomm = _writeNC->myPcomm;
623 int procs = myPcomm->proc_config().proc_size();
624 if (procs > 1) {
625 rval = myPcomm->filter_pstatus(localCellsOwned, PSTATUS_NOT_OWNED, PSTATUS_NOT);MB_CHK_SET_ERR(rval, "Trouble getting owned faces in current file set");
626 }
627 }
628 #endif
629
630 return MB_SUCCESS;
631 }
632
collect_variable_data(std::vector<std::string> & var_names,std::vector<int> & tstep_nums)633 ErrorCode ScdNCWriteHelper::collect_variable_data(std::vector<std::string>& var_names, std::vector<int>& tstep_nums)
634 {
635 NCWriteHelper::collect_variable_data(var_names, tstep_nums);
636
637 std::map<std::string, WriteNC::VarData>& varInfo = _writeNC->varInfo;
638
639 for (size_t i = 0; i < var_names.size(); i++) {
640 std::string varname = var_names[i];
641 std::map<std::string, WriteNC::VarData>::iterator vit = varInfo.find(varname);
642 if (vit == varInfo.end())
643 MB_SET_ERR(MB_FAILURE, "Can't find variable " << varname);
644
645 WriteNC::VarData& currentVarData = vit->second;
646 #ifndef NDEBUG
647 std::vector<int>& varDims = currentVarData.varDims;
648 #endif
649
650 // Skip set variables, which were already processed in NCWriteHelper::collect_variable_data()
651 if (WriteNC::ENTLOCSET == currentVarData.entLoc)
652 continue;
653
654 // Set up writeStarts and writeCounts (maximum number of dimensions is 4)
655 currentVarData.writeStarts.resize(4);
656 currentVarData.writeCounts.resize(4);
657 unsigned int dim_idx = 0;
658
659 // First: time
660 if (currentVarData.has_tsteps) {
661 // Non-set variables with timesteps
662 // 4 dimensions like (time, lev, lat, lon)
663 // 3 dimensions like (time, lat, lon)
664 assert(4 == varDims.size() || 3 == varDims.size());
665
666 // Time should be the first dimension
667 assert(tDim == varDims[0]);
668
669 currentVarData.writeStarts[dim_idx] = 0; // This value is timestep dependent, will be set later
670 currentVarData.writeCounts[dim_idx] = 1;
671 dim_idx++;
672 }
673 else {
674 // Non-set variables without timesteps
675 // 3 dimensions like (lev, lat, lon)
676 // 2 dimensions like (lat, lon)
677 assert(3 == varDims.size() || 2 == varDims.size());
678 }
679
680 // Next: lev
681 if (currentVarData.numLev > 0) {
682 // Non-set variables with levels
683 // 4 dimensions like (time, lev, lat, lon)
684 // 3 dimensions like (lev, lat, lon)
685 assert(4 == varDims.size() || 3 == varDims.size());
686
687 currentVarData.writeStarts[dim_idx] = 0;
688 currentVarData.writeCounts[dim_idx] = currentVarData.numLev;
689 dim_idx++;
690 }
691 else {
692 // Non-set variables without levels
693 // 3 dimensions like (time, lat, lon)
694 // 2 dimensions like (lat, lon)
695 assert(3 == varDims.size() || 2 == varDims.size());
696 }
697
698 // Finally: lat and lon
699 switch (currentVarData.entLoc) {
700 case WriteNC::ENTLOCFACE:
701 // Faces
702 currentVarData.writeStarts[dim_idx] = lCDims[1];
703 currentVarData.writeCounts[dim_idx] = lCDims[4] - lCDims[1] + 1;
704 currentVarData.writeStarts[dim_idx + 1] = lCDims[0];
705 currentVarData.writeCounts[dim_idx + 1] = lCDims[3] - lCDims[0] + 1;
706 break;
707 default:
708 MB_SET_ERR(MB_FAILURE, "Unexpected entity location type for variable " << varname);
709 }
710 dim_idx += 2;
711
712 // Get variable size
713 currentVarData.sz = 1;
714 for (std::size_t idx = 0; idx < dim_idx; idx++)
715 currentVarData.sz *= currentVarData.writeCounts[idx];
716 } // for (size_t i = 0; i < var_names.size(); i++)
717
718 return MB_SUCCESS;
719 }
720
721 // Write CAM-EUL and CAM-FV non-set variables on non-shared quads (e.g. T)
722 // We assume that there are no variables on vertices and we do not support
723 // variables on edges (e.g. US in CAM-FV) for the time being
write_nonset_variables(std::vector<WriteNC::VarData> & vdatas,std::vector<int> & tstep_nums)724 ErrorCode ScdNCWriteHelper::write_nonset_variables(std::vector<WriteNC::VarData>& vdatas, std::vector<int>& tstep_nums)
725 {
726 Interface*& mbImpl = _writeNC->mbImpl;
727
728 int success;
729
730 // For each indexed variable tag, write a time step data
731 for (unsigned int i = 0; i < vdatas.size(); i++) {
732 WriteNC::VarData& variableData = vdatas[i];
733
734 // Assume this variable is on faces for the time being
735 switch (variableData.entLoc) {
736 case WriteNC::ENTLOCFACE:
737 // Faces
738 break;
739 default:
740 MB_SET_ERR(MB_FAILURE, "Unexpected entity location type for variable " << variableData.varName);
741 }
742
743 unsigned int num_timesteps;
744 unsigned int lat_idx = 0;
745 unsigned int lon_idx = 1;
746 if (variableData.has_tsteps) {
747 // Non-set variables with timesteps
748 // 4 dimensions like (time, lev, lat, lon)
749 // 3 dimensions like (time, lat, lon)
750 num_timesteps = tstep_nums.size();
751 lat_idx++;
752 lon_idx++;
753 }
754 else {
755 // Non-set variables without timesteps
756 // 3 dimensions like (lev, lat, lon)
757 // 2 dimensions like (lat, lon)
758 num_timesteps = 1;
759 }
760
761 unsigned int num_lev;
762 if (variableData.numLev > 0) {
763 // Non-set variables with levels
764 // 4 dimensions like (time, lev, lat, lon)
765 // 3 dimensions like (lev, lat, lon)
766 num_lev = variableData.numLev;
767 lat_idx++;
768 lon_idx++;
769 }
770 else {
771 // Non-set variables without levels
772 // 3 dimensions like (time, lat, lon)
773 // 2 dimensions like (lat, lon)
774 num_lev = 1;
775 }
776
777 size_t ni = variableData.writeCounts[lon_idx]; // lon
778 size_t nj = variableData.writeCounts[lat_idx]; // lat
779
780 // At each timestep, we need to transpose tag format (lat, lon, lev) back
781 // to NC format (lev, lat, lon) for writing
782 for (unsigned int t = 0; t < num_timesteps; t++) {
783 // We will write one time step, and count will be one; start will be different
784 // Use tag_iterate to get tag data (assume that localCellsOwned is contiguous)
785 // We should also transpose for level so that means deep copy for transpose
786 if (tDim == variableData.varDims[0])
787 variableData.writeStarts[0] = t; // This is start for time
788 int count;
789 void* dataptr;
790 ErrorCode rval = mbImpl->tag_iterate(variableData.varTags[t], localCellsOwned.begin(), localCellsOwned.end(),
791 count, dataptr);MB_CHK_SET_ERR(rval, "Failed to iterate tag on owned faces");
792 assert(count == (int)localCellsOwned.size());
793
794 // Now transpose and write tag data
795 // Use collective I/O mode put (synchronous write) for the time being, we can try
796 // nonblocking put (request aggregation) later
797 switch (variableData.varDataType) {
798 case NC_DOUBLE: {
799 std::vector<double> tmpdoubledata(ni*nj*num_lev);
800 if (num_lev > 1)
801 // Transpose (lat, lon, lev) back to (lev, lat, lon)
802 jik_to_kji(ni, nj, num_lev, &tmpdoubledata[0], (double*)(dataptr));
803 success = NCFUNCAP(_vara_double)(_fileId, variableData.varId,
804 &variableData.writeStarts[0], &variableData.writeCounts[0],
805 &tmpdoubledata[0]);
806 if (success)
807 MB_SET_ERR(MB_FAILURE, "Failed to write double data for variable " << variableData.varName);
808 break;
809 }
810 default:
811 MB_SET_ERR(MB_NOT_IMPLEMENTED, "Writing non-double data is not implemented yet");
812 }
813 }
814 }
815
816 return MB_SUCCESS;
817 }
818
819 } /* namespace moab */
820