6#include <deal.II/base/mpi.h>
7#include <deal.II/fe/fe_values.h>
24#include <prismspf/config.h>
40template <
unsigned int dim,
unsigned int degree,
typename number>
58 const double &delta_t,
62 std::poisson_distribution<unsigned int> distribution(rate * delta_t * volume);
63 return distribution(rng);
92template <
unsigned int dim,
unsigned int degree,
typename number>
110 dealii::UpdateFlags::update_values |
111 dealii::UpdateFlags::update_JxW_values);
112 std::list<Nucleus<dim>> new_nuclei_list;
118 if (!variable.is_nucleation_rate_variable)
122 std::uniform_int_distribution<unsigned int> nucleating_index_dist(
124 variable.nucleating_field_indices.size() - 1);
129 .active_cell_iterators())
131 if (!cell->is_locally_owned())
135 std::vector<number> values(num_quad_points, 0.0);
137 const auto dof_iterator = cell->as_dof_handler_iterator(
141 fe_values.reinit(dof_iterator);
143 fe_values.get_function_values(
146 double nuc_rate = 0.0;
147 double cell_volume = 0.0;
148 for (
unsigned int q_point = 0; q_point < num_quad_points; ++q_point)
150 nuc_rate += values[q_point] * fe_values.get_quadrature().weight(q_point);
151 cell_volume += fe_values.JxW(q_point);
153 unsigned int num_nuclei_in_cell =
155 for (
unsigned int i = 0; i < num_nuclei_in_cell; ++i)
157 dealii::Point<dim> nucleus_location_unit_cell;
158 for (
unsigned int d = 0; d < dim; ++d)
162 static std::uniform_real_distribution<double> uniform_unit_interval(
165 nucleus_location_unit_cell[d] = uniform_unit_interval(rng);
167 dealii::Point<dim> nucleus_location =
169 .transform_unit_to_real_cell(cell, nucleus_location_unit_cell);
170 double seed_time = time_info.
get_time();
172 unsigned int nucleating_index =
173 variable.nucleating_field_indices[nucleating_index_dist(rng)];
175 new_nuclei_list.emplace_back(nucleating_index,
185template <
unsigned int dim,
unsigned int degree,
typename number>
194 if (!
bool(dealii::Utilities::MPI::sum(new_nuclei_list.size(), MPI_COMM_WORLD)))
204 std::vector<Nucleus<dim>> new_nuclei(new_nuclei_list.begin(), new_nuclei_list.end());
206 bool any_nucleation_occurred =
false;
207 if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0)
211 <<
"[Increment " << time_info.
get_increment() <<
"] : Nucleation\n"
212 <<
" " << new_nuclei.size() <<
" nuclei generated before exclusion.\n"
213 <<
" Excluding nuclei...\n";
214 unsigned int count = 0;
217 std::shuffle(new_nuclei.begin(), new_nuclei.end(), rng);
219 while (!new_nuclei.empty())
222 bool valid = std::none_of(
223 global_nuclei.begin(),
227 const double distance =
228 user_inputs.spatial_discretization.distance(nuc.location,
229 existing_nucleus.location);
231 return nuc_params.check_active(existing_nucleus, time_info) &&
232 (distance < nuc_params.nucleus_exclusion_distance ||
233 (nuc.field_index == existing_nucleus.field_index &&
234 distance < nuc_params.same_field_nucleus_exclusion_distance));
246 global_nuclei.push_back(nuc);
248 <<
" New nucleus at: " << nuc.
location <<
"\n";
250 any_nucleation_occurred =
true;
252 new_nuclei.pop_back();
255 <<
" new nuclei after exclusion.\n"
257 << global_nuclei.size() <<
" total nuclei.\n\n"
260 MPI_Bcast(&any_nucleation_occurred, 1, MPI_CXX_BOOL, 0, MPI_COMM_WORLD);
262 return any_nucleation_occurred;
265template <
unsigned int dim,
unsigned int degree,
typename number>
271 int rank = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
272 int num_procs = dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD);
273 int local_count = local_nuclei.size();
274 std::vector<int> nuclei_counts_per_rank;
277 nuclei_counts_per_rank.resize(num_procs);
280 MPI_Gather(&local_count,
283 nuclei_counts_per_rank.data(),
290 std::vector<int> recv_displacements;
291 std::vector<Nucleus<dim>> gathered_nuclei;
294 recv_displacements.resize(num_procs);
295 recv_displacements[0] = 0;
296 for (
int r = 1; r < num_procs; ++r)
297 recv_displacements[r] = recv_displacements[r - 1] + nuclei_counts_per_rank[r - 1];
299 int total_count = recv_displacements.back() + nuclei_counts_per_rank.back();
300 gathered_nuclei.resize(total_count);
304 MPI_Gatherv(local_nuclei.data(),
307 gathered_nuclei.data(),
308 nuclei_counts_per_rank.data(),
309 recv_displacements.data(),
315 local_nuclei = gathered_nuclei;
319template <
unsigned int dim,
unsigned int degree,
typename number>
324 int rank = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
325 int count = local_nuclei.size();
326 MPI_Bcast(&count, 1, MPI_INT, 0, MPI_COMM_WORLD);
330 local_nuclei.resize(count);
336PRISMS_PF_END_NAMESPACE
static dealii::ConditionalOStream & pout_base()
Generic parallel output stream. Used for essential information in release and debug mode.
Definition conditional_ostreams.cc:44
The class handles the stochastic nucleation in PRISMS-PF.
Definition nucleation_manager.h:42
static bool attempt_nucleation(const SolveContext< dim, degree, number > &solve_context, std::vector< Nucleus< dim > > &nuclei)
Main nucleation function. Iterates over the domain and stochastically adds nuclei to the list.
Definition nucleation_manager.h:94
static void mpi_broadcast_nuclei(std::vector< Nucleus< dim > > &local_nuclei)
Broadcasts nuclei lists from root. Modifies.
Definition nucleation_manager.h:321
static unsigned int calculate_number_of_events(const double &rate, const double &delta_t, const double &volume, RNGEngine &rng)
Samples the poisson distribution to calculate a number of events in a time-volume given a rate.
Definition nucleation_manager.h:57
static bool gather_exclude_broadcast_nuclei(std::list< Nucleus< dim > > &new_nuclei_list, std::vector< Nucleus< dim > > &global_nuclei, const UserInputParameters< dim > &user_inputs, const SimulationTimer &time_info)
Gathers the potential new nuclei from each processor onto the root process, eliminates any nuclei tha...
Definition nucleation_manager.h:187
static void mpi_gather_nuclei(std::vector< Nucleus< dim > > &local_nuclei)
Gathers nuclei lists to root. Modifies.
Definition nucleation_manager.h:267
Definition simulation_timer.h:13
unsigned int get_increment() const
Definition simulation_timer.h:23
double get_timestep() const
Definition simulation_timer.h:35
double get_time() const
Definition simulation_timer.h:29
This class provides context for a solver with ptrs to all the relevant dependencies.
Definition solve_context.h:34
const DoFManager< dim, degree > & get_dof_manager() const
Get the dof manager.
Definition solve_context.h:101
const std::vector< FieldAttributes > & get_field_attributes() const
Get the field attributes.
Definition solve_context.h:62
SolutionIndexer< dim, number > & get_solution_indexer() const
Get the solution manager.
Definition solve_context.h:159
const UserInputParameters< dim > & get_user_inputs() const
Get the user-inputs.
Definition solve_context.h:71
const SimulationTimer & get_simulation_timer() const
Get the simulation timer.
Definition solve_context.h:187
const TriangulationManager< dim > & get_triangulation_manager() const
Get the triangulation manager.
Definition solve_context.h:81
static const std::array< const dealii::FESystem< dim >, 2 > fe_systems
Scalar and Vector FE systems.
Definition system_wide.h:29
static const dealii::QGaussLobatto< dim > quadrature
Quadrature rule.
Definition system_wide.h:41
static const dealii::MappingQ1< dim > mapping
Mappings to and from reference cell.
Definition system_wide.h:36
std::mt19937 RNGEngine
Definition miscellaneous_parameters.h:23
Definition conditional_ostreams.cc:20
RNGEngine rng
Definition miscellaneous_parameters.h:66
Struct that holds nucleation parameters.
Definition nucleation_parameters.h:30
unsigned int nucleation_period
Definition nucleation_parameters.h:69
This class contains mutable utilities for phase field problems.
Definition nucleus.h:23
static MPI_Datatype mpi_datatype()
Definition nucleus.h:77
dealii::Point< dim > location
Definition nucleus.h:44