OGS
XmlPrjInterface.cpp
Go to the documentation of this file.
1
11#include "XmlPrjInterface.h"
12
13#include <QFile>
14#include <QFileInfo>
15#include <QtXml/QDomDocument>
16#include <iostream>
17#include <vector>
18
21#include "BaseLib/FileTools.h"
22#include "BaseLib/IO/Writer.h"
23#include "BaseLib/Logging.h"
24#include "GeoLib/GEOObjects.h"
29#include "MeshLib/Mesh.h"
30
31namespace FileIO
32{
34 : XMLQtInterface("OpenGeoSysProject.xsd"), _filename(""), _project(project)
35{
36}
37
38int XmlPrjInterface::readFile(const QString& fileName)
39{
40 if (XMLQtInterface::readFile(fileName) == 0)
41 {
42 return 0;
43 }
44
45 QFileInfo fi(fileName);
46 QString path =
47 (fi.path().length() > 3) ? QString(fi.path() + "/") : fi.path();
48
49 QDomNode param_root = QDomNode();
50 QDomNode pvar_root = QDomNode();
51 QDomDocument doc("OGS-PROJECT-DOM");
52 doc.setContent(getContent());
53 QDomElement docElement = doc.documentElement(); // OpenGeoSysProject
54 if (docElement.nodeName().compare("OpenGeoSysProject"))
55 {
56 ERR("XmlPrjInterface::readFile(): Unexpected XML root.");
57 return 0;
58 }
59
60 auto read_single_mesh = [&](QString const& mesh_str)
61 {
62 std::unique_ptr<MeshLib::Mesh> mesh{
63 MeshLib::IO::readMeshFromFile(mesh_str.toStdString())};
64 if (mesh != nullptr)
65 {
66 _project.addMesh(std::move(mesh));
67 }
68 };
69
70 QDomNodeList fileList = docElement.childNodes();
71
72 for (int i = 0; i < fileList.count(); i++)
73 {
74 QDomNode const node(fileList.at(i));
75 QString const node_name(node.nodeName());
76 QString const file_name(node.toElement().text().trimmed());
77 if (file_name.isEmpty())
78 {
79 continue;
80 }
81
82 if (node_name == "geometry")
83 {
85 try
86 {
87 gml.readFile(QString(path + file_name));
88 }
89 catch (std::runtime_error const& err)
90 {
91 OGSError::box(err.what(),
92 "Failed to read file `" + fileName + "'");
93 }
94 }
95 else if (node_name == "stations")
96 {
98 stn.readFile(QString(path + file_name));
99 }
100 else if (node_name == "mesh")
101 {
102 read_single_mesh(path + file_name);
103 }
104 else if (node_name == "meshes")
105 {
106 for (QDomNode meshes_node = node.firstChild();
107 meshes_node != QDomNode();
108 meshes_node = meshes_node.nextSibling())
109 {
110 if (!meshes_node.isElement())
111 {
112 ERR("Expected an XML element node.");
113 return 0;
114 }
115 if (meshes_node.nodeName() != "mesh")
116 {
117 ERR("Expected an XML element node named 'mesh' got '{:s}'.",
118 meshes_node.nodeName().toStdString());
119 return 0;
120 }
121 if (meshes_node.childNodes().count() != 1)
122 {
123 ERR("Expected an XML element node named 'mesh' to contain "
124 "exactly one child node but it has {:d} children.",
125 meshes_node.childNodes().count());
126 return 0;
127 }
128 QDomNode node_text = meshes_node.firstChild();
129 if (!node_text.isText())
130 {
131 ERR("Expected an XML element node named 'mesh' to contain "
132 "text.");
133 return 0;
134 }
135 read_single_mesh(path + node_text.toText().data().trimmed());
136 }
137 }
138
139 else if (node_name == "parameters")
140 {
141 param_root = node;
142 }
143 else if (node_name == "process_variables")
144 {
145 pvar_root = node;
146 }
147 }
148
149 if (param_root != QDomNode() && pvar_root != QDomNode())
150 {
151 readConditions(pvar_root, param_root);
152 }
153 else
154 INFO("Skipping process variables");
155
156 return 1;
157}
158
159QDomNode XmlPrjInterface::findParam(QDomNode const& param_root,
160 QString const& param_name) const
161{
162 QDomNode param = param_root.firstChild();
163
164 while (param != QDomNode())
165 {
166 QDomNodeList nodeList = param.childNodes();
167 for (int i = 0; i < nodeList.count(); i++)
168 {
169 QDomNode node = nodeList.at(i);
170 // std::cout << node.nodeName().toStdString() <<
171 // node.toElement().text().toStdString() << std::endl;
172 if (node.nodeName() == "name" &&
173 node.toElement().text() == param_name)
174 {
175 return node;
176 }
177 }
178 param = param.nextSibling();
179 }
180 return QDomNode();
181}
182
183void XmlPrjInterface::readConditions(QDomNode const& pvar_root,
184 QDomNode const& param_root)
185{
186 QDomNode pvar = pvar_root.firstChild();
187 while (pvar != QDomNode())
188 {
190 QDomNodeList nodeList = pvar.childNodes();
191 for (int i = 0; i < nodeList.count(); i++)
192 {
193 QDomNode const node = nodeList.at(i);
194 QString const node_name = node.nodeName();
195 if (node_name == "name")
196 {
197 process_var.name = node.toElement().text().toStdString();
198 }
199 else if (node_name == "components")
200 {
201 process_var.components = node.toElement().text().toInt();
202 }
203 else if (node_name == "order")
204 {
205 process_var.order = node.toElement().text().toInt();
206 }
207 else if (node_name == "boundary_conditions")
208 {
209 readBoundaryConditions(node, param_root, process_var);
210 }
211 else if (node_name == "source_terms")
212 {
213 readSourceTerms(node, param_root, process_var);
214 }
215 }
216 pvar = pvar.nextSibling();
217 }
218}
219
221 QDomNode const& bc_root,
222 QDomNode const& param_root,
224{
225 QDomNode bc = bc_root.firstChild();
226 while (bc != QDomNode())
227 {
228 std::unique_ptr<DataHolderLib::BoundaryCondition> cond(
229 parseCondition<DataHolderLib::BoundaryCondition>(bc, param_root,
230 pvar));
231 if (cond->getType() !=
233 {
234 _project.addBoundaryCondition(std::move(cond));
235 }
236
237 bc = bc.nextSibling();
238 }
239}
240
242 QDomNode const& st_root,
243 QDomNode const& param_root,
245{
246 QDomNode st = st_root.firstChild();
247 while (st != QDomNode())
248 {
249 std::unique_ptr<DataHolderLib::SourceTerm> cond(
250 parseCondition<DataHolderLib::SourceTerm>(st, param_root, pvar));
252 {
253 _project.addSourceTerm(std::move(cond));
254 }
255 st = st.nextSibling();
256 }
257}
258
259template <typename T>
261 QDomNode const& node,
262 QDomNode const& param_root,
263 DataHolderLib::ProcessVariable const& pvar) const
264{
265 DataHolderLib::BaseObjType base_obj_type =
267 typename T::ConditionType type = T::ConditionType::NONE;
268 std::string base_obj_name;
269 std::string obj_name;
270 std::string param_name;
271 QDomNode param_node = QDomNode();
272 QDomNodeList nodeList = node.childNodes();
273 for (int i = 0; i < nodeList.count(); i++)
274 {
275 QString const node_name = nodeList.at(i).nodeName();
276 QString const content = nodeList.at(i).toElement().text().trimmed();
277 if (node_name == "geometrical_set" &&
278 base_obj_type != DataHolderLib::BaseObjType::MESH)
279 {
280 base_obj_name = content.toStdString();
281 }
282 else if (node_name == "geometry" &&
283 base_obj_type != DataHolderLib::BaseObjType::MESH)
284 {
285 obj_name = content.toStdString();
286 }
287 else if (node_name == "type")
288 {
289 type = T::convertStringToType(content.toStdString());
290 }
291 else if (node_name == "mesh")
292 {
293 base_obj_type = DataHolderLib::BaseObjType::MESH;
294 base_obj_name = content.toStdString();
295 obj_name.clear();
296 }
297 else if (node_name == "field_name")
298 {
299 param_name = content.toStdString();
300 }
301 else if (node_name == "parameter")
302 {
303 QDomNode val = findParam(param_root, content);
304 if (val == QDomNode())
305 {
306 continue;
307 }
308 param_name = content.toStdString();
309 param_node = nodeList.at(i);
310 }
311 }
312
313 if (!param_name.empty())
314 {
315 T* cond = new T(pvar, param_name, type);
316 if (base_obj_type == DataHolderLib::BaseObjType::MESH)
317 {
318 cond->setMesh(base_obj_name);
319 }
320 else
321 {
322 cond->setGeoObject(base_obj_name, obj_name);
323 }
324
325 return cond;
326 }
327 return new T({"", 0, 0}, "", T::ConditionType::NONE);
328}
329
330int XmlPrjInterface::writeToFile(const std::string& filename)
331{
332 _filename = filename;
334}
335
337{
339 QFileInfo fi(QString::fromStdString(_filename));
340 std::string path((fi.absolutePath()).toStdString() + "/");
341
342 out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; // xml
343 // definition
344 out << "<?xml-stylesheet type=\"text/xsl\" "
345 "href=\"OpenGeoSysProject.xsl\"?>\n\n"; // stylefile definition
346
347 QDomDocument doc("OGS-PROJECT-DOM");
348 QDomElement root = doc.createElement("OpenGeoSysProject");
349 root.setAttribute("xmlns:ogs", "http://www.opengeosys.org");
350 root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
351
352 doc.appendChild(root);
353
354 // meshes
355 auto const& mesh_vector = _project.getMeshObjects();
356 for (auto const& mesh : mesh_vector)
357 {
358 // write mesh file
359 MeshLib::IO::writeMeshToFile(*mesh, path + mesh->getName() + ".vtu");
360
361 // write entry in project file
362 QDomElement mesh_tag = doc.createElement("mesh");
363 root.appendChild(mesh_tag);
364 QDomText filename_text =
365 doc.createTextNode(QString::fromStdString(mesh->getName()));
366 mesh_tag.appendChild(filename_text);
367 }
368
369 // geometries
370 for (std::string const& name : geo_objects.getGeometryNames())
371 {
372 // write gml file
373 GeoLib::IO::XmlGmlInterface gml(geo_objects);
374 gml.export_name = name;
376 std::string(path + name + ".gml")))
377 {
378 // write entry in project file
379 QDomElement geo_tag = doc.createElement("geometry");
380 root.appendChild(geo_tag);
381 QDomText filename_text =
382 doc.createTextNode(QString::fromStdString(name + ".gml"));
383 geo_tag.appendChild(filename_text);
384 }
385 else
386 ERR("XmlGmlInterface::writeFile(): Error writing gml-file '{:s}'.",
387 name);
388 }
389
390 // stations
391 std::vector<std::string> stn_names;
392 geo_objects.getStationVectorNames(stn_names);
393 for (std::string const& name : stn_names)
394 {
395 // write station file
396 GeoLib::IO::XmlStnInterface stn(geo_objects);
397 stn.export_name = name;
398
400 path + name + ".stn"))
401 {
402 // write entry in project file
403 QDomElement stn_tag = doc.createElement("stations");
404 root.appendChild(stn_tag);
405 QDomText filename_text =
406 doc.createTextNode(QString::fromStdString(name + ".stn"));
407 stn_tag.appendChild(filename_text);
408 }
409 else
410 ERR("XmlStnInterface::writeFile(): Error writing stn-file '{:s}'.",
411 name);
412 }
413
414 if (!_project.getBoundaryConditions().empty() ||
415 !_project.getSourceTerms().empty())
416 {
417 // parameters
418 writeProcessVariables(doc, root);
419 }
420
421 std::string xml = doc.toString().toStdString();
422 out << xml;
423 return true;
424}
425
426void addTextNode(QDomDocument& doc,
427 QDomElement& parent,
428 QString const& node_name,
429 QString const& content)
430{
431 QDomElement tag = doc.createElement(node_name);
432 parent.appendChild(tag);
433 QDomText order_text = doc.createTextNode(content);
434 tag.appendChild(order_text);
435}
436
437bool PVarExists(std::string const& name,
438 std::vector<DataHolderLib::ProcessVariable> const& p_vars)
439{
440 return std::any_of(p_vars.begin(), p_vars.end(),
441 [&](auto const& p_var) { return p_var.name == name; });
442}
443
444std::vector<DataHolderLib::ProcessVariable>
446{
447 std::vector<std::unique_ptr<DataHolderLib::BoundaryCondition>> const&
448 boundary_conditions = _project.getBoundaryConditions();
449 std::vector<std::unique_ptr<DataHolderLib::SourceTerm>> const&
450 source_terms = _project.getSourceTerms();
451
452 std::vector<DataHolderLib::ProcessVariable> p_vars;
453 for (auto& bc : boundary_conditions)
454 {
455 DataHolderLib::ProcessVariable const& pvar(bc->getProcessVar());
456 if (!PVarExists(pvar.name, p_vars))
457 {
458 p_vars.push_back(pvar);
459 }
460 }
461
462 for (auto& st : source_terms)
463 {
464 DataHolderLib::ProcessVariable const& pvar(st->getProcessVar());
465 if (!PVarExists(pvar.name, p_vars))
466 {
467 p_vars.push_back(pvar);
468 }
469 }
470 return p_vars;
471}
472
473template <typename T>
475 QDomDocument& doc,
476 QDomElement& tag,
477 DataHolderLib::FemCondition const& cond) const
478{
480 {
481 addTextNode(doc,
482 tag,
483 "geometrical_set",
484 QString::fromStdString(cond.getBaseObjName()));
485 addTextNode(doc, tag, "geometry",
486 QString::fromStdString(cond.getObjName()));
487 addTextNode(doc,
488 tag,
489 "type",
490 QString::fromStdString(T::convertTypeToString(
491 static_cast<T const&>(cond).getType())));
492 addTextNode(doc, tag, "parameter",
493 QString::fromStdString(cond.getParamName()));
494 }
496 {
497 addTextNode(doc,
498 tag,
499 "type",
500 QString::fromStdString(T::convertTypeToString(
501 static_cast<T const&>(cond).getType())));
502 addTextNode(doc, tag, "mesh",
503 QString::fromStdString(cond.getBaseObjName()));
504 addTextNode(doc,
505 tag,
506 "field_name",
507 QString::fromStdString(cond.getParamName()));
508 }
509}
510
512 QDomElement& bc_list_tag,
513 std::string const& name) const
514{
515 std::vector<std::unique_ptr<DataHolderLib::BoundaryCondition>> const&
516 boundary_conditions = _project.getBoundaryConditions();
517 for (auto& bc : boundary_conditions)
518 {
519 if (bc->getProcessVarName() != name)
520 {
521 continue;
522 }
523 QDomElement bc_tag = doc.createElement("boundary_condition");
524 bc_list_tag.appendChild(bc_tag);
525 writeCondition<DataHolderLib::BoundaryCondition>(doc, bc_tag, *bc);
526 }
527}
528
530 QDomElement& st_list_tag,
531 std::string const& name) const
532{
533 std::vector<std::unique_ptr<DataHolderLib::SourceTerm>> const&
534 source_terms = _project.getSourceTerms();
535 for (auto& st : source_terms)
536 {
537 if (st->getProcessVarName() != name)
538 {
539 continue;
540 }
541 QDomElement st_tag = doc.createElement("source_term");
542 st_list_tag.appendChild(st_tag);
543 writeCondition<DataHolderLib::SourceTerm>(doc, st_tag, *st);
544 }
545}
546
548 QDomElement& root) const
549{
550 std::vector<DataHolderLib::ProcessVariable> const p_vars(
552
553 QDomElement param_list_tag = doc.createElement("parameters");
554 root.appendChild(param_list_tag);
555
556 QDomElement pvar_list_tag = doc.createElement("process_variables");
557 root.appendChild(pvar_list_tag);
558
559 for (DataHolderLib::ProcessVariable const& p_var : p_vars)
560 {
561 QDomElement pvar_tag = doc.createElement("process_variable");
562 pvar_list_tag.appendChild(pvar_tag);
563 addTextNode(doc, pvar_tag, "name", QString::fromStdString(p_var.name));
564 addTextNode(doc, pvar_tag, "order", QString::number(p_var.order));
565 addTextNode(doc, pvar_tag, "components",
566 QString::number(p_var.components));
567 QDomElement bc_list_tag = doc.createElement("boundary_conditions");
568 pvar_tag.appendChild(bc_list_tag);
569 writeBoundaryConditions(doc, bc_list_tag, p_var.name);
570 QDomElement st_list_tag = doc.createElement("source_terms");
571 pvar_tag.appendChild(st_list_tag);
572 writeSourceTerms(doc, st_list_tag, p_var.name);
573 }
574}
575} // namespace FileIO
Filename manipulation routines.
Definition of the GEOObjects class.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
Definition of the Mesh class.
Definition of the OGSError class.
Definition of the Writer class.
Definition of the XmlGmlInterface class.
Definition of the XmlStnInterface class.
std::ostringstream out
The stream to write to.
Definition Writer.h:47
std::string writeToString()
Writes the object to a string.
Definition Writer.cpp:31
QByteArray const & getContent() const
Base class for boundary conditions, initial conditions and source terms.
std::string getBaseObjName() const
Returns the name of the base object (i.e. geometry or mesh)
BaseObjType getBaseObjType() const
Specifies if the condition is set a geometry or on a mesh.
std::string const getObjName() const
Returns the name of the geometric object.
std::string const getParamName() const
Returns the name of the parameter associated with the condition.
void addBoundaryCondition(std::unique_ptr< BoundaryCondition > bc)
Adds a boundary condition to the project.
Definition Project.h:68
const std::vector< std::unique_ptr< MeshLib::Mesh > > & getMeshObjects() const
Returns all the meshes with their respective names.
Definition Project.h:57
void addMesh(std::unique_ptr< MeshLib::Mesh > mesh)
Definition Project.cpp:21
GeoLib::GEOObjects & getGEOObjects()
Returns the GEOObjects containing all points, polylines and surfaces.
Definition Project.h:46
std::vector< std::unique_ptr< SourceTerm > > const & getSourceTerms() const
Returns the vector of source terms.
Definition Project.h:87
void addSourceTerm(std::unique_ptr< SourceTerm > st)
Adds a source term to the project.
Definition Project.h:74
std::vector< std::unique_ptr< BoundaryCondition > > const & getBoundaryConditions() const
Returns the vector of boundary conditions.
Definition Project.h:81
void readBoundaryConditions(QDomNode const &bc_root, QDomNode const &param_root, DataHolderLib::ProcessVariable const &pvar)
Reading all boundary conditions.
T * parseCondition(QDomNode const &node, QDomNode const &param_root, DataHolderLib::ProcessVariable const &pvar) const
Parsing one specific condition.
int writeToFile(const std::string &filename)
Writes a project to the specified file.
std::vector< DataHolderLib::ProcessVariable > getPrimaryVariableVec() const
Compiles a vector of all existing primary variables for writing purposes.
bool write() override
Writes the object to the internal stream. This method must be implemented by a subclass....
void writeSourceTerms(QDomDocument &doc, QDomElement &st_list_tag, std::string const &name) const
Writes a list of source terms.
void readSourceTerms(QDomNode const &st_root, QDomNode const &param_root, DataHolderLib::ProcessVariable const &pvar)
Reading all source terms.
int readFile(const QString &fileName) override
Reads an xml-file containing a project.
void writeProcessVariables(QDomDocument &doc, QDomElement &root) const
Writes information on process variables.
DataHolderLib::Project & _project
void writeCondition(QDomDocument &doc, QDomElement &tag, DataHolderLib::FemCondition const &cond) const
Writes one specific condition.
void writeBoundaryConditions(QDomDocument &doc, QDomElement &bc_list_tag, std::string const &name) const
Writes a list of boundary conditions.
XmlPrjInterface(DataHolderLib::Project &project)
void readConditions(QDomNode const &pvar_root, QDomNode const &param_root)
Manages reading all kinds of conditions.
QDomNode findParam(QDomNode const &param_root, QString const &param_name) const
Tests if a given parameter exists within the file.
Container class for geometric objects.
Definition GEOObjects.h:57
std::vector< std::string > getGeometryNames() const
Returns the names of all geometry vectors.
void getStationVectorNames(std::vector< std::string > &names) const
Returns the names of all station vectors.
Reads and writes GeoObjects to and from XML files.
int readFile(const QString &fileName) override
Reads an xml-file containing geometric object definitions into the GEOObjects used in the constructor...
Reads and writes Observation Sites to and from XML files.
int readFile(const QString &fileName) override
Reads an xml-file containing station object definitions into the GEOObjects used in the constructor (...
static void box(const QString &e)
Definition OGSError.cpp:23
int writeStringToFile(std::string_view content, std::filesystem::path const &file_path)
Definition Writer.cpp:45
void addTextNode(QDomDocument &doc, QDomElement &parent, QString const &node_name, QString const &content)
bool PVarExists(std::string const &name, std::vector< DataHolderLib::ProcessVariable > const &p_vars)
MeshLib::Mesh * readMeshFromFile(const std::string &file_name, bool const compute_element_neighbors)
int writeMeshToFile(const MeshLib::Mesh &mesh, std::filesystem::path const &file_path, std::set< std::string > variable_output_names)
Definition of readMeshFromFile function.