From 1d2c4a69066d27fda2c6c2b782be79c86f1e0c31 Mon Sep 17 00:00:00 2001
From: Norihiro Watanabe <norihiro.watanabe@ufz.de>
Date: Tue, 20 May 2014 18:35:14 +0200
Subject: [PATCH] add FEFLOEInterface class in FileIO

---
 FileIO/CMakeLists.txt      |   1 +
 FileIO/FEFLOWInterface.cpp | 406 +++++++++++++++++++++++++++++++++++++
 FileIO/FEFLOWInterface.h   | 145 +++++++++++++
 3 files changed, 552 insertions(+)
 create mode 100644 FileIO/FEFLOWInterface.cpp
 create mode 100644 FileIO/FEFLOWInterface.h

diff --git a/FileIO/CMakeLists.txt b/FileIO/CMakeLists.txt
index ee5e300aac9..00b4bac1400 100644
--- a/FileIO/CMakeLists.txt
+++ b/FileIO/CMakeLists.txt
@@ -27,6 +27,7 @@ SET (SOURCES ${SOURCES} ${SOURCES_BASE_XML})
 GET_SOURCE_FILES(SOURCES_BOOST_XML XmlIO/Boost)
 SET (SOURCES ${SOURCES} ${SOURCES_BOOST_XML})
 IF (QT4_FOUND)
+	SET ( SOURCES ${SOURCES} FEFLOWInterface.h FEFLOWInterface.cpp)
 	GET_SOURCE_FILES(SOURCES_QT_XML XmlIO/Qt)
 	SET ( SOURCES ${SOURCES} ${SOURCES_QT_XML})
 ENDIF (QT4_FOUND)
diff --git a/FileIO/FEFLOWInterface.cpp b/FileIO/FEFLOWInterface.cpp
new file mode 100644
index 00000000000..02de780c226
--- /dev/null
+++ b/FileIO/FEFLOWInterface.cpp
@@ -0,0 +1,406 @@
+/**
+ * \copyright
+ * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ */
+
+#include "FEFLOWInterface.h"
+
+#include "logog/include/logog.hpp"
+#include <QtXml>
+
+#include "StringTools.h"
+#include "FileTools.h"
+#include "Polygon.h"
+#include "Mesh.h"
+#include "Node.h"
+#include "Elements/Line.h"
+#include "Elements/Hex.h"
+#include "Elements/Prism.h"
+#include "Elements/Quad.h"
+#include "Elements/Tet.h"
+#include "Elements/Tri.h"
+
+namespace FileIO
+{
+
+MeshLib::Mesh* FEFLOWInterface::readFEFLOWFile(const std::string &filename)
+{
+	std::ifstream in(filename.c_str());
+	if (!in)
+	{
+		ERR("FEFLOWInterface::readFEFLOWFile(): Could not open file %s.", filename.c_str());
+		return nullptr;
+	}
+
+	FEM_CLASS fem_class;
+	FEM_DIM fem_dim;
+	std::vector<GeoLib::Point*>* points = NULL;
+	std::vector<GeoLib::Polyline*>* lines = NULL;
+
+	bool isXZplane = false;
+
+	std::vector<MeshLib::Node*> vec_nodes;
+	std::vector<MeshLib::Element*> vec_elements;
+
+	std::string line_string;
+	std::stringstream line_stream;
+	while (!in.eof())
+	{
+		getline(in, line_string);
+		//....................................................................
+		// CLASS
+		if (line_string.find("CLASS") != std::string::npos) // the version number follows afterward, e.g. CLASS (v.5.313)
+		{
+			getline(in, line_string);
+			line_stream.str(line_string);
+			// problem class, time mode, problem orientation, dimension, nr. layers for 3D, saturation switch, precision of results, precision of coordinates
+			line_stream >> fem_class.problem_class >> fem_class.time_mode >> fem_class.orientation >> fem_class.dimension >> fem_class.n_layers3d;
+			line_stream.clear();
+		}
+		//....................................................................
+		// DIMENS
+		else if (line_string.compare("DIMENS") == 0)
+		{
+			// DIMENS
+			getline(in, line_string);
+			line_stream.str(line_string);
+			line_stream >> fem_dim.n_nodes >> fem_dim.n_elements >> fem_dim.n_nodes_of_element >> std::ws;
+			// create node pointers with dummy coordinates to create element objects.
+			// True coordinates are set later in COOR and ELEV_I.
+			double dummy_coords[3] = {};
+			vec_nodes.reserve(fem_dim.n_nodes);
+			for (size_t i=0; i<fem_dim.n_nodes; i++)
+				vec_nodes.push_back(new MeshLib::Node(dummy_coords, i));
+			line_stream.clear();
+		}
+		//....................................................................
+		// NODE (node index for elements)
+		else if (line_string.compare("NODE") == 0)
+		{
+			assert(!vec_nodes.empty());
+
+			MeshElemType eleType = MeshElemType::INVALID;
+			if (fem_dim.n_nodes_of_element == 2)
+				eleType = MeshElemType::LINE;
+			else if (fem_dim.n_nodes_of_element == 3)
+				eleType = MeshElemType::TRIANGLE;
+			else if (fem_dim.n_nodes_of_element == 4 && fem_class.dimension == 2)
+				eleType = MeshElemType::TRIANGLE;
+			else if (fem_dim.n_nodes_of_element == 4 && fem_class.dimension == 3)
+				eleType = MeshElemType::TETRAHEDRON;
+			else if (fem_dim.n_nodes_of_element == 6 && fem_class.dimension == 3)
+				eleType = MeshElemType::PRISM;
+			else if (fem_dim.n_nodes_of_element == 8 && fem_class.dimension == 3)
+				eleType = MeshElemType::HEXAHEDRON;
+
+			if (eleType == MeshElemType::INVALID) {
+				ERR("FEFLOWInterface::readFEFLOWFile(): Unsupported element type with the number of node = %d and dim = %d", fem_dim.n_nodes_of_element, fem_class.dimension);
+				return nullptr;
+			}
+
+			vec_elements.reserve(fem_dim.n_elements);
+			for (size_t i=0; i<fem_dim.n_elements; i++)
+			{
+				getline(in, line_string);
+				vec_elements.push_back(readElement(fem_dim, eleType, line_string, vec_nodes));
+			}
+		}
+		//....................................................................
+		// COOR
+		else if (line_string.compare("COOR") == 0)
+		{
+			readNodeCoordinates(in, fem_class, fem_dim, vec_nodes);
+		}
+		//....................................................................
+		// ELEV_I
+		else if (line_string.compare("ELEV_I") == 0)
+		{
+			if (fem_class.dimension == 2)
+				continue;
+			readELEV(in, fem_class, fem_dim, vec_nodes);
+		}
+		//....................................................................
+		// EXTENTS
+		else if (line_string.compare("EXTENTS") == 0)
+		{
+		}
+		//....................................................................
+		// GRAVITY
+		else if (line_string.compare("GRAVITY") == 0)
+		{
+			getline(in, line_string);
+			line_stream.str(line_string);
+			double vec[3] = { };
+			line_stream >> vec[0] >> vec[1] >> vec[2];
+			if (vec[0] == 0.0 && vec[1] == -1.0 && vec[2] == 0.0)
+				// x-z plane
+				isXZplane = true;
+			line_stream.clear();
+		}
+		//....................................................................
+		// SUPERMESH
+		else if (line_string.compare("SUPERMESH") == 0)
+		{
+			readSuperMesh(in, fem_class, &points, &lines);
+		}
+		//....................................................................
+	}
+	in.close();
+
+	if (lines && lines->size() > 1)
+	{
+		this->setMaterialID(vec_elements, lines);
+	}
+
+	if (isXZplane)
+	{
+		for (auto* nod : vec_nodes)
+		{
+			(*nod)[2] = (*nod)[1];
+			(*nod)[1] = 0.0;
+		}
+		if (points)
+		{
+			for (auto* pt : *points)
+			{
+				(*pt)[2] = (*pt)[1];
+				(*pt)[1] = .0;
+			}
+		}
+	}
+
+	std::string project_name(BaseLib::extractBaseNameWithoutExtension(filename));
+	if (_geoObjects && points)
+		_geoObjects->addPointVec(points, project_name);
+	if (_geoObjects && lines)
+		_geoObjects->addPolylineVec(lines, project_name);
+
+	return new MeshLib::Mesh(project_name, vec_nodes, vec_elements);
+}
+
+
+void FEFLOWInterface::readNodeCoordinates(std::ifstream &in, const FEM_CLASS &fem_class, const FEM_DIM &fem_dim, std::vector<MeshLib::Node*> &vec_nodes)
+{
+	const size_t no_nodes_per_layer = (fem_class.dimension == 2) ? fem_dim.n_nodes : fem_dim.n_nodes / (fem_class.n_layers3d + 1);
+	const size_t n_lines = no_nodes_per_layer / 12 + 1;
+	const size_t n_layers = (fem_class.dimension == 3) ? fem_class.n_layers3d + 1 : 1;
+	std::string line_string;
+	std::stringstream line_stream;
+	double x;
+	char dummy_char; // for comma(,)
+	// x, y
+	for (unsigned k = 0; k < 2; k++)
+	{
+		// each line
+		for (size_t i = 0; i < n_lines; i++)
+		{
+			getline(in, line_string);
+			line_stream.str(line_string);
+			// maximum 12 columns
+			for (unsigned j = 0; j < 12; j++)
+			{
+				if (i * 12 + j >= no_nodes_per_layer)
+					break;
+				line_stream >> x >> dummy_char;
+				for (size_t l = 0; l < n_layers; l++)
+				{
+					size_t n = i * 12 + l * no_nodes_per_layer + j;
+					MeshLib::Node* m_nod = vec_nodes[n];
+					if (k == 0)
+						(*m_nod)[0] = x;
+					else
+						(*m_nod)[1] = x;
+				}
+			}
+			line_stream.clear();
+		}
+	}
+}
+
+void FEFLOWInterface::readELEV(std::ifstream &in, const FEM_CLASS &fem_class, const FEM_DIM &fem_dim, std::vector<MeshLib::Node*> &vec_nodes)
+{
+	const size_t no_nodes_per_layer = fem_dim.n_nodes / (fem_class.n_layers3d + 1);
+	double z = .0;
+	size_t n0 = 0;
+	std::string line_string;
+	std::stringstream line_stream;
+	for (size_t l = 0; l < fem_class.n_layers3d + 1; l++)
+	{
+		if (l > 0)
+			getline(in, line_string);
+
+		getline(in, line_string);
+		line_stream.str(line_string);
+		line_stream >> z >> n0;
+		line_stream.clear();
+
+		for (size_t i = 0; i < no_nodes_per_layer; i++)
+		{
+			size_t n = n0 - 1 + i + l * no_nodes_per_layer;
+			(*vec_nodes[n])[2] = z;
+		}
+	}
+}
+
+MeshLib::Element* FEFLOWInterface::readElement(const FEM_DIM &fem_dim, const MeshElemType elem_type, const std::string& line, const std::vector<MeshLib::Node*> &nodes)
+{
+	std::stringstream ss(line);
+	std::string elem_type_str("");
+
+	unsigned idx[8];
+	for (size_t i = 0; i < fem_dim.n_nodes_of_element; ++i)
+		ss >> idx[i];
+	MeshLib::Node** ele_nodes = new MeshLib::Node*[fem_dim.n_nodes_of_element];
+	for (unsigned k(0); k < fem_dim.n_nodes_of_element; ++k)
+		ele_nodes[k] = nodes[idx[k]-1];
+
+	switch (elem_type)
+	{
+	case MeshElemType::LINE:
+		return new MeshLib::Line(ele_nodes);
+	case MeshElemType::TRIANGLE:
+		return new MeshLib::Tri(ele_nodes);
+	case MeshElemType::QUAD:
+		return new MeshLib::Quad(ele_nodes);
+	case MeshElemType::TETRAHEDRON:
+		return new MeshLib::Tet(ele_nodes);
+	case MeshElemType::HEXAHEDRON:
+		return new MeshLib::Hex(ele_nodes);
+	case MeshElemType::PRISM:
+		return new MeshLib::Prism(ele_nodes);
+	default:
+		assert(false);
+		return nullptr;
+	}
+}
+
+void FEFLOWInterface::readPoints(QDomElement &nodesEle, const std::string &tag, int dim, std::vector<GeoLib::Point*> &points)
+{
+	QDomElement xmlEle = nodesEle.firstChildElement(QString::fromStdString(tag));
+	if (xmlEle.isNull())
+		return;
+	QString str_pt_list1 = xmlEle.text().simplified();
+	std::istringstream ss(str_pt_list1.toStdString());
+	while (!ss.eof())
+	{
+		int pt_id = 0;
+		double pt_xyz[3] =
+		{ };
+		ss >> pt_id;
+		for (int i = 0; i < dim; i++)
+			ss >> pt_xyz[i];
+		GeoLib::Point* pnt = new GeoLib::Point(pt_xyz[0], pt_xyz[1], pt_xyz[2]); //id?
+		points[pt_id - 1] = pnt;
+	}
+}
+
+//
+void FEFLOWInterface::readSuperMesh(std::ifstream &in, const FEM_CLASS &fem_class, std::vector<GeoLib::Point*>** p_points, std::vector<GeoLib::Polyline*>** p_lines)
+{
+	// get XML strings
+	std::ostringstream oss;
+	std::string line_string;
+	while (true)
+	{
+		getline(in, line_string);
+		BaseLib::trim(line_string);
+		oss << line_string << "\n";
+		if (line_string.find("</supermesh>") != std::string::npos)
+			break;
+	}
+//	std::cout << oss.str();
+	QString strXML(oss.str().c_str());
+	//qDebug() << strXML;
+
+	// convert string to XML
+	QDomDocument doc;
+	if (!doc.setContent(strXML))
+	{
+		ERR("FEFLOWInterface::readSuperMesh(): Illegal XML format error");
+		return;
+	}
+
+	// get geometry data from XML
+	QDomElement docElem = doc.documentElement(); // #supermesh
+	// #nodes
+	*p_points = new std::vector<GeoLib::Point*>();
+	std::vector<GeoLib::Point*>* points = *p_points;
+	QDomElement nodesEle = docElem.firstChildElement("nodes");
+	if (nodesEle.isNull())
+		return;
+	{
+		QString str = nodesEle.attribute("count");
+		const long n_points = str.toLong();
+		points->resize(n_points);
+		//fixed
+		readPoints(nodesEle, "fixed", fem_class.dimension, *points);
+		readPoints(nodesEle, "linear", fem_class.dimension, *points);
+		readPoints(nodesEle, "parabolic", fem_class.dimension, *points);
+	}
+
+	// #polygons
+	*p_lines = new std::vector<GeoLib::Polyline*>();
+	std::vector<GeoLib::Polyline*>* lines = *p_lines;
+	QDomElement polygonsEle = docElem.firstChildElement("polygons");
+	if (polygonsEle.isNull())
+		return;
+	{
+		QDomNode child = polygonsEle.firstChild();
+		while (!child.isNull())
+		{
+			if (child.nodeName() != "polygon")
+			{
+				child = child.nextSibling();
+				continue;
+			}
+			QDomElement xmlEle = child.firstChildElement("nodes");
+			if (xmlEle.isNull())
+				continue;
+			QString str = xmlEle.attribute("count");
+			const size_t n_points = str.toLong();
+			QString str_ptId_list = xmlEle.text().simplified();
+			{
+				GeoLib::Polyline* line = new GeoLib::Polyline(*points);
+				lines->push_back(line);
+				std::istringstream ss(str_ptId_list.toStdString());
+				for (size_t i = 0; i < n_points; i++)
+				{
+					int pt_id = 0;
+					ss >> pt_id;
+					line->addPoint(pt_id - 1);
+				}
+				line->addPoint(line->getPointID(0));
+			}
+			child = child.nextSibling();
+		}
+	}
+}
+
+void FEFLOWInterface::setMaterialID(std::vector<MeshLib::Element*> &vec_elements, std::vector<GeoLib::Polyline*>* lines)
+{
+	for (size_t i = 0; i < vec_elements.size(); i++)
+	{
+		MeshLib::Element* e = vec_elements[i];
+		MeshLib::Node gpt = e->getCenterOfGravity();
+		size_t matId = 0;
+		for (size_t j = 0; j < lines->size(); j++)
+		{
+			GeoLib::Polyline* poly = (*lines)[j];
+			if (!poly->isClosed())
+				continue;
+
+			GeoLib::Polygon polygon(*poly, true);
+			if (polygon.isPntInPolygon(gpt[0], gpt[1], gpt[2]))
+			{
+				matId = j;
+				break;
+			}
+		}
+		e->setValue(matId);
+	}
+}
+
+} // end namespace FileIO
diff --git a/FileIO/FEFLOWInterface.h b/FileIO/FEFLOWInterface.h
new file mode 100644
index 00000000000..ca89a6593d1
--- /dev/null
+++ b/FileIO/FEFLOWInterface.h
@@ -0,0 +1,145 @@
+/**
+ * \copyright
+ * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ */
+
+#ifndef FEFLOWINTERFACE_H_
+#define FEFLOWINTERFACE_H_
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include "GEOObjects.h"
+#include "MeshEnums.h"
+
+class QDomElement;
+class QString;
+
+namespace MeshLib
+{
+class Mesh;
+class Element;
+class Node;
+}
+
+namespace FileIO
+{
+
+/**
+ * Read FEFLOW files into OGS data structure
+ */
+class FEFLOWInterface
+{
+public:
+	/// Constructor
+	explicit FEFLOWInterface(GeoLib::GEOObjects* obj)
+			: _geoObjects(obj)
+	{
+	}
+
+	/**
+	 * read a FEFLOW Model file (*.fem) in ASCII format (Version 5.4)
+	 *
+	 * This function reads mesh data in addition to geometry data given in Supermesh.
+	 *
+	 * @param filename  FEFLOW file name
+	 * @return a pointer to a created OGS mesh
+	 */
+	MeshLib::Mesh* readFEFLOWFile(const std::string &filename);
+
+private:
+	// CLASS
+	struct FEM_CLASS
+	{
+		unsigned problem_class;
+		unsigned time_mode;
+		unsigned orientation;
+		unsigned dimension;
+		unsigned n_layers3d;
+		unsigned saturation_flag;
+		unsigned save_fsize_rreal;
+		unsigned save_fsize_creal;
+
+		FEM_CLASS()
+		{
+			problem_class = 0;
+			time_mode = 0;
+			orientation = 0;
+			dimension = 0;
+			n_layers3d = 0;
+			saturation_flag = 0;
+			save_fsize_rreal = 0;
+			save_fsize_creal = 0;
+		}
+	};
+
+	// DIMENSION
+	struct FEM_DIM
+	{
+		size_t n_nodes;
+		size_t n_elements;
+		unsigned n_nodes_of_element;
+		unsigned n_steps;
+		unsigned icrank;
+		unsigned upwind;
+		size_t obs;
+		unsigned optim;
+		unsigned aquifer_type;
+		unsigned nwca;
+		size_t np_cor;
+		unsigned adaptive_mesh;
+		unsigned sp_fem_pcs_id;
+		unsigned sorption_type;
+		unsigned reaction_type;
+		unsigned dispersion_type;
+
+		FEM_DIM()
+		{
+			n_nodes = 0;
+			n_elements = 0;
+			n_nodes_of_element = 0;
+			n_steps = 0;
+			icrank = 0;
+			upwind = 0;
+			obs = 0;
+			optim = 0;
+			aquifer_type = 0;
+			nwca = 0;
+			np_cor = 0;
+			adaptive_mesh = 0;
+			sp_fem_pcs_id = 0;
+			sorption_type = 0;
+			reaction_type = 0;
+			dispersion_type = 0;
+		}
+	};
+
+	/// read node index and create a mesh element
+	MeshLib::Element* readElement(const FEM_DIM &fem_dim, const MeshElemType elem_type, const std::string& line, const std::vector<MeshLib::Node*> &nodes);
+
+	/// read node coordinates
+	void readNodeCoordinates(std::ifstream &in, const FEM_CLASS &fem_class, const FEM_DIM &fem_dim, std::vector<MeshLib::Node*> &nodes);
+
+	/// read elevation data
+	void readELEV(std::ifstream &in, const FEM_CLASS &fem_class, const FEM_DIM &fem_dim, std::vector<MeshLib::Node*> &vec_nodes);
+
+	/// read Supermesh data
+	void readSuperMesh(std::ifstream &feflow_file, const FEM_CLASS &fem_class, std::vector<GeoLib::Point*>** points, std::vector<GeoLib::Polyline*>** lines);
+
+	//// read point data in Supermesh
+	void readPoints(QDomElement &nodesEle, const std::string &tag, int dim, std::vector<GeoLib::Point*> &points);
+
+	/// set element material IDs
+	void setMaterialID(std::vector<MeshLib::Element*> &vec_elements, std::vector<GeoLib::Polyline*>* lines);
+
+	//// Geometric objects
+	GeoLib::GEOObjects* _geoObjects;
+};
+} // end namespace FileIO
+
+#endif /* FEFLOWINTERFACE_H_ */
-- 
GitLab