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