Chaste Commit::8b5d759ac2eb95e67ae57699734101efccb0a0a9
TrapezoidEdgeVertexMeshWriter.cpp
1/*
2
3Copyright (c) 2005-2024, 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 "TrapezoidEdgeVertexMeshWriter.hpp"
37
38template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
40 const std::string& rBaseName,
41 const bool clearOutputDir)
42 : AbstractMeshWriter<ELEMENT_DIM, SPACE_DIM>(rDirectory, rBaseName, clearOutputDir)
43{
44#ifdef CHASTE_VTK
45 // Dubious, since we shouldn't yet know what any details of the mesh are.
46 mpVtkUnstructedMesh = vtkUnstructuredGrid::New();
47#endif // CHASTE_VTK
48}
49
50template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
52{
53#ifdef CHASTE_VTK
54 mpVtkUnstructedMesh->Delete();
55#endif // CHASTE_VTK
56}
57
58template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
60 const std::string& stamp)
61{
62#ifdef CHASTE_VTK
63 assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
64
65 // Create VTK mesh
66 MakeVtkMesh(rMesh);
67
68 // Now write VTK mesh to file
69 assert(mpVtkUnstructedMesh->CheckAttributes() == 0);
70 vtkXMLUnstructuredGridWriter* p_writer = vtkXMLUnstructuredGridWriter::New();
71#if VTK_MAJOR_VERSION >= 6
72 p_writer->SetInputData(mpVtkUnstructedMesh);
73#else
74 p_writer->SetInput(mpVtkUnstructedMesh);
75#endif
76 // Uninitialised stuff arises (see #1079), but you can remove valgrind problems by removing compression:
77 // **** REMOVE WITH CAUTION *****
78 p_writer->SetCompressor(nullptr);
79 // **** REMOVE WITH CAUTION *****
80
81 std::string vtk_file_name = this->mpOutputFileHandler->GetOutputDirectoryFullPath() + this->mBaseName;
82 if (!stamp.empty())
83 {
84 vtk_file_name += "_" + stamp;
85 }
86 vtk_file_name += ".vtu";
87
88 p_writer->SetFileName(vtk_file_name.c_str());
89 // p_writer->PrintSelf(std::cout, vtkIndent());
90 p_writer->Write();
91 p_writer->Delete(); // Reference counted
92#endif // CHASTE_VTK
93}
94
95template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
97{
98 // Only 2D version is supported at the moment
99 assert(SPACE_DIM == 2); // LCOV_EXCL_LINE
100#ifdef CHASTE_VTK
101 // Make the Vtk mesh
102 vtkPoints* p_pts = vtkPoints::New(VTK_DOUBLE);
103 p_pts->GetData()->SetName("Vertex positions");
104 /*
105 * Populating points. First, outer points of elements
106 */
107 const unsigned n_vertices = rMesh.GetNumNodes();
108 for (unsigned node_num = 0; node_num < rMesh.GetNumNodes(); node_num++)
109 {
110 c_vector<double, 2> position;
111 position = rMesh.GetNode(node_num)->rGetLocation();
112 p_pts->InsertPoint(node_num, position[0], position[1], 0.0);
113 }
114 /*
115 * Populating inner points.
116 * [_________________][_____][_________]....[_____]
117 * ^^^^^^^^^^^ ^^^^^ ^^^^^^^^ ^^^^
118 * Outer points Cell_1 Cell_2 Cell_{num_elements}
119 * Inner Points
120 * cell_offset_dist stores the distance from the beginning of p_pts array for each element
121 * Note that the number of inner points equals to the number of nodes of each element
122 */
123 const unsigned num_elements = rMesh.GetNumElements();
124 std::vector<unsigned> cell_offset_dist(rMesh.GetNumElements());
125 cell_offset_dist[0] = n_vertices;
126 for (unsigned i = 1; i < num_elements; ++i)
127 cell_offset_dist[i] = cell_offset_dist[i - 1] + rMesh.GetElement(i - 1)->GetNumNodes();
128 // Coefficient 0<=alpha<=1 represents how thin the trapezoid is
129 const double alpha = 0.8;
131 for (auto elem = rMesh.GetElementIteratorBegin(); elem != elem_end; ++elem)
132 {
133 const unsigned num_elem_nodes = elem->GetNumNodes();
134 const c_vector<double, SPACE_DIM> elem_centroid = rMesh.GetCentroidOfElement(elem->GetIndex());
135 for (unsigned elem_node_num = 0; elem_node_num < num_elem_nodes; elem_node_num++)
136 {
137 c_vector<double, SPACE_DIM> node_position(2);
138 node_position = elem->GetNode(elem_node_num)->rGetLocation();
139 const double new_x = (node_position[0] - elem_centroid[0]) * alpha + elem_centroid[0];
140 const double new_y = (node_position[1] - elem_centroid[1]) * alpha + elem_centroid[1];
141 p_pts->InsertPoint(cell_offset_dist[elem->GetIndex()] + elem_node_num,
142 new_x, new_y, 0.0);
143 }
144 }
145 mpVtkUnstructedMesh->SetPoints(p_pts);
146 p_pts->Delete(); // Reference counted
147 unsigned total_num_edges = 0;
148 for (auto elem = rMesh.GetElementIteratorBegin(); elem != elem_end; ++elem)
149 {
150 // First do the trapezoids for each edge
151 for (unsigned edge_index = 0; edge_index < elem->GetNumEdges(); ++edge_index)
152 {
153 vtkCell* p_cell;
154 p_cell = vtkQuad::New();
155 const unsigned num_trap_nodes = p_cell->GetNumberOfEdges(); // 4 in 2D, 8 in 3D
156 assert(num_trap_nodes == 4);
157 vtkIdList* p_cell_id_list = p_cell->GetPointIds();
158 p_cell_id_list->SetNumberOfIds(num_trap_nodes);
159 auto p_edge = elem->GetEdge(edge_index);
160 assert(p_edge->GetNumNodes() == 2);
161
162 // See the diagram above for storing pattern
163 std::array<unsigned, 2> base_ids = { { p_edge->GetNode(0)->GetIndex(), p_edge->GetNode(1)->GetIndex() } };
164 std::array<unsigned, 2> top_ids = { { elem->GetNodeLocalIndex(base_ids[0])
165 + cell_offset_dist[elem->GetIndex()],
166 elem->GetNodeLocalIndex(base_ids[1]) + cell_offset_dist[elem->GetIndex()] } };
167
168 // Assuming counter-clockwise ordering
169 p_cell_id_list->SetId(0, base_ids[0]);
170 p_cell_id_list->SetId(1, base_ids[1]);
171 p_cell_id_list->SetId(2, top_ids[1]);
172 p_cell_id_list->SetId(3, top_ids[0]);
173 mpVtkUnstructedMesh->InsertNextCell(p_cell->GetCellType(), p_cell_id_list);
174 p_cell->Delete(); // Reference counted
175 total_num_edges++;
176 }
177
178 // Now do the internal cell
179 vtkCell* p_cell;
180 p_cell = vtkPolygon::New();
181 const unsigned num_elem_nodes = elem->GetNumNodes();
182 vtkIdList* p_cell_id_list = p_cell->GetPointIds();
183 p_cell_id_list->SetNumberOfIds(num_elem_nodes);
184 for (unsigned j = 0; j < num_elem_nodes; ++j)
185 {
186 p_cell_id_list->SetId(j, cell_offset_dist[elem->GetIndex()] + j);
187 }
188
189 mpVtkUnstructedMesh->InsertNextCell(p_cell->GetCellType(), p_cell_id_list);
190
191 p_cell->Delete(); // Reference counted
192 }
193
194 // For 2D case. For 3D, we should sum the total number of faces + num_elements
195 assert(total_num_edges + num_elements == mpVtkUnstructedMesh->GetNumberOfCells());
196#endif // CHASTE_VTK
197}
198
199template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
200void TrapezoidEdgeVertexMeshWriter<ELEMENT_DIM, SPACE_DIM>::AddCellData(std::string dataName, std::vector<double> dataPayload)
201{
202#ifdef CHASTE_VTK
203 vtkDoubleArray* p_scalars = vtkDoubleArray::New();
204 p_scalars->SetName(dataName.c_str());
205 for (unsigned i = 0; i < dataPayload.size(); i++)
206 {
207 p_scalars->InsertNextValue(dataPayload[i]);
208 }
209
210 vtkCellData* p_cell_data = mpVtkUnstructedMesh->GetCellData();
211 p_cell_data->AddArray(p_scalars);
212 p_scalars->Delete(); // Reference counted
213#endif // CHASTE_VTK
214}
215
216template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
218{
219 /*
220 * Blank as we're only using the class for VTK at the moment, i.e. we don't
221 * write mesh information for the case when we have trapezoid edge elements,
222 * since trapezoids associated with each edge are only there for
223 * visualisation purposes and do not represent the actual mesh. The actual
224 * mesh can be written by VertexMeshWriter class and reconstructed by
225 * VertexMeshReader class. This method needs to be overriden here, as it is
226 * declared as a pure virtual function in the parent class.
227 */
228}
229
230// Explicit instantiation
Node< SPACE_DIM > * GetNode(unsigned index) const
TrapezoidEdgeVertexMeshWriter(const std::string &rDirectory, const std::string &rBaseName, const bool clearOutputDir=true)
void MakeVtkMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh)
void WriteVtkUsingMesh(VertexMesh< ELEMENT_DIM, SPACE_DIM > &rMesh, const std::string &stamp="")
void AddCellData(std::string dataName, std::vector< double > dataPayload)
VertexElementIterator GetElementIteratorEnd()
virtual unsigned GetNumNodes() const
VertexElement< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
VertexElementIterator GetElementIteratorBegin(bool skipDeletedElements=true)
virtual c_vector< double, SPACE_DIM > GetCentroidOfElement(unsigned index)
virtual unsigned GetNumElements() const