// `private`.
unsigned int cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status) const;
+ & cell,
+ const CellStatus status) const;
// The following two functions are responsible for outputting the simulation
// results for the particles and for the velocity profile on the background
template <int dim>
unsigned int ParticleTracking<dim>::cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
- & cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
- const
+ & cell,
+ const CellStatus status) const
{
// First, we introduce a base weight that will be assigned to every cell.
const unsigned int base_weight = 1;
unsigned int n_particles_in_cell = 0;
switch (status)
{
- case parallel::distributed::Triangulation<dim>::CELL_PERSIST:
- case parallel::distributed::Triangulation<dim>::CELL_REFINE:
+ case CELL_PERSIST:
+ case CELL_REFINE:
n_particles_in_cell = particle_handler.n_particles_in_cell(cell);
break;
- case parallel::distributed::Triangulation<dim>::CELL_INVALID:
+ case CELL_INVALID:
break;
- case parallel::distributed::Triangulation<dim>::CELL_COARSEN:
+ case CELL_COARSEN:
for (const auto &child : cell->child_iterators())
n_particles_in_cell += particle_handler.n_particles_in_cell(child);
break;
// of this class, but for the purpose of this example we want to group the
// particle related instructions.
background_triangulation.signals.weight.connect(
- [&](
- const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status) -> unsigned int { return this->cell_weight(cell, status); });
+ [&](const typename parallel::distributed::Triangulation<
+ dim>::cell_iterator &cell,
+ const CellStatus status) -> unsigned int {
+ return this->cell_weight(cell, status);
+ });
// This initializes the background triangulation where the particles are
// living and the number of properties of the particles.
std::vector<char>
pack_function(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status);
+ & cell,
+ const CellStatus status);
/**
* A callback function used to unpack the data on the current mesh that
void
unpack_function(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status,
+ & cell,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
&data_range);
data_storage = &data_storage_;
handle = triangulation->register_data_attach(
- [this](
- const typename parallel::distributed::Triangulation<
- dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status) { return this->pack_function(cell, status); },
+ [this](const typename parallel::distributed::Triangulation<
+ dim>::cell_iterator &cell,
+ const CellStatus status) {
+ return this->pack_function(cell, status);
+ },
/*returns_variable_size_data=*/true);
}
{
triangulation->notify_ready_to_unpack(
handle,
- [this](
- const typename parallel::distributed::Triangulation<
- dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status,
- const boost::iterator_range<std::vector<char>::const_iterator>
- &data_range) { this->unpack_function(cell, status, data_range); });
+ [this](const typename parallel::distributed::Triangulation<
+ dim>::cell_iterator &cell,
+ const CellStatus status,
+ const boost::iterator_range<std::vector<char>::const_iterator>
+ &data_range) {
+ this->unpack_function(cell, status, data_range);
+ });
// invalidate the pointers
data_storage = nullptr;
ContinuousQuadratureDataTransfer<dim, DataType>::pack_function(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
&cell,
- const typename parallel::distributed::Triangulation<
- dim>::CellStatus /*status*/)
+ const CellStatus /*status*/)
{
pack_cell_data(cell, data_storage, matrix_quadrature);
inline void
ContinuousQuadratureDataTransfer<dim, DataType>::unpack_function(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status,
+ & cell,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
&data_range)
{
- Assert((status !=
- parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN),
- ExcNotImplemented());
+ Assert((status != CELL_COARSEN), ExcNotImplemented());
(void)status;
matrix_dofs =
std::vector<char>
pack_callback(const typename parallel::distributed::
Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename parallel::distributed::
- Triangulation<dim, spacedim>::CellStatus status);
+ const CellStatus status);
/**
* A callback function used to unpack the data on the current mesh that
unpack_callback(
const typename parallel::distributed::Triangulation<dim, spacedim>::
cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim, spacedim>::
- CellStatus status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
& data_range,
std::vector<VectorType *> &all_out);
handle = tria->register_data_attach(
[this](const typename parallel::distributed::
Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename parallel::distributed::
- Triangulation<dim, spacedim>::CellStatus status) {
+ const CellStatus status) {
return this->pack_callback(cell, status);
},
/*returns_variable_size_data=*/transfer_variable_size_data);
[this, &all_out](
const typename parallel::distributed::Triangulation<dim, spacedim>::
cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim, spacedim>::
- CellStatus status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
&data_range) {
this->unpack_callback(cell, status, data_range, all_out);
CellDataTransfer<dim, spacedim, VectorType>::pack_callback(
const typename parallel::distributed::Triangulation<dim, spacedim>::
cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim,
- spacedim>::CellStatus
- status)
+ const CellStatus status)
{
std::vector<value_type> cell_data(input_vectors.size());
{
switch (status)
{
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_PERSIST:
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_REFINE:
+ case CELL_PERSIST:
+ case CELL_REFINE:
// Cell either persists, or will be refined, and its children do
// not exist yet in the latter case.
*it_output = (**it_input)[cell->active_cell_index()];
break;
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_COARSEN:
+ case CELL_COARSEN:
{
// Cell is parent whose children will get coarsened to.
// Decide data to store on parent by provided strategy.
CellDataTransfer<dim, spacedim, VectorType>::unpack_callback(
const typename parallel::distributed::Triangulation<dim, spacedim>::
cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim,
- spacedim>::CellStatus
- status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
& data_range,
std::vector<VectorType *> &all_out)
for (; it_input != cell_data.cend(); ++it_input, ++it_output)
switch (status)
{
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_PERSIST:
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_COARSEN:
+ case CELL_PERSIST:
+ case CELL_COARSEN:
// Cell either persists, or has been coarsened.
// Thus, cell has no (longer) children.
(**it_output)[cell->active_cell_index()] = *it_input;
break;
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_REFINE:
+ case CELL_REFINE:
{
// Cell has been refined, and is now parent of its children.
// Thus, distribute parent's data on its children.
*/
static std::function<unsigned int(
const typename dealii::Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename dealii::Triangulation<dim, spacedim>::CellStatus status)>
+ const CellStatus status)>
make_weighting_callback(const DoFHandler<dim, spacedim> &dof_handler,
const WeightingFunction &weighting_function);
static unsigned int
weighting_callback(
const typename dealii::Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename dealii::Triangulation<dim, spacedim>::CellStatus status,
+ const CellStatus status,
const DoFHandler<dim, spacedim> & dof_handler,
const parallel::TriangulationBase<dim, spacedim> &triangulation,
const WeightingFunction & weighting_function);
using active_cell_iterator =
typename dealii::Triangulation<dim, spacedim>::active_cell_iterator;
- using CellStatus =
- typename dealii::Triangulation<dim, spacedim>::CellStatus;
-
/**
* Constructor.
*
CellWeightPolicy(
const std::function<unsigned int(
const typename Triangulation<dim, spacedim>::cell_iterator &,
- const typename Triangulation<dim, spacedim>::CellStatus)>
- &weighting_function);
+ const CellStatus)> &weighting_function);
virtual LinearAlgebra::distributed::Vector<double>
partition(const Triangulation<dim, spacedim> &tria_in) const override;
*/
const std::function<
unsigned int(const typename Triangulation<dim, spacedim>::cell_iterator &,
- const typename Triangulation<dim, spacedim>::CellStatus)>
+ const CellStatus)>
weighting_function;
};
std::vector<char>
pack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename Triangulation<dim, spacedim>::CellStatus status);
+ const CellStatus status);
/**
* A callback function used to unpack the data on the current mesh that
void
unpack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename Triangulation<dim, spacedim>::CellStatus status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
& data_range,
std::vector<VectorType *> &all_out,
using active_cell_iterator =
typename dealii::Triangulation<dim, spacedim>::active_cell_iterator;
- using CellStatus =
- typename dealii::Triangulation<dim, spacedim>::CellStatus;
-
/**
* Configuration flags for distributed Triangulations to be set in the
* constructor. Settings can be combined using bitwise OR.
};
-
/**
* A base class for distributed triangulations, i.e., triangulations that
* do not store all cells on all processors. This implies that not
using cell_iterator =
typename dealii::Triangulation<dim, spacedim>::cell_iterator;
- using CellStatus =
- typename dealii::Triangulation<dim, spacedim>::CellStatus;
-
/**
* Return true if the triangulation has hanging nodes.
*
DEAL_II_DEPRECATED
virtual void
load(const std::string &filename, const bool autopartition) = 0;
-
- /**
- * Register a function that can be used to attach data of fixed size
- * to cells. This is useful for two purposes: (i) Upon refinement and
- * coarsening of a triangulation (@a e.g. in
- * parallel::distributed::Triangulation::execute_coarsening_and_refinement()),
- * one needs to be able to store one or more data vectors per cell that
- * characterizes the solution values on the cell so that this data can
- * then be transferred to the new owning processor of the cell (or
- * its parent/children) when the mesh is re-partitioned; (ii) when
- * serializing a computation to a file, it is necessary to attach
- * data to cells so that it can be saved (@a e.g. in
- * parallel::distributed::Triangulation::save()) along with the cell's
- * other information and, if necessary, later be reloaded from disk
- * with a different subdivision of cells among the processors.
- *
- * The way this function works is that it allows any number of interest
- * parties to register their intent to attach data to cells. One example
- * of classes that do this is parallel::distributed::SolutionTransfer
- * where each parallel::distributed::SolutionTransfer object that works
- * on the current Triangulation object then needs to register its intent.
- * Each of these parties registers a callback function (the first
- * argument here, @p pack_callback) that will be called whenever the
- * triangulation's execute_coarsening_and_refinement() or save()
- * functions are called.
- *
- * The current function then returns an integer handle that corresponds
- * to the number of data set that the callback provided here will attach.
- * While this number could be given a precise meaning, this is
- * not important: You will never actually have to do anything with
- * this number except return it to the notify_ready_to_unpack() function.
- * In other words, each interested party (i.e., the caller of the current
- * function) needs to store their respective returned handle for later use
- * when unpacking data in the callback provided to
- * notify_ready_to_unpack().
- *
- * Whenever @p pack_callback is then called by
- * execute_coarsening_and_refinement() or load() on a given cell, it
- * receives a number of arguments. In particular, the first
- * argument passed to the callback indicates the cell for which
- * it is supposed to attach data. This is always an active cell.
- *
- * The second, CellStatus, argument provided to the callback function
- * will tell you if the given cell will be coarsened, refined, or will
- * persist as is. (This status may be different than the refinement
- * or coarsening flags set on that cell, to accommodate things such as
- * the "one hanging node per edge" rule.). These flags need to be
- * read in context with the p4est quadrant they belong to, as their
- * relations are gathered in local_cell_relations.
- *
- * Specifically, the values for this argument mean the following:
- *
- * - `CELL_PERSIST`: The cell won't be refined/coarsened, but might be
- * moved to a different processor. If this is the case, the callback
- * will want to pack up the data on this cell into an array and store
- * it at the provided address for later unpacking wherever this cell
- * may land.
- * - `CELL_REFINE`: This cell will be refined into 4 or 8 cells (in 2d
- * and 3d, respectively). However, because these children don't exist
- * yet, you cannot access them at the time when the callback is
- * called. Thus, in local_cell_relations, the corresponding
- * p4est quadrants of the children cells are linked to the deal.II
- * cell which is going to be refined. To be specific, only the very
- * first child is marked with `CELL_REFINE`, whereas the others will be
- * marked with `CELL_INVALID`, which indicates that these cells will be
- * ignored by default during the packing or unpacking process. This
- * ensures that data is only transferred once onto or from the parent
- * cell. If the callback is called with `CELL_REFINE`, the callback
- * will want to pack up the data on this cell into an array and store
- * it at the provided address for later unpacking in a way so that
- * it can then be transferred to the children of the cell that will
- * then be available. In other words, if the data the callback
- * will want to pack up corresponds to a finite element field, then
- * the prolongation from parent to (new) children will have to happen
- * during unpacking.
- * - `CELL_COARSEN`: The children of this cell will be coarsened into the
- * given cell. These children still exist, so if this is the value
- * given to the callback as second argument, the callback will want
- * to transfer data from the children to the current parent cell and
- * pack it up so that it can later be unpacked again on a cell that
- * then no longer has any children (and may also be located on a
- * different processor). In other words, if the data the callback
- * will want to pack up corresponds to a finite element field, then
- * it will need to do the restriction from children to parent at
- * this point.
- * - `CELL_INVALID`: See `CELL_REFINE`.
- *
- * @note If this function is used for serialization of data
- * using save() and load(), then the cell status argument with which
- * the callback is called will always be `CELL_PERSIST`.
- *
- * The callback function is expected to return a memory chunk of the
- * format `std::vector<char>`, representing the packed data on a
- * certain cell.
- *
- * The second parameter @p returns_variable_size_data indicates whether
- * the returned size of the memory region from the callback function
- * varies by cell (<tt>=true</tt>) or stays constant on each one
- * throughout the whole domain (<tt>=false</tt>).
- *
- * @note The purpose of this function is to register intent to
- * attach data for a single, subsequent call to
- * execute_coarsening_and_refinement() and notify_ready_to_unpack(),
- * save(), load(). Consequently, notify_ready_to_unpack(), save(),
- * and load() all forget the registered callbacks once these
- * callbacks have been called, and you will have to re-register
- * them with a triangulation if you want them to be active for
- * another call to these functions.
- */
- unsigned int
- register_data_attach(
- const std::function<std::vector<char>(const cell_iterator &,
- const CellStatus)> &pack_callback,
- const bool returns_variable_size_data);
-
- /**
- * This function is the opposite of register_data_attach(). It is called
- * <i>after</i> the execute_coarsening_and_refinement() or save()/load()
- * functions are done when classes and functions that have previously
- * attached data to a triangulation for either transfer to other
- * processors, across mesh refinement, or serialization of data to
- * a file are ready to receive that data back. The important part about
- * this process is that the triangulation cannot do this right away from
- * the end of execute_coarsening_and_refinement() or load() via a
- * previously attached callback function (as the register_data_attach()
- * function does) because the classes that eventually want the data
- * back may need to do some setup between the point in time where the
- * mesh has been recreated and when the data can actually be received.
- * An example is the parallel::distributed::SolutionTransfer class
- * that can really only receive the data once not only the mesh is
- * completely available again on the current processor, but only
- * after a DoFHandler has been reinitialized and distributed
- * degrees of freedom. In other words, there is typically a significant
- * amount of set up that needs to happen in user space before the classes
- * that can receive data attached to cell are ready to actually do so.
- * When they are, they use the current function to tell the triangulation
- * object that now is the time when they are ready by calling the
- * current function.
- *
- * The supplied callback function is then called for each newly locally
- * owned cell. The first argument to the callback is an iterator that
- * designates the cell; the second argument indicates the status of the
- * cell in question; and the third argument localizes a memory area by
- * two iterators that contains the data that was previously saved from
- * the callback provided to register_data_attach().
- *
- * The CellStatus will indicate if the cell was refined, coarsened, or
- * persisted unchanged. The @p cell_iterator argument to the callback
- * will then either be an active,
- * locally owned cell (if the cell was not refined), or the immediate
- * parent if it was refined during execute_coarsening_and_refinement().
- * Therefore, contrary to during register_data_attach(), you can now
- * access the children if the status is `CELL_REFINE` but no longer for
- * callbacks with status `CELL_COARSEN`.
- *
- * The first argument to this function, `handle`, corresponds to
- * the return value of register_data_attach(). (The precise
- * meaning of what the numeric value of this handle is supposed
- * to represent is neither important, nor should you try to use
- * it for anything other than transmit information between a
- * call to register_data_attach() to the corresponding call to
- * notify_ready_to_unpack().)
- */
- void
- notify_ready_to_unpack(
- const unsigned int handle,
- const std::function<
- void(const cell_iterator &,
- const CellStatus,
- const boost::iterator_range<std::vector<char>::const_iterator> &)>
- &unpack_callback);
-
- protected:
- /**
- * Save additional cell-attached data into the given file. The first
- * arguments are used to determine the offsets where to write buffers to.
- *
- * Called by
- * @ref save.
- */
- void
- save_attached_data(const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const std::string &filename) const;
-
- /**
- * Load additional cell-attached data from the given file, if any was saved.
- * The first arguments are used to determine the offsets where to read
- * buffers from.
- *
- * Called by
- * @ref load.
- */
- void
- load_attached_data(const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const unsigned int local_num_cells,
- const std::string &filename,
- const unsigned int n_attached_deserialize_fixed,
- const unsigned int n_attached_deserialize_variable);
-
- /**
- * A function to record the CellStatus of currently active cells that
- * are locally owned. This information is mandatory to transfer data
- * between meshes during adaptation or serialization, e.g., using
- * parallel::distributed::SolutionTransfer.
- *
- * Relations will be stored in the private member local_cell_relations. For
- * an extensive description of CellStatus, see the documentation for the
- * member function register_data_attach().
- */
- virtual void
- update_cell_relations() = 0;
-
- /**
- * Auxiliary data structure for assigning a CellStatus to a deal.II cell
- * iterator. For an extensive description of the former, see the
- * documentation for the member function register_data_attach().
- */
- using cell_relation_t = typename std::pair<cell_iterator, CellStatus>;
-
- /**
- * Vector of pairs, each containing a deal.II cell iterator and its
- * respective CellStatus. To update its contents, use the
- * update_cell_relations() member function.
- */
- std::vector<cell_relation_t> local_cell_relations;
-
- /**
- * A structure that stores information about the data that has been, or
- * will be, attached to cells via the register_data_attach() function
- * and later retrieved via notify_ready_to_unpack().
- */
- struct CellAttachedData
- {
- /**
- * number of functions that get attached to the Triangulation through
- * register_data_attach() for example SolutionTransfer.
- */
- unsigned int n_attached_data_sets;
-
- /**
- * number of functions that need to unpack their data after a call from
- * load()
- */
- unsigned int n_attached_deserialize;
-
- using pack_callback_t = std::function<std::vector<char>(
- typename dealii::Triangulation<dim, spacedim>::cell_iterator,
- typename dealii::Triangulation<dim, spacedim>::CellStatus)>;
-
- /**
- * These callback functions will be stored in the order in which they
- * have been registered with the register_data_attach() function.
- */
- std::vector<pack_callback_t> pack_callbacks_fixed;
- std::vector<pack_callback_t> pack_callbacks_variable;
- };
-
- CellAttachedData cell_attached_data;
-
- /**
- * This class in the private scope of parallel::DistributedTriangulationBase
- * is dedicated to the data transfer across repartitioned meshes
- * and to/from the file system.
- *
- * It is designed to store all data buffers intended for transfer.
- */
- class DataTransfer
- {
- public:
- DataTransfer(const MPI_Comm mpi_communicator);
-
- /**
- * Prepare data transfer by calling the pack callback functions on each
- * cell
- * in @p cell_relations.
- *
- * All registered callback functions in @p pack_callbacks_fixed will write
- * into the fixed size buffer, whereas each entry of @p pack_callbacks_variable
- * will write its data into the variable size buffer.
- */
- void
- pack_data(const std::vector<cell_relation_t> &cell_relations,
- const std::vector<typename CellAttachedData::pack_callback_t>
- &pack_callbacks_fixed,
- const std::vector<typename CellAttachedData::pack_callback_t>
- &pack_callbacks_variable);
-
-
-
- /**
- * Unpack the CellStatus information on each entry of
- * @p cell_relations.
- *
- * Data has to be previously transferred with execute_transfer()
- * or read from the file system via load().
- */
- void
- unpack_cell_status(std::vector<cell_relation_t> &cell_relations) const;
-
- /**
- * Unpack previously transferred data on each cell registered in
- * @p cell_relations with the provided @p unpack_callback function.
- *
- * The parameter @p handle corresponds to the position where the
- * @p unpack_callback function is allowed to read from the memory. Its
- * value needs to be in accordance with the corresponding pack_callback
- * function that has been registered previously.
- *
- * Data has to be previously transferred with execute_transfer()
- * or read from the file system via load().
- */
- void
- unpack_data(
- const std::vector<cell_relation_t> &cell_relations,
- const unsigned int handle,
- const std::function<void(
- const typename dealii::Triangulation<dim, spacedim>::cell_iterator &,
- const typename dealii::Triangulation<dim, spacedim>::CellStatus &,
- const boost::iterator_range<std::vector<char>::const_iterator> &)>
- &unpack_callback) const;
-
- /**
- * Transfer data to file system.
- *
- * The data will be written in a separate file, whose name
- * consists of the stem @p filename and an attached identifier
- * <tt>_fixed.data</tt> for fixed size data and <tt>_variable.data</tt>
- * for variable size data.
- *
- * All processors write into these files simultaneously via MPIIO.
- * Each processor's position to write to will be determined
- * from the provided input parameters.
- *
- * Data has to be previously packed with pack_data().
- */
- void
- save(const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const std::string &filename) const;
-
- /**
- * Transfer data from file system.
- *
- * The data will be read from separate file, whose name
- * consists of the stem @p filename and an attached identifier
- * <tt>_fixed.data</tt> for fixed size data and <tt>_variable.data</tt>
- * for variable size data.
- * The @p n_attached_deserialize_fixed and @p n_attached_deserialize_variable
- * parameters are required to gather the memory offsets for each
- * callback.
- *
- * All processors read from these files simultaneously via MPIIO.
- * Each processor's position to read from will be determined
- * from the provided input arguments.
- *
- * After loading, unpack_data() needs to be called to finally
- * distribute data across the associated triangulation.
- */
- void
- load(const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const unsigned int local_num_cells,
- const std::string &filename,
- const unsigned int n_attached_deserialize_fixed,
- const unsigned int n_attached_deserialize_variable);
-
- /**
- * Clears all containers and associated data, and resets member
- * values to their default state.
- *
- * Frees memory completely.
- */
- void
- clear();
-
- /**
- * Flag that denotes if variable size data has been packed.
- */
- bool variable_size_data_stored;
-
- /**
- * Cumulative size in bytes that those functions that have called
- * register_data_attach() want to attach to each cell. This number
- * only pertains to fixed-sized buffers where the data attached to
- * each cell has exactly the same size.
- *
- * The last entry of this container corresponds to the data size
- * packed per cell in the fixed size buffer (which can be accessed
- * calling <tt>sizes_fixed_cumulative.back()</tt>).
- */
- std::vector<unsigned int> sizes_fixed_cumulative;
-
- /**
- * Consecutive buffers designed for the fixed size transfer
- * functions of p4est.
- */
- std::vector<char> src_data_fixed;
- std::vector<char> dest_data_fixed;
-
- /**
- * Consecutive buffers designed for the variable size transfer
- * functions of p4est.
- */
- std::vector<int> src_sizes_variable;
- std::vector<int> dest_sizes_variable;
- std::vector<char> src_data_variable;
- std::vector<char> dest_data_variable;
-
- private:
- MPI_Comm mpi_communicator;
- };
-
- DataTransfer data_transfer;
};
} // namespace parallel
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_cell_status_h
+#define dealii_cell_status_h
+
+#include <deal.II/base/config.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+/**
+ * Used to inform functions in derived classes how the cell with the given
+ * cell_iterator is going to change. Note that this may me different than
+ * the refine_flag() and coarsen_flag() in the cell_iterator in parallel
+ * calculations because of refinement constraints that this machine does not
+ * see.
+ */
+enum CellStatus
+{
+ /**
+ * The cell will not be refined or coarsened and might or might not move
+ * to a different processor.
+ */
+ CELL_PERSIST,
+ /**
+ * The cell will be or was refined.
+ */
+ CELL_REFINE,
+ /**
+ * The children of this cell will be or were coarsened into this cell.
+ */
+ CELL_COARSEN,
+ /**
+ * Invalid status. Will not occur for the user.
+ */
+ CELL_INVALID
+};
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 1998 - 2023 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_tria_data_transfer_h
+#define dealii_tria_data_transfer_h
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/base/mpi.h>
+#include <deal.II/base/mpi_large_count.h>
+#include <deal.II/base/utilities.h>
+
+#include <deal.II/grid/cell_status.h>
+#include <deal.II/grid/tria_iterator_selector.h>
+
+#include <boost/range/iterator_range.hpp>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <vector>
+
+DEAL_II_NAMESPACE_OPEN
+
+template <int dim, int spacedim = dim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+struct CellAttachedData
+{
+ using cell_iterator = TriaIterator<CellAccessor<dim, spacedim>>;
+
+ /**
+ * Number of functions that get attached to the Triangulation through
+ * register_data_attach() for example SolutionTransfer.
+ */
+ unsigned int n_attached_data_sets;
+
+ /**
+ * Number of functions that need to unpack their data after a call from
+ * load().
+ */
+ unsigned int n_attached_deserialize;
+
+ using pack_callback_t =
+ std::function<std::vector<char>(cell_iterator, CellStatus)>;
+
+ /**
+ * These callback functions will be stored in the order in which they
+ * have been registered with the register_data_attach() function.
+ */
+ std::vector<pack_callback_t> pack_callbacks_fixed;
+ std::vector<pack_callback_t> pack_callbacks_variable;
+};
+
+/**
+ * A structure that stores information about the data that has been, or
+ * will be, attached to cells via the register_data_attach() function
+ * and later retrieved via notify_ready_to_unpack().
+ *
+ * This class in the private scope of parallel::DistributedTriangulationBase
+ * is dedicated to the data transfer across repartitioned meshes
+ * and to/from the file system.
+ *
+ * It is designed to store all data buffers intended for transfer.
+ */
+template <int dim, int spacedim = dim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+class DataTransfer
+{
+public:
+ using cell_iterator = TriaIterator<CellAccessor<dim, spacedim>>;
+
+ /**
+ * Auxiliary data structure for assigning a CellStatus to a deal.II cell
+ * iterator. For an extensive description of the former, see the
+ * documentation for the member function register_data_attach().
+ */
+ using cell_relation_t = typename std::pair<cell_iterator, CellStatus>;
+
+ DataTransfer(const MPI_Comm mpi_communicator);
+
+ /**
+ * Prepare data transfer by calling the pack callback functions on each
+ * cell in @p cell_relations.
+ *
+ * All registered callback functions in @p pack_callbacks_fixed will write
+ * into the fixed size buffer, whereas each entry of @p pack_callbacks_variable
+ * will write its data into the variable size buffer.
+ */
+ void
+ pack_data(
+ const std::vector<cell_relation_t> &cell_relations,
+ const std::vector<typename CellAttachedData<dim, spacedim>::pack_callback_t>
+ &pack_callbacks_fixed,
+ const std::vector<typename CellAttachedData<dim, spacedim>::pack_callback_t>
+ &pack_callbacks_variable);
+
+ /**
+ * Unpack the CellStatus information on each entry of
+ * @p cell_relations.
+ *
+ * Data has to be previously transferred with execute_transfer()
+ * or read from the file system via load().
+ */
+ void
+ unpack_cell_status(std::vector<cell_relation_t> &cell_relations) const;
+
+ /**
+ * Unpack previously transferred data on each cell registered in
+ * @p cell_relations with the provided @p unpack_callback function.
+ *
+ * The parameter @p handle corresponds to the position where the
+ * @p unpack_callback function is allowed to read from the memory. Its
+ * value needs to be in accordance with the corresponding pack_callback
+ * function that has been registered previously.
+ *
+ * Data has to be previously transferred with execute_transfer()
+ * or read from the file system via load().
+ */
+ void
+ unpack_data(
+ const std::vector<cell_relation_t> &cell_relations,
+ const unsigned int handle,
+ const std::function<
+ void(const cell_iterator &,
+ const CellStatus &,
+ const boost::iterator_range<std::vector<char>::const_iterator> &)>
+ &unpack_callback) const;
+
+ /**
+ * Transfer data to file system.
+ *
+ * The data will be written in a separate file, whose name
+ * consists of the stem @p filename and an attached identifier
+ * <tt>_fixed.data</tt> for fixed size data and <tt>_variable.data</tt>
+ * for variable size data.
+ *
+ * All processors write into these files simultaneously via MPIIO.
+ * Each processor's position to write to will be determined
+ * from the provided input parameters.
+ *
+ * Data has to be previously packed with pack_data().
+ */
+ void
+ save(const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const std::string &filename) const;
+
+ /**
+ * Transfer data from file system.
+ *
+ * The data will be read from separate file, whose name
+ * consists of the stem @p filename and an attached identifier
+ * <tt>_fixed.data</tt> for fixed size data and <tt>_variable.data</tt>
+ * for variable size data.
+ * The @p n_attached_deserialize_fixed and @p n_attached_deserialize_variable
+ * parameters are required to gather the memory offsets for each
+ * callback.
+ *
+ * All processors read from these files simultaneously via MPIIO.
+ * Each processor's position to read from will be determined
+ * from the provided input arguments.
+ *
+ * After loading, unpack_data() needs to be called to finally
+ * distribute data across the associated triangulation.
+ */
+ void
+ load(const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const unsigned int local_num_cells,
+ const std::string &filename,
+ const unsigned int n_attached_deserialize_fixed,
+ const unsigned int n_attached_deserialize_variable);
+
+ /**
+ * Clears all containers and associated data, and resets member
+ * values to their default state.
+ *
+ * Frees memory completely.
+ */
+ void
+ clear();
+
+ /**
+ * Flag that denotes if variable size data has been packed.
+ */
+ bool variable_size_data_stored;
+
+ /**
+ * Cumulative size in bytes that those functions that have called
+ * register_data_attach() want to attach to each cell. This number
+ * only pertains to fixed-sized buffers where the data attached to
+ * each cell has exactly the same size.
+ *
+ * The last entry of this container corresponds to the data size
+ * packed per cell in the fixed size buffer (which can be accessed
+ * calling <tt>sizes_fixed_cumulative.back()</tt>).
+ */
+ std::vector<unsigned int> sizes_fixed_cumulative;
+
+ /**
+ * Consecutive buffers designed for the fixed size transfer
+ * functions of p4est.
+ */
+ std::vector<char> src_data_fixed;
+ std::vector<char> dest_data_fixed;
+
+ /**
+ * Consecutive buffers designed for the variable size transfer
+ * functions of p4est.
+ */
+ std::vector<int> src_sizes_variable;
+ std::vector<int> dest_sizes_variable;
+ std::vector<char> src_data_variable;
+ std::vector<char> dest_data_variable;
+
+private:
+ MPI_Comm mpi_communicator;
+};
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+DataTransfer<dim, spacedim>::DataTransfer(const MPI_Comm mpi_communicator)
+ : variable_size_data_stored(false)
+ , mpi_communicator(mpi_communicator)
+{}
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void DataTransfer<dim, spacedim>::pack_data(
+ const std::vector<cell_relation_t> &cell_relations,
+ const std::vector<typename CellAttachedData<dim, spacedim>::pack_callback_t>
+ &pack_callbacks_fixed,
+ const std::vector<typename CellAttachedData<dim, spacedim>::pack_callback_t>
+ &pack_callbacks_variable)
+{
+ Assert(src_data_fixed.size() == 0,
+ ExcMessage("Previously packed data has not been released yet!"));
+ Assert(src_sizes_variable.size() == 0, ExcInternalError());
+
+ const unsigned int n_callbacks_fixed = pack_callbacks_fixed.size();
+ const unsigned int n_callbacks_variable = pack_callbacks_variable.size();
+
+ // Store information that we packed variable size data in
+ // a member variable for later.
+ variable_size_data_stored = (n_callbacks_variable > 0);
+
+ // If variable transfer is scheduled, we will store the data size that
+ // each variable size callback function writes in this auxiliary
+ // container. The information will be stored by each cell in this vector
+ // temporarily.
+ std::vector<unsigned int> cell_sizes_variable_cumulative(
+ n_callbacks_variable);
+
+ // Prepare the buffer structure, in which each callback function will
+ // store its data for each active cell.
+ // The outmost shell in this container construct corresponds to the
+ // data packed per cell. The next layer resembles the data that
+ // each callback function packs on the corresponding cell. These
+ // buffers are chains of chars stored in an std::vector<char>.
+ // A visualisation of the data structure:
+ /* clang-format off */
+ // | cell_1 | | cell_2 | ...
+ // || callback_1 || callback_2 |...| || callback_1 || callback_2 |...| ...
+ // |||char|char|...|||char|char|...|...| |||char|char|...|||char|char|...|...| ...
+ /* clang-format on */
+ std::vector<std::vector<std::vector<char>>> packed_fixed_size_data(
+ cell_relations.size());
+ std::vector<std::vector<std::vector<char>>> packed_variable_size_data(
+ variable_size_data_stored ? cell_relations.size() : 0);
+
+ //
+ // --------- Pack data for fixed and variable size transfer ---------
+ //
+ // Iterate over all cells, call all callback functions on each cell,
+ // and store their data in the corresponding buffer scope.
+ {
+ auto cell_rel_it = cell_relations.cbegin();
+ auto data_cell_fixed_it = packed_fixed_size_data.begin();
+ auto data_cell_variable_it = packed_variable_size_data.begin();
+ for (; cell_rel_it != cell_relations.cend(); ++cell_rel_it)
+ {
+ const auto &dealii_cell = cell_rel_it->first;
+ const auto &cell_status = cell_rel_it->second;
+
+ // Assertions about the tree structure.
+ switch (cell_status)
+ {
+ case CELL_PERSIST:
+ case CELL_REFINE:
+ // double check the condition that we will only ever attach
+ // data to active cells when we get here
+ Assert(dealii_cell->is_active(), ExcInternalError());
+ break;
+
+ case CELL_COARSEN:
+ // double check the condition that we will only ever attach
+ // data to cells with children when we get here. however, we
+ // can only tolerate one level of coarsening at a time, so
+ // check that the children are all active
+ Assert(dealii_cell->is_active() == false, ExcInternalError());
+ for (unsigned int c = 0;
+ c < GeometryInfo<dim>::max_children_per_cell;
+ ++c)
+ Assert(dealii_cell->child(c)->is_active(), ExcInternalError());
+ break;
+
+ case CELL_INVALID:
+ // do nothing on invalid cells
+ break;
+
+ default:
+ Assert(false, ExcInternalError());
+ break;
+ }
+
+ // Reserve memory corresponding to the number of callback
+ // functions that will be called.
+ // If variable size transfer is scheduled, we need to leave
+ // room for an array that holds information about how many
+ // bytes each of the variable size callback functions will
+ // write.
+ // On cells flagged with CELL_INVALID, only its CellStatus
+ // will be stored.
+ const unsigned int n_fixed_size_data_sets_on_cell =
+ 1 + ((cell_status == CELL_INVALID) ?
+ 0 :
+ ((variable_size_data_stored ? 1 : 0) + n_callbacks_fixed));
+ data_cell_fixed_it->resize(n_fixed_size_data_sets_on_cell);
+
+ // We continue with packing all data on this specific cell.
+ auto data_fixed_it = data_cell_fixed_it->begin();
+
+ // First, we pack the CellStatus information.
+ // to get consistent data sizes on each cell for the fixed size
+ // transfer, we won't allow compression
+ *data_fixed_it =
+ Utilities::pack(cell_status, /*allow_compression=*/false);
+ ++data_fixed_it;
+
+ // Proceed with all registered callback functions.
+ // Skip cells with the CELL_INVALID flag.
+ if (cell_status != CELL_INVALID)
+ {
+ // Pack fixed size data.
+ for (auto callback_it = pack_callbacks_fixed.cbegin();
+ callback_it != pack_callbacks_fixed.cend();
+ ++callback_it, ++data_fixed_it)
+ {
+ *data_fixed_it = (*callback_it)(dealii_cell, cell_status);
+ }
+
+ // Pack variable size data.
+ // If we store variable size data, we need to transfer
+ // the sizes of each corresponding callback function
+ // via fixed size transfer as well.
+ if (variable_size_data_stored)
+ {
+ const unsigned int n_variable_size_data_sets_on_cell =
+ ((cell_status == CELL_INVALID) ? 0 : n_callbacks_variable);
+ data_cell_variable_it->resize(
+ n_variable_size_data_sets_on_cell);
+
+ auto callback_it = pack_callbacks_variable.cbegin();
+ auto data_variable_it = data_cell_variable_it->begin();
+ auto sizes_variable_it = cell_sizes_variable_cumulative.begin();
+ for (; callback_it != pack_callbacks_variable.cend();
+ ++callback_it, ++data_variable_it, ++sizes_variable_it)
+ {
+ *data_variable_it =
+ (*callback_it)(dealii_cell, cell_status);
+
+ // Store data sizes for each callback function first.
+ // Make it cumulative below.
+ *sizes_variable_it = data_variable_it->size();
+ }
+
+ // Turn size vector into its cumulative representation.
+ std::partial_sum(cell_sizes_variable_cumulative.begin(),
+ cell_sizes_variable_cumulative.end(),
+ cell_sizes_variable_cumulative.begin());
+
+ // Serialize cumulative variable size vector
+ // value-by-value. This way we can circumvent the overhead
+ // of storing the container object as a whole, since we
+ // know its size by the number of registered callback
+ // functions.
+ data_fixed_it->resize(n_callbacks_variable *
+ sizeof(unsigned int));
+ for (unsigned int i = 0; i < n_callbacks_variable; ++i)
+ std::memcpy(&(data_fixed_it->at(i * sizeof(unsigned int))),
+ &(cell_sizes_variable_cumulative.at(i)),
+ sizeof(unsigned int));
+
+ ++data_fixed_it;
+ }
+
+ // Double check that we packed everything we wanted
+ // in the fixed size buffers.
+ Assert(data_fixed_it == data_cell_fixed_it->end(),
+ ExcInternalError());
+ }
+
+ ++data_cell_fixed_it;
+
+ // Increment the variable size data iterator
+ // only if we actually pack this kind of data
+ // to avoid getting out of bounds.
+ if (variable_size_data_stored)
+ ++data_cell_variable_it;
+ } // loop over cell_relations
+ }
+
+ //
+ // ----------- Gather data sizes for fixed size transfer ------------
+ //
+ // Generate a vector which stores the sizes of each callback function,
+ // including the packed CellStatus transfer.
+ // Find the very first cell that we wrote to with all callback
+ // functions (i.e. a cell that was not flagged with CELL_INVALID)
+ // and store the sizes of each buffer.
+ //
+ // To deal with the case that at least one of the processors does not
+ // own any cell at all, we will exchange the information about the data
+ // sizes among them later. The code in between is still well-defined,
+ // since the following loops will be skipped.
+ std::vector<unsigned int> local_sizes_fixed(
+ 1 + n_callbacks_fixed + (variable_size_data_stored ? 1 : 0));
+ for (const auto &data_cell : packed_fixed_size_data)
+ {
+ if (data_cell.size() == local_sizes_fixed.size())
+ {
+ auto sizes_fixed_it = local_sizes_fixed.begin();
+ auto data_fixed_it = data_cell.cbegin();
+ for (; data_fixed_it != data_cell.cend();
+ ++data_fixed_it, ++sizes_fixed_it)
+ {
+ *sizes_fixed_it = data_fixed_it->size();
+ }
+
+ break;
+ }
+ }
+
+ // Check if all cells have valid sizes.
+ for (auto data_cell_fixed_it = packed_fixed_size_data.cbegin();
+ data_cell_fixed_it != packed_fixed_size_data.cend();
+ ++data_cell_fixed_it)
+ {
+ Assert((data_cell_fixed_it->size() == 1) ||
+ (data_cell_fixed_it->size() == local_sizes_fixed.size()),
+ ExcInternalError());
+ }
+
+ // Share information about the packed data sizes
+ // of all callback functions across all processors, in case one
+ // of them does not own any cells at all.
+ std::vector<unsigned int> global_sizes_fixed(local_sizes_fixed.size());
+ Utilities::MPI::max(local_sizes_fixed,
+ this->mpi_communicator,
+ global_sizes_fixed);
+
+ // Construct cumulative sizes, since this is the only information
+ // we need from now on.
+ sizes_fixed_cumulative.resize(global_sizes_fixed.size());
+ std::partial_sum(global_sizes_fixed.begin(),
+ global_sizes_fixed.end(),
+ sizes_fixed_cumulative.begin());
+
+ //
+ // ---------- Gather data sizes for variable size transfer ----------
+ //
+ if (variable_size_data_stored)
+ {
+ src_sizes_variable.reserve(packed_variable_size_data.size());
+ for (const auto &data_cell : packed_variable_size_data)
+ {
+ int variable_data_size_on_cell = 0;
+
+ for (const auto &data : data_cell)
+ variable_data_size_on_cell += data.size();
+
+ src_sizes_variable.push_back(variable_data_size_on_cell);
+ }
+ }
+
+ //
+ // ------------------------ Build buffers ---------------------------
+ //
+ const unsigned int expected_size_fixed =
+ cell_relations.size() * sizes_fixed_cumulative.back();
+ const unsigned int expected_size_variable =
+ std::accumulate(src_sizes_variable.begin(),
+ src_sizes_variable.end(),
+ std::vector<int>::size_type(0));
+
+ // Move every piece of packed fixed size data into the consecutive
+ // buffer.
+ src_data_fixed.reserve(expected_size_fixed);
+ for (const auto &data_cell_fixed : packed_fixed_size_data)
+ {
+ // Move every fraction of packed data into the buffer
+ // reserved for this particular cell.
+ for (const auto &data_fixed : data_cell_fixed)
+ std::move(data_fixed.begin(),
+ data_fixed.end(),
+ std::back_inserter(src_data_fixed));
+
+ // If we only packed the CellStatus information
+ // (i.e. encountered a cell flagged CELL_INVALID),
+ // fill the remaining space with invalid entries.
+ // We can skip this if there is nothing else to pack.
+ if ((data_cell_fixed.size() == 1) && (sizes_fixed_cumulative.size() > 1))
+ {
+ const std::size_t bytes_skipped =
+ sizes_fixed_cumulative.back() - sizes_fixed_cumulative.front();
+
+ src_data_fixed.insert(src_data_fixed.end(),
+ bytes_skipped,
+ static_cast<char>(-1)); // invalid_char
+ }
+ }
+
+ // Move every piece of packed variable size data into the consecutive
+ // buffer.
+ if (variable_size_data_stored)
+ {
+ src_data_variable.reserve(expected_size_variable);
+ for (const auto &data_cell : packed_variable_size_data)
+ {
+ // Move every fraction of packed data into the buffer
+ // reserved for this particular cell.
+ for (const auto &data : data_cell)
+ std::move(data.begin(),
+ data.end(),
+ std::back_inserter(src_data_variable));
+ }
+ }
+
+ // Double check that we packed everything correctly.
+ Assert(src_data_fixed.size() == expected_size_fixed, ExcInternalError());
+ Assert(src_data_variable.size() == expected_size_variable,
+ ExcInternalError());
+}
+
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void DataTransfer<dim, spacedim>::unpack_cell_status(
+ std::vector<typename DataTransfer<dim, spacedim>::cell_relation_t>
+ &cell_relations) const
+{
+ Assert(sizes_fixed_cumulative.size() > 0,
+ ExcMessage("No data has been packed!"));
+ if (cell_relations.size() > 0)
+ {
+ Assert(dest_data_fixed.size() > 0,
+ ExcMessage("No data has been received!"));
+ }
+
+ // Size of CellStatus object that will be unpacked on each cell.
+ const unsigned int size = sizes_fixed_cumulative.front();
+
+ // Iterate over all cells and overwrite the CellStatus
+ // information from the transferred data.
+ // Proceed buffer iterator position to next cell after
+ // each iteration.
+ auto cell_rel_it = cell_relations.begin();
+ auto dest_fixed_it = dest_data_fixed.cbegin();
+ for (; cell_rel_it != cell_relations.end();
+ ++cell_rel_it, dest_fixed_it += sizes_fixed_cumulative.back())
+ {
+ cell_rel_it->second = // cell_status
+ Utilities::unpack<CellStatus>(dest_fixed_it,
+ dest_fixed_it + size,
+ /*allow_compression=*/false);
+ }
+}
+
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void DataTransfer<dim, spacedim>::unpack_data(
+ const std::vector<typename DataTransfer<dim, spacedim>::cell_relation_t>
+ & cell_relations,
+ const unsigned int handle,
+ const std::function<
+ void(const cell_iterator &,
+ const CellStatus &,
+ const boost::iterator_range<std::vector<char>::const_iterator> &)>
+ &unpack_callback) const
+{
+ // We decode the handle returned by register_data_attach() back into
+ // a format we can use. All even handles belong to those callback
+ // functions which write/read variable size data, all odd handles
+ // interact with fixed size buffers.
+ const bool callback_variable_transfer = (handle % 2 == 0);
+ const unsigned int callback_index = handle / 2;
+
+ // Cells will always receive fixed size data (i.e., CellStatus
+ // information), but not necessarily variable size data (e.g., with a
+ // ParticleHandler a cell might not contain any particle at all).
+ // Thus it is sufficient to check if fixed size data has been received.
+ Assert(sizes_fixed_cumulative.size() > 0,
+ ExcMessage("No data has been packed!"));
+ if (cell_relations.size() > 0)
+ {
+ Assert(dest_data_fixed.size() > 0,
+ ExcMessage("No data has been received!"));
+ }
+
+ std::vector<char>::const_iterator dest_data_it;
+ std::vector<char>::const_iterator dest_sizes_cell_it;
+
+ // Depending on whether our callback function unpacks fixed or
+ // variable size data, we have to pursue different approaches
+ // to localize the correct fraction of the buffer from which
+ // we are allowed to read.
+ unsigned int offset = numbers::invalid_unsigned_int;
+ unsigned int size = numbers::invalid_unsigned_int;
+ unsigned int data_increment = numbers::invalid_unsigned_int;
+
+ if (callback_variable_transfer)
+ {
+ // For the variable size data, we need to extract the
+ // data size from the fixed size buffer on each cell.
+ //
+ // We packed this information last, so the last packed
+ // object in the fixed size buffer corresponds to the
+ // variable data sizes.
+ //
+ // The last entry of sizes_fixed_cumulative corresponds
+ // to the size of all fixed size data packed on the cell.
+ // To get the offset for the last packed object, we need
+ // to get the next-to-last entry.
+ const unsigned int offset_variable_data_sizes =
+ sizes_fixed_cumulative[sizes_fixed_cumulative.size() - 2];
+
+ // This iterator points to the data size that the
+ // callback_function packed for each specific cell.
+ // Adjust buffer iterator to the offset of the callback
+ // function so that we only have to advance its position
+ // to the next cell after each iteration.
+ dest_sizes_cell_it = dest_data_fixed.cbegin() +
+ offset_variable_data_sizes +
+ callback_index * sizeof(unsigned int);
+
+ // Let the data iterator point to the correct buffer.
+ dest_data_it = dest_data_variable.cbegin();
+ }
+ else
+ {
+ // For the fixed size data, we can get the information about
+ // the buffer location on each cell directly from the
+ // sizes_fixed_cumulative vector.
+ offset = sizes_fixed_cumulative[callback_index];
+ size = sizes_fixed_cumulative[callback_index + 1] - offset;
+ data_increment = sizes_fixed_cumulative.back();
+
+ // Let the data iterator point to the correct buffer.
+ // Adjust buffer iterator to the offset of the callback
+ // function so that we only have to advance its position
+ // to the next cell after each iteration.
+ if (cell_relations.begin() != cell_relations.end())
+ dest_data_it = dest_data_fixed.cbegin() + offset;
+ }
+
+ // Iterate over all cells and unpack the transferred data.
+ auto cell_rel_it = cell_relations.begin();
+ auto dest_sizes_it = dest_sizes_variable.cbegin();
+ for (; cell_rel_it != cell_relations.end(); ++cell_rel_it)
+ {
+ const auto &dealii_cell = cell_rel_it->first;
+ const auto &cell_status = cell_rel_it->second;
+
+ if (callback_variable_transfer)
+ {
+ // Update the increment according to the whole data size
+ // of the current cell.
+ data_increment = *dest_sizes_it;
+
+ if (cell_status != CELL_INVALID)
+ {
+ // Extract the corresponding values for offset and size from
+ // the cumulative sizes array stored in the fixed size
+ // buffer.
+ if (callback_index == 0)
+ offset = 0;
+ else
+ std::memcpy(&offset,
+ &(*(dest_sizes_cell_it - sizeof(unsigned int))),
+ sizeof(unsigned int));
+
+ std::memcpy(&size, &(*dest_sizes_cell_it), sizeof(unsigned int));
+
+ size -= offset;
+
+ // Move the data iterator to the corresponding position
+ // of the callback function and adjust the increment
+ // accordingly.
+ dest_data_it += offset;
+ data_increment -= offset;
+ }
+
+ // Advance data size iterators to the next cell, avoid iterating
+ // past the end of dest_sizes_cell_it
+ if (cell_rel_it != cell_relations.end() - 1)
+ dest_sizes_cell_it += sizes_fixed_cumulative.back();
+ ++dest_sizes_it;
+ }
+
+ switch (cell_status)
+ {
+ case CELL_PERSIST:
+ case CELL_COARSEN:
+ unpack_callback(dealii_cell,
+ cell_status,
+ boost::make_iterator_range(dest_data_it,
+ dest_data_it + size));
+ break;
+
+ case CELL_REFINE:
+ unpack_callback(dealii_cell->parent(),
+ cell_status,
+ boost::make_iterator_range(dest_data_it,
+ dest_data_it + size));
+ break;
+
+ case CELL_INVALID:
+ // Skip this cell.
+ break;
+
+ default:
+ Assert(false, ExcInternalError());
+ break;
+ }
+
+ if (cell_rel_it != cell_relations.end() - 1)
+ dest_data_it += data_increment;
+ }
+}
+
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void DataTransfer<dim, spacedim>::save(const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const std::string &filename) const
+{
+#ifdef DEAL_II_WITH_MPI
+ // Large fractions of this function have been copied from
+ // DataOutInterface::write_vtu_in_parallel.
+ // TODO: Write general MPIIO interface.
+
+ Assert(sizes_fixed_cumulative.size() > 0,
+ ExcMessage("No data has been packed!"));
+
+ const int myrank = Utilities::MPI::this_mpi_process(mpi_communicator);
+
+ const unsigned int bytes_per_cell = sizes_fixed_cumulative.back();
+
+ //
+ // ---------- Fixed size data ----------
+ //
+ {
+ const std::string fname_fixed = std::string(filename) + "_fixed.data";
+
+ MPI_Info info;
+ int ierr = MPI_Info_create(&info);
+ AssertThrowMPI(ierr);
+
+ MPI_File fh;
+ ierr = MPI_File_open(mpi_communicator,
+ fname_fixed.c_str(),
+ MPI_MODE_CREATE | MPI_MODE_WRONLY,
+ info,
+ &fh);
+ AssertThrowMPI(ierr);
+
+ ierr = MPI_File_set_size(fh, 0); // delete the file contents
+ AssertThrowMPI(ierr);
+ // this barrier is necessary, because otherwise others might already
+ // write while one core is still setting the size to zero.
+ ierr = MPI_Barrier(mpi_communicator);
+ AssertThrowMPI(ierr);
+ ierr = MPI_Info_free(&info);
+ AssertThrowMPI(ierr);
+ // ------------------
+
+ // Write cumulative sizes to file.
+ // Since each processor owns the same information about the data
+ // sizes, it is sufficient to let only the first processor perform
+ // this task.
+ if (myrank == 0)
+ {
+ ierr = Utilities::MPI::LargeCount::File_write_at_c(
+ fh,
+ 0,
+ sizes_fixed_cumulative.data(),
+ sizes_fixed_cumulative.size(),
+ MPI_UNSIGNED,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+ }
+
+ // Write packed data to file simultaneously.
+ const MPI_Offset size_header =
+ sizes_fixed_cumulative.size() * sizeof(unsigned int);
+
+ // Make sure we do the following computation in 64bit integers to be
+ // able to handle 4GB+ files:
+ const MPI_Offset my_global_file_position =
+ size_header + static_cast<MPI_Offset>(global_first_cell) * bytes_per_cell;
+
+ ierr = Utilities::MPI::LargeCount::File_write_at_c(fh,
+ my_global_file_position,
+ src_data_fixed.data(),
+ src_data_fixed.size(),
+ MPI_BYTE,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+
+ ierr = MPI_File_close(&fh);
+ AssertThrowMPI(ierr);
+ }
+
+
+
+ //
+ // ---------- Variable size data ----------
+ //
+ if (variable_size_data_stored)
+ {
+ const std::string fname_variable =
+ std::string(filename) + "_variable.data";
+
+ MPI_Info info;
+ int ierr = MPI_Info_create(&info);
+ AssertThrowMPI(ierr);
+
+ MPI_File fh;
+ ierr = MPI_File_open(mpi_communicator,
+ fname_variable.c_str(),
+ MPI_MODE_CREATE | MPI_MODE_WRONLY,
+ info,
+ &fh);
+ AssertThrowMPI(ierr);
+
+ ierr = MPI_File_set_size(fh, 0); // delete the file contents
+ AssertThrowMPI(ierr);
+ // this barrier is necessary, because otherwise others might already
+ // write while one core is still setting the size to zero.
+ ierr = MPI_Barrier(mpi_communicator);
+ AssertThrowMPI(ierr);
+ ierr = MPI_Info_free(&info);
+ AssertThrowMPI(ierr);
+
+ // Write sizes of each cell into file simultaneously.
+ {
+ const MPI_Offset my_global_file_position =
+ static_cast<MPI_Offset>(global_first_cell) * sizeof(unsigned int);
+
+ // It is very unlikely that a single process has more than
+ // 2 billion cells, but we might as well check.
+ AssertThrow(src_sizes_variable.size() <
+ static_cast<std::size_t>(std::numeric_limits<int>::max()),
+ ExcNotImplemented());
+
+ ierr =
+ Utilities::MPI::LargeCount::File_write_at_c(fh,
+ my_global_file_position,
+ src_sizes_variable.data(),
+ src_sizes_variable.size(),
+ MPI_INT,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+ }
+
+ // Gather size of data in bytes we want to store from this
+ // processor and compute the prefix sum. We do this in 64 bit
+ // to avoid overflow for files larger than 4GB:
+ const std::uint64_t size_on_proc = src_data_variable.size();
+ std::uint64_t prefix_sum = 0;
+ ierr = MPI_Exscan(
+ &size_on_proc, &prefix_sum, 1, MPI_UINT64_T, MPI_SUM, mpi_communicator);
+ AssertThrowMPI(ierr);
+
+ const MPI_Offset my_global_file_position =
+ static_cast<MPI_Offset>(global_num_cells) * sizeof(unsigned int) +
+ prefix_sum;
+
+ // Write data consecutively into file.
+ ierr =
+ Utilities::MPI::LargeCount::File_write_at_c(fh,
+ my_global_file_position,
+ src_data_variable.data(),
+ src_data_variable.size(),
+ MPI_BYTE,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+
+
+ ierr = MPI_File_close(&fh);
+ AssertThrowMPI(ierr);
+ }
+#else
+ (void)global_first_cell;
+ (void)global_num_cells;
+ (void)filename;
+
+ AssertThrow(false, ExcNeedsMPI());
+#endif
+}
+
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void DataTransfer<dim, spacedim>::load(
+ const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const unsigned int local_num_cells,
+ const std::string &filename,
+ const unsigned int n_attached_deserialize_fixed,
+ const unsigned int n_attached_deserialize_variable)
+{
+#ifdef DEAL_II_WITH_MPI
+ // Large fractions of this function have been copied from
+ // DataOutInterface::write_vtu_in_parallel.
+ // TODO: Write general MPIIO interface.
+
+ Assert(dest_data_fixed.size() == 0,
+ ExcMessage("Previously loaded data has not been released yet!"));
+
+ variable_size_data_stored = (n_attached_deserialize_variable > 0);
+
+ //
+ // ---------- Fixed size data ----------
+ //
+ {
+ const std::string fname_fixed = std::string(filename) + "_fixed.data";
+
+ MPI_Info info;
+ int ierr = MPI_Info_create(&info);
+ AssertThrowMPI(ierr);
+
+ MPI_File fh;
+ ierr = MPI_File_open(
+ mpi_communicator, fname_fixed.c_str(), MPI_MODE_RDONLY, info, &fh);
+ AssertThrowMPI(ierr);
+
+ ierr = MPI_Info_free(&info);
+ AssertThrowMPI(ierr);
+
+ // Read cumulative sizes from file.
+ // Since all processors need the same information about the data
+ // sizes, let each of them retrieve it by reading from the same
+ // location in the file.
+ sizes_fixed_cumulative.resize(1 + n_attached_deserialize_fixed +
+ (variable_size_data_stored ? 1 : 0));
+ ierr =
+ Utilities::MPI::LargeCount::File_read_at_c(fh,
+ 0,
+ sizes_fixed_cumulative.data(),
+ sizes_fixed_cumulative.size(),
+ MPI_UNSIGNED,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+
+ // Allocate sufficient memory.
+ const unsigned int bytes_per_cell = sizes_fixed_cumulative.back();
+ dest_data_fixed.resize(static_cast<size_t>(local_num_cells) *
+ bytes_per_cell);
+
+ // Read packed data from file simultaneously.
+ const MPI_Offset size_header =
+ sizes_fixed_cumulative.size() * sizeof(unsigned int);
+
+ // Make sure we do the following computation in 64bit integers to be
+ // able to handle 4GB+ files:
+ const MPI_Offset my_global_file_position =
+ size_header + static_cast<MPI_Offset>(global_first_cell) * bytes_per_cell;
+
+ ierr = Utilities::MPI::LargeCount::File_read_at_c(fh,
+ my_global_file_position,
+ dest_data_fixed.data(),
+ dest_data_fixed.size(),
+ MPI_BYTE,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+
+
+ ierr = MPI_File_close(&fh);
+ AssertThrowMPI(ierr);
+ }
+
+ //
+ // ---------- Variable size data ----------
+ //
+ if (variable_size_data_stored)
+ {
+ const std::string fname_variable =
+ std::string(filename) + "_variable.data";
+
+ MPI_Info info;
+ int ierr = MPI_Info_create(&info);
+ AssertThrowMPI(ierr);
+
+ MPI_File fh;
+ ierr = MPI_File_open(
+ mpi_communicator, fname_variable.c_str(), MPI_MODE_RDONLY, info, &fh);
+ AssertThrowMPI(ierr);
+
+ ierr = MPI_Info_free(&info);
+ AssertThrowMPI(ierr);
+
+ // Read sizes of all locally owned cells.
+ dest_sizes_variable.resize(local_num_cells);
+
+ const MPI_Offset my_global_file_position_sizes =
+ static_cast<MPI_Offset>(global_first_cell) * sizeof(unsigned int);
+
+ ierr = Utilities::MPI::LargeCount::File_read_at_c(
+ fh,
+ my_global_file_position_sizes,
+ dest_sizes_variable.data(),
+ dest_sizes_variable.size(),
+ MPI_INT,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+
+
+ // Compute my data size in bytes and compute prefix sum. We do this
+ // in 64 bit to avoid overflow for files larger than 4 GB:
+ const std::uint64_t size_on_proc =
+ std::accumulate(dest_sizes_variable.begin(),
+ dest_sizes_variable.end(),
+ 0ULL);
+
+ std::uint64_t prefix_sum = 0;
+ ierr = MPI_Exscan(
+ &size_on_proc, &prefix_sum, 1, MPI_UINT64_T, MPI_SUM, mpi_communicator);
+ AssertThrowMPI(ierr);
+
+ const MPI_Offset my_global_file_position =
+ static_cast<MPI_Offset>(global_num_cells) * sizeof(unsigned int) +
+ prefix_sum;
+
+ dest_data_variable.resize(size_on_proc);
+
+ ierr =
+ Utilities::MPI::LargeCount::File_read_at_c(fh,
+ my_global_file_position,
+ dest_data_variable.data(),
+ dest_data_variable.size(),
+ MPI_BYTE,
+ MPI_STATUS_IGNORE);
+ AssertThrowMPI(ierr);
+
+ ierr = MPI_File_close(&fh);
+ AssertThrowMPI(ierr);
+ }
+#else
+ (void)global_first_cell;
+ (void)global_num_cells;
+ (void)local_num_cells;
+ (void)filename;
+ (void)n_attached_deserialize_fixed;
+ (void)n_attached_deserialize_variable;
+
+ AssertThrow(false, ExcNeedsMPI());
+#endif
+}
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void DataTransfer<dim, spacedim>::clear()
+{
+ variable_size_data_stored = false;
+
+ // free information about data sizes
+ sizes_fixed_cumulative.clear();
+ sizes_fixed_cumulative.shrink_to_fit();
+
+ // free fixed size transfer data
+ src_data_fixed.clear();
+ src_data_fixed.shrink_to_fit();
+
+ dest_data_fixed.clear();
+ dest_data_fixed.shrink_to_fit();
+
+ // free variable size transfer data
+ src_sizes_variable.clear();
+ src_sizes_variable.shrink_to_fit();
+
+ src_data_variable.clear();
+ src_data_variable.shrink_to_fit();
+
+ dest_sizes_variable.clear();
+ dest_sizes_variable.shrink_to_fit();
+
+ dest_data_variable.clear();
+ dest_data_variable.shrink_to_fit();
+}
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
#include <deal.II/base/subscriptor.h>
#include <deal.II/grid/cell_id.h>
+#include <deal.II/grid/cell_status.h>
+#include <deal.II/grid/data_transfer.h>
#include <deal.II/grid/tria_description.h>
#include <deal.II/grid/tria_iterator_selector.h>
#include <deal.II/grid/tria_levels.h>
*/
- /**
- * Used to inform functions in derived classes how the cell with the given
- * cell_iterator is going to change. Note that this may me different than
- * the refine_flag() and coarsen_flag() in the cell_iterator in parallel
- * calculations because of refinement constraints that this machine does not
- * see.
- */
- enum CellStatus
- {
- /**
- * The cell will not be refined or coarsened and might or might not move
- * to a different processor.
- */
- CELL_PERSIST,
- /**
- * The cell will be or was refined.
- */
- CELL_REFINE,
- /**
- * The children of this cell will be or were coarsened into this cell.
- */
- CELL_COARSEN,
- /**
- * Invalid status. Will not occur for the user.
- */
- CELL_INVALID
- };
-
/**
* A structure used to accumulate the results of the `weight` signal slot
* functions below. It takes an iterator range and returns the sum of
BOOST_SERIALIZATION_SPLIT_MEMBER()
#endif
+ /**
+ * @name Serialization facilities.
+ * @{
+ */
+public:
+ /**
+ * Register a function that can be used to attach data of fixed size
+ * to cells. This is useful for two purposes: (i) Upon refinement and
+ * coarsening of a triangulation (@a e.g. in
+ * parallel::distributed::Triangulation::execute_coarsening_and_refinement()),
+ * one needs to be able to store one or more data vectors per cell that
+ * characterizes the solution values on the cell so that this data can
+ * then be transferred to the new owning processor of the cell (or
+ * its parent/children) when the mesh is re-partitioned; (ii) when
+ * serializing a computation to a file, it is necessary to attach
+ * data to cells so that it can be saved (@a e.g. in
+ * parallel::distributed::Triangulation::save()) along with the cell's
+ * other information and, if necessary, later be reloaded from disk
+ * with a different subdivision of cells among the processors.
+ *
+ * The way this function works is that it allows any number of interest
+ * parties to register their intent to attach data to cells. One example
+ * of classes that do this is parallel::distributed::SolutionTransfer
+ * where each parallel::distributed::SolutionTransfer object that works
+ * on the current Triangulation object then needs to register its intent.
+ * Each of these parties registers a callback function (the first
+ * argument here, @p pack_callback) that will be called whenever the
+ * triangulation's execute_coarsening_and_refinement() or save()
+ * functions are called.
+ *
+ * The current function then returns an integer handle that corresponds
+ * to the number of data set that the callback provided here will attach.
+ * While this number could be given a precise meaning, this is
+ * not important: You will never actually have to do anything with
+ * this number except return it to the notify_ready_to_unpack() function.
+ * In other words, each interested party (i.e., the caller of the current
+ * function) needs to store their respective returned handle for later use
+ * when unpacking data in the callback provided to
+ * notify_ready_to_unpack().
+ *
+ * Whenever @p pack_callback is then called by
+ * execute_coarsening_and_refinement() or load() on a given cell, it
+ * receives a number of arguments. In particular, the first
+ * argument passed to the callback indicates the cell for which
+ * it is supposed to attach data. This is always an active cell.
+ *
+ * The second, CellStatus, argument provided to the callback function
+ * will tell you if the given cell will be coarsened, refined, or will
+ * persist as is. (This status may be different than the refinement
+ * or coarsening flags set on that cell, to accommodate things such as
+ * the "one hanging node per edge" rule.). These flags need to be
+ * read in context with the p4est quadrant they belong to, as their
+ * relations are gathered in local_cell_relations.
+ *
+ * Specifically, the values for this argument mean the following:
+ *
+ * - `CELL_PERSIST`: The cell won't be refined/coarsened, but might be
+ * moved to a different processor. If this is the case, the callback
+ * will want to pack up the data on this cell into an array and store
+ * it at the provided address for later unpacking wherever this cell
+ * may land.
+ * - `CELL_REFINE`: This cell will be refined into 4 or 8 cells (in 2d
+ * and 3d, respectively). However, because these children don't exist
+ * yet, you cannot access them at the time when the callback is
+ * called. Thus, in local_cell_relations, the corresponding
+ * p4est quadrants of the children cells are linked to the deal.II
+ * cell which is going to be refined. To be specific, only the very
+ * first child is marked with `CELL_REFINE`, whereas the others will be
+ * marked with `CELL_INVALID`, which indicates that these cells will be
+ * ignored by default during the packing or unpacking process. This
+ * ensures that data is only transferred once onto or from the parent
+ * cell. If the callback is called with `CELL_REFINE`, the callback
+ * will want to pack up the data on this cell into an array and store
+ * it at the provided address for later unpacking in a way so that
+ * it can then be transferred to the children of the cell that will
+ * then be available. In other words, if the data the callback
+ * will want to pack up corresponds to a finite element field, then
+ * the prolongation from parent to (new) children will have to happen
+ * during unpacking.
+ * - `CELL_COARSEN`: The children of this cell will be coarsened into the
+ * given cell. These children still exist, so if this is the value
+ * given to the callback as second argument, the callback will want
+ * to transfer data from the children to the current parent cell and
+ * pack it up so that it can later be unpacked again on a cell that
+ * then no longer has any children (and may also be located on a
+ * different processor). In other words, if the data the callback
+ * will want to pack up corresponds to a finite element field, then
+ * it will need to do the restriction from children to parent at
+ * this point.
+ * - `CELL_INVALID`: See `CELL_REFINE`.
+ *
+ * @note If this function is used for serialization of data
+ * using save() and load(), then the cell status argument with which
+ * the callback is called will always be `CELL_PERSIST`.
+ *
+ * The callback function is expected to return a memory chunk of the
+ * format `std::vector<char>`, representing the packed data on a
+ * certain cell.
+ *
+ * The second parameter @p returns_variable_size_data indicates whether
+ * the returned size of the memory region from the callback function
+ * varies by cell (<tt>=true</tt>) or stays constant on each one
+ * throughout the whole domain (<tt>=false</tt>).
+ *
+ * @note The purpose of this function is to register intent to
+ * attach data for a single, subsequent call to
+ * execute_coarsening_and_refinement() and notify_ready_to_unpack(),
+ * save(), load(). Consequently, notify_ready_to_unpack(), save(),
+ * and load() all forget the registered callbacks once these
+ * callbacks have been called, and you will have to re-register
+ * them with a triangulation if you want them to be active for
+ * another call to these functions.
+ */
+ unsigned int
+ register_data_attach(
+ const std::function<std::vector<char>(const cell_iterator &,
+ const CellStatus)> &pack_callback,
+ const bool returns_variable_size_data);
+
+ /**
+ * This function is the opposite of register_data_attach(). It is called
+ * <i>after</i> the execute_coarsening_and_refinement() or save()/load()
+ * functions are done when classes and functions that have previously
+ * attached data to a triangulation for either transfer to other
+ * processors, across mesh refinement, or serialization of data to
+ * a file are ready to receive that data back. The important part about
+ * this process is that the triangulation cannot do this right away from
+ * the end of execute_coarsening_and_refinement() or load() via a
+ * previously attached callback function (as the register_data_attach()
+ * function does) because the classes that eventually want the data
+ * back may need to do some setup between the point in time where the
+ * mesh has been recreated and when the data can actually be received.
+ * An example is the parallel::distributed::SolutionTransfer class
+ * that can really only receive the data once not only the mesh is
+ * completely available again on the current processor, but only
+ * after a DoFHandler has been reinitialized and distributed
+ * degrees of freedom. In other words, there is typically a significant
+ * amount of set up that needs to happen in user space before the classes
+ * that can receive data attached to cell are ready to actually do so.
+ * When they are, they use the current function to tell the triangulation
+ * object that now is the time when they are ready by calling the
+ * current function.
+ *
+ * The supplied callback function is then called for each newly locally
+ * owned cell. The first argument to the callback is an iterator that
+ * designates the cell; the second argument indicates the status of the
+ * cell in question; and the third argument localizes a memory area by
+ * two iterators that contains the data that was previously saved from
+ * the callback provided to register_data_attach().
+ *
+ * The CellStatus will indicate if the cell was refined, coarsened, or
+ * persisted unchanged. The @p cell_iterator argument to the callback
+ * will then either be an active,
+ * locally owned cell (if the cell was not refined), or the immediate
+ * parent if it was refined during execute_coarsening_and_refinement().
+ * Therefore, contrary to during register_data_attach(), you can now
+ * access the children if the status is `CELL_REFINE` but no longer for
+ * callbacks with status `CELL_COARSEN`.
+ *
+ * The first argument to this function, `handle`, corresponds to
+ * the return value of register_data_attach(). (The precise
+ * meaning of what the numeric value of this handle is supposed
+ * to represent is neither important, nor should you try to use
+ * it for anything other than transmit information between a
+ * call to register_data_attach() to the corresponding call to
+ * notify_ready_to_unpack().)
+ */
+ void
+ notify_ready_to_unpack(
+ const unsigned int handle,
+ const std::function<
+ void(const cell_iterator &,
+ const CellStatus,
+ const boost::iterator_range<std::vector<char>::const_iterator> &)>
+ &unpack_callback);
+
+ CellAttachedData<dim, spacedim> cell_attached_data;
+
+protected:
+ /**
+ * Save additional cell-attached data into the given file. The first
+ * arguments are used to determine the offsets where to write buffers to.
+ *
+ * Called by @ref save.
+ */
+ void
+ save_attached_data(const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const std::string &filename) const;
+
+ /**
+ * Load additional cell-attached data from the given file, if any was saved.
+ * The first arguments are used to determine the offsets where to read
+ * buffers from.
+ *
+ * Called by @ref load.
+ */
+ void
+ load_attached_data(const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const unsigned int local_num_cells,
+ const std::string &filename,
+ const unsigned int n_attached_deserialize_fixed,
+ const unsigned int n_attached_deserialize_variable);
+
+ /**
+ * A function to record the CellStatus of currently active cells that
+ * are locally owned. This information is mandatory to transfer data
+ * between meshes during adaptation or serialization, e.g., using
+ * parallel::distributed::SolutionTransfer.
+ *
+ * Relations will be stored in the private member local_cell_relations. For
+ * an extensive description of CellStatus, see the documentation for the
+ * member function register_data_attach().
+ */
+ virtual void
+ update_cell_relations()
+ {}
+
+ /**
+ * Vector of pairs, each containing a deal.II cell iterator and its
+ * respective CellStatus. To update its contents, use the
+ * update_cell_relations() member function.
+ */
+ std::vector<typename DataTransfer<dim, spacedim>::cell_relation_t>
+ local_cell_relations;
+
+ std::unique_ptr<DataTransfer<dim, spacedim>> data_transfer;
+ /**
+ * @}
+ */
+
+public:
/**
* @name Exceptions
* @{
std::vector<char>
pack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename Triangulation<dim, spacedim>::CellStatus status) const;
+ const CellStatus status) const;
/**
* Called by listener functions after a refinement step for each cell
void
unpack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename Triangulation<dim, spacedim>::CellStatus status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
&data_range);
template <int dim, int spacedim>
std::function<unsigned int(
const typename dealii::Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename dealii::Triangulation<dim, spacedim>::CellStatus status)>
+ const CellStatus status)>
CellWeights<dim, spacedim>::make_weighting_callback(
const DoFHandler<dim, spacedim> &dof_handler,
const typename CellWeights<dim, spacedim>::WeightingFunction
ExcMessage(
"parallel::CellWeights requires a parallel::TriangulationBase object."));
- return
- [&dof_handler, tria, weighting_function](
- const typename dealii::Triangulation<dim, spacedim>::cell_iterator
- & cell,
- const typename dealii::Triangulation<dim, spacedim>::CellStatus status)
- -> unsigned int {
- return CellWeights<dim, spacedim>::weighting_callback(
- cell,
- status,
- std::cref(dof_handler),
- std::cref(*tria),
- weighting_function);
- };
+ return [&dof_handler, tria, weighting_function](
+ const typename dealii::Triangulation<dim, spacedim>::cell_iterator
+ & cell,
+ const CellStatus status) -> unsigned int {
+ return CellWeights<dim, spacedim>::weighting_callback(cell,
+ status,
+ std::cref(
+ dof_handler),
+ std::cref(*tria),
+ weighting_function);
+ };
}
unsigned int
CellWeights<dim, spacedim>::weighting_callback(
const typename dealii::Triangulation<dim, spacedim>::cell_iterator &cell_,
- const typename dealii::Triangulation<dim, spacedim>::CellStatus status,
+ const CellStatus status,
const DoFHandler<dim, spacedim> & dof_handler,
const parallel::TriangulationBase<dim, spacedim> &triangulation,
const typename CellWeights<dim, spacedim>::WeightingFunction
unsigned int fe_index = numbers::invalid_unsigned_int;
switch (status)
{
- case Triangulation<dim, spacedim>::CELL_PERSIST:
- case Triangulation<dim, spacedim>::CELL_REFINE:
- case Triangulation<dim, spacedim>::CELL_INVALID:
+ case CELL_PERSIST:
+ case CELL_REFINE:
+ case CELL_INVALID:
fe_index = cell->future_fe_index();
break;
- case Triangulation<dim, spacedim>::CELL_COARSEN:
+ case CELL_COARSEN:
#ifdef DEBUG
for (const auto &child : cell->child_iterators())
Assert(child->is_active() && child->coarsen_flag_set(),
for (const auto &cell : this->active_cell_iterators())
if (cell->is_locally_owned())
- this->local_cell_relations.emplace_back(
- cell, Triangulation<dim, spacedim>::CELL_PERSIST);
+ this->local_cell_relations.emplace_back(cell, CELL_PERSIST);
}
CellWeightPolicy<dim, spacedim>::CellWeightPolicy(
const std::function<
unsigned int(const typename Triangulation<dim, spacedim>::cell_iterator &,
- const typename Triangulation<dim, spacedim>::CellStatus)>
- &weighting_function)
+ const CellStatus)> &weighting_function)
: weighting_function(weighting_function)
{}
for (const auto &cell :
tria->active_cell_iterators() | IteratorFilters::LocallyOwnedCell())
weights[partitioner->global_to_local(cell->global_active_cell_index())] =
- weighting_function(
- cell, Triangulation<dim, spacedim>::CellStatus::CELL_PERSIST);
+ weighting_function(cell, CELL_PERSIST);
// determine weight of all the cells locally owned by this process
std::uint64_t process_local_weight = 0;
handle = tria->register_data_attach(
[this](
const typename Triangulation<dim, spacedim>::cell_iterator &cell_,
- const typename Triangulation<dim, spacedim>::CellStatus status) {
+ const CellStatus status) {
return this->pack_callback(cell_, status);
},
/*returns_variable_size_data=*/dof_handler->has_hp_capabilities());
handle,
[this, &all_out, &valence](
const typename Triangulation<dim, spacedim>::cell_iterator &cell_,
- const typename Triangulation<dim, spacedim>::CellStatus status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
&data_range) {
this->unpack_callback(cell_, status, data_range, all_out, valence);
std::vector<char>
SolutionTransfer<dim, VectorType, spacedim>::pack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator &cell_,
- const typename Triangulation<dim, spacedim>::CellStatus status)
+ const CellStatus status)
{
typename DoFHandler<dim, spacedim>::cell_iterator cell(*cell_,
dof_handler);
{
switch (status)
{
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_PERSIST:
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_REFINE:
+ case CELL_PERSIST:
+ case CELL_REFINE:
{
fe_index = cell->future_fe_index();
break;
}
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_COARSEN:
+ case CELL_COARSEN:
{
// In case of coarsening, we need to find a suitable FE index
// for the parent cell. We choose the 'least dominant fe'
void
SolutionTransfer<dim, VectorType, spacedim>::unpack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator &cell_,
- const typename Triangulation<dim, spacedim>::CellStatus status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator>
& data_range,
std::vector<VectorType *> &all_out,
{
switch (status)
{
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_PERSIST:
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_COARSEN:
+ case CELL_PERSIST:
+ case CELL_COARSEN:
{
fe_index = cell->active_fe_index();
break;
}
- case parallel::distributed::Triangulation<dim,
- spacedim>::CELL_REFINE:
+ case CELL_REFINE:
{
// After refinement, this particular cell is no longer active,
// and its children have inherited its FE index. However, to
template <int dim, int spacedim>
using cell_relation_t = typename std::pair<
typename dealii::Triangulation<dim, spacedim>::cell_iterator,
- typename dealii::Triangulation<dim, spacedim>::CellStatus>;
+ CellStatus>;
/**
* Adds a pair of a @p dealii_cell and its @p status
const typename dealii::internal::p4est::types<dim>::tree & tree,
const unsigned int idx,
const typename Triangulation<dim, spacedim>::cell_iterator &dealii_cell,
- const typename Triangulation<dim, spacedim>::CellStatus status)
+ const CellStatus status)
{
const unsigned int local_quadrant_index = tree.quadrants_offset + idx;
// this active cell didn't change
// save pair into corresponding position
add_single_cell_relation<dim, spacedim>(
- cell_rel,
- tree,
- idx,
- dealii_cell,
- Triangulation<dim, spacedim>::CELL_PERSIST);
+ cell_rel, tree, idx, dealii_cell, CELL_PERSIST);
}
else if (p4est_has_children) // based on the conditions above, we know that
// dealii_cell has no children
// mark first child with CELL_REFINE and the remaining children with
// CELL_INVALID, but associate them all with the parent cell unpack
// algorithm will be called only on CELL_REFINE flagged quadrant
- int child_idx;
- typename Triangulation<dim, spacedim>::CellStatus cell_status;
+ int child_idx;
+ CellStatus cell_status;
for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_cell;
++i)
{
&p4est_child[i],
dealii::internal::p4est::functions<dim>::quadrant_compare);
- cell_status = (i == 0) ? Triangulation<dim, spacedim>::CELL_REFINE :
- Triangulation<dim, spacedim>::CELL_INVALID;
+ cell_status = (i == 0) ? CELL_REFINE : CELL_INVALID;
add_single_cell_relation<dim, spacedim>(
cell_rel, tree, child_idx, dealii_cell, cell_status);
// its children got coarsened into this cell in p4est,
// but the dealii_cell still has its children
add_single_cell_relation<dim, spacedim>(
- cell_rel,
- tree,
- idx,
- dealii_cell,
- Triangulation<dim, spacedim>::CELL_COARSEN);
+ cell_rel, tree, idx, dealii_cell, CELL_COARSEN);
}
}
} // namespace
const typename dealii::internal::p4est::types<dim>::gloidx
*previous_global_first_quadrant)
{
- Assert(this->data_transfer.sizes_fixed_cumulative.size() > 0,
+ Assert(this->data_transfer->sizes_fixed_cumulative.size() > 0,
ExcMessage("No data has been packed!"));
// Resize memory according to the data that we will receive.
- this->data_transfer.dest_data_fixed.resize(
+ this->data_transfer->dest_data_fixed.resize(
parallel_forest->local_num_quadrants *
- this->data_transfer.sizes_fixed_cumulative.back());
+ this->data_transfer->sizes_fixed_cumulative.back());
// Execute non-blocking fixed size transfer.
typename dealii::internal::p4est::types<dim>::transfer_context
previous_global_first_quadrant,
parallel_forest->mpicomm,
0,
- this->data_transfer.dest_data_fixed.data(),
- this->data_transfer.src_data_fixed.data(),
- this->data_transfer.sizes_fixed_cumulative.back());
+ this->data_transfer->dest_data_fixed.data(),
+ this->data_transfer->src_data_fixed.data(),
+ this->data_transfer->sizes_fixed_cumulative.back());
- if (this->data_transfer.variable_size_data_stored)
+ if (this->data_transfer->variable_size_data_stored)
{
// Resize memory according to the data that we will receive.
- this->data_transfer.dest_sizes_variable.resize(
+ this->data_transfer->dest_sizes_variable.resize(
parallel_forest->local_num_quadrants);
// Execute fixed size transfer of data sizes for variable size
previous_global_first_quadrant,
parallel_forest->mpicomm,
1,
- this->data_transfer.dest_sizes_variable.data(),
- this->data_transfer.src_sizes_variable.data(),
+ this->data_transfer->dest_sizes_variable.data(),
+ this->data_transfer->src_sizes_variable.data(),
sizeof(unsigned int));
}
dealii::internal::p4est::functions<dim>::transfer_fixed_end(tf_context);
// Release memory of previously packed data.
- this->data_transfer.src_data_fixed.clear();
- this->data_transfer.src_data_fixed.shrink_to_fit();
+ this->data_transfer->src_data_fixed.clear();
+ this->data_transfer->src_data_fixed.shrink_to_fit();
- if (this->data_transfer.variable_size_data_stored)
+ if (this->data_transfer->variable_size_data_stored)
{
// Resize memory according to the data that we will receive.
- this->data_transfer.dest_data_variable.resize(
- std::accumulate(this->data_transfer.dest_sizes_variable.begin(),
- this->data_transfer.dest_sizes_variable.end(),
+ this->data_transfer->dest_data_variable.resize(
+ std::accumulate(this->data_transfer->dest_sizes_variable.begin(),
+ this->data_transfer->dest_sizes_variable.end(),
std::vector<int>::size_type(0)));
# if DEAL_II_P4EST_VERSION_GTE(2, 0, 65, 0)
// at all, which is mandatory if one of our processes does not own
// any quadrant. This bypasses the assertion from being triggered.
// - see: https://github.com/cburstedde/p4est/issues/48
- if (this->data_transfer.src_sizes_variable.size() == 0)
- this->data_transfer.src_sizes_variable.resize(1);
- if (this->data_transfer.dest_sizes_variable.size() == 0)
- this->data_transfer.dest_sizes_variable.resize(1);
+ if (this->data_transfer->src_sizes_variable.size() == 0)
+ this->data_transfer->src_sizes_variable.resize(1);
+ if (this->data_transfer->dest_sizes_variable.size() == 0)
+ this->data_transfer->dest_sizes_variable.resize(1);
# endif
// Execute variable size transfer.
previous_global_first_quadrant,
parallel_forest->mpicomm,
1,
- this->data_transfer.dest_data_variable.data(),
- this->data_transfer.dest_sizes_variable.data(),
- this->data_transfer.src_data_variable.data(),
- this->data_transfer.src_sizes_variable.data());
+ this->data_transfer->dest_data_variable.data(),
+ this->data_transfer->dest_sizes_variable.data(),
+ this->data_transfer->src_data_variable.data(),
+ this->data_transfer->src_sizes_variable.data());
// Release memory of previously packed data.
- this->data_transfer.src_sizes_variable.clear();
- this->data_transfer.src_sizes_variable.shrink_to_fit();
- this->data_transfer.src_data_variable.clear();
- this->data_transfer.src_data_variable.shrink_to_fit();
+ this->data_transfer->src_sizes_variable.clear();
+ this->data_transfer->src_sizes_variable.shrink_to_fit();
+ this->data_transfer->src_data_variable.clear();
+ this->data_transfer->src_data_variable.shrink_to_fit();
}
}
for (const auto &cell_rel : this->local_cell_relations)
{
(void)cell_rel;
- Assert(
- (cell_rel.second == // cell_status
- parallel::distributed::Triangulation<dim, spacedim>::CELL_PERSIST),
- ExcInternalError());
+ Assert((cell_rel.second == // cell_status
+ CELL_PERSIST),
+ ExcInternalError());
}
// Save cell attached data.
// pack data before triangulation gets updated
if (this->cell_attached_data.n_attached_data_sets > 0)
{
- this->data_transfer.pack_data(
+ this->data_transfer->pack_data(
this->local_cell_relations,
this->cell_attached_data.pack_callbacks_fixed,
this->cell_attached_data.pack_callbacks_variable);
previous_global_first_quadrant.data());
// also update the CellStatus information on the new mesh
- this->data_transfer.unpack_cell_status(this->local_cell_relations);
+ this->data_transfer->unpack_cell_status(this->local_cell_relations);
}
# ifdef DEBUG
// pack data before triangulation gets updated
if (this->cell_attached_data.n_attached_data_sets > 0)
{
- this->data_transfer.pack_data(
+ this->data_transfer->pack_data(
this->local_cell_relations,
this->cell_attached_data.pack_callbacks_fixed,
this->cell_attached_data.pack_callbacks_variable);
switch (status)
{
- case dealii::Triangulation<dim, spacedim>::CELL_PERSIST:
+ case CELL_PERSIST:
// cell remains unchanged
cell->clear_refine_flag();
cell->clear_coarsen_flag();
break;
- case dealii::Triangulation<dim, spacedim>::CELL_REFINE:
+ case CELL_REFINE:
// cell will be refined
cell->clear_coarsen_flag();
cell->set_refine_flag();
break;
- case dealii::Triangulation<dim, spacedim>::CELL_COARSEN:
+ case CELL_COARSEN:
// children of this cell will be coarsened
for (const auto &child : cell->child_iterators())
{
}
break;
- case dealii::Triangulation<dim, spacedim>::CELL_INVALID:
+ case CELL_INVALID:
// do nothing as cell does not exist yet
break;
mpi_communicator,
smooth_grid,
check_for_distorted_cells)
- , cell_attached_data({0, 0, {}, {}})
- , data_transfer(mpi_communicator)
{}
DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
void DistributedTriangulationBase<dim, spacedim>::clear()
{
- cell_attached_data = {0, 0, {}, {}};
- data_transfer.clear();
-
dealii::Triangulation<dim, spacedim>::clear();
}
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::save_attached_data(
- const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const std::string &filename) const
- {
- // cast away constness
- auto tria = const_cast<
- dealii::parallel::DistributedTriangulationBase<dim, spacedim> *>(this);
-
- if (this->cell_attached_data.n_attached_data_sets > 0)
- {
- // pack attached data first
- tria->data_transfer.pack_data(
- tria->local_cell_relations,
- tria->cell_attached_data.pack_callbacks_fixed,
- tria->cell_attached_data.pack_callbacks_variable);
-
- // then store buffers in file
- tria->data_transfer.save(global_first_cell, global_num_cells, filename);
-
- // and release the memory afterwards
- tria->data_transfer.clear();
- }
-
- // clear all of the callback data, as explained in the documentation of
- // register_data_attach()
- {
- tria->cell_attached_data.n_attached_data_sets = 0;
- tria->cell_attached_data.pack_callbacks_fixed.clear();
- tria->cell_attached_data.pack_callbacks_variable.clear();
- }
- }
-
-
-
template <int dim, int spacedim>
DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
bool DistributedTriangulationBase<dim, spacedim>::has_hanging_nodes() const
}
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::load_attached_data(
- const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const unsigned int local_num_cells,
- const std::string &filename,
- const unsigned int n_attached_deserialize_fixed,
- const unsigned int n_attached_deserialize_variable)
- {
- // load saved data, if any was stored
- if (this->cell_attached_data.n_attached_deserialize > 0)
- {
- this->data_transfer.load(global_first_cell,
- global_num_cells,
- local_num_cells,
- filename,
- n_attached_deserialize_fixed,
- n_attached_deserialize_variable);
-
- this->data_transfer.unpack_cell_status(this->local_cell_relations);
-
- // the CellStatus of all stored cells should always be CELL_PERSIST.
- for (const auto &cell_rel : this->local_cell_relations)
- {
- (void)cell_rel;
- Assert(
- (cell_rel.second == // cell_status
- parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_PERSIST),
- ExcInternalError());
- }
- }
- }
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- unsigned int DistributedTriangulationBase<dim, spacedim>::
- register_data_attach(
- const std::function<std::vector<char>(const cell_iterator &,
- const CellStatus)> &pack_callback,
- const bool returns_variable_size_data)
- {
- unsigned int handle = numbers::invalid_unsigned_int;
-
- // Add new callback function to the corresponding register.
- // Encode handles according to returns_variable_size_data.
- if (returns_variable_size_data)
- {
- handle = 2 * cell_attached_data.pack_callbacks_variable.size();
- cell_attached_data.pack_callbacks_variable.push_back(pack_callback);
- }
- else
- {
- handle = 2 * cell_attached_data.pack_callbacks_fixed.size() + 1;
- cell_attached_data.pack_callbacks_fixed.push_back(pack_callback);
- }
-
- // Increase overall counter.
- ++cell_attached_data.n_attached_data_sets;
-
- return handle;
- }
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::notify_ready_to_unpack(
- const unsigned int handle,
- const std::function<
- void(const cell_iterator &,
- const CellStatus,
- const boost::iterator_range<std::vector<char>::const_iterator> &)>
- &unpack_callback)
- {
- // perform unpacking
- data_transfer.unpack_data(local_cell_relations, handle, unpack_callback);
-
- // decrease counters
- --cell_attached_data.n_attached_data_sets;
- if (cell_attached_data.n_attached_deserialize > 0)
- --cell_attached_data.n_attached_deserialize;
-
- // important: only remove data if we are not in the deserialization
- // process. There, each SolutionTransfer registers and unpacks before
- // the next one does this, so n_attached_data_sets is only 1 here. This
- // would destroy the saved data before the second SolutionTransfer can
- // get it. This created a bug that is documented in
- // tests/mpi/p4est_save_03 with more than one SolutionTransfer.
-
- if (cell_attached_data.n_attached_data_sets == 0 &&
- cell_attached_data.n_attached_deserialize == 0)
- {
- // everybody got their data, time for cleanup!
- cell_attached_data.pack_callbacks_fixed.clear();
- cell_attached_data.pack_callbacks_variable.clear();
- data_transfer.clear();
-
- // reset all cell_status entries after coarsening/refinement
- for (auto &cell_rel : local_cell_relations)
- cell_rel.second =
- parallel::DistributedTriangulationBase<dim, spacedim>::CELL_PERSIST;
- }
- }
-
-
-
- /* ------------------ class DataTransfer<dim,spacedim> ----------------- */
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- DistributedTriangulationBase<dim, spacedim>::DataTransfer::DataTransfer(
- const MPI_Comm mpi_communicator)
- : variable_size_data_stored(false)
- , mpi_communicator(mpi_communicator)
- {}
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::DataTransfer::pack_data(
- const std::vector<cell_relation_t> &cell_relations,
- const std::vector<typename CellAttachedData::pack_callback_t>
- &pack_callbacks_fixed,
- const std::vector<typename CellAttachedData::pack_callback_t>
- &pack_callbacks_variable)
- {
- Assert(src_data_fixed.size() == 0,
- ExcMessage("Previously packed data has not been released yet!"));
- Assert(src_sizes_variable.size() == 0, ExcInternalError());
-
- const unsigned int n_callbacks_fixed = pack_callbacks_fixed.size();
- const unsigned int n_callbacks_variable = pack_callbacks_variable.size();
-
- // Store information that we packed variable size data in
- // a member variable for later.
- variable_size_data_stored = (n_callbacks_variable > 0);
-
- // If variable transfer is scheduled, we will store the data size that
- // each variable size callback function writes in this auxiliary
- // container. The information will be stored by each cell in this vector
- // temporarily.
- std::vector<unsigned int> cell_sizes_variable_cumulative(
- n_callbacks_variable);
-
- // Prepare the buffer structure, in which each callback function will
- // store its data for each active cell.
- // The outmost shell in this container construct corresponds to the
- // data packed per cell. The next layer resembles the data that
- // each callback function packs on the corresponding cell. These
- // buffers are chains of chars stored in an std::vector<char>.
- // A visualisation of the data structure:
- /* clang-format off */
- // | cell_1 | | cell_2 | ...
- // || callback_1 || callback_2 |...| || callback_1 || callback_2 |...| ...
- // |||char|char|...|||char|char|...|...| |||char|char|...|||char|char|...|...| ...
- /* clang-format on */
- std::vector<std::vector<std::vector<char>>> packed_fixed_size_data(
- cell_relations.size());
- std::vector<std::vector<std::vector<char>>> packed_variable_size_data(
- variable_size_data_stored ? cell_relations.size() : 0);
-
- //
- // --------- Pack data for fixed and variable size transfer ---------
- //
- // Iterate over all cells, call all callback functions on each cell,
- // and store their data in the corresponding buffer scope.
- {
- auto cell_rel_it = cell_relations.cbegin();
- auto data_cell_fixed_it = packed_fixed_size_data.begin();
- auto data_cell_variable_it = packed_variable_size_data.begin();
- for (; cell_rel_it != cell_relations.cend(); ++cell_rel_it)
- {
- const auto &dealii_cell = cell_rel_it->first;
- const auto &cell_status = cell_rel_it->second;
-
- // Assertions about the tree structure.
- switch (cell_status)
- {
- case parallel::DistributedTriangulationBase<dim, spacedim>::
- CELL_PERSIST:
- case parallel::DistributedTriangulationBase<dim, spacedim>::
- CELL_REFINE:
- // double check the condition that we will only ever attach
- // data to active cells when we get here
- Assert(dealii_cell->is_active(), ExcInternalError());
- break;
-
- case parallel::DistributedTriangulationBase<dim, spacedim>::
- CELL_COARSEN:
- // double check the condition that we will only ever attach
- // data to cells with children when we get here. however, we
- // can only tolerate one level of coarsening at a time, so
- // check that the children are all active
- Assert(dealii_cell->is_active() == false, ExcInternalError());
- for (unsigned int c = 0;
- c < GeometryInfo<dim>::max_children_per_cell;
- ++c)
- Assert(dealii_cell->child(c)->is_active(),
- ExcInternalError());
- break;
-
- case parallel::DistributedTriangulationBase<dim, spacedim>::
- CELL_INVALID:
- // do nothing on invalid cells
- break;
-
- default:
- Assert(false, ExcInternalError());
- break;
- }
-
- // Reserve memory corresponding to the number of callback
- // functions that will be called.
- // If variable size transfer is scheduled, we need to leave
- // room for an array that holds information about how many
- // bytes each of the variable size callback functions will
- // write.
- // On cells flagged with CELL_INVALID, only its CellStatus
- // will be stored.
- const unsigned int n_fixed_size_data_sets_on_cell =
- 1 +
- ((cell_status ==
- parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_INVALID) ?
- 0 :
- ((variable_size_data_stored ? 1 : 0) + n_callbacks_fixed));
- data_cell_fixed_it->resize(n_fixed_size_data_sets_on_cell);
-
- // We continue with packing all data on this specific cell.
- auto data_fixed_it = data_cell_fixed_it->begin();
-
- // First, we pack the CellStatus information.
- // to get consistent data sizes on each cell for the fixed size
- // transfer, we won't allow compression
- *data_fixed_it =
- Utilities::pack(cell_status, /*allow_compression=*/false);
- ++data_fixed_it;
-
- // Proceed with all registered callback functions.
- // Skip cells with the CELL_INVALID flag.
- if (cell_status !=
- parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_INVALID)
- {
- // Pack fixed size data.
- for (auto callback_it = pack_callbacks_fixed.cbegin();
- callback_it != pack_callbacks_fixed.cend();
- ++callback_it, ++data_fixed_it)
- {
- *data_fixed_it = (*callback_it)(dealii_cell, cell_status);
- }
-
- // Pack variable size data.
- // If we store variable size data, we need to transfer
- // the sizes of each corresponding callback function
- // via fixed size transfer as well.
- if (variable_size_data_stored)
- {
- const unsigned int n_variable_size_data_sets_on_cell =
- ((cell_status ==
- parallel::DistributedTriangulationBase<dim, spacedim>::
- CELL_INVALID) ?
- 0 :
- n_callbacks_variable);
- data_cell_variable_it->resize(
- n_variable_size_data_sets_on_cell);
-
- auto callback_it = pack_callbacks_variable.cbegin();
- auto data_variable_it = data_cell_variable_it->begin();
- auto sizes_variable_it =
- cell_sizes_variable_cumulative.begin();
- for (; callback_it != pack_callbacks_variable.cend();
- ++callback_it, ++data_variable_it, ++sizes_variable_it)
- {
- *data_variable_it =
- (*callback_it)(dealii_cell, cell_status);
-
- // Store data sizes for each callback function first.
- // Make it cumulative below.
- *sizes_variable_it = data_variable_it->size();
- }
-
- // Turn size vector into its cumulative representation.
- std::partial_sum(cell_sizes_variable_cumulative.begin(),
- cell_sizes_variable_cumulative.end(),
- cell_sizes_variable_cumulative.begin());
-
- // Serialize cumulative variable size vector
- // value-by-value. This way we can circumvent the overhead
- // of storing the container object as a whole, since we
- // know its size by the number of registered callback
- // functions.
- data_fixed_it->resize(n_callbacks_variable *
- sizeof(unsigned int));
- for (unsigned int i = 0; i < n_callbacks_variable; ++i)
- std::memcpy(&(data_fixed_it->at(i * sizeof(unsigned int))),
- &(cell_sizes_variable_cumulative.at(i)),
- sizeof(unsigned int));
-
- ++data_fixed_it;
- }
-
- // Double check that we packed everything we wanted
- // in the fixed size buffers.
- Assert(data_fixed_it == data_cell_fixed_it->end(),
- ExcInternalError());
- }
-
- ++data_cell_fixed_it;
-
- // Increment the variable size data iterator
- // only if we actually pack this kind of data
- // to avoid getting out of bounds.
- if (variable_size_data_stored)
- ++data_cell_variable_it;
- } // loop over cell_relations
- }
-
- //
- // ----------- Gather data sizes for fixed size transfer ------------
- //
- // Generate a vector which stores the sizes of each callback function,
- // including the packed CellStatus transfer.
- // Find the very first cell that we wrote to with all callback
- // functions (i.e. a cell that was not flagged with CELL_INVALID)
- // and store the sizes of each buffer.
- //
- // To deal with the case that at least one of the processors does not
- // own any cell at all, we will exchange the information about the data
- // sizes among them later. The code in between is still well-defined,
- // since the following loops will be skipped.
- std::vector<unsigned int> local_sizes_fixed(
- 1 + n_callbacks_fixed + (variable_size_data_stored ? 1 : 0));
- for (const auto &data_cell : packed_fixed_size_data)
- {
- if (data_cell.size() == local_sizes_fixed.size())
- {
- auto sizes_fixed_it = local_sizes_fixed.begin();
- auto data_fixed_it = data_cell.cbegin();
- for (; data_fixed_it != data_cell.cend();
- ++data_fixed_it, ++sizes_fixed_it)
- {
- *sizes_fixed_it = data_fixed_it->size();
- }
-
- break;
- }
- }
-
- // Check if all cells have valid sizes.
- for (auto data_cell_fixed_it = packed_fixed_size_data.cbegin();
- data_cell_fixed_it != packed_fixed_size_data.cend();
- ++data_cell_fixed_it)
- {
- Assert((data_cell_fixed_it->size() == 1) ||
- (data_cell_fixed_it->size() == local_sizes_fixed.size()),
- ExcInternalError());
- }
-
- // Share information about the packed data sizes
- // of all callback functions across all processors, in case one
- // of them does not own any cells at all.
- std::vector<unsigned int> global_sizes_fixed(local_sizes_fixed.size());
- Utilities::MPI::max(local_sizes_fixed,
- this->mpi_communicator,
- global_sizes_fixed);
-
- // Construct cumulative sizes, since this is the only information
- // we need from now on.
- sizes_fixed_cumulative.resize(global_sizes_fixed.size());
- std::partial_sum(global_sizes_fixed.begin(),
- global_sizes_fixed.end(),
- sizes_fixed_cumulative.begin());
-
- //
- // ---------- Gather data sizes for variable size transfer ----------
- //
- if (variable_size_data_stored)
- {
- src_sizes_variable.reserve(packed_variable_size_data.size());
- for (const auto &data_cell : packed_variable_size_data)
- {
- int variable_data_size_on_cell = 0;
-
- for (const auto &data : data_cell)
- variable_data_size_on_cell += data.size();
-
- src_sizes_variable.push_back(variable_data_size_on_cell);
- }
- }
-
- //
- // ------------------------ Build buffers ---------------------------
- //
- const unsigned int expected_size_fixed =
- cell_relations.size() * sizes_fixed_cumulative.back();
- const unsigned int expected_size_variable =
- std::accumulate(src_sizes_variable.begin(),
- src_sizes_variable.end(),
- std::vector<int>::size_type(0));
-
- // Move every piece of packed fixed size data into the consecutive
- // buffer.
- src_data_fixed.reserve(expected_size_fixed);
- for (const auto &data_cell_fixed : packed_fixed_size_data)
- {
- // Move every fraction of packed data into the buffer
- // reserved for this particular cell.
- for (const auto &data_fixed : data_cell_fixed)
- std::move(data_fixed.begin(),
- data_fixed.end(),
- std::back_inserter(src_data_fixed));
-
- // If we only packed the CellStatus information
- // (i.e. encountered a cell flagged CELL_INVALID),
- // fill the remaining space with invalid entries.
- // We can skip this if there is nothing else to pack.
- if ((data_cell_fixed.size() == 1) &&
- (sizes_fixed_cumulative.size() > 1))
- {
- const std::size_t bytes_skipped =
- sizes_fixed_cumulative.back() - sizes_fixed_cumulative.front();
-
- src_data_fixed.insert(src_data_fixed.end(),
- bytes_skipped,
- static_cast<char>(-1)); // invalid_char
- }
- }
-
- // Move every piece of packed variable size data into the consecutive
- // buffer.
- if (variable_size_data_stored)
- {
- src_data_variable.reserve(expected_size_variable);
- for (const auto &data_cell : packed_variable_size_data)
- {
- // Move every fraction of packed data into the buffer
- // reserved for this particular cell.
- for (const auto &data : data_cell)
- std::move(data.begin(),
- data.end(),
- std::back_inserter(src_data_variable));
- }
- }
-
- // Double check that we packed everything correctly.
- Assert(src_data_fixed.size() == expected_size_fixed, ExcInternalError());
- Assert(src_data_variable.size() == expected_size_variable,
- ExcInternalError());
- }
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::DataTransfer::
- unpack_cell_status(std::vector<cell_relation_t> &cell_relations) const
- {
- Assert(sizes_fixed_cumulative.size() > 0,
- ExcMessage("No data has been packed!"));
- if (cell_relations.size() > 0)
- {
- Assert(dest_data_fixed.size() > 0,
- ExcMessage("No data has been received!"));
- }
-
- // Size of CellStatus object that will be unpacked on each cell.
- const unsigned int size = sizes_fixed_cumulative.front();
-
- // Iterate over all cells and overwrite the CellStatus
- // information from the transferred data.
- // Proceed buffer iterator position to next cell after
- // each iteration.
- auto cell_rel_it = cell_relations.begin();
- auto dest_fixed_it = dest_data_fixed.cbegin();
- for (; cell_rel_it != cell_relations.end();
- ++cell_rel_it, dest_fixed_it += sizes_fixed_cumulative.back())
- {
- cell_rel_it->second = // cell_status
- Utilities::unpack<typename parallel::DistributedTriangulationBase<
- dim,
- spacedim>::CellStatus>(dest_fixed_it,
- dest_fixed_it + size,
- /*allow_compression=*/false);
- }
- }
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::DataTransfer::unpack_data(
- const std::vector<cell_relation_t> &cell_relations,
- const unsigned int handle,
- const std::function<
- void(const typename dealii::Triangulation<dim, spacedim>::cell_iterator &,
- const typename dealii::Triangulation<dim, spacedim>::CellStatus &,
- const boost::iterator_range<std::vector<char>::const_iterator> &)>
- &unpack_callback) const
- {
- // We decode the handle returned by register_data_attach() back into
- // a format we can use. All even handles belong to those callback
- // functions which write/read variable size data, all odd handles
- // interact with fixed size buffers.
- const bool callback_variable_transfer = (handle % 2 == 0);
- const unsigned int callback_index = handle / 2;
-
- // Cells will always receive fixed size data (i.e., CellStatus
- // information), but not necessarily variable size data (e.g., with a
- // ParticleHandler a cell might not contain any particle at all).
- // Thus it is sufficient to check if fixed size data has been received.
- Assert(sizes_fixed_cumulative.size() > 0,
- ExcMessage("No data has been packed!"));
- if (cell_relations.size() > 0)
- {
- Assert(dest_data_fixed.size() > 0,
- ExcMessage("No data has been received!"));
- }
-
- std::vector<char>::const_iterator dest_data_it;
- std::vector<char>::const_iterator dest_sizes_cell_it;
-
- // Depending on whether our callback function unpacks fixed or
- // variable size data, we have to pursue different approaches
- // to localize the correct fraction of the buffer from which
- // we are allowed to read.
- unsigned int offset = numbers::invalid_unsigned_int;
- unsigned int size = numbers::invalid_unsigned_int;
- unsigned int data_increment = numbers::invalid_unsigned_int;
-
- if (callback_variable_transfer)
- {
- // For the variable size data, we need to extract the
- // data size from the fixed size buffer on each cell.
- //
- // We packed this information last, so the last packed
- // object in the fixed size buffer corresponds to the
- // variable data sizes.
- //
- // The last entry of sizes_fixed_cumulative corresponds
- // to the size of all fixed size data packed on the cell.
- // To get the offset for the last packed object, we need
- // to get the next-to-last entry.
- const unsigned int offset_variable_data_sizes =
- sizes_fixed_cumulative[sizes_fixed_cumulative.size() - 2];
-
- // This iterator points to the data size that the
- // callback_function packed for each specific cell.
- // Adjust buffer iterator to the offset of the callback
- // function so that we only have to advance its position
- // to the next cell after each iteration.
- dest_sizes_cell_it = dest_data_fixed.cbegin() +
- offset_variable_data_sizes +
- callback_index * sizeof(unsigned int);
-
- // Let the data iterator point to the correct buffer.
- dest_data_it = dest_data_variable.cbegin();
- }
- else
- {
- // For the fixed size data, we can get the information about
- // the buffer location on each cell directly from the
- // sizes_fixed_cumulative vector.
- offset = sizes_fixed_cumulative[callback_index];
- size = sizes_fixed_cumulative[callback_index + 1] - offset;
- data_increment = sizes_fixed_cumulative.back();
-
- // Let the data iterator point to the correct buffer.
- // Adjust buffer iterator to the offset of the callback
- // function so that we only have to advance its position
- // to the next cell after each iteration.
- if (cell_relations.begin() != cell_relations.end())
- dest_data_it = dest_data_fixed.cbegin() + offset;
- }
-
- // Iterate over all cells and unpack the transferred data.
- auto cell_rel_it = cell_relations.begin();
- auto dest_sizes_it = dest_sizes_variable.cbegin();
- for (; cell_rel_it != cell_relations.end(); ++cell_rel_it)
- {
- const auto &dealii_cell = cell_rel_it->first;
- const auto &cell_status = cell_rel_it->second;
-
- if (callback_variable_transfer)
- {
- // Update the increment according to the whole data size
- // of the current cell.
- data_increment = *dest_sizes_it;
-
- if (cell_status !=
- parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_INVALID)
- {
- // Extract the corresponding values for offset and size from
- // the cumulative sizes array stored in the fixed size
- // buffer.
- if (callback_index == 0)
- offset = 0;
- else
- std::memcpy(&offset,
- &(*(dest_sizes_cell_it - sizeof(unsigned int))),
- sizeof(unsigned int));
-
- std::memcpy(&size,
- &(*dest_sizes_cell_it),
- sizeof(unsigned int));
-
- size -= offset;
-
- // Move the data iterator to the corresponding position
- // of the callback function and adjust the increment
- // accordingly.
- dest_data_it += offset;
- data_increment -= offset;
- }
-
- // Advance data size iterators to the next cell, avoid iterating
- // past the end of dest_sizes_cell_it
- if (cell_rel_it != cell_relations.end() - 1)
- dest_sizes_cell_it += sizes_fixed_cumulative.back();
- ++dest_sizes_it;
- }
-
- switch (cell_status)
- {
- case parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_PERSIST:
- case parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_COARSEN:
- unpack_callback(dealii_cell,
- cell_status,
- boost::make_iterator_range(dest_data_it,
- dest_data_it + size));
- break;
-
- case parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_REFINE:
- unpack_callback(dealii_cell->parent(),
- cell_status,
- boost::make_iterator_range(dest_data_it,
- dest_data_it + size));
- break;
-
- case parallel::DistributedTriangulationBase<dim,
- spacedim>::CELL_INVALID:
- // Skip this cell.
- break;
-
- default:
- Assert(false, ExcInternalError());
- break;
- }
-
- if (cell_rel_it != cell_relations.end() - 1)
- dest_data_it += data_increment;
- }
- }
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::DataTransfer::save(
- const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const std::string &filename) const
- {
-#ifdef DEAL_II_WITH_MPI
- // Large fractions of this function have been copied from
- // DataOutInterface::write_vtu_in_parallel.
- // TODO: Write general MPIIO interface.
-
- Assert(sizes_fixed_cumulative.size() > 0,
- ExcMessage("No data has been packed!"));
-
- const int myrank = Utilities::MPI::this_mpi_process(mpi_communicator);
-
- const unsigned int bytes_per_cell = sizes_fixed_cumulative.back();
-
- //
- // ---------- Fixed size data ----------
- //
- {
- const std::string fname_fixed = std::string(filename) + "_fixed.data";
-
- MPI_Info info;
- int ierr = MPI_Info_create(&info);
- AssertThrowMPI(ierr);
-
- MPI_File fh;
- ierr = MPI_File_open(mpi_communicator,
- fname_fixed.c_str(),
- MPI_MODE_CREATE | MPI_MODE_WRONLY,
- info,
- &fh);
- AssertThrowMPI(ierr);
-
- ierr = MPI_File_set_size(fh, 0); // delete the file contents
- AssertThrowMPI(ierr);
- // this barrier is necessary, because otherwise others might already
- // write while one core is still setting the size to zero.
- ierr = MPI_Barrier(mpi_communicator);
- AssertThrowMPI(ierr);
- ierr = MPI_Info_free(&info);
- AssertThrowMPI(ierr);
- // ------------------
-
- // Write cumulative sizes to file.
- // Since each processor owns the same information about the data
- // sizes, it is sufficient to let only the first processor perform
- // this task.
- if (myrank == 0)
- {
- ierr = Utilities::MPI::LargeCount::File_write_at_c(
- fh,
- 0,
- sizes_fixed_cumulative.data(),
- sizes_fixed_cumulative.size(),
- MPI_UNSIGNED,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
- }
-
- // Write packed data to file simultaneously.
- const MPI_Offset size_header =
- sizes_fixed_cumulative.size() * sizeof(unsigned int);
-
- // Make sure we do the following computation in 64bit integers to be
- // able to handle 4GB+ files:
- const MPI_Offset my_global_file_position =
- size_header +
- static_cast<MPI_Offset>(global_first_cell) * bytes_per_cell;
-
- ierr =
- Utilities::MPI::LargeCount::File_write_at_c(fh,
- my_global_file_position,
- src_data_fixed.data(),
- src_data_fixed.size(),
- MPI_BYTE,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
-
- ierr = MPI_File_close(&fh);
- AssertThrowMPI(ierr);
- }
-
-
-
- //
- // ---------- Variable size data ----------
- //
- if (variable_size_data_stored)
- {
- const std::string fname_variable =
- std::string(filename) + "_variable.data";
-
- MPI_Info info;
- int ierr = MPI_Info_create(&info);
- AssertThrowMPI(ierr);
-
- MPI_File fh;
- ierr = MPI_File_open(mpi_communicator,
- fname_variable.c_str(),
- MPI_MODE_CREATE | MPI_MODE_WRONLY,
- info,
- &fh);
- AssertThrowMPI(ierr);
-
- ierr = MPI_File_set_size(fh, 0); // delete the file contents
- AssertThrowMPI(ierr);
- // this barrier is necessary, because otherwise others might already
- // write while one core is still setting the size to zero.
- ierr = MPI_Barrier(mpi_communicator);
- AssertThrowMPI(ierr);
- ierr = MPI_Info_free(&info);
- AssertThrowMPI(ierr);
-
- // Write sizes of each cell into file simultaneously.
- {
- const MPI_Offset my_global_file_position =
- static_cast<MPI_Offset>(global_first_cell) * sizeof(unsigned int);
-
- // It is very unlikely that a single process has more than
- // 2 billion cells, but we might as well check.
- AssertThrow(src_sizes_variable.size() <
- static_cast<std::size_t>(
- std::numeric_limits<int>::max()),
- ExcNotImplemented());
-
- ierr = Utilities::MPI::LargeCount::File_write_at_c(
- fh,
- my_global_file_position,
- src_sizes_variable.data(),
- src_sizes_variable.size(),
- MPI_INT,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
- }
-
- // Gather size of data in bytes we want to store from this
- // processor and compute the prefix sum. We do this in 64 bit
- // to avoid overflow for files larger than 4GB:
- const std::uint64_t size_on_proc = src_data_variable.size();
- std::uint64_t prefix_sum = 0;
- ierr = MPI_Exscan(&size_on_proc,
- &prefix_sum,
- 1,
- MPI_UINT64_T,
- MPI_SUM,
- mpi_communicator);
- AssertThrowMPI(ierr);
-
- const MPI_Offset my_global_file_position =
- static_cast<MPI_Offset>(global_num_cells) * sizeof(unsigned int) +
- prefix_sum;
-
- // Write data consecutively into file.
- ierr =
- Utilities::MPI::LargeCount::File_write_at_c(fh,
- my_global_file_position,
- src_data_variable.data(),
- src_data_variable.size(),
- MPI_BYTE,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
-
-
- ierr = MPI_File_close(&fh);
- AssertThrowMPI(ierr);
- }
-#else
- (void)global_first_cell;
- (void)global_num_cells;
- (void)filename;
-
- AssertThrow(false, ExcNeedsMPI());
-#endif
- }
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::DataTransfer::load(
- const unsigned int global_first_cell,
- const unsigned int global_num_cells,
- const unsigned int local_num_cells,
- const std::string &filename,
- const unsigned int n_attached_deserialize_fixed,
- const unsigned int n_attached_deserialize_variable)
- {
-#ifdef DEAL_II_WITH_MPI
- // Large fractions of this function have been copied from
- // DataOutInterface::write_vtu_in_parallel.
- // TODO: Write general MPIIO interface.
-
- Assert(dest_data_fixed.size() == 0,
- ExcMessage("Previously loaded data has not been released yet!"));
-
- variable_size_data_stored = (n_attached_deserialize_variable > 0);
-
- //
- // ---------- Fixed size data ----------
- //
- {
- const std::string fname_fixed = std::string(filename) + "_fixed.data";
-
- MPI_Info info;
- int ierr = MPI_Info_create(&info);
- AssertThrowMPI(ierr);
-
- MPI_File fh;
- ierr = MPI_File_open(
- mpi_communicator, fname_fixed.c_str(), MPI_MODE_RDONLY, info, &fh);
- AssertThrowMPI(ierr);
-
- ierr = MPI_Info_free(&info);
- AssertThrowMPI(ierr);
-
- // Read cumulative sizes from file.
- // Since all processors need the same information about the data
- // sizes, let each of them retrieve it by reading from the same
- // location in the file.
- sizes_fixed_cumulative.resize(1 + n_attached_deserialize_fixed +
- (variable_size_data_stored ? 1 : 0));
- ierr = Utilities::MPI::LargeCount::File_read_at_c(
- fh,
- 0,
- sizes_fixed_cumulative.data(),
- sizes_fixed_cumulative.size(),
- MPI_UNSIGNED,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
-
- // Allocate sufficient memory.
- const unsigned int bytes_per_cell = sizes_fixed_cumulative.back();
- dest_data_fixed.resize(static_cast<size_t>(local_num_cells) *
- bytes_per_cell);
-
- // Read packed data from file simultaneously.
- const MPI_Offset size_header =
- sizes_fixed_cumulative.size() * sizeof(unsigned int);
-
- // Make sure we do the following computation in 64bit integers to be
- // able to handle 4GB+ files:
- const MPI_Offset my_global_file_position =
- size_header +
- static_cast<MPI_Offset>(global_first_cell) * bytes_per_cell;
-
- ierr = Utilities::MPI::LargeCount::File_read_at_c(fh,
- my_global_file_position,
- dest_data_fixed.data(),
- dest_data_fixed.size(),
- MPI_BYTE,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
-
-
- ierr = MPI_File_close(&fh);
- AssertThrowMPI(ierr);
- }
-
- //
- // ---------- Variable size data ----------
- //
- if (variable_size_data_stored)
- {
- const std::string fname_variable =
- std::string(filename) + "_variable.data";
-
- MPI_Info info;
- int ierr = MPI_Info_create(&info);
- AssertThrowMPI(ierr);
-
- MPI_File fh;
- ierr = MPI_File_open(
- mpi_communicator, fname_variable.c_str(), MPI_MODE_RDONLY, info, &fh);
- AssertThrowMPI(ierr);
-
- ierr = MPI_Info_free(&info);
- AssertThrowMPI(ierr);
-
- // Read sizes of all locally owned cells.
- dest_sizes_variable.resize(local_num_cells);
-
- const MPI_Offset my_global_file_position_sizes =
- static_cast<MPI_Offset>(global_first_cell) * sizeof(unsigned int);
-
- ierr = Utilities::MPI::LargeCount::File_read_at_c(
- fh,
- my_global_file_position_sizes,
- dest_sizes_variable.data(),
- dest_sizes_variable.size(),
- MPI_INT,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
-
-
- // Compute my data size in bytes and compute prefix sum. We do this
- // in 64 bit to avoid overflow for files larger than 4 GB:
- const std::uint64_t size_on_proc =
- std::accumulate(dest_sizes_variable.begin(),
- dest_sizes_variable.end(),
- 0ULL);
-
- std::uint64_t prefix_sum = 0;
- ierr = MPI_Exscan(&size_on_proc,
- &prefix_sum,
- 1,
- MPI_UINT64_T,
- MPI_SUM,
- mpi_communicator);
- AssertThrowMPI(ierr);
-
- const MPI_Offset my_global_file_position =
- static_cast<MPI_Offset>(global_num_cells) * sizeof(unsigned int) +
- prefix_sum;
-
- dest_data_variable.resize(size_on_proc);
-
- ierr =
- Utilities::MPI::LargeCount::File_read_at_c(fh,
- my_global_file_position,
- dest_data_variable.data(),
- dest_data_variable.size(),
- MPI_BYTE,
- MPI_STATUS_IGNORE);
- AssertThrowMPI(ierr);
-
- ierr = MPI_File_close(&fh);
- AssertThrowMPI(ierr);
- }
-#else
- (void)global_first_cell;
- (void)global_num_cells;
- (void)local_num_cells;
- (void)filename;
- (void)n_attached_deserialize_fixed;
- (void)n_attached_deserialize_variable;
-
- AssertThrow(false, ExcNeedsMPI());
-#endif
- }
-
-
-
- template <int dim, int spacedim>
- DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
- void DistributedTriangulationBase<dim, spacedim>::DataTransfer::clear()
- {
- variable_size_data_stored = false;
-
- // free information about data sizes
- sizes_fixed_cumulative.clear();
- sizes_fixed_cumulative.shrink_to_fit();
-
- // free fixed size transfer data
- src_data_fixed.clear();
- src_data_fixed.shrink_to_fit();
-
- dest_data_fixed.clear();
- dest_data_fixed.shrink_to_fit();
-
- // free variable size transfer data
- src_sizes_variable.clear();
- src_sizes_variable.shrink_to_fit();
-
- src_data_variable.clear();
- src_data_variable.shrink_to_fit();
-
- dest_sizes_variable.clear();
- dest_sizes_variable.shrink_to_fit();
-
- dest_data_variable.clear();
- dest_data_variable.shrink_to_fit();
- }
-
} // end namespace parallel
for (const auto &cell : triangulation.active_cell_iterators())
if (cell->is_locally_owned())
cell_weights[cell->active_cell_index()] =
- triangulation.signals.weight(
- cell, Triangulation<dim, spacedim>::CellStatus::CELL_PERSIST);
+ triangulation.signals.weight(cell, CELL_PERSIST);
// If this is a parallel triangulation, we then need to also
// get the weights for all other cells. We have asserted above
for (const auto &cell : triangulation.active_cell_iterators() |
IteratorFilters::LocallyOwnedCell())
cell_weights[cell->active_cell_index()] =
- triangulation.signals.weight(
- cell, Triangulation<dim, spacedim>::CellStatus::CELL_PERSIST);
+ triangulation.signals.weight(cell, CELL_PERSIST);
// If this is a parallel triangulation, we then need to also
// get the weights for all other cells. We have asserted above
signals.post_refinement.connect(signals.any_change);
signals.clear.connect(signals.any_change);
signals.mesh_movement.connect(signals.any_change);
+
+ cell_attached_data = {0, 0, {}, {}};
+ data_transfer =
+ std::make_unique<DataTransfer<dim, spacedim>>(get_communicator());
}
periodic_face_pairs_level_0.clear();
periodic_face_map.clear();
reference_cells.clear();
+
+ cell_attached_data = {0, 0, {}, {}};
+ data_transfer->clear();
}
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+unsigned int Triangulation<dim, spacedim>::register_data_attach(
+ const std::function<std::vector<char>(const cell_iterator &,
+ const CellStatus)> &pack_callback,
+ const bool returns_variable_size_data)
+{
+ unsigned int handle = numbers::invalid_unsigned_int;
+
+ // Add new callback function to the corresponding register.
+ // Encode handles according to returns_variable_size_data.
+ if (returns_variable_size_data)
+ {
+ handle = 2 * this->cell_attached_data.pack_callbacks_variable.size();
+ this->cell_attached_data.pack_callbacks_variable.push_back(pack_callback);
+ }
+ else
+ {
+ handle = 2 * this->cell_attached_data.pack_callbacks_fixed.size() + 1;
+ this->cell_attached_data.pack_callbacks_fixed.push_back(pack_callback);
+ }
+
+ // Increase overall counter.
+ ++this->cell_attached_data.n_attached_data_sets;
+
+ return handle;
+}
+
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void Triangulation<dim, spacedim>::notify_ready_to_unpack(
+ const unsigned int handle,
+ const std::function<
+ void(const cell_iterator &,
+ const CellStatus,
+ const boost::iterator_range<std::vector<char>::const_iterator> &)>
+ &unpack_callback)
+{
+ // perform unpacking
+ this->data_transfer->unpack_data(this->local_cell_relations,
+ handle,
+ unpack_callback);
+
+ // decrease counters
+ --this->cell_attached_data.n_attached_data_sets;
+ if (this->cell_attached_data.n_attached_deserialize > 0)
+ --this->cell_attached_data.n_attached_deserialize;
+
+ // important: only remove data if we are not in the deserialization
+ // process. There, each SolutionTransfer registers and unpacks before
+ // the next one does this, so n_attached_data_sets is only 1 here. This
+ // would destroy the saved data before the second SolutionTransfer can
+ // get it. This created a bug that is documented in
+ // tests/mpi/p4est_save_03 with more than one SolutionTransfer.
+
+ if (this->cell_attached_data.n_attached_data_sets == 0 &&
+ this->cell_attached_data.n_attached_deserialize == 0)
+ {
+ // everybody got their data, time for cleanup!
+ this->cell_attached_data.pack_callbacks_fixed.clear();
+ this->cell_attached_data.pack_callbacks_variable.clear();
+ this->data_transfer->clear();
+
+ // reset all cell_status entries after coarsening/refinement
+ for (auto &cell_rel : this->local_cell_relations)
+ cell_rel.second = CELL_PERSIST;
+ }
+}
+
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void Triangulation<dim, spacedim>::save_attached_data(
+ const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const std::string &filename) const
+{
+ // cast away constness
+ auto tria = const_cast<Triangulation<dim, spacedim> *>(this);
+
+ if (this->cell_attached_data.n_attached_data_sets > 0)
+ {
+ // pack attached data first
+ tria->data_transfer->pack_data(
+ tria->local_cell_relations,
+ tria->cell_attached_data.pack_callbacks_fixed,
+ tria->cell_attached_data.pack_callbacks_variable);
+
+ // then store buffers in file
+ tria->data_transfer->save(global_first_cell, global_num_cells, filename);
+
+ // and release the memory afterwards
+ tria->data_transfer->clear();
+ }
+
+ // clear all of the callback data, as explained in the documentation of
+ // register_data_attach()
+ {
+ tria->cell_attached_data.n_attached_data_sets = 0;
+ tria->cell_attached_data.pack_callbacks_fixed.clear();
+ tria->cell_attached_data.pack_callbacks_variable.clear();
+ }
+}
+
+
+template <int dim, int spacedim>
+DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
+void Triangulation<dim, spacedim>::load_attached_data(
+ const unsigned int global_first_cell,
+ const unsigned int global_num_cells,
+ const unsigned int local_num_cells,
+ const std::string &filename,
+ const unsigned int n_attached_deserialize_fixed,
+ const unsigned int n_attached_deserialize_variable)
+{
+ // load saved data, if any was stored
+ if (this->cell_attached_data.n_attached_deserialize > 0)
+ {
+ this->data_transfer->load(global_first_cell,
+ global_num_cells,
+ local_num_cells,
+ filename,
+ n_attached_deserialize_fixed,
+ n_attached_deserialize_variable);
+
+ this->data_transfer->unpack_cell_status(this->local_cell_relations);
+
+ // the CellStatus of all stored cells should always be CELL_PERSIST.
+ for (const auto &cell_rel : this->local_cell_relations)
+ {
+ (void)cell_rel;
+ Assert((cell_rel.second == // cell_status
+ CELL_PERSIST),
+ ExcInternalError());
+ }
+ }
+}
+
+
template <int dim, int spacedim>
DEAL_II_CXX20_REQUIRES((concepts::is_valid_dim_spacedim<dim, spacedim>))
void Triangulation<dim, spacedim>::clear_despite_subscriptions()
"creation and do not refine afterwards, or use a distributed triangulation."));
const auto callback_function =
- [this](
- const typename Triangulation<dim, spacedim>::cell_iterator
- & cell_iterator,
- const typename Triangulation<dim, spacedim>::CellStatus cell_status) {
+ [this](const typename Triangulation<dim, spacedim>::cell_iterator
+ & cell_iterator,
+ const CellStatus cell_status) {
return this->pack_callback(cell_iterator, cell_status);
};
if (handle != numbers::invalid_unsigned_int)
{
const auto callback_function =
- [this](
- const typename Triangulation<dim, spacedim>::cell_iterator
- &cell_iterator,
- const typename Triangulation<dim, spacedim>::CellStatus cell_status,
- const boost::iterator_range<std::vector<char>::const_iterator>
- &range_iterator) {
+ [this](const typename Triangulation<dim, spacedim>::cell_iterator
+ & cell_iterator,
+ const CellStatus cell_status,
+ const boost::iterator_range<std::vector<char>::const_iterator>
+ &range_iterator) {
this->unpack_callback(cell_iterator, cell_status, range_iterator);
};
std::vector<char>
ParticleHandler<dim, spacedim>::pack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator &cell,
- const typename Triangulation<dim, spacedim>::CellStatus status) const
+ const CellStatus status) const
{
std::vector<particle_iterator> stored_particles_on_cell;
switch (status)
{
- case parallel::TriangulationBase<dim, spacedim>::CELL_PERSIST:
- case parallel::TriangulationBase<dim, spacedim>::CELL_REFINE:
+ case CELL_PERSIST:
+ case CELL_REFINE:
// If the cell persist or is refined store all particles of the
// current cell.
{
}
break;
- case parallel::TriangulationBase<dim, spacedim>::CELL_COARSEN:
+ case CELL_COARSEN:
// If this cell is the parent of children that will be coarsened,
// collect the particles of all children.
{
void
ParticleHandler<dim, spacedim>::unpack_callback(
const typename Triangulation<dim, spacedim>::cell_iterator & cell,
- const typename Triangulation<dim, spacedim>::CellStatus status,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
{
if (data_range.begin() == data_range.end())
return;
const auto cell_to_store_particles =
- (status != parallel::TriangulationBase<dim, spacedim>::CELL_REFINE) ?
- cell :
- cell->child(0);
+ (status != CELL_REFINE) ? cell : cell->child(0);
// deserialize particles and insert into local storage
if (data_range.begin() != data_range.end())
// now update particle storage location and properties if necessary
switch (status)
{
- case parallel::TriangulationBase<dim, spacedim>::CELL_PERSIST:
+ case CELL_PERSIST:
{
// all particles are correctly inserted
}
break;
- case parallel::TriangulationBase<dim, spacedim>::CELL_COARSEN:
+ case CELL_COARSEN:
{
// all particles are in correct cell, but their reference location
// has changed
}
break;
- case parallel::TriangulationBase<dim, spacedim>::CELL_REFINE:
+ case CELL_REFINE:
{
// we need to find the correct child to store the particles and
// their reference location has changed
template <int dim, int spacedim = dim>
std::function<
unsigned int(const typename Triangulation<dim, spacedim>::cell_iterator &,
- const typename Triangulation<dim, spacedim>::CellStatus)>
+ const CellStatus)>
hanging_nodes_weighting(const double weight)
{
return [weight](const auto &cell, const auto &) -> unsigned int {
std::vector<char>
pack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status)
+ & cell,
+ const CellStatus status)
{
static int some_number = 0;
deallog << "packing cell " << cell->id() << " with data=" << some_number
<< " status=";
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST)
+ if (status == CELL_PERSIST)
deallog << "PERSIST";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ else if (status == CELL_REFINE)
deallog << "REFINE";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ else if (status == CELL_COARSEN)
deallog << "COARSEN";
deallog << std::endl;
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ if (status == CELL_COARSEN)
{
Assert(cell->has_children(), ExcInternalError());
}
void
unpack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status,
+ & cell,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
{
const int intdata = Utilities::unpack<int>(data_range.begin(),
deallog << "unpacking cell " << cell->id() << " with data=" << intdata
<< " status=";
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST)
+ if (status == CELL_PERSIST)
deallog << "PERSIST";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ else if (status == CELL_REFINE)
deallog << "REFINE";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ else if (status == CELL_COARSEN)
deallog << "COARSEN";
deallog << std::endl;
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ if (status == CELL_REFINE)
{
Assert(cell->has_children(), ExcInternalError());
}
std::vector<char>
pack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status)
+ & cell,
+ const CellStatus status)
{
static unsigned int some_number = 1;
std::vector<unsigned int> some_vector(some_number);
<< " with data size =" << buffer.size() << " accumulated data="
<< std::accumulate(some_vector.begin(), some_vector.end(), 0)
<< " status=";
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST)
+ if (status == CELL_PERSIST)
deallog << "PERSIST";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ else if (status == CELL_REFINE)
deallog << "REFINE";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ else if (status == CELL_COARSEN)
deallog << "COARSEN";
deallog << std::endl;
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ if (status == CELL_COARSEN)
{
Assert(cell->has_children(), ExcInternalError());
}
void
unpack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status,
+ & cell,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
{
const unsigned int data_in_bytes =
<< " accumulated data="
<< std::accumulate(intdatavector.begin(), intdatavector.end(), 0)
<< " status=";
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST)
+ if (status == CELL_PERSIST)
deallog << "PERSIST";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ else if (status == CELL_REFINE)
deallog << "REFINE";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ else if (status == CELL_COARSEN)
deallog << "COARSEN";
deallog << std::endl;
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ if (status == CELL_REFINE)
{
Assert(cell->has_children(), ExcInternalError());
}
unsigned int
cell_weight_1(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
return current_cell_weight++;
}
unsigned int
cell_weight_2(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
return 1;
}
unsigned int
cell_weight_1(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
return current_cell_weight++;
}
unsigned int
cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
return 1;
}
unsigned int
cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
const unsigned int cell_weight =
(cell->center()[0] < 0.5 || cell->center()[1] < 0.5 ? 1 : 4);
std::vector<unsigned int> integrated_weights(numproc, 0);
for (const auto &cell :
tr.active_cell_iterators() | IteratorFilters::LocallyOwnedCell())
- integrated_weights[myid] +=
- cell_weight<dim>(cell,
- parallel::distributed::Triangulation<dim>::CELL_PERSIST);
+ integrated_weights[myid] += cell_weight<dim>(cell, CELL_PERSIST);
Utilities::MPI::sum(integrated_weights, MPI_COMM_WORLD, integrated_weights);
if (myid == 0)
unsigned int
cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
const unsigned int cell_weight =
(cell->center()[0] < 0.5 || cell->center()[1] < 0.5 ? 1 : 1000);
std::vector<unsigned int> integrated_weights(numproc, 0);
for (const auto &cell :
tr.active_cell_iterators() | IteratorFilters::LocallyOwnedCell())
- integrated_weights[myid] +=
- cell_weight<dim>(cell,
- parallel::distributed::Triangulation<dim>::CELL_PERSIST);
+ integrated_weights[myid] += cell_weight<dim>(cell, CELL_PERSIST);
Utilities::MPI::sum(integrated_weights, MPI_COMM_WORLD, integrated_weights);
if (myid == 0)
unsigned int
cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
unsigned int weight = 1;
std::vector<unsigned int> integrated_weights(numproc, 0);
for (const auto &cell :
tr.active_cell_iterators() | IteratorFilters::LocallyOwnedCell())
- integrated_weights[myid] +=
- cell_weight<dim>(cell,
- parallel::distributed::Triangulation<dim>::CELL_PERSIST);
+ integrated_weights[myid] += cell_weight<dim>(cell, CELL_PERSIST);
Utilities::MPI::sum(integrated_weights, MPI_COMM_WORLD, integrated_weights);
if (myid == 0)
unsigned int
cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
+ const CellStatus status)
{
unsigned int weight = 1;
std::vector<unsigned int> integrated_weights(numproc, 0);
for (const auto &cell :
tr.active_cell_iterators() | IteratorFilters::LocallyOwnedCell())
- integrated_weights[myid] +=
- cell_weight<dim>(cell,
- parallel::distributed::Triangulation<dim>::CELL_PERSIST);
+ integrated_weights[myid] += cell_weight<dim>(cell, CELL_PERSIST);
Utilities::MPI::sum(integrated_weights, MPI_COMM_WORLD, integrated_weights);
if (myid == 0)
std::vector<char>
pack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status)
+ & cell,
+ const CellStatus status)
{
static unsigned int some_number = 1;
std::vector<unsigned int> some_vector(some_number);
<< std::accumulate(some_vector.begin(), some_vector.end(), 0)
<< std::endl;
- Assert((status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST),
- ExcInternalError());
+ Assert((status == CELL_PERSIST), ExcInternalError());
++some_number;
return buffer;
void
unpack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status,
+ & cell,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
{
const unsigned int data_in_bytes =
<< std::accumulate(intdatavector.begin(), intdatavector.end(), 0)
<< std::endl;
- Assert((status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST),
- ExcInternalError());
+ Assert((status == CELL_PERSIST), ExcInternalError());
}
std::vector<char>
pack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status)
+ & cell,
+ const CellStatus status)
{
static unsigned int some_number = 1;
std::vector<unsigned int> some_vector(some_number);
<< std::accumulate(some_vector.begin(), some_vector.end(), 0)
<< std::endl;
- Assert((status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST),
- ExcInternalError());
+ Assert((status == CELL_PERSIST), ExcInternalError());
++some_number;
return buffer;
void
unpack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status,
+ & cell,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
{
const unsigned int data_in_bytes =
<< std::accumulate(intdatavector.begin(), intdatavector.end(), 0)
<< std::endl;
- Assert((status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST),
- ExcInternalError());
+ Assert((status == CELL_PERSIST), ExcInternalError());
}
std::vector<char>
pack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status)
+ & cell,
+ const CellStatus status)
{
static int some_number = cell->index();
deallog << "packing cell " << cell->id() << " with data=" << some_number
<< " status=";
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST)
+ if (status == CELL_PERSIST)
deallog << "PERSIST";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ else if (status == CELL_REFINE)
deallog << "REFINE";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ else if (status == CELL_COARSEN)
deallog << "COARSEN";
deallog << std::endl;
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ if (status == CELL_COARSEN)
{
Assert(cell->has_children(), ExcInternalError());
}
void
unpack_function(
const typename parallel::distributed::Triangulation<dim, dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim, dim>::CellStatus
- status,
+ & cell,
+ const CellStatus status,
const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
{
const int number = Utilities::unpack<int>(data_range.begin(),
deallog << "unpacking cell " << cell->id() << " with data=" << number
<< " status=";
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_PERSIST)
+ if (status == CELL_PERSIST)
deallog << "PERSIST";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ else if (status == CELL_REFINE)
deallog << "REFINE";
- else if (status ==
- parallel::distributed::Triangulation<dim, dim>::CELL_COARSEN)
+ else if (status == CELL_COARSEN)
deallog << "COARSEN";
deallog << std::endl;
- if (status == parallel::distributed::Triangulation<dim, dim>::CELL_REFINE)
+ if (status == CELL_REFINE)
{
Assert(cell->has_children(), ExcInternalError());
}
// register weighting function that returns the number of particles per cell
triangulation.signals.weight.connect(
- [&particle_handler](
- const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status) -> unsigned int {
+ [&particle_handler](const typename parallel::distributed::Triangulation<
+ dim>::cell_iterator &cell,
+ const CellStatus status) -> unsigned int {
unsigned int n_particles_in_cell = 0;
switch (status)
{
- case parallel::distributed::Triangulation<dim>::CELL_PERSIST:
- case parallel::distributed::Triangulation<dim>::CELL_REFINE:
+ case CELL_PERSIST:
+ case CELL_REFINE:
n_particles_in_cell = particle_handler.n_particles_in_cell(cell);
break;
- case parallel::distributed::Triangulation<dim>::CELL_INVALID:
+ case CELL_INVALID:
break;
- case parallel::distributed::Triangulation<dim>::CELL_COARSEN:
+ case CELL_COARSEN:
for (const auto &child : cell->child_iterators())
n_particles_in_cell +=
particle_handler.n_particles_in_cell(child);
unsigned int
cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status) const;
+ & cell,
+ const CellStatus status) const;
// The following two functions are responsible for outputting the simulation
// results for the particles and for the velocity profile on the background
unsigned int
ParticleTracking<dim>::cell_weight(
const typename parallel::distributed::Triangulation<dim>::cell_iterator
- & cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus status)
- const
+ & cell,
+ const CellStatus status) const
{
// First, we introduce a base weight that will be assigned to every cell.
const unsigned int base_weight = 1;
unsigned int n_particles_in_cell = 0;
switch (status)
{
- case parallel::distributed::Triangulation<dim>::CELL_PERSIST:
- case parallel::distributed::Triangulation<dim>::CELL_REFINE:
+ case CELL_PERSIST:
+ case CELL_REFINE:
n_particles_in_cell = particle_handler.n_particles_in_cell(cell);
break;
- case parallel::distributed::Triangulation<dim>::CELL_INVALID:
+ case CELL_INVALID:
break;
- case parallel::distributed::Triangulation<dim>::CELL_COARSEN:
+ case CELL_COARSEN:
for (const auto &child : cell->child_iterators())
n_particles_in_cell += particle_handler.n_particles_in_cell(child);
break;
// of this class, but for the purpose of this example we want to group the
// particle related instructions.
background_triangulation.signals.weight.connect(
- [&](
- const typename parallel::distributed::Triangulation<dim>::cell_iterator
- &cell,
- const typename parallel::distributed::Triangulation<dim>::CellStatus
- status) -> unsigned int { return this->cell_weight(cell, status); });
+ [&](const typename parallel::distributed::Triangulation<
+ dim>::cell_iterator &cell,
+ const CellStatus status) -> unsigned int {
+ return this->cell_weight(cell, status);
+ });
// This initializes the background triangulation where the particles are
// living and the number of properties of the particles.