CEPS  24.01
Cardiac ElectroPhysiology Simulator
GmshMeshReader.cpp
Go to the documentation of this file.
1 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2  This file is part of CEPS.
3 
4  CEPS is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  CEPS is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with CEPS (see file LICENSE at root of project).
16  If not, see <https://www.gnu.org/licenses/>.
17 
18 
19  Copyright 2019-2024 Inria, Universite de Bordeaux
20 
21  Authors, in alphabetical order:
22 
23  Pierre-Elliott BECUE, Florian CARO, Yves COUDIERE(*), Andjela DAVIDOVIC,
24  Charlie DOUANLA-LONTSI, Marc FUENTES, Mehdi JUHOOR, Michael LEGUEBE(*),
25  Pauline MIGERDITICHAN, Valentin PANNETIER(*), Nejib ZEMZEMI.
26  * : currently active authors
27 
28 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
31 #include "GmshMeshReader.hpp"
32 
33 GmshMeshReader::GmshMeshReader(const CepsString &fileName, const CepsUInt &dim, CepsBool quads) :
34  MeshReader (fileName,dim,quads)
35 {
36 
38  m_extension = "msh";
40 
41  if (m_quads)
42  {
43  m_cellType = m_keywordsQ[dim];
44  m_bdryCellType = m_keywordsQ[dim-1];
45  }
46  else
47  {
48  m_cellType = m_keywordsT[dim];
49  m_bdryCellType = m_keywordsT[dim-1];
50  }
51 }
52 
54 {
55  this->close ();
56 }
57 
58 void
60  CepsUInt indexStart,
61  CepsUInt indexEnd,
62  CepsUInt nodeOffset,
63  CepsVector<CepsReal>& coords,
65  CepsVector<CepsUInt>& attrPtr
66 )
67 {
68  checkCanReadNodes(indexStart,indexEnd);
69 
70  // Skip to the correct line
71  this->close();
72  this->open ();
73  CepsInt nbToRead = indexEnd-indexStart;
74  CepsString dummy;
75  for (CepsUInt i=0U; i<indexStart+m_nodesBegin; i++)
76  std::getline(m_file,dummy);
77 
78  std::stringstream h;
79  h << "Gmsh mesh reader: in file " << m_fileName << "," << std::endl
80  << " unable to read ";
81 
82  for (CepsInt i=0; i<nbToRead; i++)
83  {
84  CepsUInt nodeId = nodeOffset+i;
85  CepsString n = ceps::toString(i+1);
86  // Ignore index of node
87  ceps::readInt(m_file,h.str()+"expected node index "+n);
88  for (CepsUInt j=0; j<3;j++)
89  coords[3*nodeId+j] = ceps::readReal(m_file,h.str()+"coordinates of point #"+n);
90 
91  // No attribute to read in this file format, we put -1
92  attr [nodeId ] = -1;
93  attrPtr[nodeId+1] = attrPtr[nodeId] + 1;
94  }
95 }
96 
97 void
99  CepsUInt indexStart,
100  CepsUInt indexEnd,
101  CepsUInt nodeOffset,
102  CepsUInt cellOffset,
103  CepsVector<CepsNodeGlobalIndex>& nodeIndices,
104  CepsVector<CepsUInt>& nodeIndicesPtr,
105  CepsVector<CepsAttribute>& cellAttr,
106  CepsVector<CepsUInt>& cellAttrPtr,
107  CepsVector<CepsChar>& isBoundaryCell
108 )
109 {
110  checkCanReadCells(indexStart,indexEnd);
111 
112  // 0. Init
113  this->reset();
114 
115  // Reach starting line
116  CepsString line;
118  for (CepsInt i = 0; i < m_cellsBegin; i++)
119  std::getline(m_file,line);
120 
121  // Cells and boundary cells can be mixed in the file, so we loop
122  // twice in the list of cells
123 
124  // 1. Non-boundary cells
125  for (CepsUInt i=0; i<m_nbCellsTotal; ++i)
126  getNextCell(
127  cellOffset+m_cellsRead,i,nodeOffset,nodeIndices,nodeIndicesPtr,
128  cellAttr,cellAttrPtr,isBoundaryCell,false
129  );
130 
131  // 2. Boundary cells
132  // Reach starting line (same as cells)
133  this->reset();
134  for (CepsInt i=0U; i<m_cellsBegin; i++)
135  std::getline(m_file,line);
136 
137  for (CepsUInt i=0; i<m_nbCellsTotal; ++i)
138  getNextCell(
139  cellOffset+m_cellsRead+m_bdryCellsRead,i,nodeOffset,nodeIndices,nodeIndicesPtr,
140  cellAttr,cellAttrPtr,isBoundaryCell,true
141  );
142 
143  return;
144 }
145 
146 void
148  CepsUInt cellId,
149  CepsUInt fileCellId,
150  CepsUInt nodeOffset,
151  CepsVector<CepsNodeGlobalIndex>& nodeIndices,
152  CepsVector<CepsUInt>& nodeIndicesPtr,
153  CepsVector<CepsAttribute>& cellAttr,
154  CepsVector<CepsUInt>& cellAttrPtr,
155  CepsVector<CepsChar>& isBoundaryCell,
156  CepsBool boundaryFlag
157 )
158 {
159  CepsString line;
160  std::getline(m_file,line);
161  auto words = ceps::split(line);
162 
163  CepsUInt nbPoints = boundaryFlag ? m_nbNodesPerBdryCell : m_nbNodesPerCell;
164  CepsString cellType = boundaryFlag ? m_bdryCellType : m_cellType;
165 
166  // Cell line format:
167  // cellID cellType Ntags <tags> <nodes list>
168  if (words.size()>1 and words[1] == cellType)
169  {
170  std::stringstream hh;
171  hh << "Gmsh mesh reader: in file " << m_fileName << "," << std::endl << " unable to read ";
172  CepsString h = hh.str();
173  CepsString c = ceps::toString(fileCellId+1);
174 
175  std::istringstream iss(line);
176  ceps::readInt(iss,h+"expected cell #"+c);
177  ceps::readInt(iss,h+"type of cell for cell #"+c);
178  CepsUInt nbAttrToRead = ceps::readInt(iss,h+"number of attributes of cell #"+c);
179  CepsUInt nbAttr = boundaryFlag ? m_nbAttrPerBdryCell : m_nbAttrPerCell;
180 
181  for (CepsUInt i=0u; i<nbAttr; i++)
182  cellAttr[cellAttrPtr[cellId]+i] = i<nbAttrToRead ? ceps::readInt(iss,h+"attribute of cell #"+c) :-1;
183 
184  for (CepsUInt i=0U; i<nbPoints; i++)
185  nodeIndices[nodeIndicesPtr[cellId]+i] = ceps::readInt(iss,h+"node indices of cell #"+c)+nodeOffset-1;
186 
187  cellAttrPtr [cellId+1] = cellAttrPtr [cellId] + nbAttr;
188  nodeIndicesPtr[cellId+1] = nodeIndicesPtr[cellId] + nbPoints;
189  isBoundaryCell[cellId ] = boundaryFlag;
190 
191  if (boundaryFlag)
192  m_bdryCellsRead++;
193  else
194  m_cellsRead++;
195  }
196 
197 }
198 
199 void
201 {
202  CEPS_SAYS (" Reading " << m_fileName << " for dimension " << m_expectedDim);
203  std::stringstream hh;
204  hh << "Gmsh mesh reader: in file " << m_fileName << "," << std::endl << " ";
205  CepsString h = hh.str();
206 
207  // Find the nodes
208  this->reset();
209  m_nodesBegin = this->lineIndex("$Nodes");
210  CEPS_ABORT_IF(m_nodesBegin==-1, h+"\"$Nodes\" keyword not found");
211 
212  m_nbNodes = ceps::readInt(m_file,h+"unable to read the number of nodes");
213  m_nodesBegin += 2;
214  m_nbAttrPerNode = 1; // nodes don't have any attribute in msh format v2, we will put -1...
215 
216  // Try to find cells first
219 
220  this->reset();
221  m_cellsBegin = this->lineIndex ("$Elements");
222  CEPS_ABORT_IF(m_cellsBegin==-1,h+"\"$Elements\" keyword not found");
223 
224  // Read cell types (second number on each cell line) and count for each type
225  CepsString line;
226  CepsVector<CepsString> words, readElemTypes;
227  m_nbCellsTotal = 0u;
228  m_nbCells = 0u;
229  m_nbBdryCells = 0u;
230  m_nbAttrPerCell = 0u;
231  m_nbAttrPerBdryCell = 0u;
234 
235  m_nbCellsTotal = ceps::readInt(m_file,h+"unable to read the number of cells");
236  std::getline(m_file, line); // End the line with number of cells
237  for (CepsUInt i=0; i<m_nbCellsTotal; i++)
238  {
239  std::getline (m_file, line);
240  words = ceps::split (line);
241 
242  try
243  {
244  CepsUInt nAttr(std::stoi(words[2]));
245  if (words[1]==m_cellType)
246  {
247  m_nbCells++;
249  }
250  else if (words[1]==m_bdryCellType)
251  {
252  m_nbBdryCells++;
254  }
255  }
256  catch (...)
257  {
258  CEPS_ABORT (h+"error while reading cell types and number of attributes");
259  }
260  }
261 
263  h+"could not find any cells for dimension " << m_expectedDim
264  );
265 
266  this->reset();
267  m_initialized = true;
268 }
269 
270 void
272 {
273  this->reset();
274  CepsInt index = this->lineIndex ("$MeshFormat");
275  CEPS_ABORT_IF(index==-1,"Unable to determine mesh format in " << m_fileName);
276 
277  CepsString line;
278  std::getline(m_file, line);
279  CEPS_ABORT_IF(not line.starts_with ("2"),
280  "Gmsh files format other than 2 are not supported by CEPS."
281  << "Please select \"version 2\" when exporting your mesh in gmsh." << std::endl
282  << "File : " << m_fileName
283  );
284 }
#define CEPS_ABORT(message)
Stops the execution with a message. If testing is enabled, only throws a runtime_error.
#define CEPS_SAYS(message)
Writes a message in the debug log and in the terminal (stdio).
#define CEPS_ABORT_IF(condition, message)
Stops the execution with a message if condition is true. If testing is enabled, only throws a runtime...
std::basic_string< CepsChar > CepsString
C++ format string.
Definition: CepsTypes.hpp:128
std::vector< _Type, _Alloc > CepsVector
C++ vector.
Definition: CepsTypes.hpp:155
bool CepsBool
Booleans.
Definition: CepsTypes.hpp:124
std::make_unsigned_t< CepsInt > CepsUInt
Unsigned version on CepsInt.
Definition: CepsTypes.hpp:109
int32_t CepsInt
Need 32 bit integer.
Definition: CepsTypes.hpp:106
CepsInt lineIndex(const CepsString &word)
Index of first line starting with word, search starting from the current stream position.
Definition: FileReader.cpp:209
void reset()
Set file stream to the beginning of the file.
Definition: FileReader.cpp:98
virtual CepsBool open()
Opens the designated file in read mode.
Definition: FileReader.cpp:70
CepsString m_fileName
file to open
Definition: FileReader.hpp:145
std::ifstream m_file
stream
Definition: FileReader.hpp:146
virtual void close()
Close the file.
Definition: FileReader.cpp:84
void readCells(CepsUInt indexStart, CepsUInt indexEnd, CepsUInt nodeOffset, CepsUInt cellOffset, CepsVector< CepsNodeGlobalIndex > &nodeIndices, CepsVector< CepsUInt > &nodeIndicesPtr, CepsVector< CepsAttribute > &cellAttr, CepsVector< CepsUInt > &cellAttrPtr, CepsVector< CepsChar > &isBoundaryCell) override
Reads several cells in mesh file.
GmshMeshReader(const CepsString &fileName, const CepsUInt &dim, CepsBool quads=false)
Constructor with full fileName.
CepsString m_bdryCellType
CepsVector< CepsString > m_keywordsT
Read type of cells (tetras, tris, etc)
void checkFormatVersion()
Stops if the format version of the msh file is not 2.X.
void initialize() override
Get the number of nodes cells and boundary cells before reading.
void getNextCell(CepsUInt cellId, CepsUInt fileCellId, CepsUInt nodeOffset, CepsVector< CepsNodeGlobalIndex > &nodeIndices, CepsVector< CepsUInt > &nodeIndicesPtr, CepsVector< CepsAttribute > &cellAttr, CepsVector< CepsUInt > &cellAttrPtr, CepsVector< CepsChar > &isBoundaryCell, CepsBool boundaryFlag) override
Reads a single cell in mesh file.
CepsVector< CepsString > m_keywordsQ
Keywords used to separate cells in medit format, for quads.
void readNodes(CepsUInt indexStart, CepsUInt indexEnd, CepsUInt nodeOffset, CepsVector< CepsReal > &coords, CepsVector< CepsAttribute > &attr, CepsVector< CepsUInt > &attrPtr) override
Reads several nodes in mesh file.
~GmshMeshReader() override
Destructor.
CepsString m_cellType
Abstract base class that encapsulates primary functionalities of each mesh reader.
Definition: MeshReader.hpp:42
CepsInt m_nodesBegin
line start of nodes
Definition: MeshReader.hpp:183
CepsUInt m_nbAttrPerCell
attributes per cell
Definition: MeshReader.hpp:194
CepsBool m_initialized
Flag to ensure call of initializeReader()
Definition: MeshReader.hpp:176
void checkCanReadNodes(CepsUInt indexStart, CepsUInt indexEnd) const
Aborts if passed indices are wrong.
Definition: MeshReader.cpp:137
CepsUInt m_nbNodesPerBdryCell
nb nodes per boundary cell
Definition: MeshReader.hpp:181
CepsBool m_quads
Reader for quadratic cells.
Definition: MeshReader.hpp:175
CepsUInt m_bdryCellsRead
Keeps track of already read boundary cells.
Definition: MeshReader.hpp:180
CepsUInt m_nbNodesPerCell
nb nodes per cell
Definition: MeshReader.hpp:179
CepsUInt m_nbBdryCells
number of boundary cells in mesh, appropriate for dimension
Definition: MeshReader.hpp:191
CepsUInt m_nbAttrPerBdryCell
attributes per boundary cell
Definition: MeshReader.hpp:195
CepsUInt m_cellsRead
Keeps track of already read cells.
Definition: MeshReader.hpp:178
CepsUInt m_nbAttrPerNode
attributes per node
Definition: MeshReader.hpp:193
virtual CepsBool checkExtension() const
Stop if extension is not ok, extension must be defined in child classes.
Definition: MeshReader.cpp:123
CepsInt m_cellsBegin
line start of cells
Definition: MeshReader.hpp:186
CepsUInt m_expectedDim
Expected dimension of mesh.
Definition: MeshReader.hpp:174
CepsUInt m_nbCellsTotal
number of all cells in file
Definition: MeshReader.hpp:188
CepsInt m_bdryCellsBegin
line start of boundary cells
Definition: MeshReader.hpp:190
CepsString m_extension
File name extension.
Definition: MeshReader.hpp:172
CepsUInt m_nbNodes
number of nodes in mesh
Definition: MeshReader.hpp:184
CepsUInt m_nbCells
number of cells in mesh, appropriate for dimension
Definition: MeshReader.hpp:187
void checkCanReadCells(CepsUInt indexStart, CepsUInt indexEnd) const
Aborts if passed indices are wrong.
Definition: MeshReader.cpp:151
CepsString toString(_Tp value)
Convert a given value to a string (input has to be compatible with std::to_string)
Definition: CepsString.hpp:409
const _Type & max(const CepsVector< _Type, _Alloc > &vec)
Returns the maximum of the vector, const version.
Definition: CepsVector.hpp:464
CepsInt readInt(std::istream &file, const CepsString &errorMessage="")
Reads an integral number from an istream, aborts if conversion fails advances the stream by 1 word.
Definition: CepsString.cpp:677
CepsVector< CepsString > split(const CepsString &s, const CepsString &delimiters=CepsString(" \t"))
Splits a string using mulitple delimiters in a single string.
Definition: CepsString.cpp:38
CepsReal readReal(std::istream &file, const CepsString &errorMessage="")
Reads a floating point number from an istream, aborts if conversion fails advances the stream by 1 wo...
Definition: CepsString.cpp:661