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