1 #include "Worker.h"
2 
3 #include "adios2/helper/adiosXMLUtil.h"
4 
5 #include <pugixml.hpp>
6 
7 namespace adios2
8 {
9 namespace query
10 {
ParseMe()11 void XmlWorker::ParseMe()
12 {
13     auto lf_FileContents = [&](const std::string &configXML) -> std::string {
14         std::ifstream fileStream(configXML);
15         if (!fileStream)
16         {
17             throw std::ios_base::failure("ERROR: file " + configXML +
18                                          " not found. ");
19         }
20         std::ostringstream fileSS;
21         fileSS << fileStream.rdbuf();
22         fileStream.close();
23 
24         if (fileSS.str().empty())
25         {
26             throw std::invalid_argument("ERROR: config xml file is empty.");
27         }
28 
29         return fileSS.str();
30     }; // local  function lf_FileContents
31 
32     const std::string fileContents = lf_FileContents(m_QueryFile);
33     const std::unique_ptr<pugi::xml_document> document =
34         adios2::helper::XMLDocument(fileContents, "in Query XMLWorker");
35 
36     const std::unique_ptr<pugi::xml_node> config = adios2::helper::XMLNode(
37         "adios-query", *document, "in adios-query", true);
38 
39     const pugi::xml_node ioNode = config->child("io");
40     ParseIONode(ioNode);
41 
42 } // Parse()
43 
ParseIONode(const pugi::xml_node & ioNode)44 void XmlWorker::ParseIONode(const pugi::xml_node &ioNode)
45 {
46 #ifdef PARSE_IO
47     const std::unique_ptr<pugi::xml_attribute> ioName =
48         adios2::helper::XMLAttribute("name", ioNode, "in query");
49     const std::unique_ptr<pugi::xml_attribute> fileName =
50         adios2::helper::XMLAttribute("file", ioNode, "in query");
51 
52     // must be unique per io
53     const std::unique_ptr<pugi::xml_node> &engineNode =
54         adios2::helper::XMLNode("engine", ioNode, "in query", false, true);
55     m_IO = &(m_Adios2.DeclareIO(ioName->value()));
56 
57     if (engineNode)
58     {
59         const std::unique_ptr<pugi::xml_attribute> type =
60             adios2::query::XmlUtil::XMLAttribute("type", engineNode,
61                                                  "in query");
62         m_IO->SetEngine(type->value());
63 
64         const adios2::Params parameters =
65             helper::GetParameters(engineNode, "in query");
66         m_IO->SetParameters(parameters);
67     }
68     else
69     {
70         m_IO->SetEngine("BPFile");
71     }
72     // adios2::Engine reader =  currIO.Open(fileName.value(),
73     // adios2::Mode::Read, m_Comm);
74     m_SourceReader =
75         &(m_IO->Open(fileName.value(), adios2::Mode::Read, m_Comm));
76 #else
77     const std::unique_ptr<pugi::xml_attribute> ioName =
78         adios2::helper::XMLAttribute("name", ioNode, "in query");
79     if (m_SourceReader->m_IO.m_Name.compare(ioName->value()) != 0)
80     {
81         throw std::ios_base::failure("invalid query io. Expecting io name = " +
82                                      m_SourceReader->m_IO.m_Name +
83                                      " found:" + ioName->value());
84     }
85 #endif
86 
87     std::map<std::string, QueryBase *> subqueries;
88 
89     adios2::Box<adios2::Dims> ref;
90     for (const pugi::xml_node &qTagNode : ioNode.children("tag"))
91     {
92         const std::unique_ptr<pugi::xml_attribute> name =
93             adios2::helper::XMLAttribute("name", qTagNode, "in query");
94         const pugi::xml_node &variable = qTagNode.child("var");
95         QueryVar *q =
96             ParseVarNode(variable, m_SourceReader->m_IO, *m_SourceReader);
97         if (ref.first.size() == 0)
98         {
99             ref = q->m_Selection;
100         }
101         else if (!q->IsCompatible(ref))
102         {
103             throw std::ios_base::failure("impactible query found on var:" +
104                                          q->GetVarName());
105         }
106         subqueries[name->value()] = q;
107     }
108 
109     const pugi::xml_node &qNode = ioNode.child("query");
110     if (qNode == nullptr)
111     {
112         const pugi::xml_node &variable = ioNode.child("var");
113         m_Query = ParseVarNode(variable, m_SourceReader->m_IO, *m_SourceReader);
114     }
115     else
116     {
117         const std::unique_ptr<pugi::xml_attribute> op =
118             adios2::helper::XMLAttribute("op", qNode, "in query");
119         QueryComposite *q =
120             new QueryComposite(adios2::query::strToRelation(op->value()));
121         for (const pugi::xml_node &sub : qNode.children())
122         {
123             q->AddNode(subqueries[sub.name()]);
124         }
125         m_Query = q;
126     }
127 } // parse_io_node
128 
129 // node is the variable node
ParseVarNode(const pugi::xml_node & node,adios2::core::IO & currentIO,adios2::core::Engine & reader)130 QueryVar *XmlWorker::ParseVarNode(const pugi::xml_node &node,
131                                   adios2::core::IO &currentIO,
132                                   adios2::core::Engine &reader)
133 
134 {
135     const std::string variableName = std::string(
136         adios2::helper::XMLAttribute("name", node, "in query")->value());
137 
138     // const std::string varType = currentIO.VariableType(variableName);
139     const DataType varType = currentIO.InquireVariableType(variableName);
140     if (varType == DataType::None)
141     {
142         std::cerr << "No such variable: " << variableName << std::endl;
143         return nullptr;
144     }
145 #define declare_type(T)                                                        \
146     if (varType == helper::GetDataType<T>())                                   \
147     {                                                                          \
148         core::Variable<T> *var = currentIO.InquireVariable<T>(variableName);   \
149         if (var)                                                               \
150         {                                                                      \
151             QueryVar *q = new QueryVar(variableName);                          \
152             adios2::Dims zero(var->Shape().size(), 0);                         \
153             adios2::Dims shape = var->Shape();                                 \
154             q->SetSelection(zero, shape);                                      \
155             ConstructQuery(*q, node);                                          \
156             return q;                                                          \
157         }                                                                      \
158     }
159     ADIOS2_FOREACH_ATTRIBUTE_PRIMITIVE_STDTYPE_1ARG(declare_type)
160 #undef declare_type
161     return nullptr;
162 } //  parse_var_node
163 
ConstructTree(RangeTree & host,const pugi::xml_node & node)164 void XmlWorker::ConstructTree(RangeTree &host, const pugi::xml_node &node)
165 {
166     std::string relationStr =
167         adios2::helper::XMLAttribute("value", node, "in query")->value();
168     host.SetRelation(adios2::query::strToRelation(relationStr));
169     for (const pugi::xml_node rangeNode : node.children("range"))
170     {
171         std::string valStr =
172             adios2::helper::XMLAttribute("value", rangeNode, "in query")
173                 ->value();
174         std::string opStr =
175             adios2::helper::XMLAttribute("compare", rangeNode, "in query")
176                 ->value();
177 
178         host.AddLeaf(adios2::query::strToQueryOp(opStr), valStr);
179     }
180 
181     for (const pugi::xml_node opNode : node.children("op"))
182     {
183         adios2::query::RangeTree subNode;
184         ConstructTree(subNode, opNode);
185         host.AddNode(subNode);
186     }
187 }
188 
ConstructQuery(QueryVar & simpleQ,const pugi::xml_node & node)189 void XmlWorker::ConstructQuery(QueryVar &simpleQ, const pugi::xml_node &node)
190 {
191     // QueryVar* simpleQ = new QueryVar(variableName);
192     pugi::xml_node bbNode = node.child("boundingbox");
193 
194     if (bbNode)
195     {
196         adios2::Box<adios2::Dims> box =
197             adios2::Box<adios2::Dims>({100, 100}, {200, 200});
198         std::string startStr =
199             adios2::helper::XMLAttribute("start", bbNode, "in query")->value();
200         std::string countStr =
201             adios2::helper::XMLAttribute("count", bbNode, "in query")->value();
202 
203         adios2::Dims start = split(startStr, ',');
204         adios2::Dims count = split(countStr, ',');
205 
206         if (start.size() != count.size())
207         {
208             throw std::ios_base::failure(
209                 "dim of startcount does match in the bounding box definition");
210         }
211 
212         // simpleQ.setSelection(box.first, box.second);
213         adios2::Dims shape =
214             simpleQ.m_Selection.second; // set at the creation for default
215         simpleQ.SetSelection(start, count);
216         if (!simpleQ.IsSelectionValid(shape))
217         {
218             throw std::ios_base::failure(
219                 "invalid selections for selection of var: " +
220                 simpleQ.GetVarName());
221         }
222     }
223 
224 #ifdef NEVER // don't know whether this is useful.
225     pugi::xml_node tsNode = node.child("tstep");
226     if (tsNode)
227     {
228         std::string startStr =
229             adios2::helper::XMLAttribute("start", tsNode, "in query").value();
230         std::string countStr =
231             adios2::helper::XMLAttribute("count", tsNode, "in query").value();
232 
233         if ((startStr.size() > 0) && (countStr.size() > 0))
234         {
235             std::stringstream ss(startStr), cc(countStr);
236             ss >> simpleQ.m_TimestepStart;
237             cc >> simpleQ.m_TimestepCount;
238         }
239     }
240 #endif
241     pugi::xml_node relationNode = node.child("op");
242     ConstructTree(simpleQ.m_RangeTree, relationNode);
243 }
244 
245 } // namespace query
246 } // namespace adios2
247