https://gitlab.opengeosys.org/ogs/ogs.git
Revision f211773854621c777e8b74b6ff59cd58555fbf15 authored by Wenqing Wang on 15 December 2015, 12:18:29 UTC, committed by Wenqing Wang on 15 December 2015, 12:20:50 UTC
1 parent 22a6215
Raw File
Tip revision: f211773854621c777e8b74b6ff59cd58555fbf15 authored by Wenqing Wang on 15 December 2015, 12:18:29 UTC
[CHLog] Updated the changlog for v6.0.4
Tip revision: f211773
GMSHInterface.cpp
/**
 * \file
 * \author Thomas Fischer
 * \date   2010-04-29
 * \brief  Implementation of the GMSHInterface class.
 *
 * \copyright
 * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 *
 * @file GMSHInterface.cpp
 * @date 2010-04-29
 * @author Thomas Fischer
 */

#include <fstream>
#include <vector>

#include <logog/include/logog.hpp>

#include "BaseLib/BuildInfo.h"
#include "BaseLib/FileTools.h"
#include "BaseLib/StringTools.h"

#include "FileIO/GMSHInterface.h"
#include "FileIO/GmshIO/GMSHAdaptiveMeshDensity.h"
#include "FileIO/GmshIO/GMSHFixedMeshDensity.h"
#include "FileIO/GmshIO/GMSHNoMeshDensity.h"

#include "GeoLib/GEOObjects.h"
#include "GeoLib/Point.h"
#include "GeoLib/Polygon.h"
#include "GeoLib/Polyline.h"
#include "GeoLib/PolylineWithSegmentMarker.h"
#include "GeoLib/QuadTree.h"

#include "MeshLib/Elements/Elements.h"
#include "MeshLib/Mesh.h"
#include "MeshLib/Node.h"

namespace FileIO
{
GMSHInterface::GMSHInterface(GeoLib::GEOObjects & geo_objs,
                             bool /*include_stations_as_constraints*/,
                             GMSH::MeshDensityAlgorithm mesh_density_algorithm,
                             double param1,
                             double param2,
                             std::size_t param3,
                             std::vector<std::string>& selected_geometries) :
	_n_lines(0), _n_plane_sfc(0), _geo_objs(geo_objs), _selected_geometries(selected_geometries)
{
	switch (mesh_density_algorithm) {
	case GMSH::MeshDensityAlgorithm::NoMeshDensity:
		_mesh_density_strategy = new GMSH::GMSHNoMeshDensity;
		break;
	case GMSH::MeshDensityAlgorithm::FixedMeshDensity:
		_mesh_density_strategy = new GMSH::GMSHFixedMeshDensity(param1);
		break;
	case GMSH::MeshDensityAlgorithm::AdaptiveMeshDensity:
		_mesh_density_strategy = new GMSH::GMSHAdaptiveMeshDensity(param1, param2, param3);
		break;
	}
}

int GMSHInterface::writeGeoFile(GeoLib::GEOObjects &geo_objects, std::string const& file_name)
{
	std::vector<std::string> names;
	geo_objects.getGeometryNames(names);

	if (names.empty())
	{
		ERR ("No geometry information available.");
		return 1;
	}

	bool const multiple_geometries = (names.size() > 1);
	std::string merge_name("MergedGeometry");
	if (multiple_geometries)
	{
		if (geo_objects.mergeGeometries (names, merge_name) != 1)
			return 2;
		names.clear();
		names.push_back(merge_name);
	}
	else
		merge_name = names[0];

	// default parameters for GMSH interface
	double param1(0.5);    // mesh density scaling on normal points
	double param2(0.05);   // mesh density scaling on station points
	std::size_t param3(2); // points per leaf
	GMSHInterface gmsh_io(geo_objects, true, FileIO::GMSH::MeshDensityAlgorithm::AdaptiveMeshDensity, param1, param2, param3, names);
	int const writer_return_val = gmsh_io.writeToFile(file_name);

	if (multiple_geometries)
	{
		geo_objects.removeSurfaceVec(merge_name);
		geo_objects.removePolylineVec(merge_name);
		geo_objects.removePointVec(merge_name);
	}
	return (writer_return_val==1) ? 0 : 3;
}

bool GMSHInterface::isGMSHMeshFile(const std::string& fname)
{
	std::ifstream input(fname.c_str());

	if (!input) {
		ERR("GMSHInterface::isGMSHMeshFile(): Could not open file %s.", fname.c_str());
		return false;
	}

	std::string header_first_line;
	input >> header_first_line;
	if (header_first_line.find("$MeshFormat") != std::string::npos) {
		// read version
		std::string version;
		getline(input, version);
		getline(input, version);
		INFO("GMSHInterface::isGMSHMeshFile(): Found GMSH mesh file version: %s.",
		     version.c_str());
		input.close();
		return true;
	}

	return false;
}

MeshLib::Mesh* GMSHInterface::readGMSHMesh(std::string const& fname)
{
	std::string line;
	std::ifstream in(fname.c_str(), std::ios::in);
	if (!in.is_open())
	{
		WARN ("GMSHInterface::readGMSHMesh() - Could not open file %s.", fname.c_str());
		return nullptr;
	}

	getline(in, line); // $MeshFormat keyword
	if (line.find("$MeshFormat") == std::string::npos)
	{
		in.close();
		WARN ("No GMSH file format recognized.");
		return nullptr;
	}

	getline(in, line); // version-number file-type data-size
	if (line.substr(0,3).compare("2.2") != 0) {
		WARN("Wrong gmsh file format version.");
		return nullptr;
	}

	if (line.substr(4,1).compare("0") != 0) {
		WARN("Currently reading gmsh binary file type is not supported.");
		return nullptr;
	}
	getline(in, line); //$EndMeshFormat

	std::vector<MeshLib::Node*> nodes;
	std::vector<MeshLib::Element*> elements;
	std::vector<int> materials;
	std::map<unsigned, unsigned> id_map;
	while (line.find("$EndElements") == std::string::npos)
	{
		// Node data
		getline(in, line); //$Nodes Keywords
		if (line.find("$Nodes") != std::string::npos)
		{
			std::size_t n_nodes(0);
			long id;
			double x, y, z;
			in >> n_nodes >> std::ws;
			nodes.resize(n_nodes);
			for (std::size_t i = 0; i < n_nodes; i++) {
				in >> id >> x >> y >> z >> std::ws;
				id_map.insert(std::map<unsigned, unsigned>::value_type(id, i));
				nodes[i] = new MeshLib::Node(x,y,z,id);
			}
			getline(in, line); // End Node keyword $EndNodes
		}

		// Element data
		if (line.find("$Elements") != std::string::npos)
		{
			std::size_t n_elements(0);
			if (! (in >> n_elements >> std::ws)) { // number-of-elements
				ERR("Read GMSH mesh does not contain any elements");
			}
			elements.reserve(n_elements);
			materials.reserve(n_elements);
			for (std::size_t i = 0; i < n_elements; i++)
			{
				MeshLib::Element* elem(nullptr);
				int mat_id(0);
				std::tie(elem, mat_id) = readElement(in, nodes, id_map);

				if (elem) {
					elements.push_back(elem);
					materials.push_back(mat_id);
				}
			}
			getline(in, line); // END keyword
		}

		if (line.find("PhysicalNames") != std::string::npos)
		{
			std::size_t n_lines(0);
			in >> n_lines >> std::ws; // number-of-lines
			for (std::size_t i = 0; i < n_lines; i++)
				getline(in, line);
			getline(in, line); // END keyword
		}
	}
	in.close();
	if (elements.empty()) {
		for (auto it(nodes.begin()); it != nodes.end(); ++it) {
			delete *it;
		}
		return nullptr;
	}

	MeshLib::Mesh * mesh(new MeshLib::Mesh(
		BaseLib::extractBaseNameWithoutExtension(fname), nodes, elements));

	boost::optional<MeshLib::PropertyVector<int> &> opt_material_ids(
		mesh->getProperties().createNewPropertyVector<int>(
			"MaterialIDs", MeshLib::MeshItemType::Cell, 1)
	);
	if (!opt_material_ids) {
		WARN("Could not create PropertyVector for MaterialIDs in Mesh.");
	} else {
		MeshLib::PropertyVector<int> & material_ids(opt_material_ids.get());
		material_ids.insert(material_ids.end(), materials.cbegin(),
			materials.cend());
	}
	INFO("\t... finished.");
	INFO("Nr. Nodes: %d.", nodes.size());
	INFO("Nr. Elements: %d.", elements.size());

	return mesh;
}

void GMSHInterface::readNodeIDs(std::ifstream &in,
                                unsigned n_nodes,
                                std::vector<unsigned> &node_ids,
                                std::map<unsigned, unsigned> const& id_map)
{
	unsigned idx;
	for (unsigned i = 0; i < n_nodes; i++)
	{
		in >> idx;
		node_ids.push_back(id_map.at(idx));
	}
}

std::pair<MeshLib::Element*, int>
GMSHInterface::readElement(std::ifstream &in,
	std::vector<MeshLib::Node*> const& nodes,
	std::map<unsigned, unsigned> const& id_map)
{
	unsigned idx, type, n_tags, dummy;
	int mat_id;
	std::vector<unsigned> node_ids;
	std::vector<MeshLib::Node*> elem_nodes;
	in >> idx >> type >> n_tags >> mat_id >> dummy;

	// skip tags
	for (std::size_t j = 2; j < n_tags; j++)
		in >> dummy;

	switch (type)
	{
	case 1: {
		readNodeIDs(in, 2, node_ids, id_map);
		// edge_nodes array will be deleted from Line object
		MeshLib::Node** edge_nodes = new MeshLib::Node*[2];
		edge_nodes[0] = nodes[node_ids[0]];
		edge_nodes[1] = nodes[node_ids[1]];
		return std::make_pair(new MeshLib::Line(edge_nodes), 0);
	}
	case 2: {
		readNodeIDs(in, 3, node_ids, id_map);
		MeshLib::Node** tri_nodes = new MeshLib::Node*[3];
		tri_nodes[0] = nodes[node_ids[2]];
		tri_nodes[1] = nodes[node_ids[1]];
		tri_nodes[2] = nodes[node_ids[0]];
		return std::make_pair(new MeshLib::Tri(tri_nodes), mat_id);
	}
	case 3: {
		readNodeIDs(in, 4, node_ids, id_map);
		MeshLib::Node** quad_nodes = new MeshLib::Node*[4];
		for (unsigned k(0); k < 4; k++)
			quad_nodes[k] = nodes[node_ids[k]];
		return std::make_pair(new MeshLib::Quad(quad_nodes), mat_id);
	}
	case 4: {
		readNodeIDs(in, 4, node_ids, id_map);
		MeshLib::Node** tet_nodes = new MeshLib::Node*[5];
		for (unsigned k(0); k < 4; k++)
			tet_nodes[k] = nodes[node_ids[k]];
		return std::make_pair(new MeshLib::Tet(tet_nodes), mat_id);
	}
	case 5: {
		readNodeIDs(in, 8, node_ids, id_map);
		MeshLib::Node** hex_nodes = new MeshLib::Node*[8];
		for (unsigned k(0); k < 8; k++)
			hex_nodes[k] = nodes[node_ids[k]];
		return std::make_pair(new MeshLib::Hex(hex_nodes), mat_id);
	}
	case 6: {
		readNodeIDs(in, 6, node_ids, id_map);
		MeshLib::Node** prism_nodes = new MeshLib::Node*[6];
		for (unsigned k(0); k < 6; k++)
			prism_nodes[k] = nodes[node_ids[k]];
		return std::make_pair(new MeshLib::Prism(prism_nodes), mat_id);
	}
	case 7: {
		readNodeIDs(in, 5, node_ids, id_map);
		MeshLib::Node** pyramid_nodes = new MeshLib::Node*[5];
		for (unsigned k(0); k < 5; k++)
			pyramid_nodes[k] = nodes[node_ids[k]];
		return std::make_pair(new MeshLib::Pyramid(pyramid_nodes), mat_id);
	}
	case 15:
		in >> dummy; // skip rest of line
		break;
	default:
		WARN("GMSHInterface::readGMSHMesh(): Unknown element type %d.", type);
	}
	return std::make_pair(nullptr, -1);
}


bool GMSHInterface::write()
{
	_out << "// GMSH input file created by OpenGeoSys " << BaseLib::BuildInfo::git_describe;
#ifdef BUILD_TIMESTAMP
	_out << " built on " << BaseLib::BuildInfo::build_timestamp;
#endif
	_out << "\n\n";

	writeGMSHInputFile(_out);
	return true;
}

void GMSHInterface::writeGMSHInputFile(std::ostream& out)
{
	DBUG("GMSHInterface::writeGMSHInputFile(): get data from GEOObjects.");

	if (_selected_geometries.empty())
		return;

	bool remove_geometry(false);
	// *** get and merge data from _geo_objs
	if (_selected_geometries.size() > 1) {
		_gmsh_geo_name = "GMSHGeometry";
		remove_geometry = true;
		_geo_objs.mergeGeometries(_selected_geometries, _gmsh_geo_name);
	} else {
		_gmsh_geo_name = _selected_geometries[0];
		remove_geometry = false;
	}
	std::vector<GeoLib::Point*> * merged_pnts(const_cast<std::vector<GeoLib::Point*> *>(_geo_objs.getPointVec(_gmsh_geo_name)));
	if (! merged_pnts) {
		ERR("GMSHInterface::writeGMSHInputFile(): Did not found any points.");
		return;
	} else {
		const std::size_t n_pnts(merged_pnts->size());
		for (std::size_t k(0); k<n_pnts; k++) {
			(*((*merged_pnts)[k]))[2] = 0.0;
		}
	}
	std::vector<GeoLib::Polyline*> const* merged_plys(_geo_objs.getPolylineVec(_gmsh_geo_name));
	DBUG("GMSHInterface::writeGMSHInputFile(): \t ok.");

	// *** compute topological hierarchy of polygons
	if (merged_plys) {
		for (std::vector<GeoLib::Polyline*>::const_iterator it(merged_plys->begin());
			it!=merged_plys->end(); ++it) {
			if ((*it)->isClosed()) {
				_polygon_tree_list.push_back(new GMSH::GMSHPolygonTree(new GeoLib::Polygon(*(*it), true), NULL, _geo_objs, _gmsh_geo_name, _mesh_density_strategy));
			}
		}
		DBUG("GMSHInterface::writeGMSHInputFile(): Compute topological hierarchy - detected %d polygons.", _polygon_tree_list.size());
		GeoLib::createPolygonTrees<GMSH::GMSHPolygonTree>(_polygon_tree_list);
		DBUG("GMSHInterface::writeGMSHInputFile(): Compute topological hierarchy - calculated %d polygon trees.", _polygon_tree_list.size());
	} else {
		return;
	}

	// *** insert stations and polylines (except polygons) in the appropriate object of
	//     class GMSHPolygonTree
	// *** insert stations
	const std::size_t n_geo_names(_selected_geometries.size());
	for (std::size_t j(0); j < n_geo_names; j++) {
		const std::vector<GeoLib::Point*>* stations (_geo_objs.getStationVec(_selected_geometries[j]));
		if (stations) {
			const std::size_t n_stations(stations->size());
			for (std::size_t k(0); k < n_stations; k++) {
				bool found(false);
				for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin());
					it != _polygon_tree_list.end() && !found; ++it) {
					if ((*it)->insertStation((*stations)[k])) {
						found = true;
					}
				}
			}
		}
	}
	// *** insert polylines
	const std::size_t n_plys(merged_plys->size());
	for (std::size_t k(0); k<n_plys; k++) {
		if (! (*merged_plys)[k]->isClosed()) {
			for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin());
				it != _polygon_tree_list.end(); ++it) {
				(*it)->insertPolyline(new GeoLib::PolylineWithSegmentMarker(*(*merged_plys)[k]));
			}
		}
	}

	// *** init mesh density strategies
	for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin());
		it != _polygon_tree_list.end(); ++it) {
		(*it)->initMeshDensityStrategy();
	}

	// *** create GMSH data structures
	const std::size_t n_merged_pnts(merged_pnts->size());
	_gmsh_pnts.resize(n_merged_pnts);
	for (std::size_t k(0); k<n_merged_pnts; k++) {
		_gmsh_pnts[k] = NULL;
	}
	for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin());
		it != _polygon_tree_list.end(); ++it) {
		(*it)->createGMSHPoints(_gmsh_pnts);
	}

	// *** finally write data :-)
	writePoints(out);
	std::size_t pnt_id_offset(_gmsh_pnts.size());
	for (std::list<GMSH::GMSHPolygonTree*>::iterator it(_polygon_tree_list.begin());
		it != _polygon_tree_list.end(); ++it) {
		(*it)->writeLineLoop(_n_lines, _n_plane_sfc, out);
		(*it)->writeSubPolygonsAsLineConstraints(_n_lines, _n_plane_sfc-1, out);
		(*it)->writeLineConstraints(_n_lines, _n_plane_sfc-1, out);
		(*it)->writeStations(pnt_id_offset, _n_plane_sfc-1, out);
		(*it)->writeAdditionalPointData(pnt_id_offset, _n_plane_sfc-1, out);
	}

	if (remove_geometry) {
		_geo_objs.removeSurfaceVec(_gmsh_geo_name);
		_geo_objs.removePolylineVec(_gmsh_geo_name);
		_geo_objs.removePointVec(_gmsh_geo_name);
	}
}

void GMSHInterface::writePoints(std::ostream& out) const
{
	const std::size_t n_gmsh_pnts(_gmsh_pnts.size());
	for (std::size_t k(0); k<n_gmsh_pnts; k++) {
		if (_gmsh_pnts[k]) {
			out << *(_gmsh_pnts[k]) << "\n";
		}
	}
}

} // end namespace FileIO
back to top