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 ¤tIO,
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