1 #include "NCHelper.hpp"
2 #include "NCHelperEuler.hpp"
3 #include "NCHelperFV.hpp"
4 #include "NCHelperHOMME.hpp"
5 #include "NCHelperMPAS.hpp"
6 #include "NCHelperGCRM.hpp"
7 
8 #include <sstream>
9 
10 #include "MBTagConventions.hpp"
11 
12 #ifdef WIN32
13 #ifdef size_t
14 #undef size_t
15 #endif
16 #endif
17 
18 namespace moab {
19 
get_nc_helper(ReadNC * readNC,int fileId,const FileOptions & opts,EntityHandle fileSet)20 NCHelper* NCHelper::get_nc_helper(ReadNC* readNC, int fileId, const FileOptions& opts, EntityHandle fileSet)
21 {
22   // Check if CF convention is being followed
23   bool is_CF = false;
24 
25   std::map<std::string, ReadNC::AttData>& globalAtts = readNC->globalAtts;
26   std::map<std::string, ReadNC::AttData>::iterator attIt = globalAtts.find("conventions");
27   if (attIt == globalAtts.end())
28     attIt = globalAtts.find("Conventions");
29 
30   if (attIt != globalAtts.end()) {
31     unsigned int sz = attIt->second.attLen;
32     std::string att_data;
33     att_data.resize(sz + 1);
34     att_data[sz] = '\000';
35     int success = NCFUNC(get_att_text)(fileId, attIt->second.attVarId, attIt->second.attName.c_str(), &att_data[0]);
36     if (0 == success && att_data.find("CF") != std::string::npos)
37       is_CF = true;
38   }
39 
40   if (is_CF) {
41     if (NCHelperEuler::can_read_file(readNC, fileId))
42       return new (std::nothrow) NCHelperEuler(readNC, fileId, opts, fileSet);
43     else if (NCHelperFV::can_read_file(readNC, fileId))
44       return new (std::nothrow) NCHelperFV(readNC, fileId, opts, fileSet);
45     else if (NCHelperHOMME::can_read_file(readNC, fileId))
46       return new (std::nothrow) NCHelperHOMME(readNC, fileId, opts, fileSet);
47   }
48   else {
49     if (NCHelperMPAS::can_read_file(readNC))
50       return new (std::nothrow) NCHelperMPAS(readNC, fileId, opts, fileSet);
51     // For a HOMME connectivity file, there might be no CF convention
52     else if (NCHelperHOMME::can_read_file(readNC, fileId))
53       return new (std::nothrow) NCHelperHOMME(readNC, fileId, opts, fileSet);
54     // gcrm reader
55     else if (NCHelperGCRM::can_read_file(readNC))
56       return new (std::nothrow) NCHelperGCRM(readNC, fileId, opts, fileSet);
57   }
58 
59   // Unknown NetCDF grid (will fill this in later for POP, CICE and CLM)
60   return NULL;
61 }
62 
create_conventional_tags(const std::vector<int> & tstep_nums)63 ErrorCode NCHelper::create_conventional_tags(const std::vector<int>& tstep_nums)
64 {
65   Interface*& mbImpl = _readNC->mbImpl;
66   std::vector<std::string>& dimNames = _readNC->dimNames;
67   std::vector<int>& dimLens = _readNC->dimLens;
68   std::map<std::string, ReadNC::AttData>& globalAtts = _readNC->globalAtts;
69   std::map<std::string, ReadNC::VarData>& varInfo = _readNC->varInfo;
70   DebugOutput& dbgOut = _readNC->dbgOut;
71   int& partMethod = _readNC->partMethod;
72   ScdInterface* scdi = _readNC->scdi;
73 
74   ErrorCode rval;
75   std::string tag_name;
76 
77   // <__NUM_DIMS>
78   Tag numDimsTag = 0;
79   tag_name = "__NUM_DIMS";
80   int numDims = dimNames.size();
81   rval = mbImpl->tag_get_handle(tag_name.c_str(), 1, MB_TYPE_INTEGER, numDimsTag,
82                                 MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
83   rval = mbImpl->tag_set_data(numDimsTag, &_fileSet, 1, &numDims);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
84   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
85 
86   // <__NUM_VARS>
87   Tag numVarsTag = 0;
88   tag_name = "__NUM_VARS";
89   int numVars = varInfo.size();
90   rval = mbImpl->tag_get_handle(tag_name.c_str(), 1, MB_TYPE_INTEGER, numVarsTag,
91                                 MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
92   rval = mbImpl->tag_set_data(numVarsTag, &_fileSet, 1, &numVars);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
93   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
94 
95   // <__DIM_NAMES>
96   Tag dimNamesTag = 0;
97   tag_name = "__DIM_NAMES";
98   std::string dimnames;
99   unsigned int dimNamesSz = dimNames.size();
100   for (unsigned int i = 0; i != dimNamesSz; i++) {
101     dimnames.append(dimNames[i]);
102     dimnames.push_back('\0');
103   }
104   int dimnamesSz = dimnames.size();
105   rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, dimNamesTag,
106                                 MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
107   const void* ptr = dimnames.c_str();
108   rval = mbImpl->tag_set_by_ptr(dimNamesTag, &_fileSet, 1, &ptr, &dimnamesSz);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
109   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
110 
111   // <__DIM_LENS>
112   Tag dimLensTag = 0;
113   tag_name = "__DIM_LENS";
114   int dimLensSz = dimLens.size();
115   rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_INTEGER, dimLensTag,
116                                 MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
117   ptr = &(dimLens[0]);
118   rval = mbImpl->tag_set_by_ptr(dimLensTag, &_fileSet, 1, &ptr, &dimLensSz);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
119   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
120 
121   // <__VAR_NAMES>
122   Tag varNamesTag = 0;
123   tag_name = "__VAR_NAMES";
124   std::string varnames;
125   std::map<std::string, ReadNC::VarData>::iterator mapIter;
126   for (mapIter = varInfo.begin(); mapIter != varInfo.end(); ++mapIter) {
127     varnames.append(mapIter->first);
128     varnames.push_back('\0');
129   }
130   int varnamesSz = varnames.size();
131   rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, varNamesTag,
132                                 MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
133   ptr = varnames.c_str();
134   rval = mbImpl->tag_set_by_ptr(varNamesTag, &_fileSet, 1, &ptr, &varnamesSz);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
135   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
136 
137   // __<dim_name>_LOC_MINMAX (for time)
138   for (unsigned int i = 0; i != dimNamesSz; i++) {
139     if (dimNames[i] == "time" || dimNames[i] == "Time" || dimNames[i] == "t") {
140       // some files might have Time dimension as 0, it will not appear in any
141       // variables, so skip it
142       if (nTimeSteps==0)
143         continue;
144       std::stringstream ss_tag_name;
145       ss_tag_name << "__" << dimNames[i] << "_LOC_MINMAX";
146       tag_name = ss_tag_name.str();
147       Tag tagh = 0;
148       std::vector<int> val(2, 0);
149       val[0] = 0;
150       val[1] = nTimeSteps - 1;
151       rval = mbImpl->tag_get_handle(tag_name.c_str(), 2, MB_TYPE_INTEGER, tagh,
152                                     MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
153       rval = mbImpl->tag_set_data(tagh, &_fileSet, 1, &val[0]);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
154       dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
155     }
156   }
157 
158   // __<dim_name>_LOC_VALS (for time)
159   for (unsigned int i = 0; i != dimNamesSz; i++) {
160     if (dimNames[i] == "time" || dimNames[i] == "Time" || dimNames[i] == "t") {
161       std::vector<int> val;
162       if (!tstep_nums.empty())
163         val = tstep_nums;
164       else {
165         // some files might have Time dimension as 0, it will not appear in any
166         // variables, so skip it
167         if (tVals.empty())
168           continue;
169         val.resize(tVals.size());
170         for (unsigned int j = 0; j != tVals.size(); j++)
171           val[j] = j;
172       }
173       Tag tagh = 0;
174       std::stringstream ss_tag_name;
175       ss_tag_name << "__" << dimNames[i] << "_LOC_VALS";
176       tag_name = ss_tag_name.str();
177       rval = mbImpl->tag_get_handle(tag_name.c_str(), val.size(), MB_TYPE_INTEGER, tagh,
178                                     MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
179       rval = mbImpl->tag_set_data(tagh, &_fileSet, 1, &val[0]);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
180       dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
181     }
182   }
183 
184   // __<var_name>_DIMS
185   for (mapIter = varInfo.begin(); mapIter != varInfo.end(); ++mapIter) {
186     Tag varNamesDimsTag = 0;
187     std::stringstream ss_tag_name;
188     ss_tag_name << "__" << mapIter->first << "_DIMS";
189     tag_name = ss_tag_name.str();
190     unsigned int varDimSz = varInfo[mapIter->first].varDims.size();
191     if (varDimSz == 0)
192       continue;
193     std::vector<Tag> varDimTags(varDimSz);
194     for (unsigned int i = 0; i != varDimSz; i++) {
195       Tag tmptag = 0;
196       std::string tmptagname = dimNames[varInfo[mapIter->first].varDims[i]];
197       rval = mbImpl->tag_get_handle(tmptagname.c_str(), 0, MB_TYPE_OPAQUE, tmptag, MB_TAG_ANY);MB_CHK_SET_ERR(rval, "Trouble getting tag " << tmptagname);
198       varDimTags[i] = tmptag;
199     }
200     // rval = mbImpl->tag_get_handle(tag_name.c_str(), varDimSz, MB_TYPE_HANDLE, varNamesDimsTag, MB_TAG_SPARSE | MB_TAG_CREAT);
201     // We should not use MB_TYPE_HANDLE for Tag here. Tag is a pointer, which is 4 bytes on 32 bit machines and 8 bytes on 64 bit machines.
202     // Normally, entity handle is 8 bytes on 64 bit machines, but it can also be configured to 4 bytes.
203     rval = mbImpl->tag_get_handle(tag_name.c_str(), varDimSz*sizeof(Tag), MB_TYPE_OPAQUE, varNamesDimsTag,
204                                   MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
205     rval = mbImpl->tag_set_data(varNamesDimsTag, &_fileSet, 1, &(varDimTags[0]));MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
206     dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
207   }
208 
209   // <PARTITION_METHOD>
210   Tag part_tag = scdi->part_method_tag();
211   if (!part_tag)
212     MB_SET_ERR(MB_FAILURE, "Trouble getting PARTITION_METHOD tag");
213   rval = mbImpl->tag_set_data(part_tag, &_fileSet, 1, &partMethod);MB_CHK_SET_ERR(rval, "Trouble setting data to PARTITION_METHOD tag");
214   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
215 
216   // <__GLOBAL_ATTRIBS>
217   tag_name = "__GLOBAL_ATTRIBS";
218   Tag globalAttTag = 0;
219   rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, globalAttTag,
220                                 MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
221   std::string gattVal;
222   std::vector<int> gattLen;
223   rval = create_attrib_string(globalAtts, gattVal, gattLen);MB_CHK_SET_ERR(rval, "Trouble creating global attribute string");
224   const void* gattptr = gattVal.c_str();
225   int globalAttSz = gattVal.size();
226   rval = mbImpl->tag_set_by_ptr(globalAttTag, &_fileSet, 1, &gattptr, &globalAttSz);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
227   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
228 
229   // <__GLOBAL_ATTRIBS_LEN>
230   tag_name = "__GLOBAL_ATTRIBS_LEN";
231   Tag globalAttLenTag = 0;
232   if (gattLen.size() == 0)
233     gattLen.push_back(0);
234   rval = mbImpl->tag_get_handle(tag_name.c_str(), gattLen.size(), MB_TYPE_INTEGER, globalAttLenTag,
235                                 MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
236   rval = mbImpl->tag_set_data(globalAttLenTag, &_fileSet, 1, &gattLen[0]);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
237   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
238 
239   // __<var_name>_ATTRIBS and __<var_name>_ATTRIBS_LEN
240   for (mapIter = varInfo.begin(); mapIter != varInfo.end(); ++mapIter) {
241     std::stringstream ssTagName;
242     ssTagName << "__" << mapIter->first << "_ATTRIBS";
243     tag_name = ssTagName.str();
244     Tag varAttTag = 0;
245     rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, varAttTag,
246                                   MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
247 
248     std::string varAttVal;
249     std::vector<int> varAttLen;
250     if (mapIter->second.numAtts < 1) {
251       if (dummyVarNames.find(mapIter->first) != dummyVarNames.end()) {
252         // This variable is a dummy coordinate variable
253         varAttVal = "DUMMY_VAR";
254       }
255       else {
256         // This variable has no attributes
257         varAttVal = "NO_ATTRIBS";
258       }
259     }
260     else {
261       rval = create_attrib_string(mapIter->second.varAtts, varAttVal, varAttLen);MB_CHK_SET_ERR(rval, "Trouble creating attribute string for variable " << mapIter->first);
262     }
263     const void* varAttPtr = varAttVal.c_str();
264     int varAttSz = varAttVal.size();
265     if (0 == varAttSz)
266       varAttSz = 1;
267     rval = mbImpl->tag_set_by_ptr(varAttTag, &_fileSet, 1, &varAttPtr, &varAttSz);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
268     dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
269 
270     ssTagName << "_LEN";
271     tag_name = ssTagName.str();
272     Tag varAttLenTag = 0;
273     if (0 == varAttLen.size())
274       varAttLen.push_back(0);
275     rval = mbImpl->tag_get_handle(tag_name.c_str(), varAttLen.size(), MB_TYPE_INTEGER, varAttLenTag,
276                                   MB_TAG_SPARSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
277     rval = mbImpl->tag_set_data(varAttLenTag, &_fileSet, 1, &varAttLen[0]);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
278     dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
279   }
280 
281   // <__VAR_NAMES_LOCATIONS>
282   tag_name = "__VAR_NAMES_LOCATIONS";
283   Tag varNamesLocsTag = 0;
284   std::vector<int> varNamesLocs(varInfo.size());
285   rval = mbImpl->tag_get_handle(tag_name.c_str(), varNamesLocs.size(), MB_TYPE_INTEGER, varNamesLocsTag,
286                                 MB_TAG_CREAT | MB_TAG_SPARSE);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
287   for (mapIter = varInfo.begin(); mapIter != varInfo.end(); ++mapIter) {
288     varNamesLocs[std::distance(varInfo.begin(), mapIter)] = mapIter->second.entLoc;
289   }
290   rval = mbImpl->tag_set_data(varNamesLocsTag, &_fileSet, 1, &varNamesLocs[0]);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
291   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
292 
293   // <__MESH_TYPE>
294   Tag meshTypeTag = 0;
295   tag_name = "__MESH_TYPE";
296   std::string meshTypeName = get_mesh_type_name();
297 
298   rval = mbImpl->tag_get_handle(tag_name.c_str(), 0, MB_TYPE_OPAQUE, meshTypeTag,
299                                 MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating conventional tag " << tag_name);
300   ptr = meshTypeName.c_str();
301   int leng = meshTypeName.size();
302   rval = mbImpl->tag_set_by_ptr(meshTypeTag, &_fileSet, 1, &ptr, &leng);MB_CHK_SET_ERR(rval, "Trouble setting data to conventional tag " << tag_name);
303   dbgOut.tprintf(2, "Conventional tag %s created\n", tag_name.c_str());
304 
305   return MB_SUCCESS;
306 }
307 
update_time_tag_vals()308 ErrorCode NCHelper::update_time_tag_vals()
309 {
310   Interface*& mbImpl = _readNC->mbImpl;
311   std::vector<std::string>& dimNames = _readNC->dimNames;
312 
313   ErrorCode rval;
314 
315   // The time tag might be a dummy one (e.g. 'Time' for MPAS)
316   std::string time_tag_name = dimNames[tDim];
317   if (dummyVarNames.find(time_tag_name) != dummyVarNames.end())
318     return MB_SUCCESS;
319 
320   Tag time_tag = 0;
321   const void* data = NULL;
322   int time_tag_size = 0;
323   rval = mbImpl->tag_get_handle(time_tag_name.c_str(), 0, MB_TYPE_DOUBLE, time_tag, MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble getting tag " << time_tag_name);
324   rval = mbImpl->tag_get_by_ptr(time_tag, &_fileSet, 1, &data, &time_tag_size);MB_CHK_SET_ERR(rval, "Trouble getting data of tag " << time_tag_name);
325   const double* time_tag_vals = static_cast<const double*>(data);
326 
327   // Merge tVals (read from current file) to existing time tag
328   // Assume that time_tag_vals and tVals are both sorted
329   std::vector<double> merged_time_vals;
330   merged_time_vals.reserve(time_tag_size + nTimeSteps);
331   int i = 0;
332   int j = 0;
333 
334   // Merge time values from time_tag_vals and tVals
335   while (i < time_tag_size && j < nTimeSteps) {
336     if (time_tag_vals[i] < tVals[j])
337       merged_time_vals.push_back(time_tag_vals[i++]);
338     else
339       merged_time_vals.push_back(tVals[j++]);
340   }
341 
342   // Append remaining time values of time_tag_vals (if any)
343   while (i < time_tag_size)
344     merged_time_vals.push_back(time_tag_vals[i++]);
345 
346   // Append remaining time values of tVals (if any)
347   while (j < nTimeSteps)
348     merged_time_vals.push_back(tVals[j++]);
349 
350   data = &merged_time_vals[0];
351   time_tag_size = merged_time_vals.size();
352   rval = mbImpl->tag_set_by_ptr(time_tag, &_fileSet, 1, &data, &time_tag_size);MB_CHK_SET_ERR(rval, "Trouble setting data to tag " << time_tag_name);
353 
354   return MB_SUCCESS;
355 }
356 
read_variables_setup(std::vector<std::string> & var_names,std::vector<int> & tstep_nums,std::vector<ReadNC::VarData> & vdatas,std::vector<ReadNC::VarData> & vsetdatas)357 ErrorCode NCHelper::read_variables_setup(std::vector<std::string>& var_names, std::vector<int>& tstep_nums,
358                                         std::vector<ReadNC::VarData>& vdatas, std::vector<ReadNC::VarData>& vsetdatas)
359 {
360   std::map<std::string, ReadNC::VarData>& varInfo = _readNC->varInfo;
361   std::vector<std::string>& dimNames = _readNC->dimNames;
362 
363   std::map<std::string, ReadNC::VarData>::iterator mit;
364 
365   // If empty read them all (except ignored variables)
366   if (var_names.empty()) {
367     for (mit = varInfo.begin(); mit != varInfo.end(); ++mit) {
368       ReadNC::VarData vd = (*mit).second;
369 
370       // If read all variables at once, skip ignored ones
371       if (ignoredVarNames.find(vd.varName) != ignoredVarNames.end())
372          continue;
373 
374       // Coordinate variables (include dummy ones) were read to the file set by default
375       if (std::find(dimNames.begin(), dimNames.end(), vd.varName) != dimNames.end())
376         continue;
377 
378       if (vd.entLoc == ReadNC::ENTLOCSET)
379         vsetdatas.push_back(vd);
380       else
381         vdatas.push_back(vd);
382     }
383   }
384   else {
385     // Read specified variables (might include ignored ones)
386     for (unsigned int i = 0; i < var_names.size(); i++) {
387       mit = varInfo.find(var_names[i]);
388       if (mit != varInfo.end()) {
389         ReadNC::VarData vd = (*mit).second;
390 
391         // Upon creation of dummy coordinate variables, tag values have already been set
392         if (dummyVarNames.find(vd.varName) != dummyVarNames.end())
393            continue;
394 
395         if (vd.entLoc == ReadNC::ENTLOCSET)
396           vsetdatas.push_back(vd);
397         else
398           vdatas.push_back(vd);
399       }
400       else {
401         MB_SET_ERR(MB_FAILURE, "Couldn't find specified variable " << var_names[i]);
402       }
403     }
404   }
405 
406   if (tstep_nums.empty() && nTimeSteps > 0) {
407     // No timesteps input, get them all
408     for (int i = 0; i < nTimeSteps; i++)
409       tstep_nums.push_back(i);
410   }
411 
412   if (!tstep_nums.empty()) {
413     for (unsigned int i = 0; i < vdatas.size(); i++) {
414       vdatas[i].varTags.resize(tstep_nums.size(), 0);
415       vdatas[i].varDatas.resize(tstep_nums.size());
416       // NC reader assumes that non-set variables always have timesteps
417       assert(std::find(vdatas[i].varDims.begin(), vdatas[i].varDims.end(), tDim) != vdatas[i].varDims.end());
418       vdatas[i].has_tsteps = true;
419     }
420 
421     for (unsigned int i = 0; i < vsetdatas.size(); i++) {
422       if ((std::find(vsetdatas[i].varDims.begin(), vsetdatas[i].varDims.end(), tDim) != vsetdatas[i].varDims.end())
423           && (vsetdatas[i].varName != dimNames[tDim])) {
424         // Set variables with timesteps: e.g. xtime(Time) or xtime(Time, StrLen)
425         vsetdatas[i].varTags.resize(tstep_nums.size(), 0);
426         vsetdatas[i].varDatas.resize(tstep_nums.size());
427         vsetdatas[i].has_tsteps = true;
428       }
429       else {
430         // Set variables without timesteps: no time dimension, or time itself
431         vsetdatas[i].varTags.resize(1, 0);
432         vsetdatas[i].varDatas.resize(1);
433         vsetdatas[i].has_tsteps = false;
434       }
435     }
436   }
437 
438   return MB_SUCCESS;
439 }
440 
read_variables_to_set(std::vector<ReadNC::VarData> & vdatas,std::vector<int> & tstep_nums)441 ErrorCode NCHelper::read_variables_to_set(std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
442 {
443   Interface*& mbImpl = _readNC->mbImpl;
444   DebugOutput& dbgOut = _readNC->dbgOut;
445 
446   ErrorCode rval = read_variables_to_set_allocate(vdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble allocating space to read set variables");
447 
448   // Finally, read into that space
449   int success;
450   for (unsigned int i = 0; i < vdatas.size(); i++) {
451     // Note, for set variables without timesteps, loop one time and then break
452     for (unsigned int t = 0; t < tstep_nums.size(); t++) {
453       void* data = vdatas[i].varDatas[t];
454 
455       // Set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen)
456       if (vdatas[i].has_tsteps) {
457         // Set readStart for each timestep along time dimension
458         vdatas[i].readStarts[0] = tstep_nums[t];
459       }
460 
461       switch (vdatas[i].varDataType) {
462         case NC_BYTE:
463         case NC_CHAR:
464           success = NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdatas[i].readStarts[0],
465                                         &vdatas[i].readCounts[0], (char*) data);
466           if (success)
467             MB_SET_ERR(MB_FAILURE, "Failed to read byte/char data for variable " << vdatas[i].varName);
468           break;
469         case NC_SHORT:
470         case NC_INT:
471           success = NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdatas[i].readStarts[0],
472                                         &vdatas[i].readCounts[0], (int*) data);
473           if (success)
474             MB_SET_ERR(MB_FAILURE, "Failed to read short/int data for variable " << vdatas[i].varName);
475           break;
476         case NC_FLOAT:
477         case NC_DOUBLE:
478           success = NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vdatas[i].readStarts[0],
479                                         &vdatas[i].readCounts[0], (double*) data);
480           if (success)
481             MB_SET_ERR(MB_FAILURE, "Failed to read float/double data for variable " << vdatas[i].varName);
482           break;
483         default:
484           MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName);
485       }
486 
487       dbgOut.tprintf(2, "Setting data for variable %s, time step %d\n", vdatas[i].varName.c_str(), tstep_nums[t]);
488       rval = mbImpl->tag_set_by_ptr(vdatas[i].varTags[t], &_fileSet, 1, &data, &vdatas[i].sz);MB_CHK_SET_ERR(rval, "Trouble setting tag data for variable " << vdatas[i].varName);
489 
490       // Memory pointed by pointer data can be deleted, as tag_set_by_ptr() has already copied the tag values
491       switch (vdatas[i].varDataType) {
492         case NC_BYTE:
493         case NC_CHAR:
494           delete[] (char*) data;
495           break;
496         case NC_SHORT:
497         case NC_INT:
498           delete[] (int*) data;
499           break;
500         case NC_FLOAT:
501         case NC_DOUBLE:
502           delete[] (double*) data;
503           break;
504         default:
505           break;
506       }
507       vdatas[i].varDatas[t] = NULL;
508 
509       // Loop continues only for set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen)
510       if (!vdatas[i].has_tsteps)
511         break;
512     }
513   }
514 
515   // Debug output, if requested
516   if (1 == dbgOut.get_verbosity()) {
517     dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str());
518     for (unsigned int i = 1; i < vdatas.size(); i++)
519       dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
520     dbgOut.tprintf(1, "\n");
521   }
522 
523   return rval;
524 }
525 
read_coordinate(const char * var_name,int lmin,int lmax,std::vector<double> & cvals)526 ErrorCode NCHelper::read_coordinate(const char* var_name, int lmin, int lmax, std::vector<double>& cvals)
527 {
528   std::map<std::string, ReadNC::VarData>& varInfo = _readNC->varInfo;
529   std::map<std::string, ReadNC::VarData>::iterator vmit = varInfo.find(var_name);
530   if (varInfo.end() == vmit)
531     MB_SET_ERR(MB_FAILURE, "Couldn't find variable " << var_name);
532 
533   assert(lmin >= 0 && lmax >= lmin);
534   NCDF_SIZE tstart = lmin;
535   NCDF_SIZE tcount = lmax - lmin + 1;
536   NCDF_DIFF dum_stride = 1;
537   int success;
538 
539   // Check size
540   if ((std::size_t)tcount != cvals.size())
541     cvals.resize(tcount);
542 
543   // Check to make sure it's a float or double
544   switch ((*vmit).second.varDataType) {
545     case NC_FLOAT:
546     case NC_DOUBLE:
547       // Read float as double
548       success = NCFUNCAG(_vars_double)(_fileId, (*vmit).second.varId, &tstart, &tcount, &dum_stride, &cvals[0]);
549       if (success)
550         MB_SET_ERR(MB_FAILURE, "Failed to read float/double data for variable " << var_name);
551       break;
552     default:
553       MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << var_name);
554   }
555 
556   return MB_SUCCESS;
557 }
558 
get_tag_to_set(ReadNC::VarData & var_data,int tstep_num,Tag & tagh)559 ErrorCode NCHelper::get_tag_to_set(ReadNC::VarData& var_data, int tstep_num, Tag& tagh)
560 {
561   Interface*& mbImpl = _readNC->mbImpl;
562   DebugOutput& dbgOut = _readNC->dbgOut;
563   int& tStepBase = _readNC->tStepBase;
564 
565   if (tStepBase > 0)
566     tstep_num += tStepBase;
567 
568   std::ostringstream tag_name;
569   if (var_data.has_tsteps)
570     tag_name << var_data.varName << tstep_num;
571   else
572     tag_name << var_data.varName;
573 
574   ErrorCode rval = MB_SUCCESS;
575   tagh = 0;
576   switch (var_data.varDataType) {
577     case NC_BYTE:
578     case NC_CHAR:
579       rval = mbImpl->tag_get_handle(tag_name.str().c_str(), 0, MB_TYPE_OPAQUE, tagh,
580                                     MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating tag " << tag_name.str());
581       break;
582     case NC_SHORT:
583     case NC_INT:
584       rval = mbImpl->tag_get_handle(tag_name.str().c_str(), 0, MB_TYPE_INTEGER, tagh,
585                                     MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating tag " << tag_name.str());
586       break;
587     case NC_FLOAT:
588     case NC_DOUBLE:
589       rval = mbImpl->tag_get_handle(tag_name.str().c_str(), 0, MB_TYPE_DOUBLE, tagh,
590                                     MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating tag " << tag_name.str());
591       break;
592     default:
593       MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << var_data.varName);
594   }
595 
596   dbgOut.tprintf(2, "Tag %s created\n", tag_name.str().c_str());
597 
598   return rval;
599 }
600 
get_tag_to_nonset(ReadNC::VarData & var_data,int tstep_num,Tag & tagh,int num_lev)601 ErrorCode NCHelper::get_tag_to_nonset(ReadNC::VarData& var_data, int tstep_num, Tag& tagh, int num_lev)
602 {
603   Interface*& mbImpl = _readNC->mbImpl;
604   DebugOutput& dbgOut = _readNC->dbgOut;
605   int& tStepBase = _readNC->tStepBase;
606 
607   if (tStepBase > 0)
608     tstep_num += tStepBase;
609 
610   std::ostringstream tag_name;
611   tag_name << var_data.varName << tstep_num;
612 
613   ErrorCode rval = MB_SUCCESS;
614   tagh = 0;
615   switch (var_data.varDataType) {
616     case NC_BYTE:
617     case NC_CHAR:
618       rval = mbImpl->tag_get_handle(tag_name.str().c_str(), num_lev, MB_TYPE_OPAQUE, tagh,
619                                     MB_TAG_DENSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating tag " << tag_name.str());
620       break;
621     case NC_SHORT:
622     case NC_INT:
623       rval = mbImpl->tag_get_handle(tag_name.str().c_str(), num_lev, MB_TYPE_INTEGER, tagh,
624                                     MB_TAG_DENSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating tag " << tag_name.str());
625       break;
626     case NC_FLOAT:
627     case NC_DOUBLE:
628       rval = mbImpl->tag_get_handle(tag_name.str().c_str(), num_lev, MB_TYPE_DOUBLE, tagh,
629                                     MB_TAG_DENSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating tag " << tag_name.str());
630       break;
631     default:
632       MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << var_data.varName);
633   }
634 
635   dbgOut.tprintf(2, "Tag %s created\n", tag_name.str().c_str());
636 
637   return rval;
638 }
639 
create_attrib_string(const std::map<std::string,ReadNC::AttData> & attMap,std::string & attVal,std::vector<int> & attLen)640 ErrorCode NCHelper::create_attrib_string(const std::map<std::string, ReadNC::AttData>& attMap, std::string& attVal, std::vector<int>& attLen)
641 {
642   int success;
643   std::stringstream ssAtt;
644   unsigned int sz = 0;
645   std::map<std::string, ReadNC::AttData>::const_iterator attIt = attMap.begin();
646   for (; attIt != attMap.end(); ++attIt) {
647     ssAtt << attIt->second.attName;
648     ssAtt << '\0';
649     void* attData = NULL;
650     switch (attIt->second.attDataType) {
651       case NC_BYTE:
652       case NC_CHAR:
653         sz = attIt->second.attLen;
654         attData = (char *) malloc(sz);
655         success = NCFUNC(get_att_text)(_fileId, attIt->second.attVarId, attIt->second.attName.c_str(), (char*) attData);
656         if (success)
657           MB_SET_ERR(MB_FAILURE, "Failed to read byte/char data for attribute " << attIt->second.attName);
658         ssAtt << "char;";
659         break;
660       case NC_SHORT:
661         sz = attIt->second.attLen * sizeof(short);
662         attData = (short *) malloc(sz);
663         success = NCFUNC(get_att_short)(_fileId, attIt->second.attVarId, attIt->second.attName.c_str(), (short*) attData);
664         if (success)
665           MB_SET_ERR(MB_FAILURE, "Failed to read short data for attribute " << attIt->second.attName);
666         ssAtt << "short;";
667         break;
668       case NC_INT:
669         sz = attIt->second.attLen * sizeof(int);
670         attData = (int *) malloc(sz);
671         success = NCFUNC(get_att_int)(_fileId, attIt->second.attVarId, attIt->second.attName.c_str(), (int*) attData);
672         if (success)
673           MB_SET_ERR(MB_FAILURE, "Failed to read int data for attribute " << attIt->second.attName);
674         ssAtt << "int;";
675         break;
676       case NC_FLOAT:
677         sz = attIt->second.attLen * sizeof(float);
678         attData = (float *) malloc(sz);
679         success = NCFUNC(get_att_float)(_fileId, attIt->second.attVarId, attIt->second.attName.c_str(), (float*) attData);
680         if (success)
681           MB_SET_ERR(MB_FAILURE, "Failed to read float data for attribute " << attIt->second.attName);
682         ssAtt << "float;";
683         break;
684       case NC_DOUBLE:
685         sz = attIt->second.attLen * sizeof(double);
686         attData = (double *) malloc(sz);
687         success = NCFUNC(get_att_double)(_fileId, attIt->second.attVarId, attIt->second.attName.c_str(), (double*) attData);
688         if (success)
689           MB_SET_ERR(MB_FAILURE, "Failed to read double data for attribute " << attIt->second.attName);
690         ssAtt << "double;";
691         break;
692       default:
693         MB_SET_ERR(MB_FAILURE, "Unexpected data type for attribute " << attIt->second.attName);
694     }
695     char* tmpc = (char *) attData;
696     for (unsigned int counter = 0; counter != sz; ++counter)
697       ssAtt << tmpc[counter];
698     free(attData);
699     ssAtt << ';';
700     attLen.push_back(ssAtt.str().size() - 1);
701   }
702   attVal = ssAtt.str();
703 
704   return MB_SUCCESS;
705 }
706 
create_dummy_variables()707 ErrorCode NCHelper::create_dummy_variables()
708 {
709   Interface*& mbImpl = _readNC->mbImpl;
710   std::vector<std::string>& dimNames = _readNC->dimNames;
711   std::vector<int>& dimLens = _readNC->dimLens;
712   std::map<std::string, ReadNC::VarData>& varInfo = _readNC->varInfo;
713   DebugOutput& dbgOut = _readNC->dbgOut;
714 
715   // Hack: look at all dimensions, and see if we have one that does not appear in the list of varInfo names
716   // Right now, candidates are from unstructured meshes, such as ncol (HOMME) and nCells (MPAS)
717   // For each of them, create a dummy coordinate variable with a sparse tag to store the dimension length
718   for (unsigned int i = 0; i < dimNames.size(); i++) {
719     // If there is a variable with this dimension name, skip
720     if (varInfo.find(dimNames[i]) != varInfo.end())
721       continue;
722 
723     // Create a dummy coordinate variable
724     int sizeTotalVar = varInfo.size();
725     std::string var_name(dimNames[i]);
726     ReadNC::VarData& data = varInfo[var_name];
727     data.varName = var_name;
728     data.varId = sizeTotalVar;
729     data.varTags.resize(1, 0);
730     data.varDataType = NC_INT;
731     data.varDims.resize(1);
732     data.varDims[0] = (int)i;
733     data.numAtts = 0;
734     data.entLoc = ReadNC::ENTLOCSET;
735     dummyVarNames.insert(var_name);
736     dbgOut.tprintf(2, "Dummy coordinate variable created for dimension %s\n", var_name.c_str());
737 
738     // Create a corresponding sparse tag
739     Tag tagh;
740     ErrorCode rval = mbImpl->tag_get_handle(var_name.c_str(), 0, MB_TYPE_INTEGER, tagh,
741                                             MB_TAG_CREAT | MB_TAG_SPARSE | MB_TAG_VARLEN);MB_CHK_SET_ERR(rval, "Trouble creating tag for dummy coordinate variable " << var_name);
742 
743     // Tag value is the dimension length
744     const void* ptr = &dimLens[i];
745     // Tag size is 1
746     int size = 1;
747     rval = mbImpl->tag_set_by_ptr(tagh, &_fileSet, 1, &ptr, &size);MB_CHK_SET_ERR(rval, "Trouble setting tag data for dummy coordinate variable " << var_name);
748 
749     dbgOut.tprintf(2, "Sparse tag created for dimension %s\n", var_name.c_str());
750   }
751 
752   return MB_SUCCESS;
753 }
754 
read_variables_to_set_allocate(std::vector<ReadNC::VarData> & vdatas,std::vector<int> & tstep_nums)755 ErrorCode NCHelper::read_variables_to_set_allocate(std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
756 {
757   std::vector<int>& dimLens = _readNC->dimLens;
758   DebugOutput& dbgOut = _readNC->dbgOut;
759 
760   ErrorCode rval = MB_SUCCESS;
761 
762   for (unsigned int i = 0; i < vdatas.size(); i++) {
763     // Set up readStarts and readCounts
764     if (vdatas[i].has_tsteps) {
765       // First: time
766       vdatas[i].readStarts.push_back(0); // This value is timestep dependent, will be set later
767       vdatas[i].readCounts.push_back(1);
768 
769       // Next: other dimensions
770       for (unsigned int idx = 1; idx != vdatas[i].varDims.size(); idx++) {
771         vdatas[i].readStarts.push_back(0);
772         vdatas[i].readCounts.push_back(dimLens[vdatas[i].varDims[idx]]);
773       }
774     }
775     else {
776       if (vdatas[i].varDims.empty()) {
777         // Scalar variable
778         vdatas[i].readStarts.push_back(0);
779         vdatas[i].readCounts.push_back(1);
780       }
781       else {
782         for (unsigned int idx = 0; idx != vdatas[i].varDims.size(); idx++) {
783           vdatas[i].readStarts.push_back(0);
784           vdatas[i].readCounts.push_back(dimLens[vdatas[i].varDims[idx]]);
785         }
786       }
787     }
788 
789     // Get variable size
790     vdatas[i].sz = 1;
791     for (std::size_t idx = 0; idx != vdatas[i].readCounts.size(); idx++)
792       vdatas[i].sz *= vdatas[i].readCounts[idx];
793 
794     // Note, for set variables without timesteps, loop one time and then break
795     for (unsigned int t = 0; t < tstep_nums.size(); t++) {
796       dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].varName.c_str(), tstep_nums[t]);
797 
798       if (tstep_nums[t] >= dimLens[tDim]) {
799         MB_SET_ERR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number " << tstep_nums[t]);
800       }
801 
802       // Get the tag to read into
803       if (!vdatas[i].varTags[t]) {
804         rval = get_tag_to_set(vdatas[i], tstep_nums[t], vdatas[i].varTags[t]);MB_CHK_SET_ERR(rval, "Trouble getting tag to set variable " << vdatas[i].varName);
805       }
806 
807       switch (vdatas[i].varDataType) {
808         case NC_BYTE:
809         case NC_CHAR:
810           vdatas[i].varDatas[t] = new char[vdatas[i].sz];
811           break;
812         case NC_SHORT:
813         case NC_INT:
814           vdatas[i].varDatas[t] = new int[vdatas[i].sz];
815           break;
816         case NC_FLOAT:
817         case NC_DOUBLE:
818           vdatas[i].varDatas[t] = new double[vdatas[i].sz];
819           break;
820         default:
821           MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName);
822       }
823 
824       // Loop continues only for set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen)
825       if (!vdatas[i].has_tsteps)
826         break;
827     }
828   }
829 
830   return rval;
831 }
832 
check_existing_mesh()833 ErrorCode ScdNCHelper::check_existing_mesh() {
834   Interface*& mbImpl = _readNC->mbImpl;
835 
836   // Get the number of vertices
837   int num_verts;
838   ErrorCode rval = mbImpl->get_number_entities_by_dimension(_fileSet, 0, num_verts);MB_CHK_SET_ERR(rval, "Trouble getting number of vertices");
839 
840   /*
841   // Check against parameters
842   // When ghosting is used, this check might fail (to be updated later)
843   if (num_verts > 0) {
844     int expected_verts = (lDims[3] - lDims[0] + 1) * (lDims[4] - lDims[1] + 1) * (-1 == lDims[2] ? 1 : lDims[5] - lDims[2] + 1);
845     if (num_verts != expected_verts) {
846       MB_SET_ERR(MB_FAILURE, "Number of vertices doesn't match");
847     }
848   }
849   */
850 
851   // Check the number of elements too
852   int num_elems;
853   rval = mbImpl->get_number_entities_by_dimension(_fileSet, (-1 == lCDims[2] ? 2 : 3), num_elems);MB_CHK_SET_ERR(rval, "Trouble getting number of elements");
854 
855   /*
856   // Check against parameters
857   // When ghosting is used, this check might fail (to be updated later)
858   if (num_elems > 0) {
859     int expected_elems = (lCDims[3] - lCDims[0] + 1) * (lCDims[4] - lCDims[1] + 1) * (-1 == lCDims[2] ? 1 : (lCDims[5] - lCDims[2] + 1));
860     if (num_elems != expected_elems) {
861       MB_SET_ERR(MB_FAILURE, "Number of elements doesn't match");
862     }
863   }
864   */
865 
866   return MB_SUCCESS;
867 }
868 
create_mesh(Range & faces)869 ErrorCode ScdNCHelper::create_mesh(Range& faces)
870 {
871   Interface*& mbImpl = _readNC->mbImpl;
872   Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
873   const Tag*& mpFileIdTag = _readNC->mpFileIdTag;
874   DebugOutput& dbgOut = _readNC->dbgOut;
875   ScdInterface* scdi = _readNC->scdi;
876   ScdParData& parData = _readNC->parData;
877 
878   Range tmp_range;
879   ScdBox* scd_box;
880 
881   ErrorCode rval = scdi->construct_box(HomCoord(lDims[0], lDims[1], lDims[2], 1), HomCoord(lDims[3], lDims[4], lDims[5], 1),
882                                        NULL, 0, scd_box, locallyPeriodic, &parData, true);MB_CHK_SET_ERR(rval, "Trouble creating scd vertex sequence");
883 
884   // Add verts to tmp_range first, so we can duplicate global ids in vertex ids
885   tmp_range.insert(scd_box->start_vertex(), scd_box->start_vertex() + scd_box->num_vertices() - 1);
886 
887   if (mpFileIdTag) {
888     int count;
889     void* data;
890     rval = mbImpl->tag_iterate(*mpFileIdTag, tmp_range.begin(), tmp_range.end(), count, data);MB_CHK_SET_ERR(rval, "Failed to iterate file ID tag on local vertices");
891     assert(count == scd_box->num_vertices());
892     int* fid_data = (int*) data;
893     rval = mbImpl->tag_iterate(mGlobalIdTag, tmp_range.begin(), tmp_range.end(), count, data);MB_CHK_SET_ERR(rval, "Failed to iterate global ID tag on local vertices");
894     assert(count == scd_box->num_vertices());
895     int* gid_data = (int*) data;
896     for (int i = 0; i < count; i++)
897       fid_data[i] = gid_data[i];
898   }
899 
900   // Then add box set and elements to the range, then to the file set
901   tmp_range.insert(scd_box->start_element(), scd_box->start_element() + scd_box->num_elements() - 1);
902   tmp_range.insert(scd_box->box_set());
903   rval = mbImpl->add_entities(_fileSet, tmp_range);MB_CHK_SET_ERR(rval, "Couldn't add new vertices to current file set");
904 
905   dbgOut.tprintf(1, "scdbox %d quads, %d vertices\n", scd_box->num_elements(), scd_box->num_vertices());
906 
907   // Set the vertex coordinates
908   double *xc, *yc, *zc;
909   rval = scd_box->get_coordinate_arrays(xc, yc, zc);MB_CHK_SET_ERR(rval, "Couldn't get vertex coordinate arrays");
910 
911   int i, j, k, il, jl, kl;
912   int dil = lDims[3] - lDims[0] + 1;
913   int djl = lDims[4] - lDims[1] + 1;
914   assert(dil == (int)ilVals.size() && djl == (int)jlVals.size() &&
915       (-1 == lDims[2] || lDims[5] - lDims[2] + 1 == (int)levVals.size()));
916 
917   for (kl = lDims[2]; kl <= lDims[5]; kl++) {
918     k = kl - lDims[2];
919     for (jl = lDims[1]; jl <= lDims[4]; jl++) {
920       j = jl - lDims[1];
921       for (il = lDims[0]; il <= lDims[3]; il++) {
922         i = il - lDims[0];
923         unsigned int pos = i + j * dil + k * dil * djl;
924         xc[pos] = ilVals[i];
925         yc[pos] = jlVals[j];
926         zc[pos] = (-1 == lDims[2] ? 0.0 : levVals[k]);
927       }
928     }
929   }
930 
931 #ifndef NDEBUG
932   int num_verts = (lDims[3] - lDims[0] + 1) * (lDims[4] - lDims[1] + 1) * (-1 == lDims[2] ? 1 : lDims[5] - lDims[2] + 1);
933   std::vector<int> gids(num_verts);
934   Range verts(scd_box->start_vertex(), scd_box->start_vertex() + scd_box->num_vertices() - 1);
935   rval = mbImpl->tag_get_data(mGlobalIdTag, verts, &gids[0]);MB_CHK_SET_ERR(rval, "Trouble getting local gid values of vertices");
936   int vmin = *(std::min_element(gids.begin(), gids.end())), vmax = *(std::max_element(gids.begin(), gids.end()));
937   dbgOut.tprintf(1, "Vertex gids %d-%d\n", vmin, vmax);
938 #endif
939 
940   // Add elements to the range passed in
941   faces.insert(scd_box->start_element(), scd_box->start_element() + scd_box->num_elements() - 1);
942 
943   if (2 <= dbgOut.get_verbosity()) {
944     assert(scd_box->boundary_complete());
945     EntityHandle dum_ent = scd_box->start_element();
946     rval = mbImpl->list_entities(&dum_ent, 1);MB_CHK_SET_ERR(rval, "Trouble listing first hex");
947 
948     std::vector<EntityHandle> connect;
949     rval = mbImpl->get_connectivity(&dum_ent, 1, connect);MB_CHK_SET_ERR(rval, "Trouble getting connectivity");
950 
951     rval = mbImpl->list_entities(&connect[0], connect.size());MB_CHK_SET_ERR(rval, "Trouble listing element connectivity");
952   }
953 
954   Range edges;
955   mbImpl->get_adjacencies(faces, 1, true, edges, Interface::UNION);
956 
957   // Create COORDS tag for quads
958   rval = create_quad_coordinate_tag();MB_CHK_SET_ERR(rval, "Trouble creating COORDS tag for quads");
959 
960   return MB_SUCCESS;
961 }
962 
read_variables(std::vector<std::string> & var_names,std::vector<int> & tstep_nums)963 ErrorCode ScdNCHelper::read_variables(std::vector<std::string>& var_names, std::vector<int>& tstep_nums)
964 {
965   std::vector<ReadNC::VarData> vdatas;
966   std::vector<ReadNC::VarData> vsetdatas;
967 
968   ErrorCode rval = read_variables_setup(var_names, tstep_nums, vdatas, vsetdatas);MB_CHK_SET_ERR(rval, "Trouble setting up to read variables");
969 
970   if (!vsetdatas.empty()) {
971     rval = read_variables_to_set(vsetdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble reading variables to set");
972   }
973 
974   if (!vdatas.empty()) {
975     rval = read_scd_variables_to_nonset(vdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble reading variables to verts/edges/faces");
976   }
977 
978   return MB_SUCCESS;
979 }
980 
read_scd_variables_to_nonset_allocate(std::vector<ReadNC::VarData> & vdatas,std::vector<int> & tstep_nums)981 ErrorCode ScdNCHelper::read_scd_variables_to_nonset_allocate(std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
982 {
983   Interface*& mbImpl = _readNC->mbImpl;
984   std::vector<int>& dimLens = _readNC->dimLens;
985   DebugOutput& dbgOut = _readNC->dbgOut;
986 
987   Range* range = NULL;
988 
989   // Get vertices
990   Range verts;
991   ErrorCode rval = mbImpl->get_entities_by_dimension(_fileSet, 0, verts);MB_CHK_SET_ERR(rval, "Trouble getting vertices in current file set");
992   assert("Should only have a single vertex subrange, since they were read in one shot" &&
993       verts.psize() == 1);
994 
995   Range edges;
996   rval = mbImpl->get_entities_by_dimension(_fileSet, 1, edges);MB_CHK_SET_ERR(rval, "Trouble getting edges in current file set");
997 
998   // Get faces
999   Range faces;
1000   rval = mbImpl->get_entities_by_dimension(_fileSet, 2, faces);MB_CHK_SET_ERR(rval, "Trouble getting faces in current file set");
1001   assert("Should only have a single face subrange, since they were read in one shot" &&
1002       faces.psize() == 1);
1003 
1004 #ifdef MOAB_HAVE_MPI
1005   moab::Range faces_owned;
1006   bool& isParallel = _readNC->isParallel;
1007   if (isParallel) {
1008     ParallelComm*& myPcomm = _readNC->myPcomm;
1009     rval = myPcomm->filter_pstatus(faces, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &faces_owned);MB_CHK_SET_ERR(rval, "Trouble getting owned faces in current file set");
1010   }
1011   else
1012     faces_owned = faces; // Not running in parallel, but still with MPI
1013 #endif
1014 
1015   for (unsigned int i = 0; i < vdatas.size(); i++) {
1016     // Support non-set variables with 4 dimensions like (time, lev, lat, lon)
1017     assert(4 == vdatas[i].varDims.size());
1018 
1019     // For a non-set variable, time should be the first dimension
1020     assert(tDim == vdatas[i].varDims[0]);
1021 
1022     // Set up readStarts and readCounts
1023     vdatas[i].readStarts.resize(4);
1024     vdatas[i].readCounts.resize(4);
1025 
1026     // First: time
1027     vdatas[i].readStarts[0] = 0; // This value is timestep dependent, will be set later
1028     vdatas[i].readCounts[0] = 1;
1029 
1030     // Next: lev
1031     vdatas[i].readStarts[1] = 0;
1032     vdatas[i].readCounts[1] = vdatas[i].numLev;
1033 
1034     // Finally: lat (or slat) and lon (or slon)
1035     switch (vdatas[i].entLoc) {
1036       case ReadNC::ENTLOCVERT:
1037         // Vertices
1038         vdatas[i].readStarts[2] = lDims[1];
1039         vdatas[i].readCounts[2] = lDims[4] - lDims[1] + 1;
1040         vdatas[i].readStarts[3] = lDims[0];
1041         vdatas[i].readCounts[3] = lDims[3] - lDims[0] + 1;
1042         range = &verts;
1043         break;
1044       case ReadNC::ENTLOCNSEDGE:
1045       case ReadNC::ENTLOCEWEDGE:
1046       case ReadNC::ENTLOCEDGE:
1047         // Not implemented yet, set a global error
1048         MB_SET_GLB_ERR(MB_NOT_IMPLEMENTED, "Reading edge data is not implemented yet");
1049       case ReadNC::ENTLOCFACE:
1050         // Faces
1051         vdatas[i].readStarts[2] = lCDims[1];
1052         vdatas[i].readCounts[2] = lCDims[4] - lCDims[1] + 1;
1053         vdatas[i].readStarts[3] = lCDims[0];
1054         vdatas[i].readCounts[3] = lCDims[3] - lCDims[0] + 1;
1055 #ifdef MOAB_HAVE_MPI
1056         range = &faces_owned;
1057 #else
1058         range = &faces;
1059 #endif
1060         break;
1061       default:
1062         MB_SET_ERR(MB_FAILURE, "Unexpected entity location type for variable " << vdatas[i].varName);
1063     }
1064 
1065     for (unsigned int t = 0; t < tstep_nums.size(); t++) {
1066       dbgOut.tprintf(2, "Reading variable %s, time step %d\n", vdatas[i].varName.c_str(), tstep_nums[t]);
1067 
1068       if (tstep_nums[t] >= dimLens[tDim]) {
1069         MB_SET_ERR(MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number " << tstep_nums[t]);
1070       }
1071 
1072       // Get the tag to read into
1073       if (!vdatas[i].varTags[t]) {
1074         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 to non-set variable " << vdatas[i].varName);
1075       }
1076 
1077       // Get ptr to tag space
1078       void* data;
1079       int count;
1080       rval = mbImpl->tag_iterate(vdatas[i].varTags[t], range->begin(), range->end(), count, data);MB_CHK_SET_ERR(rval, "Failed to iterate tag for non-set variable " << vdatas[i].varName);
1081       assert((unsigned)count == range->size());
1082       vdatas[i].varDatas[t] = data;
1083     }
1084 
1085     // Get variable size
1086     vdatas[i].sz = 1;
1087     for (std::size_t idx = 0; idx != vdatas[i].readCounts.size(); idx++)
1088       vdatas[i].sz *= vdatas[i].readCounts[idx];
1089   }
1090 
1091   return rval;
1092 }
1093 
read_scd_variables_to_nonset(std::vector<ReadNC::VarData> & vdatas,std::vector<int> & tstep_nums)1094 ErrorCode ScdNCHelper::read_scd_variables_to_nonset(std::vector<ReadNC::VarData>& vdatas, std::vector<int>& tstep_nums)
1095 {
1096   DebugOutput& dbgOut = _readNC->dbgOut;
1097 
1098   ErrorCode rval = read_scd_variables_to_nonset_allocate(vdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble allocating space to read non-set variables");
1099 
1100   // Finally, read into that space
1101   int success;
1102   for (unsigned int i = 0; i < vdatas.size(); i++) {
1103     std::size_t sz = vdatas[i].sz;
1104 
1105     // A typical supported variable: float T(time, lev, lat, lon)
1106     // For tag values, need transpose (lev, lat, lon) to (lat, lon, lev)
1107     size_t ni = vdatas[i].readCounts[3]; // lon or slon
1108     size_t nj = vdatas[i].readCounts[2]; // lat or slat
1109     size_t nk = vdatas[i].readCounts[1]; // lev
1110 
1111     for (unsigned int t = 0; t < tstep_nums.size(); t++) {
1112       // Tag data for this timestep
1113       void* data = vdatas[i].varDatas[t];
1114 
1115       // Set readStart for each timestep along time dimension
1116       vdatas[i].readStarts[0] = tstep_nums[t];
1117 
1118       switch (vdatas[i].varDataType) {
1119         case NC_BYTE:
1120         case NC_CHAR: {
1121           std::vector<char> tmpchardata(sz);
1122           success = NCFUNCAG(_vara_text)(_fileId, vdatas[i].varId, &vdatas[i].readStarts[0], &vdatas[i].readCounts[0],
1123                                         &tmpchardata[0]);
1124           if (success)
1125             MB_SET_ERR(MB_FAILURE, "Failed to read byte/char data for variable " << vdatas[i].varName);
1126           if (vdatas[i].numLev > 1)
1127             // Transpose (lev, lat, lon) to (lat, lon, lev)
1128             kji_to_jik(ni, nj, nk, data, &tmpchardata[0]);
1129           else {
1130             for (std::size_t idx = 0; idx != tmpchardata.size(); idx++)
1131               ((char*) data)[idx] = tmpchardata[idx];
1132           }
1133           break;
1134         }
1135         case NC_SHORT:
1136         case NC_INT: {
1137           std::vector<int> tmpintdata(sz);
1138           success = NCFUNCAG(_vara_int)(_fileId, vdatas[i].varId, &vdatas[i].readStarts[0], &vdatas[i].readCounts[0],
1139                                         &tmpintdata[0]);
1140           if (success)
1141             MB_SET_ERR(MB_FAILURE, "Failed to read short/int data for variable " << vdatas[i].varName);
1142           if (vdatas[i].numLev > 1)
1143             // Transpose (lev, lat, lon) to (lat, lon, lev)
1144             kji_to_jik(ni, nj, nk, data, &tmpintdata[0]);
1145           else {
1146             for (std::size_t idx = 0; idx != tmpintdata.size(); idx++)
1147               ((int*) data)[idx] = tmpintdata[idx];
1148           }
1149           break;
1150         }
1151         case NC_FLOAT:
1152         case NC_DOUBLE: {
1153           std::vector<double> tmpdoubledata(sz);
1154           success = NCFUNCAG(_vara_double)(_fileId, vdatas[i].varId, &vdatas[i].readStarts[0], &vdatas[i].readCounts[0],
1155                                           &tmpdoubledata[0]);
1156           if (success)
1157             MB_SET_ERR(MB_FAILURE, "Failed to read float/double data for variable " << vdatas[i].varName);
1158           if (vdatas[i].numLev > 1)
1159             // Transpose (lev, lat, lon) to (lat, lon, lev)
1160             kji_to_jik(ni, nj, nk, data, &tmpdoubledata[0]);
1161           else {
1162             for (std::size_t idx = 0; idx != tmpdoubledata.size(); idx++)
1163               ((double*) data)[idx] = tmpdoubledata[idx];
1164           }
1165           break;
1166         }
1167         default:
1168           MB_SET_ERR(MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName);
1169       }
1170     }
1171   }
1172 
1173   // Debug output, if requested
1174   if (1 == dbgOut.get_verbosity()) {
1175     dbgOut.printf(1, "Read variables: %s", vdatas.begin()->varName.c_str());
1176     for (unsigned int i = 1; i < vdatas.size(); i++)
1177       dbgOut.printf(1, ", %s ", vdatas[i].varName.c_str());
1178     dbgOut.tprintf(1, "\n");
1179   }
1180 
1181   return rval;
1182 }
1183 
create_quad_coordinate_tag()1184 ErrorCode ScdNCHelper::create_quad_coordinate_tag() {
1185   Interface*& mbImpl = _readNC->mbImpl;
1186 
1187   Range ents;
1188   ErrorCode rval = mbImpl->get_entities_by_type(_fileSet, moab::MBQUAD, ents);MB_CHK_SET_ERR(rval, "Trouble getting quads");
1189 
1190   std::size_t numOwnedEnts = 0;
1191 #ifdef MOAB_HAVE_MPI
1192   Range ents_owned;
1193   bool& isParallel = _readNC->isParallel;
1194   if (isParallel) {
1195     ParallelComm*& myPcomm = _readNC->myPcomm;
1196     rval = myPcomm->filter_pstatus(ents, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &ents_owned);MB_CHK_SET_ERR(rval, "Trouble getting owned quads");
1197     numOwnedEnts = ents_owned.size();
1198   }
1199   else {
1200     numOwnedEnts = ents.size();
1201     ents_owned = ents;
1202   }
1203 #else
1204   numOwnedEnts = ents.size();
1205 #endif
1206 
1207   if (numOwnedEnts == 0)
1208     return MB_SUCCESS;
1209 
1210   assert(numOwnedEnts == ilCVals.size() * jlCVals.size());
1211   std::vector<double> coords(numOwnedEnts * 3);
1212   std::size_t pos = 0;
1213   for (std::size_t j = 0; j != jlCVals.size(); ++j) {
1214     for (std::size_t i = 0; i != ilCVals.size(); ++i) {
1215       pos = j * ilCVals.size() * 3 + i * 3;
1216       coords[pos] = ilCVals[i];
1217       coords[pos + 1] = jlCVals[j];
1218       coords[pos + 2] = 0.0;
1219     }
1220   }
1221   std::string tag_name = "COORDS";
1222   Tag tagh = 0;
1223   rval = mbImpl->tag_get_handle(tag_name.c_str(), 3, MB_TYPE_DOUBLE, tagh,
1224                                 MB_TAG_DENSE | MB_TAG_CREAT);MB_CHK_SET_ERR(rval, "Trouble creating COORDS tag");
1225 
1226   void *data;
1227   int count;
1228 #ifdef MOAB_HAVE_MPI
1229   rval = mbImpl->tag_iterate(tagh, ents_owned.begin(), ents_owned.end(), count, data);MB_CHK_SET_ERR(rval, "Failed to iterate COORDS tag on quads");
1230 #else
1231   rval = mbImpl->tag_iterate(tagh, ents.begin(), ents.end(), count, data);MB_CHK_SET_ERR(rval, "Failed to iterate COORDS tag on quads");
1232 #endif
1233   assert(count == (int)numOwnedEnts);
1234   double* quad_data = (double*) data;
1235   std::copy(coords.begin(), coords.end(), quad_data);
1236 
1237   return MB_SUCCESS;
1238 }
1239 
read_variables(std::vector<std::string> & var_names,std::vector<int> & tstep_nums)1240 ErrorCode UcdNCHelper::read_variables(std::vector<std::string>& var_names, std::vector<int>& tstep_nums)
1241 {
1242   std::vector<ReadNC::VarData> vdatas;
1243   std::vector<ReadNC::VarData> vsetdatas;
1244 
1245   ErrorCode rval = read_variables_setup(var_names, tstep_nums, vdatas, vsetdatas);MB_CHK_SET_ERR(rval, "Trouble setting up to read variables");
1246 
1247   if (!vsetdatas.empty()) {
1248     rval = read_variables_to_set(vsetdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble reading variables to set");
1249   }
1250 
1251   if (!vdatas.empty()) {
1252 #ifdef MOAB_HAVE_PNETCDF
1253     // With pnetcdf support, we will use async read
1254     rval = read_ucd_variables_to_nonset_async(vdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble reading variables to verts/edges/faces");
1255 #else
1256     // Without pnetcdf support, we will use old read
1257     rval = read_ucd_variables_to_nonset(vdatas, tstep_nums);MB_CHK_SET_ERR(rval, "Trouble reading variables to verts/edges/faces");
1258 #endif
1259   }
1260 
1261   return MB_SUCCESS;
1262 }
1263 
1264 } // namespace moab
1265