14#include "libmesh/nanoflann.hpp"
15#include "libmesh/parallel_algebra.h"
16#include "libmesh/mesh_tools.h"
17#include "libmesh/int_range.h"
24#if NANOFLANN_VERSION < 0x150
29template <
typename T,
typename U>
50 "Name of the material property to average");
51 MooseEnum weights_type(
"constant linear cosine",
"linear");
58 "Padding for communication. This gets added to the radius when determining which QPs to send "
59 "to other processors. Increase this gradually if inconsistent parallel results occur.");
75 _prop(getMaterialProperty<Real>(
"prop_name")),
76 _radius(getParam<Real>(
"radius")),
77 _padding(getParam<Real>(
"padding")),
78 _update_communication_lists(false),
79 _my_pid(processor_id()),
80 _perf_meshchanged(registerTimedSection(
"meshChanged", 3)),
81 _perf_updatelists(registerTimedSection(
"updateCommunicationLists", 3)),
82 _perf_finalize(registerTimedSection(
"finalize", 2))
105 for (
const auto qp : make_range(
_qrule->n_points()))
111 _average.insert(std::make_pair(
id, std::vector<Real>(
_qrule->n_points())));
113 i->second.resize(
_qrule->n_points());
122 unsigned int local_size =
_qp_data.size();
141 std::vector<QPData> receive;
152 send[i].reserve(list.size());
153 for (
const auto & item : list)
169 const auto source_pid = TIMPI::cast_int<processor_id_type>(status.source());
170 const auto message_size = status.size(item_type);
173 receive.resize(message_size);
182 Parallel::wait(send_requests);
186 const unsigned int max_leaf_size = 20;
188 _kd_tree = std::make_unique<KDTreeType>(
189 LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
191 mooseAssert(
_kd_tree !=
nullptr,
"KDTree was not properly initialized.");
198 auto local_range_begin =
_qp_data.begin();
199 auto local_range_end = local_range_begin;
200 std::advance(local_range_end, local_size);
208 const auto & uo = cast_ref<const RadialAverage &>(y);
210 _average.insert(uo._average.begin(), uo._average.end());
231 const auto end =
mesh.active_local_elements_end();
232 for (
auto it =
mesh.active_local_elements_begin(); it != end; ++it)
234 for (
const auto s : make_range((*it)->n_sides()))
236 const auto * neighbor = (*it)->neighbor_ptr(s);
237 if (neighbor && neighbor->processor_id() !=
_my_pid)
239 for (
const auto n : make_range((*it)->n_nodes()))
240 if ((*it)->is_node_on_side(n, s))
258 const unsigned int max_leaf_size = 20;
260 auto kd_tree = std::make_unique<KDTreeType>(
261 LIBMESH_DIM, point_list, nanoflann::KDTreeSingleIndexAdaptorParams(max_leaf_size));
262 mooseAssert(kd_tree !=
nullptr,
"KDTree was not properly initialized.");
263 kd_tree->buildIndex();
265 std::vector<nanoflann::ResultItem<std::size_t, Real>> ret_matches;
273 kd_tree->radiusSearch(
274 &(bn(0)), Utility::pow<2>(
_radius +
_padding), ret_matches, search_params);
275 for (
auto & match : ret_matches)
280 std::vector<std::pair<Point, Point>> pps(
n_processors());
282 std::pair<Point, Point> mypp = mybb;
286 const auto rpoint = Point(1, 1, 1) *
_radius;
287 std::vector<BoundingBox> bbs;
288 for (
const auto & pp : pps)
289 bbs.emplace_back(pp.first - rpoint, pp.second + rpoint);
293 for (
const auto pid : index_range(bbs))
294 if (pid !=
_my_pid && bbs[pid].intersects(mypp))
317#ifdef LIBMESH_HAVE_MPI
327 MPI_Datatype types[] = {
329 int blocklengths[] = {1, 1, 1, 1, 1};
330 MPI_Aint displs[5], start;
333 libmesh_call_mpi(MPI_Get_address(
const_cast<Point *
>(&example->
_q_point), &displs[0]));
334 libmesh_call_mpi(MPI_Get_address(
const_cast<dof_id_type *
>(&example->
_elem_id), &displs[1]));
335 libmesh_call_mpi(MPI_Get_address(
const_cast<short *
>(&example->
_qp), &displs[2]));
336 libmesh_call_mpi(MPI_Get_address(
const_cast<Real *
>(&example->
_volume), &displs[3]));
337 libmesh_call_mpi(MPI_Get_address(
const_cast<Real *
>(&example->
_value), &displs[4]));
339 for (std::size_t i = 0; i < 5; ++i)
343 MPI_Datatype tmptype;
344 libmesh_call_mpi(MPI_Type_create_struct(5, blocklengths, displs, types, &tmptype));
345 libmesh_call_mpi(MPI_Type_commit(&tmptype));
349 libmesh_call_mpi(MPI_Type_free(&tmptype));
359#ifdef LIBMESH_HAVE_MPI
360 libmesh_call_mpi(MPI_Type_dup(t._datatype, &_datatype));
const ExecFlagType EXEC_TIMESTEP_BEGIN
registerMooseObject("MooseApp", RadialAverage)
StoredRange< std::vector< RadialAverage::QPData >::const_iterator, RadialAverage::QPData > QPDataRange
static InputParameters validParams()
const QBase *const & _qrule
const Elem *const & _current_elem
The current element pointer (available during execute())
const MooseArray< Real > & _coord
const MooseArray< Real > & _JxW
const MooseArray< Point > & _q_point
A MultiMooseEnum object to hold "execute_on" flags.
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
MooseApp & getMooseApp() const
Get the MooseApp this class is associated with.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
libMesh::BoundingBox getInflatedProcessorBoundingBox(Real inflation_multiplier=0.01) const
Get a (slightly inflated) processor bounding box.
MeshBase & getMesh()
Accessor for the underlying libMesh Mesh object.
MooseApp & _app
The MOOSE application this is associated with.
const Point & getPoint(const PointObject &item) const
get a Point reference from the PointData object at index idx in the list
Gather and communicate a full list of all quadrature points and the values of a selected material pro...
virtual void initialSetup() override
Gets called at the beginning of the simulation before this object is asked to do its job.
std::vector< std::vector< const Elem * > > _nodes_to_elem_map
The data structure used to find neighboring elements give a node ID.
virtual void initialize() override
Called before execute() is ever called so that data can be cleared.
const Real _radius
cut-off radius
std::vector< std::set< std::size_t > > _communication_lists
QPData indices to send to the various processors.
std::set< Point > _boundary_nodes
set of nodes on the boundary of the current processor domain
const Real _padding
communication padding distance
virtual void execute() override
Execute method.
processor_id_type _my_pid
bool _update_communication_lists
RadialAverage(const InputParameters ¶meters)
std::unique_ptr< KDTreeType > _kd_tree
spatial index (nanoflann guarantees this to be threadsafe under read-only operations)
virtual void threadJoin(const UserObject &y) override
Must override.
std::vector< processor_id_type > _candidate_procs
processors to send (potentially empty) data to
virtual void meshChanged() override
Called on this object when the mesh changes.
void updateCommunicationLists()
static InputParameters validParams()
Result _average
average result
WeightsType
distance based weight function
virtual void finalize() override
Finalize.
std::set< std::size_t > _boundary_data_indices
set of all _qp_data indices that are within _radius of any _boundary_nodes
const MaterialProperty< Real > & _prop
material to be averaged
std::vector< QPData > _qp_data
gathered data
MessageTag get_unique_tag(int tagvalue=MessageTag::invalid_tag) const
status probe(const unsigned int src_processor_id, const MessageTag &tag=any_tag) const
Status receive(const unsigned int dest_processor_id, T &buf, const MessageTag &tag=any_tag) const
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
void send(const unsigned int dest_processor_id, const T &buf, const MessageTag &tag=no_tag) const
StandardType(const T *example=nullptr)
RadialAverage threaded loop.
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
Base class for user-specific data.
const Parallel::Communicator & _communicator
processor_id_type n_processors() const
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
std::pair< T, U > ResultItem
SearchParams SearchParameters
dof_id_type _elem_id
element id
Real _volume
current value * _JxW
short _qp
index of the quadrature point
Point _q_point
physical coordinates of the quadrature point
Real _value
variable value