Chaste Commit::29c3c4ab2bee00ddd311a035a1e522c03cbe928a
VertexMeshWriter.cpp
1/*
2
3Copyright (c) 2005-2026, University of Oxford.
4All rights reserved.
5
6University of Oxford means the Chancellor, Masters and Scholars of the
7University of Oxford, having an administrative office at Wellington
8Square, Oxford OX1 2JD, UK.
9
10This file is part of Chaste.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14 * Redistributions of source code must retain the above copyright notice,
15 this list of conditions and the following disclaimer.
16 * Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 * Neither the name of the University of Oxford nor the names of its
20 contributors may be used to endorse or promote products derived from this
21 software without specific prior written permission.
22
23THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34*/
35
36#include "VertexMeshWriter.hpp"
37#include "Version.hpp"
38
42template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
44{
49};
50
52// Implementation
54
55template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
57 const std::string& rBaseName,
58 const bool clearOutputDir)
59 : AbstractMeshWriter<ELEMENT_DIM, SPACE_DIM>(rDirectory, rBaseName, clearOutputDir),
60 mpMesh(nullptr),
61 mpIters(new MeshWriterIterators<ELEMENT_DIM, SPACE_DIM>),
62 mpNodeMap(nullptr),
63 mNodeMapCurrentIndex(0)
64{
65 mpIters->pNodeIter = nullptr;
66 mpIters->pElemIter = nullptr;
67
68 // Dubious, since we shouldn't yet know what any details of the mesh are.
69 mpVtkUnstructedMesh = vtkUnstructuredGrid::New();
70}
71
72template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
74{
75 if (mpIters->pNodeIter)
76 {
77 delete mpIters->pNodeIter;
78 delete mpIters->pElemIter;
79 }
80
81 delete mpIters;
82
83 if (mpNodeMap)
84 {
85 delete mpNodeMap;
86 }
87
88 // Dubious, since we shouldn't yet know what any details of the mesh are.
89 mpVtkUnstructedMesh->Delete(); // Reference counted
90}
91
92template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
94{
95 if (mpMesh)
96 {
97 // Sanity check
98 assert(this->mNumNodes == mpMesh->GetNumNodes());
99
100 std::vector<double> coordinates(SPACE_DIM+1);
101
102 // Get the node coordinates using the node iterator (thus skipping deleted nodes)
103 for (unsigned j=0; j<SPACE_DIM; j++)
104 {
105 coordinates[j] = (*(mpIters->pNodeIter))->GetPoint()[j];
106 }
107 coordinates[SPACE_DIM] = (*(mpIters->pNodeIter))->IsBoundaryNode();
108
109 ++(*(mpIters->pNodeIter));
110
111 return coordinates;
112 }
113 else
114 {
116 }
117}
118
119template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
121{
122 // This method should only be called in 3D
123 assert(SPACE_DIM == 3); // LCOV_EXCL_LINE
124 assert(mpMesh);
125 assert(this->mNumElements == mpMesh->GetNumElements());
126
127 // Create data structure for this element
128 VertexElementData elem_data;
129
130 // Store node indices owned by this element
131 elem_data.NodeIndices.resize((*(mpIters->pElemIter))->GetNumNodes());
132 for (unsigned j=0; j<elem_data.NodeIndices.size(); j++)
133 {
134 unsigned old_index = (*(mpIters->pElemIter))->GetNodeGlobalIndex(j);
135 elem_data.NodeIndices[j] = mpMesh->IsMeshChanging() ? mpNodeMap->GetNewIndex(old_index) : old_index;
136 }
137
138 // Store faces owned by this element
139 elem_data.Faces.resize((*(mpIters->pElemIter))->GetNumFaces());
140 for (unsigned i=0; i<elem_data.Faces.size(); i++)
141 {
142 // Get pointer to this face
143 VertexElement<ELEMENT_DIM-1, SPACE_DIM>* p_face = (*(mpIters->pElemIter))->GetFace(i);
144
145 // Create data structure for this face
146 ElementData face_data;
147
148 // Store this face's index
149 face_data.AttributeValue = p_face->GetIndex();
150
151 // Store node indices owned by this face
152 face_data.NodeIndices.resize(p_face->GetNumNodes());
153 for (unsigned j=0; j<face_data.NodeIndices.size(); j++)
154 {
155 unsigned old_index = p_face->GetNodeGlobalIndex(j);
156 face_data.NodeIndices[j] = mpMesh->IsMeshChanging() ? mpNodeMap->GetNewIndex(old_index) : old_index;
157 }
158
159 // Store this face
160 elem_data.Faces[i] = face_data;
161
163 }
164
165 // Set attribute
166 elem_data.AttributeValue = (unsigned)(*(mpIters->pElemIter))->GetAttribute();
167 ++(*(mpIters->pElemIter));
168
169 return elem_data;
170}
171
172template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
174{
176
177 if (mpMesh)
178 {
179 assert(this->mNumElements == mpMesh->GetNumElements());
180
181 ElementData elem_data;
182 elem_data.NodeIndices.resize((*(mpIters->pElemIter))->GetNumNodes());
183 for (unsigned j=0; j<elem_data.NodeIndices.size(); j++)
184 {
185 unsigned old_index = (*(mpIters->pElemIter))->GetNodeGlobalIndex(j);
186 elem_data.NodeIndices[j] = mpMesh->IsMeshChanging() ? mpNodeMap->GetNewIndex(old_index) : old_index;
187 }
188
189 // Set attribute
190 elem_data.AttributeValue = (*(mpIters->pElemIter))->GetAttribute();
191 ++(*(mpIters->pElemIter));
192
193 return elem_data;
194 }
195 else
196 {
198 }
199}
200
201template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
203{
204 assert(SPACE_DIM==3 || SPACE_DIM == 2); // LCOV_EXCL_LINE
205
206 // Create VTK mesh
207 MakeVtkMesh(rMesh);
208
209 // Now write VTK mesh to file
210 assert(mpVtkUnstructedMesh->CheckAttributes() == 0);
211 vtkXMLUnstructuredGridWriter* p_writer = vtkXMLUnstructuredGridWriter::New();
212 p_writer->SetInputData(mpVtkUnstructedMesh);
213 // Uninitialised stuff arises (see #1079), but you can remove valgrind problems by removing compression:
214 // **** REMOVE WITH CAUTION *****
215 p_writer->SetCompressor(nullptr);
216 // **** REMOVE WITH CAUTION *****
217
218 std::string vtk_file_name = this->mpOutputFileHandler->GetOutputDirectoryFullPath() + this->mBaseName;
219 if (stamp != "")
220 {
221 vtk_file_name += "_" + stamp;
222 }
223 vtk_file_name += ".vtu";
224
225 p_writer->SetFileName(vtk_file_name.c_str());
226 //p_writer->PrintSelf(std::cout, vtkIndent());
227 p_writer->Write();
228 p_writer->Delete(); // Reference counted
229}
230
237template<>
239{
240 // Create VTK mesh
241 VertexMesh<2, 2>* p_mesh_for_vtk = rMesh.GetMeshForVtk();
242 MakeVtkMesh(*p_mesh_for_vtk);
243
244 // Now write VTK mesh to file
245 assert(mpVtkUnstructedMesh->CheckAttributes() == 0);
246 vtkXMLUnstructuredGridWriter* p_writer = vtkXMLUnstructuredGridWriter::New();
247 p_writer->SetInputData(mpVtkUnstructedMesh);
248 // Uninitialised stuff arises (see #1079), but you can remove valgrind problems by removing compression:
249 // **** REMOVE WITH CAUTION *****
250 p_writer->SetCompressor(nullptr);
251 // **** REMOVE WITH CAUTION *****
252
253 std::string vtk_file_name = this->mpOutputFileHandler->GetOutputDirectoryFullPath() + this->mBaseName;
254 if (stamp != "")
255 {
256 vtk_file_name += "_" + stamp;
257 }
258 vtk_file_name += ".vtu";
259
260 p_writer->SetFileName(vtk_file_name.c_str());
261 //p_writer->PrintSelf(std::cout, vtkIndent());
262 p_writer->Write();
263 p_writer->Delete(); // Reference counted
264}
265
266template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
268{
269 // Make the Vtk mesh
270 vtkPoints* p_pts = vtkPoints::New(VTK_DOUBLE);
271 p_pts->GetData()->SetName("Vertex positions");
272 for (unsigned node_num = 0; node_num < rMesh.GetNumNodes(); node_num++)
273 {
274 c_vector<double, SPACE_DIM> position;
275 position = rMesh.GetNode(node_num)->rGetLocation();
276 if constexpr (SPACE_DIM == 2)
277 {
278 p_pts->InsertPoint(node_num, position[0], position[1], 0.0);
279 }
280 else if constexpr (SPACE_DIM == 3)
281 {
282 p_pts->InsertPoint(node_num, position[0], position[1], position[2]);
283 }
284 else
285 {
287 }
288 }
289
290 mpVtkUnstructedMesh->SetPoints(p_pts);
291 p_pts->Delete(); // Reference counted
293 iter != rMesh.GetElementIteratorEnd();
294 ++iter)
295 {
296 vtkCell* p_cell;
297 if (SPACE_DIM == 2)
298 {
299 p_cell = vtkPolygon::New();
300 }
301 else
302 {
303 p_cell = vtkConvexPointSet::New();
304 }
305 vtkIdList* p_cell_id_list = p_cell->GetPointIds();
306 p_cell_id_list->SetNumberOfIds(iter->GetNumNodes());
307 for (unsigned j=0; j<iter->GetNumNodes(); ++j)
308 {
309 p_cell_id_list->SetId(j, iter->GetNodeGlobalIndex(j));
310 }
311 mpVtkUnstructedMesh->InsertNextCell(p_cell->GetCellType(), p_cell_id_list);
312 p_cell->Delete(); // Reference counted
313 }
314}
315
316template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
317void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::AddCellData(std::string dataName, std::vector<double> dataPayload)
318{
319 vtkDoubleArray* p_scalars = vtkDoubleArray::New();
320 p_scalars->SetName(dataName.c_str());
321 for (unsigned i=0; i<dataPayload.size(); i++)
322 {
323 p_scalars->InsertNextValue(dataPayload[i]);
324 }
325
326 vtkCellData* p_cell_data = mpVtkUnstructedMesh->GetCellData();
327 p_cell_data->AddArray(p_scalars);
328 p_scalars->Delete(); // Reference counted
329}
330
331template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
332void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::AddPointData(std::string dataName, std::vector<double> dataPayload)
333{
334 vtkDoubleArray* p_scalars = vtkDoubleArray::New();
335 p_scalars->SetName(dataName.c_str());
336 for (unsigned i=0; i<dataPayload.size(); i++)
337 {
338 p_scalars->InsertNextValue(dataPayload[i]);
339 }
340
341 vtkPointData* p_point_data = mpVtkUnstructedMesh->GetPointData();
342 p_point_data->AddArray(p_scalars);
343 p_scalars->Delete(); // Reference counted
344}
345
347template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
349{
350 this->mpMeshReader = nullptr;
351 mpMesh = &rMesh;
352
353 this->mNumNodes = mpMesh->GetNumNodes();
354 this->mNumElements = mpMesh->GetNumElements();
355
356 typedef typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator NodeIterType;
357 mpIters->pNodeIter = new NodeIterType(mpMesh->GetNodeIteratorBegin());
358
360 mpIters->pElemIter = new ElemIterType(mpMesh->GetElementIteratorBegin());
361
362 // Set up node map if we might have deleted nodes
363 mNodeMapCurrentIndex = 0;
364 if (mpMesh->IsMeshChanging())
365 {
366 mpNodeMap = new NodeMap(mpMesh->GetNumAllNodes());
367 for (NodeIterType it = mpMesh->GetNodeIteratorBegin(); it != mpMesh->GetNodeIteratorEnd(); ++it)
368 {
369 mpNodeMap->SetNewIndex(it->GetIndex(), mNodeMapCurrentIndex++);
370 }
371 }
372 WriteFiles();
373}
374
375template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
377{
378 std::string comment = "# " + ChasteBuildInfo::GetProvenanceString();
379
380 // Write node file
381 std::string node_file_name = this->mBaseName + ".node";
382 out_stream p_node_file = this->mpOutputFileHandler->OpenOutputFile(node_file_name);
383
384 // Write the node header
385 unsigned num_attr = 0;
386 unsigned max_bdy_marker = 1; // as we include boundary node information in the node file
387 unsigned num_nodes = this->GetNumNodes();
388
389 *p_node_file << num_nodes << "\t";
390 *p_node_file << SPACE_DIM << "\t";
391 *p_node_file << num_attr << "\t";
392 *p_node_file << max_bdy_marker << "\n";
393 *p_node_file << std::setprecision(6);
394
395 // Write each node's data
396 for (unsigned item_num=0; item_num<num_nodes; item_num++)
397 {
398 std::vector<double> current_item = this->GetNextNode();
399 *p_node_file << item_num;
400 for (unsigned i=0; i<SPACE_DIM+1; i++)
401 {
402 *p_node_file << "\t" << current_item[i];
403 }
404 *p_node_file << "\n";
405 }
406 *p_node_file << comment << "\n";
407 p_node_file->close();
408
409 // Write element file
410 std::string element_file_name = this->mBaseName + ".cell";
411 out_stream p_element_file = this->mpOutputFileHandler->OpenOutputFile(element_file_name);
412
413 // Write the element header
414 num_attr = 1; //Always write element attributes
415 unsigned num_elements = this->GetNumElements();
416 *p_element_file << num_elements << "\t" << num_attr << "\n";
417
418 // Write each element's data
419 for (unsigned item_num=0; item_num<num_elements; item_num++)
420 {
421 if (SPACE_DIM == 2) // In 2D, write the node indices owned by this element
422 {
423 // Get data for this element
424 ElementData elem_data = this->GetNextElement();
425
426 // Get the node indices owned by this element
427 std::vector<unsigned> node_indices = elem_data.NodeIndices;
428
429 // Write this element's index and the number of nodes owned by it to file
430 *p_element_file << item_num << "\t" << node_indices.size();
431
432 // Write the node indices owned by this element to file
433 for (unsigned i=0; i<node_indices.size(); i++)
434 {
435 *p_element_file << "\t" << node_indices[i];
436 }
437
438 *p_element_file << "\t" << elem_data.AttributeValue;
439
440 // New line
441 *p_element_file << "\n";
442 }
443 else // 3D
444 {
445 assert(SPACE_DIM == 3); // LCOV_EXCL_LINE
446
447 // Get data for this element
448 VertexElementData elem_data_with_faces = this->GetNextElementWithFaces();
449
450 // Get the node indices owned by this element
451 std::vector<unsigned> node_indices = elem_data_with_faces.NodeIndices;
452
453 // Write this element's index and the number of nodes owned by it to file
454 *p_element_file << item_num << "\t" << node_indices.size();
455
456 // Write the node indices owned by this element to file
457 for (unsigned i=0; i<node_indices.size(); i++)
458 {
459 *p_element_file << "\t" << node_indices[i];
460 }
461
462 // Get the faces owned by this element (if any)
463 std::vector<ElementData> faces = elem_data_with_faces.Faces;
464
465 // Write the number of faces owned by this element to file
466 *p_element_file << "\t" << faces.size();
467
468 for (unsigned j=0; j<faces.size(); j++)
469 {
470 // Get the node indices owned by this face
471 std::vector<unsigned> face_node_indices = faces[j].NodeIndices;
472
473 // Write this face's index and the number of nodes owned by it to file
474 *p_element_file << "\t" << faces[j].AttributeValue << "\t" << face_node_indices.size();
475
476 // Write the node indices owned by this element to file
477 for (unsigned i=0; i<face_node_indices.size(); i++)
478 {
479 *p_element_file << "\t" << face_node_indices[i];
480 }
481
483 }
484
485 *p_element_file << "\t" << elem_data_with_faces.AttributeValue;
486
487 // New line
488 *p_element_file << "\n";
489 }
490 }
491
492 *p_element_file << comment << "\n";
493 p_element_file->close();
494}
495
497
498template class VertexMeshWriter<1,1>;
499template class VertexMeshWriter<1,2>;
500template class VertexMeshWriter<1,3>;
501template class VertexMeshWriter<2,2>;
502template class VertexMeshWriter<2,3>;
503template class VertexMeshWriter<3,3>;
#define NEVER_REACHED
virtual ElementData GetNextElement()
virtual std::vector< double > GetNextNode()
Node< SPACE_DIM > * GetNode(unsigned index) const
static std::string GetProvenanceString()
VertexElement< ELEMENT_DIM-1, SPACE_DIM > * GetFace(unsigned index) const
vtkUnstructuredGrid * mpVtkUnstructedMesh
ElementData GetNextElement()
std::vector< double > GetNextNode()
void AddPointData(std::string dataName, std::vector< double > dataPayload)
void MakeVtkMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::string stamp="")
MeshWriterIterators< ELEMENT_DIM, SPACE_DIM > * mpIters
void AddCellData(std::string dataName, std::vector< double > dataPayload)
VertexElementData GetNextElementWithFaces()
void WriteFilesUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
VertexMeshWriter(const std::string &rDirectory, const std::string &rBaseName, const bool clearOutputDir=true)
VertexElementIterator GetElementIteratorEnd()
virtual unsigned GetNumNodes() const
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
virtual VertexMesh< ELEMENT_DIM, SPACE_DIM > * GetMeshForVtk()
std::vector< unsigned > NodeIndices
VertexMesh< ELEMENT_DIM, SPACE_DIM >::VertexElementIterator * pElemIter
AbstractMesh< ELEMENT_DIM, SPACE_DIM >::NodeIterator * pNodeIter
std::vector< ElementData > Faces
std::vector< unsigned > NodeIndices