CEPS  24.01
Cardiac ElectroPhysiology Simulator
TetgenMeshReader.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 "TetgenMeshReader.hpp"
32 
34  const CepsString &fileName,
35  const CepsUInt &dim,
36  CepsBool quads
37 ) :
38  MeshReader(fileName,dim,quads),
39  m_indexOffset(0),
40  m_bdryIndexOffset(0),
41  m_bdryMarker(0)
42 {
43  m_extension = "ele";
44  m_initialized = false;
46  this->open ();
47 }
48 
50 {
51  if (m_file.is_open())
52  m_file.close();
53  if (m_bdryFile.is_open())
54  m_bdryFile.close();
55  if (m_nodesFile.is_open())
56  m_nodesFile.close();
57 }
58 
59 // redefinition of the FileReader open method
62 {
63  CEPS_SAYS(" Reading " << m_fileName << " and associated files");
64  // The cell file
65  m_file.open(m_fileName.c_str(), std::ifstream::in | std::ifstream::binary);
66  // Check has already been done in FileReader::open()
67 
68  // The node file
70  m_nodesFile.open (m_nodesFileName, std::fstream::in | std::ifstream::binary);
71  CEPS_ABORT_IF(not m_nodesFile.good(),"Could not open mesh file " << m_nodesFileName);
72 
73  // Are there boundary cell files ?
74  // check for faces first
76  m_bdryFile.open (m_bdryFileName, std::fstream::in | std::ifstream::binary);
77  if (!m_bdryFile.good())
78  {
79  // Did not find face file, maybe there is an edge file ?
81 
82  m_bdryFile.open(m_bdryFileName, std::fstream::in | std::ifstream::binary);
83  if (!m_bdryFile.good())
84  {
85  // No edge file, so no boundary cells
86  CEPS_WARNS (
87  "Tetgen mesh : found no boundary cell file " << std::quoted("*.face") << " or "
88  << std::quoted("*.edge") << " associated to "
89  << m_fileName
90  );
91  }
92  }
93 
94  return true;
95 }
96 
97 void
99 {
100  CepsString dum;
101 
102  // Nodes
103 
104  m_nodesFile.seekg(0, std::ios::beg);
105  std::stringstream hn;
106  hn << "Tetgen mesh reader: in file " << m_nodesFileName << "," << std::endl << " ";
107 
108  m_nbNodes = ceps::readInt(m_nodesFile,hn.str()+"unable to read number of nodes" );
109  m_nodesFile >> dum; // ignore dimensionality
110  m_nbAttrPerNode = ceps::readInt(m_nodesFile,hn.str()+"unable to read nb of attributes per node");
111  m_bdryMarker = ceps::readInt(m_nodesFile,hn.str()+"unable to read boundary marker" );
112 
113  m_nodesBegin = 1;
114 
115  // Cells
116 
117  m_file.seekg (0, std::ios::beg);
118  std::stringstream hc;
119  hc << "Tetgen mesh reader: in file " << m_fileName << "," << std::endl << " ";
120 
121  m_nbCells = ceps::readInt(m_file,hc.str()+"unable to read number of cells" );
122  m_nbNodesPerCell = ceps::readInt(m_file,hc.str()+"unable to read number of nodes per cell" );
123  m_nbAttrPerCell = ceps::readInt(m_file,hc.str()+"unable to read number of attributes per cell");
124  m_indexOffset = ceps::readInt(m_file,hc.str()+"unable to read index offset" );
125 
126  // Check nbNodesPerCell with expected dimension
127  CepsBool incorrectNNodes = (m_quads and m_nbNodesPerCell != pow (2, m_expectedDim))
128  or (not m_quads and m_nbNodesPerCell != m_expectedDim + 1);
129  CEPS_ABORT_IF (incorrectNNodes,
130  "Provided .ele file does not have elements with the expected number of nodes " << m_fileName
131  );
132 
133  m_cellsBegin = 1;
134 
135  // Boundary cells
136  if (m_bdryFile.is_open())
137  {
138  m_bdryFile.seekg (0, std::ios::beg);
139  std::stringstream hb;
140  hb << "Tetgen mesh reader: in file " << m_bdryFileName << "," << std::endl << " ";
141 
142  m_nbBdryCells = ceps::readInt(m_bdryFile,hb.str()+"unable to read number of boundary cells" );
143  m_nbNodesPerBdryCell = ceps::readInt(m_bdryFile,hb.str()+"unable to read number of nodes per boundary cell" );
144  m_nbAttrPerBdryCell = ceps::readInt(m_bdryFile,hb.str()+"unable to read number of attributes per boundary cell");
145  m_bdryIndexOffset = ceps::readInt(m_bdryFile,hb.str()+"unable to read index offset of boundary cells" );
146  m_bdryCellsBegin = 1;
147  // Check nbNodesPerCell with expected dimension
148  incorrectNNodes = (m_quads and m_nbNodesPerBdryCell != pow (2, m_expectedDim - 1))
150  CEPS_ABORT_IF (incorrectNNodes,
151  "Provided .face or .edge file does not have elements with the expected number of nodes "
152  << m_bdryFileName
153  );
154  }
155  else
156  {
157  // no boundary
158  m_nbBdryCells = 0;
161  m_bdryIndexOffset = 0;
162  m_bdryCellsBegin = 0;
163  }
164 
166  m_initialized = true;
167  this->resetStreams();
168 }
169 
170 CepsBool
172 {
173  return static_cast<CepsBool>(m_bdryMarker);
174 }
175 
176 void
178  CepsUInt indexStart,
179  CepsUInt indexEnd,
180  CepsUInt nodeOffset,
181  CepsVector<CepsReal>& coords,
183  CepsVector<CepsUInt>& attrPtr
184 )
185 {
186  checkCanReadNodes(indexStart,indexEnd);
187 
188  CepsUInt nbToRead = indexEnd-indexStart;
189 
190  // place stream
191  CepsString dummy;
192  for (CepsUInt i=0U; i<indexStart; i++)
193  getline(m_nodesFile,dummy);
194 
195  std::stringstream hh;
196  hh << "Tetgen mesh reader: in file " << m_nodesFileName << ","
197  << std::endl << " unable to read ";
198  CepsString h = hh.str();
199 
200  for (CepsUInt i=0; i<nbToRead; i++)
201  {
202  CepsString n = ceps::toString(i+1);
203  CepsUInt nodeId = nodeOffset+i;
204  // Ignore index of node
205  ceps::readInt(m_nodesFile,h+"expected node index "+n);
206  for (CepsUInt j=0; j<3;j++)
207  coords[nodeId*3+j] = ceps::readReal(m_nodesFile,h+"coordinates of point #"+n);
208 
209  for (CepsUInt j=0; j<(CepsUInt)m_nbAttrPerNode;j++)
210  attr[attrPtr[nodeId]+j] = ceps::readInt(m_nodesFile,h+"attributes of point #"+n);
211 
212  attrPtr[nodeId+1] = attrPtr[nodeId] + m_nbAttrPerNode;
213 
214  // ignore boundary marker
215  if (m_bdryMarker)
216  ceps::readInt(m_nodesFile,h+"boundary marker");
217  }
218 
219 }
220 
221 void
223  CepsUInt indexStart,
224  CepsUInt indexEnd,
225  CepsUInt nodeOffset,
226  CepsUInt cellOffset,
227  CepsVector<CepsNodeGlobalIndex>& nodeIndices,
228  CepsVector<CepsUInt>& nodeIndicesPtr,
229  CepsVector<CepsAttribute>& cellAttr,
230  CepsVector<CepsUInt>& cellAttrPtr,
231  CepsVector<CepsChar>& isBoundaryCell
232 )
233 {
234  checkCanReadCells(indexStart,indexEnd);
235 
236  // 0. Init
237 
238  CepsInt nbToRead = indexEnd-indexStart;
239 
240  // Place streams
241  CepsInt nbCellsToRead = 0;
242  CepsInt nbBoundaryToRead = 0;
243 
244  // No cells to read, only boundary
245  if (indexStart >= m_nbCells)
246  {
247  nbBoundaryToRead = nbToRead;
248  CepsString dummy;
249  for (CepsUInt i=0U; i < indexStart-m_nbCells; i++)
250  getline(m_bdryFile, dummy);
251  }
252  else
253  {
254  nbCellsToRead = m_nbCells-indexStart;
255  nbBoundaryToRead = nbToRead-nbCellsToRead;
256  CepsString dummy;
257  for (CepsUInt i = 0U; i < indexStart; i++)
258  getline (m_file, dummy);
259  }
260 
261  // Actually read
262  CepsInt i;
263  for (i = 0; i < nbCellsToRead; i++)
264  getNextCell(
265  cellOffset+i,i,nodeOffset,nodeIndices,nodeIndicesPtr,
266  cellAttr,cellAttrPtr,isBoundaryCell,false
267  );
268 
269  for (; i < nbBoundaryToRead+nbCellsToRead; i++)
270  getNextCell(
271  cellOffset+i,i-m_cellsRead,nodeOffset,nodeIndices,nodeIndicesPtr,
272  cellAttr,cellAttrPtr,isBoundaryCell,true
273  );
274 
275  return;
276 }
277 
278 void
280  CepsUInt cellId,
281  CepsUInt fileCellId,
282  CepsUInt nodeOffset,
283  CepsVector<CepsNodeGlobalIndex>& nodeIndices,
284  CepsVector<CepsUInt>& nodeIndicesPtr,
285  CepsVector<CepsAttribute>& cellAttr,
286  CepsVector<CepsUInt>& cellAttrPtr,
287  CepsVector<CepsChar>& isBoundaryCell,
288  CepsBool boundaryFlag
289 )
290 {
291  std::stringstream hh;
292  hh << "Tetgen mesh reader: in file " << m_fileName << "," << std::endl << " unable to read ";
293  CepsString c = ceps::toString(fileCellId+1);
294  CepsString h = hh.str();
295 
296  std::ifstream* file = boundaryFlag ? &m_bdryFile : &m_file;
297  CepsUInt nbPts = boundaryFlag ? m_nbNodesPerBdryCell : m_nbNodesPerCell;
298  CepsUInt nAttr = boundaryFlag ? m_nbAttrPerBdryCell : m_nbAttrPerCell ;
299 
300  // ignore the index that comes first
301  ceps::readInt(*file,h+"expected cell index "+c);
302 
303  for(CepsUInt i=0;i<nbPts;i++)
304  nodeIndices[nodeIndicesPtr[cellId]+i] = ceps::readInt(*file,h+"node IDs of cell #"+c)
305  + nodeOffset - m_indexOffset;
306 
307  for (CepsUInt i=0;i<nAttr;i++)
308  cellAttr[cellAttrPtr[cellId]+i] = ceps::readInt(*file,h+"attributes of cell #"+c);
309 
310  cellAttrPtr [cellId+1] = cellAttrPtr [cellId] + nAttr;
311  nodeIndicesPtr[cellId+1] = nodeIndicesPtr[cellId] + nbPts;
312 
313  isBoundaryCell[cellId] = boundaryFlag;
314 
315  if (boundaryFlag)
316  m_bdryCellsRead++;
317  else
318  m_cellsRead++;
319 
320 }
321 
322 
323 void
325 {
326  CepsString temp;
327  m_file.seekg(0,std::ios::beg);
328  for (CepsInt i=0U; i<m_cellsBegin; i++)
329  std::getline(m_file,temp);
330 
331  m_nodesFile.seekg(0,std::ios::beg);
332  for (CepsInt i=0U; i<m_nodesBegin; i++)
333  std::getline(m_nodesFile,temp);
334 
335  if (m_bdryFile.is_open())
336  {
337  m_bdryFile.seekg(0,std::ios::beg);
338  for (CepsInt i=0U; i<m_bdryCellsBegin; i++)
339  std::getline(m_bdryFile,temp);
340  }
341  return;
342 }
#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...
#define CEPS_WARNS(message)
Writes a warning in the debug log and in the terminal (stderr).
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
CepsString m_fileName
file to open
Definition: FileReader.hpp:145
std::ifstream m_file
stream
Definition: FileReader.hpp:146
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
TetgenMeshReader(const CepsString &fileName, const CepsUInt &dim, CepsBool quads=false)
Constructor. The .ele file name must be provided.
CepsString m_bdryFileName
File with boundary cells.
CepsUInt m_indexOffset
Cells and nodes indices may start from 0 or 1...
CepsBool open() override
Redefinition of base class open method as more than 1 file must be opened.
CepsString m_nodesFileName
File with nodes.
std::ifstream m_nodesFile
File with nodes.
CepsBool hasBoundaryMarker() const
True if current mesh has boundary markers.
void initialize() override
Get number of nodes and cells from files. Prior to any reading.
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.
std::ifstream m_bdryFile
File with boundary cells.
~TetgenMeshReader() override
Destructor.
CepsInt m_bdryMarker
Should be 1 or 0.
void resetStreams()
Place the streams at the correct lines.
CepsUInt m_bdryIndexOffset
Index offset for boundary cells.
void readNodes(CepsUInt indexStart, CepsUInt indexEnd, CepsUInt nodeOffset, CepsVector< CepsReal > &coords, CepsVector< CepsAttribute > &attr, CepsVector< CepsUInt > &attrPtr) override
Reads several nodes in mesh file.
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.
CepsString toString(_Tp value)
Convert a given value to a string (input has to be compatible with std::to_string)
Definition: CepsString.hpp:409
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
CepsString changeExtension(const CepsString &str, const CepsString &ext)
Change the extension of a file name (does not check if file exists).
Definition: CepsString.cpp:588
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