diff --git a/dumux/io/artmeshreader.hh b/dumux/io/artmeshreader.hh new file mode 100644 index 0000000000000000000000000000000000000000..c65bc669c8ce2e4e2180edc51169c04a76ec86bb --- /dev/null +++ b/dumux/io/artmeshreader.hh @@ -0,0 +1,633 @@ +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * + * \brief Artmesh reader: Reads Artmesh files (ASCII) and constructs a UG grid + * for modeling lower dimensional discrete fracture-matrix problems. + */ + +#ifndef DUMUX_IO_ARTMESH_READER_HH +#define DUMUX_IO_ARTMESH_READER_HH + +#include <algorithm> +#include <iostream> +#include <fstream> +#include <sstream> +#include <iomanip> + +#include <dune/grid/common/mcmgmapper.hh> +#include <dune/grid/uggrid.hh> + +#include <dumux/common/math.hh> +#include <dumux/common/valgrind.hh> + +// plot the vertices, edges, elements +#define PLOT 0 +// TODO: this is a verbosity level + +namespace Dumux +{ +#ifdef HAVE_UG +typedef Dune::UGGrid<2> GridType; // Currently implemented for 2D fractured systems +#else +typedef Dune::YaspGrid<2> GridType; +#endif + +typedef Dune::FieldVector<double, 3> Coordinates; +typedef std::vector<Coordinates> VerticesVector; +typedef Dune::FieldVector<int, 3> EdgePoints; +typedef std::vector<EdgePoints> EdgesVector; +typedef Dune::FieldVector<int, 4> Faces; +typedef std::vector<Faces> FacesVector; + +typedef double NumberType; // TODO: from parameter system? + +/* +The number of + boundary vertices, + boundary edges (connecting two boundary vertices), + boundary faces (connecting n boundary edges) and + boundary elements (should be 0) +are read from the boundarty description file and stored here. +*/ +int bVertices, bEdges, bFaces, bElements; + +// Store the vertex coordinates, edge infos, face infos. +Dune::FieldVector<double, 2> vertexPosition; + +template<int dim> +struct P1Layout +{ + bool contains (Dune::GeometryType gt) + { + return (gt.dim() == 0); + } +}; + +/*! + * \brief Reads in Artmesh files. + */ +template <class GridType> +class ArtReader { + +public: + /*! + * \brief Reads the file formats obtained with the Artmesh generator + * + * \param + */ + void read_art_file(const char *artFileName) + { + std::cout << "Opening " << artFileName << std::endl; + std::ifstream inFile(artFileName); + + //intialize + Coordinates coordinate_; + EdgePoints edge_points_; + Faces faces_; + std::string jump; + + while (inFile >> jump) + { + //do nothing with the first lines in the code + //start reading information only after getting to %Points + if (jump == "VertexNumber:") + { + inFile >> jump; + double dummy = atof(jump.c_str()); + vertexNumber = dummy; + break; + } + } + while (inFile >> jump) + { + if (jump == "EdgeNumber:") + { + inFile >> jump; + double dummy = atof(jump.c_str()); + edgeNumber = dummy; + break; + } + } + while (inFile >> jump) + { + if (jump == "FaceNumber:") + { + inFile >> jump; + double dummy = atof(jump.c_str()); + faceNumber = dummy; + break; + } + } + while (inFile >> jump) + { + if (jump == "ElementNumber:") + { + inFile >> jump; + double dummy = atof(jump.c_str()); + elementNumber = dummy; + break; + } + } + //// finished reading the header information: total number of verts, etc.. + /////////////////////////////////////////////////////////////////////////// + while (inFile >> jump) + { + //jump over the lines until the ones with the vertices "% Vertices: x y z" + if (jump == "Vertices:") + { + break; + } + } + while (inFile >> jump) + { + //jskip words until "z" from the line "% Vertices: x y z" + if (jump == "z") + { + std::cout << "Start reading the vertices" << std::endl; + break; + } + } + + while (inFile >> jump) + { + if (jump == "$") + { + std::cout << "Finished reading the vertices" << std::endl; + break; + } + double dummy = atof(jump.c_str()); + coordinate_[0] = dummy; + for (int k=1; k<3; k++) + { + inFile >> jump; + dummy = atof(jump.c_str()); + coordinate_[k] = dummy; + } + vertices_.push_back(coordinate_); + } + /////Reading Edges + while (inFile >> jump) + { + //jump over the characters until the ones with the edges + if (jump == "Points):") + { + std::cout << std::endl << "Start reading the edges" << std::endl; + break; + } + } + while (inFile >> jump) + { + if (jump == "$") + { + std::cout << "Finished reading the edges" << std::endl; + break; + } + double dummy = atof(jump.c_str()); + edge_points_[0] = dummy; + for (int k=1; k<3; k++) + { + inFile >> jump; + dummy = atof(jump.c_str()); + edge_points_[k] = dummy; + } + edges_vector_.push_back(edge_points_); + } + + /////Reading Faces + while (inFile >> jump) + { + //jump over the characters until the ones with the edges + if (jump == "Edges):") + { + std::cout << std::endl << "Start reading the elements" << std::endl; + break; + } + } + while (inFile >> jump) + { + if (jump == "$") + { + std::cout << "Finished reading the elements" << std::endl; + break; + } + double dummy = atof(jump.c_str()); + faces_[0] = dummy; + for (int k=1; k<4; k++) + { + inFile >> jump; + dummy = atof(jump.c_str()); + faces_[k] = dummy; + } + faces_vector_.push_back(faces_); + } + } + void outputARTtoScreen() + { + ////////OUTPUT for verification + ////////////////////////////////////////////////////////////////// + std::cout << std::endl << "printing VERTICES" << std::endl; + for (int i = 0; i < vertices_.size(); i++) + { + for (int j=0; j < 3; j++) + std::cout << vertices_[i][j]<<"\t"; + std::cout << std::endl; + } + + std::cout << std::endl << "printing EDGES" << std::endl; + for (int i = 0; i < edges_vector_.size(); i++) + { + for (int j=0; j < 3; j++) + std::cout<<edges_vector_[i][j]<<"\t"; + std::cout<<std::endl; + } + ////Printing Faces + std::cout << std::endl << "printing FACES" << std::endl; + for (int i = 0; i < faces_vector_.size(); i++) + { + for (int j=0; j < 4; j++) + { + std::cout<<faces_vector_[i][j]<<" "; + } + std::cout<<std::endl; + } + + std::cout << std::endl << "Total number of vertices "<<vertexNumber<<std::endl; + std::cout << "Total number of edges: "<<edgeNumber<<std::endl; + std::cout << "Total number of faces: "<<faceNumber<<std::endl; + std::cout << "Total number of elements: "<<elementNumber<<std::endl; + + if (vertices_.size() != vertexNumber ) + { + std::cout << "The total given number of vertices: "<<vertexNumber + <<" is not the same with the read number of entries: " + <<vertices_.size()<<"" << std::endl; + } + if (edges_vector_.size() != edgeNumber ) + { + std::cout << "The total given number of edges: "<<edgeNumber + <<" is not the same with the read number of entries: " + <<edges_vector_.size()<<"" << std::endl; + } + if (faces_vector_.size() != faceNumber ) + { + std::cout << "The total given number of faces: "<<faceNumber + <<" is not the same with the read number of entries: " + <<faces_vector_.size()<<"" << std::endl; + } + } + + /*! + * \brief Create the UG grid from the read in data + */ + GridType* createGrid() + { + // set up the grid factory + Dune::FieldVector<double,2> position; + Dune::GridFactory<GridType> factory; + bVertices = vertexNumber; + bEdges = edgeNumber; + bFaces = faceNumber; + VerticesVector verts(bVertices); + EdgesVector edges(bEdges); + FacesVector elems(bFaces); + + // Plot the vertices + #if PLOT + std::cout << "*================*"<<std::endl; + std::cout << "* Vertices"<<std::endl; + std::cout << "*================*"<<std::endl; + #endif + for (int k=0; k<bVertices; k++) + { + verts[k][0] = vertices_[k][0]; + verts[k][1] = vertices_[k][1]; + verts[k][2] = vertices_[k][2]; + + //Printing the vertices vector + #if PLOT + std::cout << verts[k][0]<<"\t\t"; + std::cout << verts[k][1]<<"\t\t"; + std::cout << verts[k][2]<<std::endl; + #endif + for (int i=0; i<2; i++) + { + position[i]=verts[k][i]; + } + factory.insertVertex(position); + } + #if PLOT + std::cout << "*================*"<<std::endl; + std::cout << "* Edges"<<std::endl; + std::cout << "*================*"<<std::endl; + #endif + for (int k=0; k<bEdges; k++) + { + edges[k][0]=edges_vector_[k][0]; + edges[k][1]=edges_vector_[k][1]; + edges[k][2]=edges_vector_[k][2]; + #if PLOT + //Printing the Edge vector + std::cout<<edges[k][0]<<"\t\t"; + std::cout<<edges[k][1]<<"\t"; + std::cout<<edges[k][2]<<std::endl; + #endif + } + + // Plot the Elements (Faces) + #if PLOT + std::cout << "*================*"<<std::endl; + std::cout << "* Faces"<<std::endl; + std::cout << "*================*"<<std::endl; + #endif + + for (int k=0; k<faceNumber; k++) + { + elems[k][0]=faces_vector_[k][1]; + elems[k][1]=faces_vector_[k][2]; + elems[k][2]=faces_vector_[k][3]; + #if PLOT + std::cout<<elems[k][0]<<"\t"; + std::cout<<elems[k][1]<<"\t"; + std::cout<<elems[k][2]<<std::endl; + #endif + } + + //***********************************************************************// + //Create the Elements in Dune::GridFactory // + //***********************************************************************// + + for (int i=0; i<bFaces; i++) + { + std::vector<unsigned int> nodeIdx(3); + Dune::FieldVector<double,3> point(0); + #if PLOT + std::cout << "====================================="<<std::endl; + std::cout << "globalElemIdx "<<i<<std::endl; + std::cout << "====================================="<<std::endl; + #endif + int edgeIdx = 0; + //first node of the element - from first edge Node 1 + nodeIdx[0] = edges[elems[i][edgeIdx]][1]; + //second node of the element- from first edge Node 2 + nodeIdx[1] = edges[elems[i][edgeIdx]][2]; + //third node of the element - from the second edge + nodeIdx[2] = edges[elems[i][edgeIdx+1]][1]; + // if the nodes of the edges are identical swap + if (nodeIdx[1] == nodeIdx[2] || nodeIdx[0] == nodeIdx[2]) + { + nodeIdx[2] = edges[elems[i][edgeIdx+1]][2]; + } + + /* Check if the order of the nodes is trigonometric + by computing the cross product + If not then the two nodes are switched among each other*/ + Dune::FieldVector<double, 2> v(0); + Dune::FieldVector<double, 2> w(0); + double cross1; + v[0] = verts[nodeIdx[0]][0] - verts[nodeIdx[1]][0]; + v[1] = verts[nodeIdx[0]][1] - verts[nodeIdx[1]][1]; + w[0] = verts[nodeIdx[0]][0] - verts[nodeIdx[2]][0]; + w[1] = verts[nodeIdx[0]][1] - verts[nodeIdx[2]][1]; + cross1 = v[0]*w[1]-v[1]*w[0]; + //If the cross product is negative switch the order of the vertices + if (cross1 < 0) + { + nodeIdx[0] = edges[elems[i][edgeIdx]][2]; //node 0 is node 1 + nodeIdx[1] = edges[elems[i][edgeIdx]][1]; //node 1 is node 0 + } + v[0] = verts[nodeIdx[0]][0] - verts[nodeIdx[1]][0]; + v[1] = verts[nodeIdx[0]][1] - verts[nodeIdx[1]][1]; + w[0] = verts[nodeIdx[0]][0] - verts[nodeIdx[2]][0]; + w[1] = verts[nodeIdx[0]][1] - verts[nodeIdx[2]][1]; + + factory.insertElement(Dune::GeometryType(Dune::GeometryType::simplex,2), + nodeIdx); + #if PLOT + std::cout << "edges of the element "<< elems[i] << std::endl; + std::cout << "nodes of the element " << nodeIdx[0] + << ", " << nodeIdx[1] << ", " + << nodeIdx[2] << std::endl; + std::cout << "1st "<<nodeIdx[0]<<"\t"<<"2nd "<<nodeIdx[1] + << "\t"<<"3rd "<<nodeIdx[2] + << std::endl; + #endif + if (nodeIdx[0] == nodeIdx[1]||nodeIdx[1] == nodeIdx[2] + ||nodeIdx[0] == nodeIdx[2] ) + { + std::cout << "Error. The node index is identical in the element" + << std::endl; + } + + } + + Valgrind::CheckDefined(verts); + + return factory.createGrid(); + } + +public: + VerticesVector vertices_; + EdgesVector edges_vector_; + FacesVector faces_vector_ ; + int vertexNumber; + int edgeNumber; + int faceNumber; //in 2D + int elementNumber; //in 3D +}; + +/*! + * \brief Maps the fractures from the Artmesh to the UG grid ones + */ +template<class GridType> +class FractureMapper +{ +public: + // mapper: one data element in every entity + template<int dim> + struct FaceLayout + { + bool contains (Dune::GeometryType gt) + { + return gt.dim() == dim-1; + } + }; + template<int dim> + struct VertexLayout + { + bool contains (Dune::GeometryType gt) + { + return gt.dim() == 0; + } + }; + typedef typename GridType::LeafGridView GV; + typedef typename GridType::ctype DT; + enum {dim=GridType::dimension}; + typedef typename GV::IndexSet IS; + typedef typename GridType::template Codim<0>::Entity Entity; + typedef typename GV::template Codim<dim>::Iterator VertexLeafIterator; + typedef typename GV::template Codim<0>::Iterator ElementLeafIterator; + typedef typename GridType::template Codim<0>::EntityPointer EEntityPointer; + typedef typename GridType::Traits::GlobalIdSet IDS; + typedef typename IDS::IdType IdType; + typedef std::set<IdType> GIDSet; + typedef Dune::MultipleCodimMultipleGeomTypeMapper<GV,FaceLayout> FaceMapper; + typedef Dune::MultipleCodimMultipleGeomTypeMapper<GV,VertexLayout> VertexMapper; + typedef Dumux::ArtReader<GridType> ArtReader; + +public: + /*! + * \brief Constructor + * + * \param grid The grid + * \param geomArt Artmesh reader + */ + FractureMapper (const GridType& grid, ArtReader geomArt) + : grid_(grid), + facemapper(grid.leafView()), + vertexmapper(grid.leafView()), + artgeom_(geomArt) + {} + + /*! + * \brief Constructor + * + * \param grid The grid + * \param geomArt Artmesh reader + */ + FractureMapper (const GridType& grid) + : grid_(grid), + facemapper(grid.leafView()), + vertexmapper(grid.leafView()) + {} + + /*! + * + */ + void fractureMapper() + { + //call the new_read art + int nVertices = artgeom_.vertexNumber; + int nEdges = artgeom_.edgeNumber; + //The vertexes which are located on fractures + isDuneFractureVertex_.resize(nVertices); + std::fill(isDuneFractureVertex_.begin(), isDuneFractureVertex_.end(), false); + + //The edge which are fractures + isDuneFractureEdge_.resize(nEdges); + fractureEdgesIdx_.resize(nEdges); + std::fill(isDuneFractureEdge_.begin(), isDuneFractureEdge_.end(), false); + + GV leafView = grid_.leafView(); + + ElementLeafIterator eendit = leafView. template end<0>(); + for (ElementLeafIterator it = leafView .template begin<0>(); it != eendit; ++it) + { + Dune::GeometryType gt = it->geometry().type(); + const typename Dune::GenericReferenceElementContainer<DT,dim>::value_type& + refElem = Dune::GenericReferenceElements<DT,dim>::general(gt); + + // Loop over element faces + for (int i = 0; i < refElem.size(1); i++) + { + int indexFace = facemapper.map(*it, i, 1); + /* + * it maps the local element vertices "localV1Idx" -> indexVertex1 + * then it gets the coordinates of the nodes in the ART file and + * by comparing them with the ones in the DUNE grid maps them too. + */ + int localV1Idx = refElem.subEntity(i, 1, 0, dim); + int localV2Idx = refElem.subEntity(i, 1, 1, dim); + int indexVertex1 = vertexmapper.map(*it, localV1Idx, dim); + int indexVertex2 = vertexmapper.map(*it, localV2Idx, dim); + Dune::FieldVector<DT, dim> nodeART_from; + Dune::FieldVector<DT, dim> nodeART_to; + Dune::FieldVector<DT, dim> nodeDune_from; + Dune::FieldVector<DT, dim> nodeDune_to; + + nodeDune_from = it-> geometry(). corner (localV1Idx); + nodeDune_to = it-> geometry(). corner (localV2Idx); + + for (int j=0; j < nEdges; j++) + { + nodeART_from[0] = artgeom_.vertices_[artgeom_.edges_vector_[j][1]][0]; + nodeART_from[1] = artgeom_.vertices_[artgeom_.edges_vector_[j][1]][1]; + nodeART_to[0] = artgeom_.vertices_[artgeom_.edges_vector_[j][2]][0]; + nodeART_to[1] = artgeom_.vertices_[artgeom_.edges_vector_[j][2]][1]; + + if ((nodeART_from == nodeDune_from && nodeART_to == nodeDune_to) + || (nodeART_from == nodeDune_to && nodeART_to == nodeDune_from)) + { +#if PLOT + std::cout << " ART edge index is "<< j; +// std::cout << " Node ART_from: " +// << nodeART_from<<std::endl; + std::cout << " Dune edge is " << indexFace + <<std::endl; +#endif + /* assigns a value 1 for the edges + * which are fractures */ + if (artgeom_.edges_vector_[j][0] < 0) + { + isDuneFractureEdge_[indexFace] = true; + fractureEdgesIdx_[indexFace] = artgeom_.edges_vector_[j][0]; + isDuneFractureVertex_[indexVertex1]=true; + isDuneFractureVertex_[indexVertex2]=true; + +#if PLOT + std::cout << "isDuneFractureEdge_ "<< + isDuneFractureEdge_[indexFace]<<"\t"; + std::cout << "vertex1 "<<indexVertex1<<"\t"; + std::cout << "vertex2 "<<indexVertex2<<"" << std::endl; +#endif + } + } + } + } + } + +#if PLOT + int i=0; + for (VertexLeafIterator vIt=leafView. template begin<dim> (); + vIt != leafView. template end<dim> (); ++vIt) + { + Dune::GeometryType gt = vIt->type(); + std::cout << "visiting " << gt + << " at " << vIt->geometry().corner(0) + << "\t" << isDuneFractureVertex_[i] + << std::endl; + i++; + } +#endif + + } + +private: + const GridType& grid_; + FaceMapper facemapper; + VertexMapper vertexmapper; + ArtReader artgeom_; +public: + std::vector<bool> isDuneFractureVertex_; + std::vector<bool> isDuneFractureEdge_; + std::vector<int> fractureEdgesIdx_; +}; + +} // end namespace + +#endif // DUMUX_IO_ARTMESH_READER_HH