Chaste  Release::2018.1
VertexMeshWriter.cpp
1 /*
2 
3 Copyright (c) 2005-2018, 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 = rMesh.GetNode(node_num)->rGetLocation();
294  if (SPACE_DIM==2)
295  {
296  p_pts->InsertPoint(node_num, position[0], position[1], 0.0);
297  }
298  else
299  {
300  p_pts->InsertPoint(node_num, position[0], position[1], position[2]);
301  }
302  }
303 
304  mpVtkUnstructedMesh->SetPoints(p_pts);
305  p_pts->Delete(); // Reference counted
307  iter != rMesh.GetElementIteratorEnd();
308  ++iter)
309  {
310  vtkCell* p_cell;
311  if (SPACE_DIM == 2)
312  {
313  p_cell = vtkPolygon::New();
314  }
315  else
316  {
317  p_cell = vtkConvexPointSet::New();
318  }
319  vtkIdList* p_cell_id_list = p_cell->GetPointIds();
320  p_cell_id_list->SetNumberOfIds(iter->GetNumNodes());
321  for (unsigned j=0; j<iter->GetNumNodes(); ++j)
322  {
323  p_cell_id_list->SetId(j, iter->GetNodeGlobalIndex(j));
324  }
325  mpVtkUnstructedMesh->InsertNextCell(p_cell->GetCellType(), p_cell_id_list);
326  p_cell->Delete(); // Reference counted
327  }
328 #endif //CHASTE_VTK
329 }
330 
331 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
332 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::AddCellData(std::string dataName, std::vector<double> dataPayload)
333 {
334 #ifdef CHASTE_VTK
335  vtkDoubleArray* p_scalars = vtkDoubleArray::New();
336  p_scalars->SetName(dataName.c_str());
337  for (unsigned i=0; i<dataPayload.size(); i++)
338  {
339  p_scalars->InsertNextValue(dataPayload[i]);
340  }
341 
342  vtkCellData* p_cell_data = mpVtkUnstructedMesh->GetCellData();
343  p_cell_data->AddArray(p_scalars);
344  p_scalars->Delete(); // Reference counted
345 #endif //CHASTE_VTK
346 }
347 
348 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
349 void VertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::AddPointData(std::string dataName, std::vector<double> dataPayload)
350 {
351 #ifdef CHASTE_VTK
352  vtkDoubleArray* p_scalars = vtkDoubleArray::New();
353  p_scalars->SetName(dataName.c_str());
354  for (unsigned i=0; i<dataPayload.size(); i++)
355  {
356  p_scalars->InsertNextValue(dataPayload[i]);
357  }
358 
359  vtkPointData* p_point_data = mpVtkUnstructedMesh->GetPointData();
360  p_point_data->AddArray(p_scalars);
361  p_scalars->Delete(); // Reference counted
362 #endif //CHASTE_VTK
363 }
364 
366 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
368 {
369  this->mpMeshReader = nullptr;
370  mpMesh = &rMesh;
371 
372  this->mNumNodes = mpMesh->GetNumNodes();
373  this->mNumElements = mpMesh->GetNumElements();
374 
375  typedef typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator NodeIterType;
376  mpIters->pNodeIter = new NodeIterType(mpMesh->GetNodeIteratorBegin());
377 
378  typedef typename VertexMesh<ELEMENT_DIM,SPACE_DIM>::VertexElementIterator ElemIterType;
379  mpIters->pElemIter = new ElemIterType(mpMesh->GetElementIteratorBegin());
380 
381  // Set up node map if we might have deleted nodes
382  mNodeMapCurrentIndex = 0;
383  if (mpMesh->IsMeshChanging())
384  {
385  mpNodeMap = new NodeMap(mpMesh->GetNumAllNodes());
386  for (NodeIterType it = mpMesh->GetNodeIteratorBegin(); it != mpMesh->GetNodeIteratorEnd(); ++it)
387  {
388  mpNodeMap->SetNewIndex(it->GetIndex(), mNodeMapCurrentIndex++);
389  }
390  }
391  WriteFiles();
392 }
393 
394 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
396 {
397  std::string comment = "# " + ChasteBuildInfo::GetProvenanceString();
398 
399  // Write node file
400  std::string node_file_name = this->mBaseName + ".node";
401  out_stream p_node_file = this->mpOutputFileHandler->OpenOutputFile(node_file_name);
402 
403  // Write the node header
404  unsigned num_attr = 0;
405  unsigned max_bdy_marker = 1; // as we include boundary node information in the node file
406  unsigned num_nodes = this->GetNumNodes();
407 
408  *p_node_file << num_nodes << "\t";
409  *p_node_file << SPACE_DIM << "\t";
410  *p_node_file << num_attr << "\t";
411  *p_node_file << max_bdy_marker << "\n";
412  *p_node_file << std::setprecision(6);
413 
414  // Write each node's data
415  for (unsigned item_num=0; item_num<num_nodes; item_num++)
416  {
417  std::vector<double> current_item = this->GetNextNode();
418  *p_node_file << item_num;
419  for (unsigned i=0; i<SPACE_DIM+1; i++)
420  {
421  *p_node_file << "\t" << current_item[i];
422  }
423  *p_node_file << "\n";
424  }
425  *p_node_file << comment << "\n";
426  p_node_file->close();
427 
428  // Write element file
429  std::string element_file_name = this->mBaseName + ".cell";
430  out_stream p_element_file = this->mpOutputFileHandler->OpenOutputFile(element_file_name);
431 
432  // Write the element header
433  num_attr = 1; //Always write element attributes
434  unsigned num_elements = this->GetNumElements();
435  *p_element_file << num_elements << "\t" << num_attr << "\n";
436 
437  // Write each element's data
438  for (unsigned item_num=0; item_num<num_elements; item_num++)
439  {
440  if (SPACE_DIM == 2) // In 2D, write the node indices owned by this element
441  {
442  // Get data for this element
443  ElementData elem_data = this->GetNextElement();
444 
445  // Get the node indices owned by this element
446  std::vector<unsigned> node_indices = elem_data.NodeIndices;
447 
448  // Write this element's index and the number of nodes owned by it to file
449  *p_element_file << item_num << "\t" << node_indices.size();
450 
451  // Write the node indices owned by this element to file
452  for (unsigned i=0; i<node_indices.size(); i++)
453  {
454  *p_element_file << "\t" << node_indices[i];
455  }
456 
457  *p_element_file << "\t" << elem_data.AttributeValue;
458 
459  // New line
460  *p_element_file << "\n";
461  }
462  else // 3D
463  {
464  assert(SPACE_DIM == 3); // LCOV_EXCL_LINE
465 
466  // Get data for this element
467  VertexElementData elem_data_with_faces = this->GetNextElementWithFaces();
468 
469  // Get the node indices owned by this element
470  std::vector<unsigned> node_indices = elem_data_with_faces.NodeIndices;
471 
472  // Write this element's index and the number of nodes owned by it to file
473  *p_element_file << item_num << "\t" << node_indices.size();
474 
475  // Write the node indices owned by this element to file
476  for (unsigned i=0; i<node_indices.size(); i++)
477  {
478  *p_element_file << "\t" << node_indices[i];
479  }
480 
481  // Get the faces owned by this element (if any)
482  std::vector<ElementData> faces = elem_data_with_faces.Faces;
483 
484  // Write the number of faces owned by this element to file
485  *p_element_file << "\t" << faces.size();
486 
487  for (unsigned j=0; j<faces.size(); j++)
488  {
489  // Get the node indices owned by this face
490  std::vector<unsigned> face_node_indices = faces[j].NodeIndices;
491 
492  // Write this face's index and the number of nodes owned by it to file
493  *p_element_file << "\t" << faces[j].AttributeValue << "\t" << face_node_indices.size();
494 
495  // Write the node indices owned by this element to file
496  for (unsigned i=0; i<face_node_indices.size(); i++)
497  {
498  *p_element_file << "\t" << face_node_indices[i];
499  }
500 
502  }
503 
504  *p_element_file << "\t" << elem_data_with_faces.AttributeValue;
505 
506  // New line
507  *p_element_file << "\n";
508  }
509  }
510 
511  *p_element_file << comment << "\n";
512  p_element_file->close();
513 }
514 
516 
517 template class VertexMeshWriter<1,1>;
518 template class VertexMeshWriter<1,2>;
519 template class VertexMeshWriter<1,3>;
520 template class VertexMeshWriter<2,2>;
521 template class VertexMeshWriter<2,3>;
522 template class VertexMeshWriter<3,3>;
void AddCellData(std::string dataName, std::vector< double > dataPayload)
MeshWriterIterators< ELEMENT_DIM, SPACE_DIM > * mpIters
void WriteFilesUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
Node< SPACE_DIM > * GetNode(unsigned index) const
virtual unsigned GetNumNodes() const
Definition: VertexMesh.cpp:604
AbstractMesh< ELEMENT_DIM, SPACE_DIM >::NodeIterator * pNodeIter
virtual std::vector< double > GetNextNode()
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
VertexElement< ELEMENT_DIM-1, SPACE_DIM > * GetFace(unsigned index) const
VertexElementData GetNextElementWithFaces()
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
Definition: VertexMesh.hpp:679
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, std::string stamp="")
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()
virtual VertexMesh< ELEMENT_DIM, SPACE_DIM > * GetMeshForVtk()
Definition: VertexMesh.cpp:817
virtual ElementData GetNextElement()
VertexElementIterator GetElementIteratorEnd()
Definition: VertexMesh.hpp:686
std::vector< unsigned > NodeIndices
void AddPointData(std::string dataName, std::vector< double > dataPayload)