Loading...
Searching...
No Matches
voloctree_adaptation_example_00001.cpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#include <array>
26
27#if BITPIT_ENABLE_MPI==1
28#include <mpi.h>
29#endif
30
31#include "bitpit_common.hpp"
32#include "bitpit_voloctree.hpp"
33
34using namespace bitpit;
35
50// Auxiliary class to write fields in VTK format.
52
53public:
54 FieldStreamer(const PatchKernel &patch, const PiercedStorage<double, long> &scalarField, const PiercedStorage<std::array<double, 3>, long> &vectorField)
55 : m_patch(patch), m_scalarField(scalarField), m_vectorField(vectorField)
56 {
57 };
58
59 void flushData(std::fstream &stream, const std::string &name, VTKFormat format) override
60 {
61 if (name == "scalarField") {
62 for (const Cell &cell : m_patch.getVTKCellWriteRange()) {
63 long id = cell.getId();
64 flushValue(stream, format, m_scalarField.at(id));
65 }
66 } else if (name == "vectorField") {
67 for (const Cell &cell : m_patch.getVTKCellWriteRange()) {
68 long id = cell.getId();
69 flushValue(stream, format, m_vectorField.at(id));
70 }
71 }
72 };
73
74private:
75 const PatchKernel &m_patch;
76 const PiercedStorage<double, long> &m_scalarField;
77 const PiercedStorage<std::array<double, 3>, long> &m_vectorField;
78
79};
80
81// Main program
82int main(int argc, char *argv[])
83{
84 BITPIT_UNUSED(argc);
85 BITPIT_UNUSED(argv);
86
87
88#if BITPIT_ENABLE_MPI == 1
89 // Initialize MPI
90 MPI_Init(&argc, &argv);
91#endif
92
93 //
94 // Domain initialization
95 //
96
97 // Initializing mesh
98 log::cout() << " Initializing mesh..." << std::endl;
99
100 double length = 1.0;
101 std::array<double, 3> center = {{0.0,0.0,0.0}};
102 std::array<double, 3> minimum = center - length / 2.;
103 double dh = length / 16.;
104
105#if BITPIT_ENABLE_MPI
106 VolOctree mesh(3, minimum, length, dh, MPI_COMM_NULL);
107#else
108 VolOctree mesh(3, minimum, length, dh);
109#endif
110 mesh.initializeAdjacencies();
111 mesh.update();
112
113 // Initialize fields
114 log::cout() << "Initializing fields..." << std::endl;
115
117 PiercedStorage<std::array<double, 3>, long> vectorField;
118 scalarField.setDynamicKernel(&(mesh.getCells()), PiercedVector<Cell>::SYNC_MODE_JOURNALED);
119 vectorField.setDynamicKernel(&(mesh.getCells()), PiercedVector<Cell>::SYNC_MODE_JOURNALED);
120 for (const Cell &cell : mesh.getCells()) {
121 const long cellId = cell.getId();
122 std::array<double, 3> cellCentroid = mesh.evalCellCentroid(cellId);
123 double r = std::sqrt(cellCentroid[0] * cellCentroid[0] + cellCentroid[1] * cellCentroid[1] + cellCentroid[2] * cellCentroid[2]);
124
125 scalarField.set(cellId, r);
126 vectorField.set(cellId, {{cellCentroid[0] / r, cellCentroid[1] / r, cellCentroid[2] / r}});
127 }
128
129 // Initialize mesh output
130 FieldStreamer dataStreamer(mesh, scalarField, vectorField);
131
132 mesh.getVTK().setName("voloctree_adaptation_example_00001");
133 mesh.getVTK().setCounter();
134 mesh.getVTK().addData<double>("scalarField", VTKFieldType::SCALAR, VTKLocation::CELL, &dataStreamer);
135 mesh.getVTK().addData<std::array<double, 3>>("vectorField", VTKFieldType::VECTOR, VTKLocation::CELL, &dataStreamer);
136
137 // Write mesh
138 mesh.write();
139
140 //
141 // Mesh adaptation
142 //
143 bool trackAdaptation = true;
144 bool squeeshPatchStorage = false;
145 std::vector<adaption::Info> adaptionData;
146
147 // Refinement
148 log::cout() << "Performing refinement..." << std::endl;
149
150 int nRefinements = 2;
151 for (int i = 0; i < nRefinements; ++i) {
152 // Mark cells that need refinement
153 //
154 // All cells inside a circle centered in the origin and with a radius
155 // equal to 0.2 will be refined.
156 log::cout() << " Marking cells that need refinement..." << std::endl;
157
158 for (const Cell &cell : mesh.getCells()) {
159 long cellId = cell.getId();
160 std::array<double, 3> cellCentroid = mesh.evalCellCentroid(cellId);
161
162 double r = std::sqrt(cellCentroid[0] * cellCentroid[0] + cellCentroid[1] * cellCentroid[1] + cellCentroid[2] * cellCentroid[2]);
163 if (r < 0.2) {
164 mesh.markCellForRefinement(cellId);
165 }
166 }
167
168 // Update the mesh
169 //
170 // Adaption data structure contains the information needed for mapping
171 // the fields from the previous mesh to the updated mesh.
172 adaptionData = mesh.adaptionPrepare(trackAdaptation);
173
174 // Save values needed for remapping
175 //
176 // Data of cells no longer in the mesh are moved in a temporary
177 // container to be ued later for remapping.
178 PiercedVector<double, long> previousScalarField;
179 PiercedVector<std::array<double, 3>, long> previousVectorField;
180 for (const adaption::Info &adaptionInfo : adaptionData) {
181 // Consider only cell refinements
182 if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
183 continue;
184 } else if (adaptionInfo.type != adaption::TYPE_REFINEMENT) {
185 continue;
186 }
187
188 // Save parent data
189 for (long previousId : adaptionInfo.previous) {
190 previousScalarField.insert(previousId, std::move(scalarField.at(previousId)));
191 previousVectorField.insert(previousId, std::move(vectorField.at(previousId)));
192 }
193
194 }
195
196 adaptionData = mesh.adaptionAlter(trackAdaptation, squeeshPatchStorage);
197
198 // Map the fields on newly created cells
199 //
200 // On refinement one parent cell has been divided in many children
201 // cells. At every children it will be assigned the value of their
202 // parent.
203 for (const adaption::Info &adaptionInfo : adaptionData) {
204 // Consider only cell refinements
205 if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
206 continue;
207 } else if (adaptionInfo.type != adaption::TYPE_REFINEMENT) {
208 continue;
209 }
210
211 // Assign data to children
212 long parentId = adaptionInfo.previous.front();
213 for (long currentId : adaptionInfo.current) {
214 scalarField.set(currentId, previousScalarField.at(parentId));
215 vectorField.set(currentId, previousVectorField.at(parentId));
216 }
217 }
218
219 mesh.adaptionCleanup();
220
221 // Write mesh
222 mesh.write();
223 }
224
225 // Coarsening
226 int nofCoarsening = 1;
227 for (int i = 0; i < nofCoarsening; ++i) {
228 // Mark cells that need coarsening
229 //
230 // All cells inside a circle centered in the origin and with a radius
231 // equal to 0.15 will be coarsened.
232 for (const Cell &cell : mesh.getCells()) {
233 long cellId = cell.getId();
234 std::array<double, 3> cellCentroid = mesh.evalCellCentroid(cellId);
235
236 double r = std::sqrt(cellCentroid[0] * cellCentroid[0] + cellCentroid[1] * cellCentroid[1] + cellCentroid[2] * cellCentroid[2]);
237 if (r < 0.15) {
238 mesh.markCellForCoarsening(cellId);
239 }
240 }
241
242 adaptionData = mesh.adaptionPrepare(trackAdaptation);
243
244 // Save values needed for remapping
245 //
246 // Data of cells no longer in the mesh are moved in a temporary
247 // container to be ued later for remapping.
248 PiercedVector<double, long> previousScalarField;
249 PiercedVector<std::array<double, 3>, long> previousVectorField;
250 for (const adaption::Info &adaptionInfo : adaptionData) {
251 // Consider only cell coarsenings
252 if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
253 continue;
254 } else if (adaptionInfo.type != adaption::TYPE_COARSENING) {
255 continue;
256 }
257
258 // Save parent data
259 for (long previousId : adaptionInfo.previous) {
260 previousScalarField.insert(previousId, std::move(scalarField.at(previousId)));
261 previousVectorField.insert(previousId, std::move(vectorField.at(previousId)));
262 }
263 }
264
265 // Update the mesh
266 //
267 // Adaption data structure contains the information needed for mapping
268 // the fields from the previous mesh to the updated mesh.
269 adaptionData = mesh.adaptionAlter(trackAdaptation, squeeshPatchStorage);
270
271 // Map the fields on newly created cells
272 //
273 // On coarsening many parent cell have been merged together to create
274 // one child cell. The child fields will be set equal to the average
275 // of the parent fields.
276 for (const adaption::Info &adaptionInfo : adaptionData) {
277 // Consider only cell coarsening
278 if (adaptionInfo.entity != adaption::Entity::ENTITY_CELL) {
279 continue;
280 } else if (adaptionInfo.type != adaption::TYPE_COARSENING) {
281 continue;
282 }
283
284 // Evaluate parent average
285 int nParents = adaptionInfo.previous.size();
286 double scalarParentAverage = 0.;
287 std::array<double, 3> vectorParentAverage = {{0., 0., 0.}};
288 for (long parentId : adaptionInfo.previous) {
289 scalarParentAverage += previousScalarField.at(parentId);
290 vectorParentAverage += previousVectorField.at(parentId);
291 }
292 scalarParentAverage /= nParents;
293 vectorParentAverage /= (double) nParents;
294
295 // Assign data to the child
296 long childId = adaptionInfo.current.front();
297 scalarField.set(childId, scalarParentAverage);
298 vectorField.set(childId, vectorParentAverage);
299 }
300
301 mesh.adaptionCleanup();
302
303 // Write mesh
304 mesh.write();
305 }
306
307#if BITPIT_ENABLE_MPI == 1
308 // Finalize MPI
309 MPI_Finalize();
310#endif
311}
void flushData(std::fstream &stream, const std::string &name, VTKFormat format) override
The Cell class defines the cells.
Definition cell.hpp:42
The PatchKernel class provides an interface for defining patches.
const CellConstRange getVTKCellWriteRange() const
void setDynamicKernel(const PiercedKernel< id_t > *kernel, PiercedSyncMaster::SyncMode syncMode)
Metafunction for generating a pierced storage.
void set(id_t id, const value_t &value)
__PS_REFERENCE__ at(id_t id, std::size_t k=0)
__PVS_REFERENCE__ at(id_t id)
Metafunction for generating a pierced vector.
iterator insert(id_t id, const value_t &value)
The base class to be used to derive VTK streamers form.
Definition VTK.hpp:209
void flushValue(std::fstream &, VTKFormat, const T &value) const
The VolOctree defines a Octree patch.
Definition voloctree.hpp:37
VTKFormat
Definition VTK.hpp:92
#define BITPIT_UNUSED(variable)
Definition compiler.hpp:63
Logger & cout(log::Level defaultSeverity, log::Visibility defaultVisibility)
Definition logger.cpp:1705
The Info struct defines the information associated to an adaption.
Definition adaption.hpp:63
--- layout: doxygen_footer ---