Chaste Commit::29c3c4ab2bee00ddd311a035a1e522c03cbe928a
VtkMeshReader.cpp
1/*
2
3Copyright (C) Fujitsu Laboratories of Europe, 2009
4
5*/
6
7/*
8
9Copyright (c) 2005-2026, University of Oxford.
10All rights reserved.
11
12University of Oxford means the Chancellor, Masters and Scholars of the
13University of Oxford, having an administrative office at Wellington
14Square, Oxford OX1 2JD, UK.
15
16This file is part of Chaste.
17
18Redistribution and use in source and binary forms, with or without
19modification, are permitted provided that the following conditions are met:
20 * Redistributions of source code must retain the above copyright notice,
21 this list of conditions and the following disclaimer.
22 * Redistributions in binary form must reproduce the above copyright notice,
23 this list of conditions and the following disclaimer in the documentation
24 and/or other materials provided with the distribution.
25 * Neither the name of the University of Oxford nor the names of its
26 contributors may be used to endorse or promote products derived from this
27 software without specific prior written permission.
28
29THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
33LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
35GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
40*/
41
42#include <vtkCellTypes.h>
43#include <vtkVersion.h>
44
45#include "VtkMeshReader.hpp"
46#include "Exception.hpp"
47
48template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
50 mIndexFromZero(true),
51 mNumNodes(0),
52 mNumElements(0),
53 mNumFaces(0),
54 mNumCableElements(0),
55 mNodesRead(0),
56 mElementsRead(0),
57 mFacesRead(0),
58 mBoundaryFacesRead(0),
59 mBoundaryFacesSkipped(0),
60 mCableElementsRead(0),
61 mNumElementAttributes(0),
62 mNumFaceAttributes(0),
63 mNumCableElementAttributes(0),
64 mOrderOfElements(1),
65 mNodesPerElement(4),
66 mVtkCellType(VTK_TETRA)
67{
68 vtkXMLUnstructuredGridReader* vtk_xml_unstructured_grid_reader;
69
70 // Check file exists
71 mVtuFile.open(pathBaseName.c_str());
72 if (!mVtuFile.is_open())
73 {
74 EXCEPTION("Could not open VTU file: " + pathBaseName);
75 }
76 mVtuFile.close();
77
78 // Load the mesh geometry and data from a file
79 vtk_xml_unstructured_grid_reader = vtkXMLUnstructuredGridReader::New();
80 vtk_xml_unstructured_grid_reader->SetFileName( pathBaseName.c_str() );
81 vtk_xml_unstructured_grid_reader->Update();
82 mpVtkUnstructuredGrid = vtk_xml_unstructured_grid_reader->GetOutput();
84 vtk_xml_unstructured_grid_reader->Delete();
85}
86
87template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
89{
90
91 mNumNodes = mpVtkUnstructuredGrid->GetNumberOfPoints();
92 unsigned num_cells = mpVtkUnstructuredGrid->GetNumberOfCells();
93
94 if (ELEMENT_DIM == 2u)
95 {
96 mNodesPerElement = 3;
97 mVtkCellType = VTK_TRIANGLE;
98 }
99 else if (ELEMENT_DIM == 1u)
100 {
101 mNodesPerElement = 2;
102 mVtkCellType = VTK_LINE;
103 }
104
105#if (VTK_MAJOR_VERSION >= 9 && VTK_MINOR_VERSION >= 2)
106 const auto num_distinct_cell_types = static_cast<unsigned>(mpVtkUnstructuredGrid->GetDistinctCellTypesArray()->GetNumberOfTuples());
107#else // VTK older than 9.2
108 vtkCellTypes* cell_types = vtkCellTypes::New();
109 mpVtkUnstructuredGrid->GetCellTypes(cell_types);
110 const auto num_distinct_cell_types = static_cast<unsigned>(cell_types->GetNumberOfTypes());
111 cell_types->Delete();
112#endif
113
114 if (num_distinct_cell_types > 1u)
115 {
116 mNumCableElementAttributes = 1;
117 for (unsigned cell_id = 0; cell_id < num_cells; ++cell_id)
118 {
119 if (mpVtkUnstructuredGrid->GetCellType(cell_id) == mVtkCellType)
120 {
121 ++mNumElements;
122 assert(mNumCableElements == 0); //We expect all the simplices first and then the cables at the end of the array
123 }
124 else if (mpVtkUnstructuredGrid->GetCellType(cell_id) == VTK_LINE)
125 {
126 ++mNumCableElements;
127 }
128 else
129 {
131 }
132 }
133 }
134 else
135 {
136 //There is only 1 cell type, so all cells are elements
137 mNumElements = num_cells;
138 }
139
140 // Extract the surface faces
141 if (ELEMENT_DIM == 2u)
142 {
143 vtkDataSetSurfaceFilter* p_surface = vtkDataSetSurfaceFilter::New();
144 mpVtkFilterEdges = vtkFeatureEdges::New();
145 p_surface->SetInputData(mpVtkUnstructuredGrid);
146 mpVtkFilterEdges->SetInputConnection(p_surface->GetOutputPort());
147 mpVtkFilterEdges->Update();
148 mNumFaces = mpVtkFilterEdges->GetOutput()->GetNumberOfCells();
149 p_surface->Delete();
150 }
151 else if (ELEMENT_DIM == 3u)
152 {
153 mpVtkGeometryFilter = vtkGeometryFilter::New();
154 mpVtkGeometryFilter->SetInputData(mpVtkUnstructuredGrid);
155
156#if (VTK_MAJOR_VERSION >= 9 && VTK_MINOR_VERSION >= 1)
157 // Change to indexing in vtkGeometryFilter happened in VTK 9.1
158 mpVtkGeometryFilter->SetPassThroughPointIds(1);
159#endif
160 mpVtkGeometryFilter->Update();
161
162 mNumFaces = mpVtkGeometryFilter->GetOutput()->GetNumberOfCells();
163 if (mNumCableElements > 0)
164 {
165 //The boundary face filter includes the cable elements - get rid of them
166 unsigned num_all_cells = mNumFaces;
167 for (unsigned i=0; i<num_all_cells; i++)
168 {
169 if (mpVtkGeometryFilter->GetOutput()->GetCellType(i) == VTK_LINE)
170 {
171 mNumFaces--;
172 }
173 }
174 }
175 }
176 else if (ELEMENT_DIM == 1u)
177 {
178 mNumFaces = 0;
179 vtkSmartPointer<vtkIdList> enclosing_cells = vtkSmartPointer<vtkIdList>::New();
180 assert(mNumNodes == (unsigned) mpVtkUnstructuredGrid->GetNumberOfPoints());
181 for (unsigned point_index = 0; point_index < mNumNodes; ++point_index)
182 {
183 mpVtkUnstructuredGrid->GetPointCells(point_index, enclosing_cells);
184
185 if (enclosing_cells->GetNumberOfIds() == 1u)
186 {
187 mNumFaces++;
188 }
189 }
190 }
191 else
192 {
194 }
195}
196
197template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
198VtkMeshReader<ELEMENT_DIM,SPACE_DIM>::VtkMeshReader(vtkUnstructuredGrid* p_vtkUnstructuredGrid) :
199 mIndexFromZero(true),
200 mNumNodes(0),
201 mNumElements(0),
202 mNumFaces(0),
203 mNumCableElements(0),
204 mNodesRead(0),
205 mElementsRead(0),
206 mFacesRead(0),
207 mBoundaryFacesRead(0),
208 mBoundaryFacesSkipped(0),
209 mCableElementsRead(0),
210 mNumElementAttributes(0),
211 mNumFaceAttributes(0),
212 mNumCableElementAttributes(0),
213 mOrderOfElements(1),
214 mNodesPerElement(4),
215 mVtkCellType(VTK_TETRA)
216{
217 mpVtkUnstructuredGrid = p_vtkUnstructuredGrid;
219}
220
221template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
223{
224 if (ELEMENT_DIM == 3u)
225 {
226 mpVtkGeometryFilter->Delete();
227 }
228 else if (ELEMENT_DIM == 2u)
229 {
230 mpVtkFilterEdges->Delete();
231 }
232}
233
234template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
236{
237 return mNumElements;
238}
239
240template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
242{
243 return mNumCableElements;
244}
245
246template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
248{
249 return mNumNodes;
250}
251
252template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
254{
255 return mNumFaces;
256}
257
258template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
260{
261 return mNumFaces;
262}
263
264template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
266{
267 return mNumElementAttributes;
268}
269
270template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
272{
273 return mNumCableElementAttributes;
274}
275
276template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
278{
279 return mNumFaceAttributes;
280}
281
282template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
284{
285 mNodesRead = 0;
286 mElementsRead = 0;
287 mFacesRead = 0;
288 mBoundaryFacesRead = 0;
289 mBoundaryFacesSkipped = 0;
290 mCableElementsRead = 0;
291}
292
293template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
295{
296 if (mNodesRead >= mNumNodes)
297 {
298 EXCEPTION( "Trying to read data for a node that doesn't exist" );
299 }
300
301 std::vector<double> next_node;
302
303 for (unsigned i = 0; i < 3; i++)
304 {
305 next_node.push_back( mpVtkUnstructuredGrid->GetPoint(mNodesRead)[i] );
306 }
307
308 mNodesRead++;
309 return next_node;
310}
311
312template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
314{
315 if (mElementsRead >= mNumElements)
316 {
317 EXCEPTION( "Trying to read data for an element that doesn't exist" );
318 }
319
320 if (mpVtkUnstructuredGrid->GetCellType(mElementsRead)!= mVtkCellType)
321 {
322 EXCEPTION("Element is not of expected type (vtkTetra/vtkTriangle)");
323 }
324
325 ElementData next_element_data;
326
327 for (unsigned i = 0; i < mNodesPerElement; i++)
328 {
329 next_element_data.NodeIndices.push_back(mpVtkUnstructuredGrid->GetCell(mElementsRead)->GetPointId(i));
330 }
331
332 // \todo implement method to read element data properly (currently returns zero always...)
333 next_element_data.AttributeValue = 0;
334
335 mElementsRead++;
336 return next_element_data;
337}
338
339template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
341{
342 if (mCableElementsRead >= mNumCableElements)
343 {
344 EXCEPTION( "Trying to read data for a cable element that doesn't exist" );
345 }
346
347 unsigned next_index = mNumElements + mCableElementsRead;
348 assert(mpVtkUnstructuredGrid->GetCellType(next_index)==VTK_LINE);
349
350 ElementData next_element_data;
351
352 for (unsigned i = 0; i < 2; i++)
353 {
354 next_element_data.NodeIndices.push_back(mpVtkUnstructuredGrid->GetCell(next_index)->GetPointId(i));
355 }
356
357 vtkDataArray *p_scalars = mpVtkUnstructuredGrid->GetCellData()->GetArray( "Cable radius" );
358 next_element_data.AttributeValue = p_scalars->GetTuple(next_index)[0];
359
360 mCableElementsRead++;
361 return next_element_data;
362}
363
364
365template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
367{
368 if (mBoundaryFacesRead >= mNumFaces)
369 {
370 EXCEPTION( "Trying to read data for a boundary element that doesn't exist");
371 }
372
373 ElementData next_face_data;
374 if (ELEMENT_DIM == 3u)
375 {
376#if (VTK_MAJOR_VERSION >= 9 && VTK_MINOR_VERSION >= 1)
377 // Change to indexing in vtkGeometryFilter happened in VTK 9.1
378 vtkDataArray *original_ids = mpVtkGeometryFilter->GetOutput()->GetPointData()->GetArray("vtkOriginalPointIds");
379#endif
380 while (mpVtkGeometryFilter->GetOutput()->GetCellType(mBoundaryFacesRead + mBoundaryFacesSkipped) == VTK_LINE)
381 {
382 mBoundaryFacesSkipped++;
383 }
384 for (unsigned i = 0; i < (mNodesPerElement-1); i++)
385 {
386 unsigned id = mpVtkGeometryFilter->GetOutput()->GetCell(mBoundaryFacesRead + mBoundaryFacesSkipped)->GetPointId(i);
387#if (VTK_MAJOR_VERSION >= 9 && VTK_MINOR_VERSION >= 1)
388 // Change to indexing in vtkGeometryFilter happened in VTK 9.1
389 next_face_data.NodeIndices.push_back(original_ids->GetTuple1(id));
390#else
391 next_face_data.NodeIndices.push_back(id);
392#endif
393 }
394 }
395 else if (ELEMENT_DIM == 2u)
396 {
397 for (unsigned i = 0; i < (mNodesPerElement-1); i++)
398 {
399 next_face_data.NodeIndices.push_back(mpVtkFilterEdges->GetOutput()->GetCell(mBoundaryFacesRead)->GetPointId(i));
400 }
401 }
402 else if (ELEMENT_DIM == 1u)
403 {
404 vtkSmartPointer<vtkIdList> enclosing_cells = vtkSmartPointer<vtkIdList>::New();
405 assert(mNumNodes == (unsigned) mpVtkUnstructuredGrid->GetNumberOfPoints());
406 for (unsigned point_index = mBoundaryFacesSkipped; point_index < mNumNodes; ++point_index)
407 {
408 mBoundaryFacesSkipped++;
409 mpVtkUnstructuredGrid->GetPointCells(point_index, enclosing_cells);
410
411 if (enclosing_cells->GetNumberOfIds() == 1u)
412 {
413 next_face_data.NodeIndices.push_back(point_index);
414 break;
415 }
416 }
417 }
418 else
419 {
421 }
422
423 mBoundaryFacesRead++;
424 return next_face_data;
425}
426
427
428template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
429void VtkMeshReader<ELEMENT_DIM,SPACE_DIM>::GetCellData(std::string dataName, std::vector<double>& dataPayload)
430{
431 vtkCellData *p_cell_data = mpVtkUnstructuredGrid->GetCellData();
432
433 if (!p_cell_data->HasArray(dataName.c_str()))
434 {
435 EXCEPTION("No cell data '" + dataName + "'");
436 }
437
438 vtkDataArray *p_scalars = p_cell_data->GetArray( dataName.c_str() );
439 if (p_scalars->GetNumberOfComponents() != 1)
440 {
441 EXCEPTION("The cell data '" + dataName + "' is not scalar data.");
442 }
443
444 dataPayload.clear();
445 for (unsigned i = 0; i < mNumElements; i++)
446 {
447 dataPayload.push_back( p_scalars->GetTuple(i)[0] );
448 }
449}
450
451template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
452void VtkMeshReader<ELEMENT_DIM,SPACE_DIM>::GetCellData(std::string dataName, std::vector<c_vector<double,SPACE_DIM> >& dataPayload)
453{
454 vtkCellData *p_cell_data = mpVtkUnstructuredGrid->GetCellData();
455
456 if (!p_cell_data->HasArray(dataName.c_str()))
457 {
458 EXCEPTION("No cell data '" + dataName + "'");
459 }
460
461 vtkDataArray *p_scalars = p_cell_data->GetArray( dataName.c_str() );
462 if (p_scalars->GetNumberOfComponents() != 3)
463 {
464 EXCEPTION("The cell data '" + dataName + "' is not 3-vector data.");
465 }
466
467 dataPayload.clear();
468 for (unsigned i = 0; i < mNumElements; i++)
469 {
470 c_vector <double, SPACE_DIM> data;
471 for (unsigned j = 0; j < SPACE_DIM; j++)
472 {
473 data[j]= p_scalars->GetTuple(i)[j];
474 }
475 dataPayload.push_back(data);
476 }
477}
478
479
480template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
481void VtkMeshReader<ELEMENT_DIM,SPACE_DIM>::GetPointData(std::string dataName, std::vector<double>& dataPayload)
482{
483 vtkPointData *p_point_data = mpVtkUnstructuredGrid->GetPointData();
484
485 if (!p_point_data->HasArray(dataName.c_str()))
486 {
487 EXCEPTION("No point data '" + dataName + "'");
488 }
489
490 vtkDataArray *p_scalars = p_point_data->GetArray( dataName.c_str() );
491 if (p_scalars->GetNumberOfComponents() != 1)
492 {
493 EXCEPTION("The point data '" + dataName + "' is not scalar data.");
494 }
495
496 dataPayload.clear();
497
498 for (unsigned i = 0; i < mNumNodes; i++)
499 {
500 dataPayload.push_back( p_scalars->GetTuple(i)[0] );
501 }
502}
503
504template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
505void VtkMeshReader<ELEMENT_DIM,SPACE_DIM>::GetPointData(std::string dataName, std::vector<c_vector<double,SPACE_DIM> >& dataPayload)
506{
507 vtkPointData *p_point_data = mpVtkUnstructuredGrid->GetPointData();
508
509 if (!p_point_data->HasArray(dataName.c_str()))
510 {
511 EXCEPTION("No point data '" + dataName + "'");
512 }
513
514 vtkDataArray *p_scalars = p_point_data->GetArray( dataName.c_str() );
515
516 if (p_scalars->GetNumberOfComponents() != 3)
517 {
518 EXCEPTION("The point data '" + dataName + "' is not 3-vector data.");
519 }
520 dataPayload.clear();
521 for (unsigned i = 0; i < mNumNodes; i++)
522 {
523 c_vector<double, SPACE_DIM> data;
524 for (unsigned j = 0; j< SPACE_DIM; j++)
525 {
526 data[j] = p_scalars->GetTuple(i)[j];
527 }
528 dataPayload.push_back( data );
529 }
530}
531
532
533template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
535{
536 return mpVtkUnstructuredGrid;
537}
538
539// Explicit instantiation
540template class VtkMeshReader<1,1>;
541template class VtkMeshReader<1,2>;
542template class VtkMeshReader<1,3>;
543template class VtkMeshReader<2,2>;
544template class VtkMeshReader<2,3>;
545template class VtkMeshReader<3,3>;
#define EXCEPTION(message)
#define NEVER_REACHED
ElementData GetNextCableElementData()
unsigned GetNumCableElementAttributes() const
vtkSmartPointer< vtkUnstructuredGrid > mpVtkUnstructuredGrid
void GetPointData(std::string dataName, std::vector< double > &dataPayload)
unsigned GetNumElementAttributes() const
unsigned GetNumCableElements() const
void GetCellData(std::string dataName, std::vector< double > &dataPayload)
VtkMeshReader(std::string pathBaseName)
void CommonConstructor()
unsigned GetNumFaceAttributes() const
std::ifstream mVtuFile
std::vector< double > GetNextNode()
virtual ~VtkMeshReader()
vtkUnstructuredGrid * OutputMeshAsVtkUnstructuredGrid()
unsigned GetNumNodes() const
unsigned GetNumEdges() const
ElementData GetNextFaceData()
unsigned GetNumFaces() const
unsigned GetNumElements() const
ElementData GetNextElementData()
std::vector< unsigned > NodeIndices