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