include/meltpooldg/cut/repartition.hpp Source File

Developer Documentation: include/meltpooldg/cut/repartition.hpp Source File
Developer Documentation
repartition.hpp
Go to the documentation of this file.
1
13#pragma once
14
15#include <deal.II/base/exceptions.h>
16#include <deal.II/base/mpi.h>
17#include <deal.II/base/numbers.h>
18#include <deal.II/base/utilities.h>
19
20#include <deal.II/distributed/tria.h>
21
22#include <deal.II/dofs/dof_handler.h>
23
24#include <deal.II/grid/tria.h>
25
26#include <deal.II/non_matching/mesh_classifier.h>
27
28#include <deal.II/numerics/solution_transfer.h>
29
32
33#include <boost/range/iterator_range.hpp>
34#include <boost/signals2/connection.hpp>
35
36#include <algorithm>
37#include <functional>
38#include <memory>
39#include <vector>
40
41namespace MeltPoolDG::CutUtil
42{
80 template <int dim>
82 {
83 public:
84 using CellIterator = typename dealii::Triangulation<dim>::cell_iterator;
85
92 explicit PartitionWeights(const dealii::Triangulation<dim> &tria_in,
93 const CutRepartitionData &repartition_data_in)
94 : tria(&tria_in)
95 , repartition_data(repartition_data_in)
96 {
97 AssertThrow(
98 (dynamic_cast<const dealii::parallel::distributed::Triangulation<dim> *>(&tria_in) !=
99 nullptr),
100 dealii::ExcMessage(
101 "The weighted repartitioning requires a parallel::distributed::Triangulation."));
102 }
103
120 void
121 update(const dealii::NonMatching::MeshClassifier<dim> &mesh_classifier)
122 {
123 // resize weight vector and initialize to 1
124 weights.assign(tria->n_active_cells(), 1);
125
126 // loop over cells and set the partitioning weight
127 for (const auto &cell : tria->active_cell_iterators())
128 if (cell->is_locally_owned())
129 weights[cell->active_cell_index()] =
130 get_partition_weight(mesh_classifier.location_to_level_set(cell));
131
132 if (connections.empty())
134 }
135
145 unsigned int
146 get_weight(const CellIterator &cell) const
147 {
148 if (cell->has_children())
149 {
150 unsigned int weight = 0;
151 for (unsigned int c = 0; c < cell->n_children(); ++c)
152 weight = std::max(weight, get_weight(cell->child(c)));
153 return weight;
154 }
155
156 const unsigned int index = cell->active_cell_index();
157
158 // assert that the cached weights are up-to-date with the current triangulation
159 Assert(index < weights.size(),
160 dealii::ExcMessage("The cached partitioning weights are outdated. Call "
161 "PartitionWeights::update() after each change of the "
162 "triangulation."));
163
164 return weights[index];
165 }
166
175 dealii::Utilities::MPI::MinMaxAvg
176 compute_load_statistics(const MPI_Comm mpi_comm) const
177 {
178 double local_load = 0.;
179 for (const auto &cell : tria->active_cell_iterators())
180 if (cell->is_locally_owned())
181 local_load += get_weight(cell);
182
183 return dealii::Utilities::MPI::min_max_avg(local_load, mpi_comm);
184 }
185
186 private:
188 const dealii::Triangulation<dim> *tria;
189
192
194 std::vector<unsigned int> weights;
195
197 unsigned int weights_handle = dealii::numbers::invalid_unsigned_int;
198
200 std::vector<boost::signals2::scoped_connection> connections;
201
207 void
209 {
210 auto &signals = tria->signals;
211
212 connections.emplace_back(signals.weight.connect(
213 [this](const CellIterator &cell, const dealii::CellStatus) -> unsigned int {
214 return this->get_weight(cell);
215 }));
216
217 for (auto *signal :
218 {&signals.pre_distributed_refinement, &signals.pre_distributed_repartition})
219 connections.emplace_back(signal->connect([this]() { this->prepare_transfer(); }));
220
221 for (auto *signal :
222 {&signals.post_distributed_refinement, &signals.post_distributed_repartition})
223 connections.emplace_back(signal->connect([this]() { this->finish_transfer(); }));
224 }
225
233 void
235 {
236 Assert(weights_handle == dealii::numbers::invalid_unsigned_int, dealii::ExcInternalError());
237
238 // get_weight() returns the maximum weight of the children for cells whose children will be
239 // coarsened
240 weights_handle = const_cast<dealii::Triangulation<dim> &>(*tria).register_data_attach(
241 [this](const CellIterator &cell, const dealii::CellStatus) {
242 return dealii::Utilities::pack(this->get_weight(cell), /*allow_compression=*/false);
243 },
244 /*returns_variable_size_data=*/false);
245 }
246
252 void
254 {
255 Assert(weights_handle != dealii::numbers::invalid_unsigned_int, dealii::ExcInternalError());
256
257 std::vector<unsigned int> new_weights(tria->n_active_cells(), 1);
258
259 const_cast<dealii::Triangulation<dim> &>(*tria).notify_ready_to_unpack(
261 [&new_weights](const CellIterator &cell,
262 const dealii::CellStatus status,
263 const boost::iterator_range<std::vector<char>::const_iterator> &data) {
264 const auto weight = dealii::Utilities::unpack<unsigned int>(data.begin(),
265 data.end(),
266 /*allow_compression=*/false);
267
268 // the children of a refined cell inherit the weight of their parent
269 if (status == dealii::CellStatus::cell_will_be_refined)
270 for (const auto &child : cell->child_iterators())
271 new_weights[child->active_cell_index()] = weight;
272 else
273 new_weights[cell->active_cell_index()] = weight;
274 });
275
276 weights.swap(new_weights);
277 weights_handle = dealii::numbers::invalid_unsigned_int;
278 }
279
288 unsigned int
289 get_partition_weight(const dealii::NonMatching::LocationToLevelSet location) const
290 {
291 switch (location)
292 {
293 case dealii::NonMatching::LocationToLevelSet::inside:
295
296 case dealii::NonMatching::LocationToLevelSet::outside:
298
299 case dealii::NonMatching::LocationToLevelSet::intersected:
301
302 default:
303 AssertThrow(false, dealii::ExcMessage("Unknown location of the cell."));
304 }
305 }
306 };
307
345 template <int dim, typename VectorType>
346 bool
348 [[maybe_unused]] dealii::Triangulation<dim> &tria,
349 [[maybe_unused]] const AttachDoFHandlerAndVectorsType<dim, VectorType> &attach_vectors,
350 [[maybe_unused]] const std::function<void()> &distribute_level_set_dofs,
351 [[maybe_unused]] const dealii::DoFHandler<dim> &level_set_dof_handler,
352 [[maybe_unused]] VectorType &level_set_dof_vector,
353 [[maybe_unused]] const std::function<void()> &setup_dof_system,
354 [[maybe_unused]] const std::function<void()> &post = {})
355 {
356 if constexpr (dim == 1)
357 {
358 // parallel::distributed::Triangulation is not available for dim = 1
359 return false;
360 }
361 else
362 {
363 // check that the triangulation is of type parallel::distributed::Triangulation
364 auto *distributed_tria =
365 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> *>(&tria);
366
367 if (distributed_tria == nullptr)
368 return false;
369
370 // 1. prepare the solution transfer
371 DoFHandlerAndVectorDataType<dim, VectorType> data;
372 if (attach_vectors)
373 {
374 attach_vectors(data);
375 data.shrink_to_fit();
376 }
377
378 const unsigned int n_dof_handlers = data.size();
379
380 // create a solution transfer for all DoFHandlers
381 std::vector<std::unique_ptr<dealii::SolutionTransfer<dim, VectorType>>> solution_transfers(
382 n_dof_handlers);
383 std::vector<std::vector<const VectorType *>> old_vectors(n_dof_handlers);
384 std::vector<std::vector<bool>> had_ghost_values(n_dof_handlers);
385
386 for (unsigned int j = 0; j < n_dof_handlers; ++j)
387 {
388 std::vector<VectorType *> vectors;
389 data[j].second(vectors);
390
391 for (const auto &v : vectors)
392 {
393 had_ghost_values[j].push_back(v->has_ghost_elements());
394 // ghost values are required to read the DoF values of the locally owned cells
395 v->update_ghost_values();
396 old_vectors[j].push_back(v);
397 }
398
399 solution_transfers[j] =
400 std::make_unique<dealii::SolutionTransfer<dim, VectorType>>(*data[j].first);
401 solution_transfers[j]->prepare_for_coarsening_and_refinement(old_vectors[j]);
402 }
403
404 level_set_dof_vector.update_ghost_values();
405 dealii::SolutionTransfer<dim, VectorType> level_set_transfer(level_set_dof_handler);
406 level_set_transfer.prepare_for_coarsening_and_refinement(level_set_dof_vector);
407
408 // 2. repartition the triangulation according to the connected cell weights; the active FE
409 // indices of hp-DoFHandlers are transferred automatically
410 distributed_tria->repartition();
411
412 // 3. transfer the level set first, so that the cut operations can classify the cells
413 distribute_level_set_dofs();
414 level_set_dof_vector.zero_out_ghost_values();
415 level_set_transfer.interpolate(level_set_dof_vector);
416 level_set_dof_vector.update_ghost_values();
417
418 // 4. update dof-related data to match the new partitioning
419 setup_dof_system();
420
421 // 5. transfer the attached vectors; collect the target vectors again, since they might have
422 // been reinitialized/reallocated in setup_dof_system()
423 if (n_dof_handlers > 0)
424 {
425 DoFHandlerAndVectorDataType<dim, VectorType> new_data;
426 attach_vectors(new_data);
427
428 for (unsigned int j = 0; j < n_dof_handlers; ++j)
429 {
430 std::vector<VectorType *> new_vectors;
431 new_data[j].second(new_vectors);
432
433 for (const auto &v : new_vectors)
435
436 solution_transfers[j]->interpolate(new_vectors);
437
438 for (unsigned int i = 0; i < new_vectors.size(); ++i)
439 if (had_ghost_values[j][i])
440 new_vectors[i]->update_ghost_values();
441 }
442 }
443
444 // 6. post-processing
445 if (post)
446 post();
447
448 return true;
449 }
450 }
451
460 inline bool
461 do_repartition(const unsigned int n_time_step, const CutRepartitionData &repartition_data)
462 {
463 return repartition_data.enable and (n_time_step % repartition_data.every_n_step == 0);
464 }
465} // namespace MeltPoolDG::CutUtil
Cell weights for the repartitioning of a parallel::distributed::Triangulation according to the locati...
Definition repartition.hpp:82
void update(const dealii::NonMatching::MeshClassifier< dim > &mesh_classifier)
Compute and cache the weights of the locally owned active cells according to their location with resp...
Definition repartition.hpp:121
void finish_transfer()
Unpack the cached weights after the triangulation has changed.
Definition repartition.hpp:253
void prepare_transfer()
Attach the cached weights to the cells before the triangulation changes.
Definition repartition.hpp:234
dealii::Utilities::MPI::MinMaxAvg compute_load_statistics(const MPI_Comm mpi_comm) const
Compute statistics of the summed cell weights (i.e. the estimated load) of the locally owned cells ov...
Definition repartition.hpp:176
const CutRepartitionData repartition_data
Repartitioning parameters including the cell weights.
Definition repartition.hpp:191
typename dealii::Triangulation< dim >::cell_iterator CellIterator
Definition repartition.hpp:84
const dealii::Triangulation< dim > * tria
Pointer to the triangulation.
Definition repartition.hpp:188
std::vector< unsigned int > weights
Cached weights of the active cells (indexed by the active cell index)
Definition repartition.hpp:194
PartitionWeights(const dealii::Triangulation< dim > &tria_in, const CutRepartitionData &repartition_data_in)
Constructor.
Definition repartition.hpp:92
unsigned int get_partition_weight(const dealii::NonMatching::LocationToLevelSet location) const
Get the partitioning weight of a cell according to its location with respect to the level set.
Definition repartition.hpp:289
unsigned int weights_handle
Handle of the cell-attached weights during a change of the triangulation.
Definition repartition.hpp:197
unsigned int get_weight(const CellIterator &cell) const
Get the cached weight of a cell.
Definition repartition.hpp:146
void connect_to_triangulation()
Connect the function returning the cached weights to the weight signal of the triangulation,...
Definition repartition.hpp:208
std::vector< boost::signals2::scoped_connection > connections
Connections to the signals of the triangulation.
Definition repartition.hpp:200
Utilities for the weighted repartitioning of a parallel::distributed::Triangulation in cutFEM/cutDG a...
Definition amr.hpp:15
bool repartition_triangulation(dealii::Triangulation< dim > &tria, const AttachDoFHandlerAndVectorsType< dim, VectorType > &attach_vectors, const std::function< void()> &distribute_level_set_dofs, const dealii::DoFHandler< dim > &level_set_dof_handler, VectorType &level_set_dof_vector, const std::function< void()> &setup_dof_system, const std::function< void()> &post={})
Repartition the triangulation tria among the MPI processes and transfer the attached DoF vectors and ...
Definition repartition.hpp:347
bool do_repartition(const unsigned int n_time_step, const CutRepartitionData &repartition_data)
Determine whether the triangulation should be repartitioned at time step number n_time_step.
Definition repartition.hpp:461
void zero_out_ghost_values(const T &...args)
Definition vector_tools.hpp:108
std::function< void(DoFHandlerAndVectorDataType< dim, VectorType > &)> AttachDoFHandlerAndVectorsType
Definition attach_vectors.hpp:21
unsigned int intersected
Weight of cells intersected by the zero level-set isosurface.
Definition cut_data.hpp:97
unsigned int inside
Weight of cells located completely inside (negative level set)
Definition cut_data.hpp:91
unsigned int outside
Weight of cells located completely outside (positive level set)
Definition cut_data.hpp:94
Collection of parameters for the weighted repartitioning of the triangulation in cut applications.
Definition cut_data.hpp:74
bool enable
Definition cut_data.hpp:77
struct MeltPoolDG::CutRepartitionData::Weights weights
unsigned int every_n_step
The triangulation is repartitioned every n-th time step.
Definition cut_data.hpp:80