1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //  This software is distributed WITHOUT ANY WARRANTY; without even
6 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 //  PURPOSE.  See the above copyright notice for more information.
8 //
9 //============================================================================
10 
11 #include <fides/DataSetReader.h>
12 #include <fides/predefined/DataModelFactory.h>
13 #include <fides/predefined/DataModelHelperFunctions.h>
14 #include <fides/predefined/InternalMetadataSource.h>
15 
16 #include <ios>
17 #include <stdexcept>
18 #include <unordered_map>
19 #include <vector>
20 
21 #include <fides_rapidjson.h>
22 // clang-format off
23 #include FIDES_RAPIDJSON(rapidjson/document.h)
24 #include FIDES_RAPIDJSON(rapidjson/error/en.h)
25 #include FIDES_RAPIDJSON(rapidjson/filereadstream.h)
26 // clang-format on
27 
28 #include <vtkm/cont/CoordinateSystem.h>
29 #include <vtkm/cont/DataSet.h>
30 #include <vtkm/cont/DynamicCellSet.h>
31 
32 #include <fides/CellSet.h>
33 #include <fides/CoordinateSystem.h>
34 #include <fides/DataSource.h>
35 #include <fides/Field.h>
36 #include <fides/Keys.h>
37 
38 namespace fides
39 {
40 namespace io
41 {
42 
43 using DataSourceType = fides::io::DataSource;
44 using DataSourcesType = std::unordered_map<std::string, std::shared_ptr<DataSourceType>>;
45 
46 class DataSetReader::DataSetReaderImpl
47 {
48 public:
DataSetReaderImpl(const std::string dataModel,DataModelInput inputType,const Params & params)49   DataSetReaderImpl(const std::string dataModel, DataModelInput inputType, const Params& params)
50   {
51     this->Cleanup();
52     if (inputType == DataModelInput::BPFile)
53     {
54       // in this case the bp file passed in becomes our MetadataSource
55       // which is used to select a predefined data model
56       this->MetadataSource.reset(new fides::predefined::InternalMetadataSource(dataModel));
57       auto dm = predefined::DataModelFactory::GetInstance().CreateDataModel(this->MetadataSource);
58       this->ReadJSON(dm->GetDOM());
59     }
60     else
61     {
62       rapidjson::Document doc = this->GetJSONDocument(dataModel, inputType);
63       this->ParsingChecks(doc, dataModel, inputType);
64       this->ReadJSON(doc);
65     }
66 
67     this->SetDataSourceParameters(params);
68   }
69 
~DataSetReaderImpl()70   virtual ~DataSetReaderImpl() { this->Cleanup(); }
71 
Cleanup()72   void Cleanup()
73   {
74     this->DataSources.clear();
75     this->CoordinateSystem.reset();
76     this->CellSet.reset();
77   }
78 
GetJSONDocument(const std::string & dataModel,DataModelInput inputType)79   rapidjson::Document GetJSONDocument(const std::string& dataModel, DataModelInput inputType)
80   {
81     rapidjson::Document d;
82     if (inputType == DataModelInput::JSONFile)
83     {
84       FILE* fp = std::fopen(dataModel.c_str(), "rb");
85       if (!fp)
86       {
87         throw std::ios_base::failure("Unable to open metadata file; does '" + dataModel +
88                                      "' exist?");
89       }
90       std::vector<char> buffer(65536);
91       rapidjson::FileReadStream is(fp, buffer.data(), buffer.size());
92       d.ParseStream(is);
93       std::fclose(fp);
94     }
95     else if (inputType == DataModelInput::JSONString)
96     {
97       rapidjson::StringStream s(dataModel.c_str());
98       d.ParseStream(s);
99     }
100     else
101     {
102       throw std::runtime_error(
103         "DataModelInput should be either Filename or String containing JSON");
104     }
105     return d;
106   }
107 
SetDataSourceParameters(const Params & params)108   void SetDataSourceParameters(const Params& params)
109   {
110     for (const auto& p : params)
111     {
112       this->SetDataSourceParameters(p.first, p.second);
113     }
114   }
115 
SetDataSourceParameters(const std::string source,const DataSourceParams & params)116   void SetDataSourceParameters(const std::string source, const DataSourceParams& params)
117   {
118     auto it = this->DataSources.find(source);
119     if (it == this->DataSources.end())
120     {
121       throw std::runtime_error("Source name was not found in DataSources.");
122     }
123     auto& ds = *(it->second);
124     ds.SetDataSourceParameters(params);
125   }
126 
SetDataSourceIO(const std::string source,void * io)127   void SetDataSourceIO(const std::string source, void* io)
128   {
129     auto it = this->DataSources.find(source);
130     if (it == this->DataSources.end())
131     {
132       throw std::runtime_error("Source name was not found in DataSources.");
133     }
134     auto& ds = *(it->second);
135     ds.SetDataSourceIO(io);
136   }
137 
138   template <typename ValueType>
ProcessDataSources(const ValueType & dataSources)139   void ProcessDataSources(const ValueType& dataSources)
140   {
141     for (auto& dataSource : dataSources)
142     {
143       if (!dataSource.IsObject())
144       {
145         throw std::runtime_error("data_sources must contain data_source objects.");
146       }
147       if (!dataSource.GetObject().HasMember("name"))
148       {
149         throw std::runtime_error("data_source objects must have name.");
150       }
151       std::string name = dataSource.GetObject()["name"].GetString();
152       if (name.empty())
153       {
154         throw std::runtime_error("data_source name must be a non-empty string.");
155       }
156       if (!dataSource.GetObject().HasMember("filename_mode"))
157       {
158         throw std::runtime_error("data_source objects must have filename_mode.");
159       }
160       std::string filename_mode = dataSource.GetObject()["filename_mode"].GetString();
161       if (filename_mode.empty())
162       {
163         throw std::runtime_error("data_source filename_mode must be a non-empty string.");
164       }
165       auto source = std::make_shared<DataSourceType>();
166       if (filename_mode == "input")
167       {
168         source->Mode = fides::io::FileNameMode::Input;
169       }
170       else if (filename_mode == "relative")
171       {
172         source->Mode = fides::io::FileNameMode::Relative;
173         if (!dataSource.GetObject().HasMember("filename"))
174         {
175           throw std::runtime_error("data_source objects must have filename.");
176         }
177         source->FileName = dataSource.GetObject()["filename"].GetString();
178       }
179       else
180       {
181         throw std::runtime_error("data_source filename_mode must be input or relative.");
182       }
183 
184       this->DataSources[name] = source;
185     }
186   }
187 
ProcessCoordinateSystem(const rapidjson::Value & coordSys)188   void ProcessCoordinateSystem(const rapidjson::Value& coordSys)
189   {
190     this->CoordinateSystem = std::make_shared<fides::datamodel::CoordinateSystem>();
191     this->CoordinateSystem->ObjectName = "coordinate_system";
192 
193     this->CoordinateSystem->ProcessJSON(coordSys, this->DataSources);
194   }
195 
ProcessCellSet(const rapidjson::Value & cellSet)196   void ProcessCellSet(const rapidjson::Value& cellSet)
197   {
198     this->CellSet = std::make_shared<fides::datamodel::CellSet>();
199     this->CellSet->ObjectName = "cell_set";
200 
201     this->CellSet->ProcessJSON(cellSet, this->DataSources);
202   }
203 
ProcessField(const rapidjson::Value & fieldJson)204   std::shared_ptr<fides::datamodel::Field> ProcessField(const rapidjson::Value& fieldJson)
205   {
206     if (!fieldJson.IsObject())
207     {
208       throw std::runtime_error("field needs to be an object.");
209     }
210     auto field = std::make_shared<fides::datamodel::Field>();
211     field->ProcessJSON(fieldJson, this->DataSources);
212     field->ObjectName = "field";
213     return field;
214   }
215 
ProcessFields(const rapidjson::Value & fields)216   void ProcessFields(const rapidjson::Value& fields)
217   {
218     this->Fields.clear();
219     if (!fields.IsArray())
220     {
221       throw std::runtime_error("fields is not an array.");
222     }
223     auto fieldsArray = fields.GetArray();
224     for (auto& field : fieldsArray)
225     {
226       auto fieldPtr = this->ProcessField(field);
227       this->Fields[std::make_pair(fieldPtr->Name, fieldPtr->Association)] = fieldPtr;
228     }
229   }
230 
GetNumberOfSteps()231   size_t GetNumberOfSteps()
232   {
233     if (this->StepSource.empty())
234     {
235       return 0;
236     }
237     auto sourceIter = this->DataSources.find(this->StepSource);
238     if (sourceIter == this->DataSources.end())
239     {
240       return 0;
241     }
242     return sourceIter->second->GetNumberOfSteps();
243   }
244 
ProcessStepInformation(const rapidjson::Value & sinf)245   void ProcessStepInformation(const rapidjson::Value& sinf)
246   {
247     if (!sinf.IsObject())
248     {
249       throw std::runtime_error("step_information needs to be an object.");
250     }
251     auto sInf = sinf.GetObject();
252     if (!sInf.HasMember("data_source"))
253     {
254       throw std::runtime_error("step_information needs a data_source.");
255     }
256     this->StepSource = sInf["data_source"].GetString();
257   }
258 
259   template <typename ValueType>
FindAndReturnObject(ValueType & root,const std::string name)260   const rapidjson::Value& FindAndReturnObject(ValueType& root, const std::string name)
261   {
262     if (!root.HasMember(name.c_str()))
263     {
264       throw std::runtime_error("Missing " + name + " member.");
265     }
266     auto& val = root[name.c_str()];
267     if (!val.IsObject())
268     {
269       throw std::runtime_error(name + " is expected to be an object.");
270     }
271     return val;
272   }
273 
ParsingChecks(rapidjson::Document & document,const std::string & fileName,DataModelInput inputType)274   void ParsingChecks(rapidjson::Document& document,
275                      const std::string& fileName,
276                      DataModelInput inputType)
277   {
278     std::string nameStr;
279     if (inputType == DataModelInput::JSONFile)
280     {
281       nameStr = fileName;
282     }
283     else if (inputType == DataModelInput::JSONString)
284     {
285       nameStr = "the passed string";
286     }
287 
288     if (document.HasParseError())
289     {
290       throw std::logic_error("Unable to parse " + nameStr + " as a json file. Error: " +
291                              rapidjson::GetParseError_En(document.GetParseError()));
292     }
293     if (!document.IsObject())
294     {
295       throw std::logic_error("Unable to parse '" + nameStr + "' as a json file; is it valid json?");
296     }
297 
298     auto m = document.GetObject().begin();
299     if (m == document.GetObject().end())
300     {
301       throw std::logic_error("There is no data in '" + nameStr +
302                              "'; there is nothing that can be achieved with this file/string.");
303     }
304     if (!m->value.IsObject())
305     {
306       throw std::logic_error("Unable to create a sensible object from '" + nameStr +
307                              "'; aborting.");
308     }
309   }
310 
ReadJSON(rapidjson::Document & document)311   void ReadJSON(rapidjson::Document& document)
312   {
313     auto m = document.GetObject().begin();
314     const auto obj = m->value.GetObject();
315     if (!obj.HasMember("data_sources"))
316     {
317       throw std::runtime_error("Missing data_sources member.");
318     }
319     this->ProcessDataSources(obj["data_sources"].GetArray());
320 
321     if (obj.HasMember("number_of_planes"))
322     {
323       auto& nPlanes = obj["number_of_planes"];
324       fides::datamodel::XGCCommon::ProcessNumberOfPlanes(nPlanes, this->DataSources);
325     }
326 
327     if (!obj.HasMember("coordinate_system"))
328     {
329       throw std::runtime_error("Missing coordinate_system member.");
330     }
331     auto& cs = this->FindAndReturnObject(obj, "coordinate_system");
332     this->ProcessCoordinateSystem(cs);
333 
334     if (!obj.HasMember("cell_set"))
335     {
336       throw std::runtime_error("Missing cell_set member.");
337     }
338     auto& cells = this->FindAndReturnObject(obj, "cell_set");
339     this->ProcessCellSet(cells);
340 
341     if (obj.HasMember("fields"))
342     {
343       auto& fields = obj["fields"];
344       this->ProcessFields(fields);
345     }
346 
347     if (obj.HasMember("step_information"))
348     {
349       auto& sinf = obj["step_information"];
350       this->ProcessStepInformation(sinf);
351     }
352   }
353 
ReadCoordinateSystem(const std::unordered_map<std::string,std::string> & paths,const fides::metadata::MetaData & selections)354   std::vector<vtkm::cont::CoordinateSystem> ReadCoordinateSystem(
355     const std::unordered_map<std::string, std::string>& paths,
356     const fides::metadata::MetaData& selections)
357   {
358     if (!this->CoordinateSystem)
359     {
360       throw std::runtime_error("Cannot read missing coordinate system.");
361     }
362     return this->CoordinateSystem->Read(paths, this->DataSources, selections);
363   }
364 
ReadCellSet(const std::unordered_map<std::string,std::string> & paths,const fides::metadata::MetaData & selections)365   std::vector<vtkm::cont::DynamicCellSet> ReadCellSet(
366     const std::unordered_map<std::string, std::string>& paths,
367     const fides::metadata::MetaData& selections)
368   {
369     if (!this->CellSet)
370     {
371       throw std::runtime_error("Cannot read missing cell set.");
372     }
373     return this->CellSet->Read(paths, this->DataSources, selections);
374   }
375 
376   // updates this->Fields if we have any wildcard fields. Should be used
377   // in ReadMetaData()
ExpandWildcardFields()378   void ExpandWildcardFields()
379   {
380     auto it = this->Fields.begin();
381     while (it != this->Fields.end())
382     {
383       auto& origField = it->second;
384       // find fields to expand
385       if (origField->IsWildcardField())
386       {
387         auto lists = origField->GetWildcardFieldLists(this->MetadataSource);
388         // need to add each name, association pair to Fields
389         // as well as create the associated Field object
390         auto& names = lists.Names;
391         auto& associations = lists.Associations;
392 
393         for (size_t i = 0; i < names.size(); ++i)
394         {
395           std::string isVector = "auto";
396           std::string source = "source";
397           std::string arrayType = "basic";
398           if (!lists.IsVector.empty() && i < lists.IsVector.size())
399           {
400             isVector = lists.IsVector[i];
401           }
402           if (!lists.Sources.empty() && i < lists.Sources.size())
403           {
404             source = lists.Sources[i];
405           }
406           if (!lists.ArrayTypes.empty() && i < lists.ArrayTypes.size())
407           {
408             arrayType = lists.ArrayTypes[i];
409           }
410 
411           // the wildcard field uses an ArrayPlaceholder. Now we have enough info
412           // to create the actual JSON for the Array object for this Field. This can
413           // then be passed to Field.ProcessExpandedField which will use it to create
414           // the actual array object.
415           rapidjson::Document arrayObj;
416           arrayObj = predefined::CreateFieldArrayDoc(names[i], source, arrayType, isVector);
417 
418           if (!arrayObj.HasMember("array"))
419           {
420             throw std::runtime_error("Field Array Object was not created correctly");
421           }
422           auto fieldPtr = std::make_shared<fides::datamodel::Field>();
423           fieldPtr->ProcessExpandedField(names[i], associations[i], arrayObj, this->DataSources);
424           fieldPtr->ObjectName = "field";
425           this->Fields[std::make_pair(fieldPtr->Name, fieldPtr->Association)] = fieldPtr;
426         }
427 
428         // remove the wildcard field now that we're done expanding it
429         it = this->Fields.erase(it);
430       }
431       else
432       {
433         ++it;
434       }
435     }
436   }
437 
ReadMetaData(const std::unordered_map<std::string,std::string> & paths)438   fides::metadata::MetaData ReadMetaData(const std::unordered_map<std::string, std::string>& paths)
439   {
440     if (!this->CoordinateSystem)
441     {
442       throw std::runtime_error("Cannot read missing coordinate system.");
443     }
444     size_t nBlocks = this->CoordinateSystem->GetNumberOfBlocks(paths, this->DataSources);
445     fides::metadata::MetaData metaData;
446     fides::metadata::Size nBlocksM(nBlocks);
447     metaData.Set(fides::keys::NUMBER_OF_BLOCKS(), nBlocksM);
448 
449     if (!this->Fields.empty())
450     {
451       // updates this->Fields if necessary
452       this->ExpandWildcardFields();
453       fides::metadata::Vector<fides::metadata::FieldInformation> fields;
454       for (auto& item : this->Fields)
455       {
456         auto& field = item.second;
457         fides::metadata::FieldInformation afield(field->Name, field->Association);
458         fields.Data.push_back(afield);
459       }
460       metaData.Set(fides::keys::FIELDS(), fields);
461     }
462 
463     size_t nSteps = this->GetNumberOfSteps();
464     if (nSteps > 0)
465     {
466       fides::metadata::Size nStepsM(nSteps);
467       metaData.Set(fides::keys::NUMBER_OF_STEPS(), nStepsM);
468     }
469     return metaData;
470   }
471 
PostRead(std::vector<vtkm::cont::DataSet> & pds,const fides::metadata::MetaData & selections)472   void PostRead(std::vector<vtkm::cont::DataSet>& pds, const fides::metadata::MetaData& selections)
473   {
474     this->CoordinateSystem->PostRead(pds, selections);
475     this->CellSet->PostRead(pds, selections);
476     for (auto& f : this->Fields)
477       f.second->PostRead(pds, selections);
478   }
479 
DoAllReads()480   void DoAllReads()
481   {
482     for (const auto& source : this->DataSources)
483     {
484       source.second->DoAllReads();
485     }
486   }
487 
488   // For BeginStep, we loop on a DataSource if its status is NotReady, because
489   // otherwise with multiple sources, we can get into a weird situation where
490   // step i for DataSource A may take longer to write than step i for DataSource B.
491   // So if we return NotReady in this situation, then on the next call to BeginStep,
492   // DataSource A may finally be ready for step i, but it's possible that DataSource
493   // B is ready for i+1. Or we could run into an ADIOS error, due to not having an
494   // EndStep for DataSource B before the next BeginStep in this type of situation.
495   // Also this function only returns EndOfStream when all DataSources have reached
496   // EndOfStream. In a situation with multiple source, users shouldn't need to worry
497   // about when a single DataSource reaches EndOfStream, because Fides handles this internally
498   // (e.g., having the variables making up a mesh marked as static and only reading initially).
499   // So the user should only care about PrepareNextStep returning EndOfStream when all
500   // DataSources are at the end of their Streams.
BeginStep(const std::unordered_map<std::string,std::string> & paths)501   StepStatus BeginStep(const std::unordered_map<std::string, std::string>& paths)
502   {
503     StepStatus retVal = StepStatus::EndOfStream;
504     for (const auto& source : this->DataSources)
505     {
506       auto& ds = *(source.second);
507       std::string name = source.first;
508       auto itr = paths.find(name);
509       if (itr == paths.end())
510       {
511         throw std::runtime_error("Could not find data_source with name " + name +
512                                  " among the input paths.");
513       }
514       std::string path = itr->second + ds.FileName;
515       ds.OpenSource(path);
516       auto rc = ds.BeginStep();
517       while (rc == StepStatus::NotReady)
518       {
519         rc = ds.BeginStep();
520       }
521       if (rc == StepStatus::OK)
522       {
523         retVal = StepStatus::OK;
524       }
525     }
526     return retVal;
527   }
528 
EndStep()529   void EndStep()
530   {
531     for (const auto& source : this->DataSources)
532     {
533       source.second->EndStep();
534     }
535   }
536 
537   DataSourcesType DataSources;
538   std::shared_ptr<fides::predefined::InternalMetadataSource> MetadataSource = nullptr;
539   std::shared_ptr<fides::datamodel::CoordinateSystem> CoordinateSystem = nullptr;
540   std::shared_ptr<fides::datamodel::CellSet> CellSet = nullptr;
541   using FieldsKeyType = std::pair<std::string, vtkm::cont::Field::Association>;
542   std::map<FieldsKeyType, std::shared_ptr<fides::datamodel::Field>> Fields;
543   std::string StepSource;
544 };
545 
CheckForDataModelAttribute(const std::string & filename,const std::string & attrName)546 bool DataSetReader::CheckForDataModelAttribute(const std::string& filename,
547                                                const std::string& attrName /*="Fides_Data_Model"*/)
548 {
549   bool found = false;
550   auto source = std::make_shared<DataSourceType>();
551   source->Mode = fides::io::FileNameMode::Relative;
552   source->FileName = filename;
553   source->OpenSource(filename);
554   if (source->GetAttributeType(attrName) == "string")
555   {
556     std::vector<std::string> result = source->ReadAttribute<std::string>(attrName);
557     if (!result.empty())
558     {
559       found = predefined::DataModelSupported(result[0]);
560     }
561   }
562   if (!found)
563   {
564     // Fides_Data_Model attribute not found, now look for a fides/schema attribute
565     std::string schemaAttr = "fides/schema";
566     if (source->GetAttributeType(schemaAttr) == "string")
567     {
568       found = true;
569     }
570   }
571   return found;
572 }
573 
DataSetReader(const std::string dataModel,DataModelInput inputType,const Params & params)574 DataSetReader::DataSetReader(const std::string dataModel,
575                              DataModelInput inputType /*=DataModelInput::JSONFile*/,
576                              const Params& params)
577   : Impl(nullptr)
578 {
579   if (inputType != DataModelInput::BPFile)
580   {
581     this->Impl.reset(new DataSetReaderImpl(dataModel, inputType, params));
582     return;
583   }
584 
585   // we have a BPFile and we need to look for either Fides_Data_Model
586   // or fides/schema attributes
587   std::string fidesAttr = "Fides_Data_Model";
588   auto source = std::make_shared<DataSourceType>();
589   source->Mode = fides::io::FileNameMode::Relative;
590   source->FileName = dataModel; // in this case dataModel should be bp filename
591   source->OpenSource(dataModel);
592   if (source->GetAttributeType(fidesAttr) == "string")
593   {
594     std::vector<std::string> result = source->ReadAttribute<std::string>(fidesAttr);
595     if (!result.empty())
596     {
597       if (predefined::DataModelSupported(result[0]))
598       {
599         this->Impl.reset(new DataSetReaderImpl(dataModel, inputType, params));
600         return;
601       }
602     }
603   }
604 
605   // Fides_Data_Model either not found or value was incorrect, now look for fides/schema
606   std::string schemaAttr = "fides/schema";
607   if (source->GetAttributeType(schemaAttr) == "string")
608   {
609     auto schema = source->ReadAttribute<std::string>(schemaAttr);
610     if (!schema.empty())
611     {
612       this->Impl.reset(new DataSetReaderImpl(schema[0], DataModelInput::JSONString, params));
613       return;
614     }
615   }
616 
617   throw std::runtime_error("InputType is a BP File, but valid 'Fides_Data_Model' or "
618                            "'fides/schema' attributes could not be found in the file.");
619 }
620 
621 DataSetReader::~DataSetReader() = default;
622 
ReadMetaData(const std::unordered_map<std::string,std::string> & paths)623 fides::metadata::MetaData DataSetReader::ReadMetaData(
624   const std::unordered_map<std::string, std::string>& paths)
625 {
626   return this->Impl->ReadMetaData(paths);
627 }
628 
ReadDataSet(const std::unordered_map<std::string,std::string> & paths,const fides::metadata::MetaData & selections)629 vtkm::cont::PartitionedDataSet DataSetReader::ReadDataSet(
630   const std::unordered_map<std::string, std::string>& paths,
631   const fides::metadata::MetaData& selections)
632 {
633   auto ds = this->ReadDataSetInternal(paths, selections);
634   this->Impl->DoAllReads();
635   this->Impl->PostRead(ds, selections);
636 
637   // for(size_t i=0; i<ds.GetNumberOfPartitions(); i++)
638   // {
639   //   vtkm::io::writer::VTKDataSetWriter writer(
640   //     "output" + std::to_string(i) + ".vtk");
641   //   writer.WriteDataSet(ds.GetPartition(i));
642   // }
643 
644   return vtkm::cont::PartitionedDataSet(ds);
645 }
646 
PrepareNextStep(const std::unordered_map<std::string,std::string> & paths)647 StepStatus DataSetReader::PrepareNextStep(const std::unordered_map<std::string, std::string>& paths)
648 {
649   return this->Impl->BeginStep(paths);
650 }
651 
ReadStep(const std::unordered_map<std::string,std::string> & paths,const fides::metadata::MetaData & selections)652 vtkm::cont::PartitionedDataSet DataSetReader::ReadStep(
653   const std::unordered_map<std::string, std::string>& paths,
654   const fides::metadata::MetaData& selections)
655 {
656   auto ds = this->ReadDataSetInternal(paths, selections);
657   this->Impl->EndStep();
658   this->Impl->PostRead(ds, selections);
659 
660   return vtkm::cont::PartitionedDataSet(ds);
661 }
662 
663 // Returning vector of DataSets instead of PartitionedDataSet because
664 // PartitionedDataSet::GetPartition always returns a const DataSet, but
665 // we may need to update the DataSet in the PostRead call
ReadDataSetInternal(const std::unordered_map<std::string,std::string> & paths,const fides::metadata::MetaData & selections)666 std::vector<vtkm::cont::DataSet> DataSetReader::ReadDataSetInternal(
667   const std::unordered_map<std::string, std::string>& paths,
668   const fides::metadata::MetaData& selections)
669 {
670   std::vector<vtkm::cont::CoordinateSystem> coordSystems =
671     this->Impl->ReadCoordinateSystem(paths, selections);
672   std::vector<vtkm::cont::DynamicCellSet> cellSets = this->Impl->ReadCellSet(paths, selections);
673   size_t nPartitions = cellSets.size();
674   std::vector<vtkm::cont::DataSet> dataSets(nPartitions);
675   for (size_t i = 0; i < nPartitions; i++)
676   {
677     if (i < coordSystems.size())
678     {
679       dataSets[i].AddCoordinateSystem(coordSystems[i]);
680     }
681     if (i < cellSets.size())
682     {
683       dataSets[i].SetCellSet(cellSets[i]);
684     }
685   }
686 
687   if (selections.Has(fides::keys::FIELDS()))
688   {
689     using FieldInfoType = fides::metadata::Vector<fides::metadata::FieldInformation>;
690     auto& fields = selections.Get<FieldInfoType>(fides::keys::FIELDS());
691     for (auto& field : fields.Data)
692     {
693       auto itr = this->Impl->Fields.find(std::make_pair(field.Name, field.Association));
694       if (itr != this->Impl->Fields.end())
695       {
696         std::vector<vtkm::cont::Field> fieldVec =
697           itr->second->Read(paths, this->Impl->DataSources, selections);
698         for (size_t i = 0; i < nPartitions; i++)
699         {
700           if (i < fieldVec.size())
701           {
702             dataSets[i].AddField(fieldVec[i]);
703           }
704         }
705       }
706     }
707   }
708   else
709   {
710     for (auto& field : this->Impl->Fields)
711     {
712       std::vector<vtkm::cont::Field> fields =
713         field.second->Read(paths, this->Impl->DataSources, selections);
714       for (size_t i = 0; i < nPartitions; i++)
715       {
716         if (i < fields.size())
717         {
718           dataSets[i].AddField(fields[i]);
719         }
720       }
721     }
722   }
723 
724   return dataSets;
725 }
726 
SetDataSourceParameters(const std::string source,const DataSourceParams & params)727 void DataSetReader::SetDataSourceParameters(const std::string source,
728                                             const DataSourceParams& params)
729 {
730   this->Impl->SetDataSourceParameters(source, params);
731 }
732 
SetDataSourceIO(const std::string source,void * io)733 void DataSetReader::SetDataSourceIO(const std::string source, void* io)
734 {
735   this->Impl->SetDataSourceIO(source, io);
736 }
737 
738 FIDES_DEPRECATED_SUPPRESS_BEGIN
GetFieldData()739 std::shared_ptr<fides::datamodel::FieldDataManager> DataSetReader::GetFieldData()
740 {
741   // Function to be removed in next version
742   return nullptr;
743 }
744 FIDES_DEPRECATED_SUPPRESS_END
745 
GetDataSourceNames()746 std::vector<std::string> DataSetReader::GetDataSourceNames()
747 {
748   std::vector<std::string> names;
749   for (const auto& source : this->Impl->DataSources)
750   {
751     names.push_back(source.first);
752   }
753   return names;
754 }
755 
756 } // end namespace io
757 } // end namespace fides
758