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 
31 namespace FileIO
32 {
34  : XMLQtInterface("OpenGeoSysProject.xsd"), _filename(""), _project(project)
35 {
36 }
37 
38 int 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 
159 QDomNode 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 
183 void XmlPrjInterface::readConditions(QDomNode const& pvar_root,
184  QDomNode const& param_root)
185 {
186  QDomNode pvar = pvar_root.firstChild();
187  while (pvar != QDomNode())
188  {
189  DataHolderLib::ProcessVariable process_var;
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,
223  DataHolderLib::ProcessVariable const& pvar)
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,
244  DataHolderLib::ProcessVariable const& pvar)
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));
251  if (cond->getType() != DataHolderLib::SourceTerm::ConditionType::NONE)
252  {
253  _project.addSourceTerm(std::move(cond));
254  }
255  st = st.nextSibling();
256  }
257 }
258 
259 template <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 
330 int XmlPrjInterface::writeToFile(const std::string& filename)
331 {
332  _filename = filename;
333  return BaseLib::IO::writeStringToFile(writeToString(), filename);
334 }
335 
337 {
338  GeoLib::GEOObjects& geo_objects = _project.getGEOObjects();
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 
426 void 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 
437 bool 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 
444 std::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 
473 template <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 
529 void XmlPrjInterface::writeSourceTerms(QDomDocument& doc,
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(char const *fmt, Args const &... args)
Definition: Logging.h:32
void ERR(char const *fmt, Args const &... args)
Definition: Logging.h:42
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:46
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.
Definition: FemCondition.h:40
std::string getBaseObjName() const
Returns the name of the base object (i.e. geometry or mesh)
Definition: FemCondition.h:59
BaseObjType getBaseObjType() const
Specifies if the condition is set a geometry or on a mesh.
Definition: FemCondition.h:56
std::string const getObjName() const
Returns the name of the geometric object.
Definition: FemCondition.h:62
std::string const getParamName() const
Returns the name of the parameter associated with the condition.
Definition: FemCondition.h:53
GeoLib::GEOObjects & getGEOObjects()
Returns the GEOObjects containing all points, polylines and surfaces.
Definition: Project.h:46
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
std::vector< std::unique_ptr< BoundaryCondition > > const & getBoundaryConditions() const
Returns the vector of boundary conditions.
Definition: Project.h:81
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
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:61
std::vector< std::string > getGeometryNames() const
Returns the names of all geometry vectors.
Definition: GEOObjects.cpp:342
void getStationVectorNames(std::vector< std::string > &names) const
Returns the names of all station vectors.
Definition: GEOObjects.cpp:331
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 content, std::filesystem::path const &file_path)
Definition: Writer.cpp:45
constexpr bool any_of(List const &values)
Checks if any of the elements in the given list is true.
Definition: Algorithm.h:325
bool readFile(std::string const &file_name, std::vector< std::unique_ptr< MeshLib::Mesh >> &meshes, DataType const export_type)
Reads the specified file and writes data into internal mesh vector.
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)
int writeMeshToFile(const MeshLib::Mesh &mesh, std::filesystem::path const &file_path, [[maybe_unused]] std::set< std::string > variable_output_names)
Definition of readMeshFromFile function.