34 template <
int dim,
int spacedim>
36 pack_particles(std::vector<ParticleIterator<dim, spacedim>> &particles)
38 std::vector<char> buffer;
40 if (particles.empty())
43 buffer.resize(particles.size() *
44 particles.front()->serialized_size_in_bytes());
45 void *current_data = buffer.data();
47 for (
const auto &particle : particles)
49 current_data = particle->write_particle_data_to_memory(current_data);
58 template <
int dim,
int spacedim>
63 , global_number_of_particles(0)
64 , number_of_locally_owned_particles(0)
65 , global_max_particles_per_cell(0)
66 , next_free_particle_index(0)
70 , tria_attached_data_index(
numbers::invalid_unsigned_int)
78 template <
int dim,
int spacedim>
82 const unsigned int n_properties)
84 , mapping(&mapping, typeid(*this).name())
85 , property_pool(
std::make_unique<
PropertyPool<dim, spacedim>>(n_properties))
86 , cells_to_particle_cache(
triangulation.n_active_cells(), particles.end())
87 , global_number_of_particles(0)
88 , number_of_locally_owned_particles(0)
89 , global_max_particles_per_cell(0)
90 , next_free_particle_index(0)
94 , tria_attached_data_index(
numbers::invalid_unsigned_int)
95 , triangulation_cache(
106 template <
int dim,
int spacedim>
111 for (
const auto &connection : tria_listeners)
112 connection.disconnect();
117 template <
int dim,
int spacedim>
122 const unsigned int n_properties)
127 mapping = &new_mapping;
129 reset_particle_container(particles);
132 property_pool = std::make_unique<PropertyPool<dim, spacedim>>(n_properties);
136 triangulation_cache =
137 std::make_unique<GridTools::Cache<dim, spacedim>>(new_triangulation,
140 cells_to_particle_cache.resize(
triangulation->n_active_cells(),
143 connect_to_triangulation_signals();
148 template <
int dim,
int spacedim>
153 const unsigned int n_properties =
159 property_pool = std::make_unique<PropertyPool<dim, spacedim>>(
164 number_of_locally_owned_particles =
167 global_max_particles_per_cell =
173 particles.insert(particle_container_owned_end(),
176 particles.insert(particle_container_ghost_end(),
180 for (
auto it = particles.begin(); it != particles.end(); ++it)
181 if (!it->particles.empty())
182 cells_to_particle_cache[it->cell->active_cell_index()] = it;
184 ghost_particles_cache.ghost_particles_by_domain =
191 template <
int dim,
int spacedim>
196 global_number_of_particles = 0;
197 number_of_locally_owned_particles = 0;
198 next_free_particle_index = 0;
199 global_max_particles_per_cell = 0;
204 template <
int dim,
int spacedim>
208 for (
auto &particles_in_cell : particles)
209 for (
auto &particle : particles_in_cell.particles)
211 property_pool->deregister_particle(particle);
213 cells_to_particle_cache.clear();
214 reset_particle_container(particles);
216 cells_to_particle_cache.resize(
triangulation->n_active_cells(),
221 property_pool->clear();
226 template <
int dim,
int spacedim>
230 property_pool->reserve(n_particles);
235 template <
int dim,
int spacedim>
243 past_the_end_iterator =
248 given_particles.clear();
249 for (
unsigned int i = 0; i < 3; ++i)
250 given_particles.emplace_back(
252 past_the_end_iterator);
255 const_cast<typename particle_container::iterator &
>(owned_particles_end) =
256 ++given_particles.begin();
261 template <
int dim,
int spacedim>
266 bool sort_is_necessary =
false;
268 auto previous = particle_container_owned_begin();
269 for (
auto next = previous; next != particle_container_owned_end(); ++next)
273 previous->cell > next->cell)
275 sort_is_necessary =
true;
281 if (sort_is_necessary)
296 reset_particle_container(sorted_particles);
299 for (
const auto &cell :
triangulation->active_cell_iterators())
300 if (!cell->is_artificial())
301 if (cells_to_particle_cache[cell->active_cell_index()] !=
308 typename particle_container::iterator insert_position =
309 cell->is_locally_owned() ? particle_container_owned_end() :
310 --sorted_particles.end();
311 typename particle_container::iterator new_entry =
312 sorted_particles.insert(
313 insert_position,
typename particle_container::value_type());
314 new_entry->cell = cell;
315 new_entry->particles =
316 std::move(cells_to_particle_cache[cell->active_cell_index()]
319 particles = std::move(sorted_particles);
322 cells_to_particle_cache.clear();
323 cells_to_particle_cache.resize(
triangulation->n_active_cells(),
325 for (
auto it = particles.begin(); it != particles.end(); ++it)
326 if (!it->particles.empty())
327 cells_to_particle_cache[it->cell->active_cell_index()] = it;
333 particles.front().particles.empty() &&
335 particles.back().particles.empty() &&
337 owned_particles_end->particles.empty(),
343 for (
const auto &it : cells_to_particle_cache)
344 Assert(it != particles.begin() && it != owned_particles_end &&
345 it != --(particles.end()),
350 for (
auto it = particle_container_owned_begin();
351 it != particle_container_owned_end();
356 std::vector<typename particle_container::iterator> verify_cache(
358 for (
auto it = particles.begin(); it != particles.end(); ++it)
359 if (!it->particles.empty())
360 verify_cache[it->cell->active_cell_index()] = it;
362 for (
unsigned int i = 0; i < verify_cache.size(); ++i)
368 number_of_locally_owned_particles = 0;
371 for (
const auto &particles_in_cell : particles)
374 particles_in_cell.particles.size();
377 result[0] =
std::max(result[0], n_particles_in_cell);
380 if (n_particles_in_cell > 0 &&
381 particles_in_cell.cell->is_locally_owned())
382 number_of_locally_owned_particles += n_particles_in_cell;
385 for (
const auto &particle : particles_in_cell.particles)
386 result[1] =
std::max(result[1], property_pool->get_id(particle));
389 global_number_of_particles =
393 if (global_number_of_particles == 0)
395 next_free_particle_index = 0;
396 global_max_particles_per_cell = 0;
404 next_free_particle_index = result[1] + 1;
405 global_max_particles_per_cell = result[0];
411 template <
int dim,
int spacedim>
417 if (cells_to_particle_cache.empty())
420 if (cell->is_artificial() ==
false)
422 return cells_to_particle_cache[cell->active_cell_index()] !=
424 cells_to_particle_cache[cell->active_cell_index()]
430 ExcMessage(
"You can't ask for the particles on an artificial "
431 "cell since we don't know what exists on these "
439 template <
int dim,
int spacedim>
446 ->particles_in_cell(cell);
451 template <
int dim,
int spacedim>
456 const unsigned int active_cell_index = cell->active_cell_index();
458 if (cell->is_artificial() ==
false)
460 if (cells_to_particle_cache[active_cell_index] == particles.end())
462 return boost::make_iterator_range(
468 const typename particle_container::iterator
469 particles_in_current_cell =
470 cells_to_particle_cache[active_cell_index];
471 typename particle_container::iterator particles_in_next_cell =
472 particles_in_current_cell;
473 ++particles_in_next_cell;
474 return boost::make_iterator_range(
481 ExcMessage(
"You can't ask for the particles on an artificial "
482 "cell since we don't know what exists on these "
490 template <
int dim,
int spacedim>
495 auto &particles_on_cell = particle->particles_in_cell->particles;
500 auto handle = particle->get_handle();
502 property_pool->deregister_particle(handle);
507 const auto cell = particle->get_surrounding_cell();
508 const bool owned_cell = cell->is_locally_owned();
510 --number_of_locally_owned_particles;
512 if (particles_on_cell.size() > 1)
514 particles_on_cell[particle->particle_index_within_cell] =
515 std::move(particles_on_cell.back());
516 particles_on_cell.resize(particles_on_cell.size() - 1);
520 particles.erase(particle->particles_in_cell);
521 cells_to_particle_cache[cell->active_cell_index()] = particles.end();
527 template <
int dim,
int spacedim>
531 &particles_to_remove)
539 return a->particles_in_cell->cell > b->particles_in_cell->cell ||
540 (a->particles_in_cell->cell == b->particles_in_cell->cell &&
541 a->particle_index_within_cell > b->particle_index_within_cell);
544 bool particles_are_sorted =
true;
545 auto previous = particles_to_remove.begin();
546 for (
auto next = previous; next != particles_to_remove.end(); ++next)
548 if (check_greater(*previous, *next))
550 particles_are_sorted =
false;
555 if (particles_are_sorted)
558 for (
auto it = particles_to_remove.rbegin();
559 it != particles_to_remove.rend();
561 remove_particle(*it);
565 std::vector<ParticleHandler<dim, spacedim>::particle_iterator>
566 sorted_particles(particles_to_remove);
567 std::sort(sorted_particles.begin(),
568 sorted_particles.end(),
571 for (
const auto &particle : sorted_particles)
572 remove_particle(particle);
575 update_cached_numbers();
580 template <
int dim,
int spacedim>
595 template <
int dim,
int spacedim>
601 const unsigned int active_cell_index = cell->active_cell_index();
602 typename particle_container::iterator &cache =
603 cells_to_particle_cache[active_cell_index];
604 if (cache == particles.end())
606 const typename particle_container::iterator insert_position =
607 cell->is_locally_owned() ? particle_container_owned_end() :
608 particle_container_ghost_end();
609 cache = particles.emplace(
616 cache->particles.push_back(handle);
621 cache->particles.size() - 1);
626 template <
int dim,
int spacedim>
635 Assert(cell->is_locally_owned(),
636 ExcMessage(
"You tried to insert particles into a cell that is not "
637 "locally owned. This is not supported."));
640 insert_particle(property_pool->register_particle(), cell);
642 data = particle_it->read_particle_data_from_memory(
data);
644 ++number_of_locally_owned_particles;
651 template <
int dim,
int spacedim>
664 Assert(cell->is_locally_owned(),
665 ExcMessage(
"You tried to insert particles into a cell that is not "
666 "locally owned. This is not supported."));
669 insert_particle(property_pool->register_particle(), cell);
671 particle_it->set_location(position);
672 particle_it->set_reference_location(reference_position);
673 particle_it->set_id(particle_index);
675 if (properties.
size() != 0)
676 particle_it->set_properties(properties);
678 ++number_of_locally_owned_particles;
685 template <
int dim,
int spacedim>
692 reserve(n_locally_owned_particles() + new_particles.size());
693 for (
const auto &cell_and_particle : new_particles)
694 insert_particle(cell_and_particle.second, cell_and_particle.first);
696 update_cached_numbers();
701 template <
int dim,
int spacedim>
708 update_cached_numbers();
709 reserve(n_locally_owned_particles() + positions.size());
716 get_next_free_particle_index();
719#ifdef DEAL_II_WITH_MPI
720 if (
const auto parallel_triangulation =
726 MPI_Scan(&particles_to_add_locally,
731 parallel_triangulation->get_mpi_communicator());
733 local_start_index -= particles_to_add_locally;
737 local_start_index += local_next_particle_index;
739 auto point_locations =
743 auto &cells = std::get<0>(point_locations);
744 auto &local_positions = std::get<1>(point_locations);
745 auto &index_map = std::get<2>(point_locations);
746 auto &missing_points = std::get<3>(point_locations);
752 (void)missing_points;
754 for (
unsigned int i = 0; i < cells.size(); ++i)
755 for (
unsigned int p = 0; p < local_positions[i].size(); ++p)
756 insert_particle(positions[index_map[i][p]],
757 local_positions[i][p],
758 local_start_index + index_map[i][p],
761 update_cached_numbers();
766 template <
int dim,
int spacedim>
767 std::map<unsigned int, IndexSet>
771 &global_bounding_boxes,
772 const std::vector<std::vector<double>> &properties,
773 const std::vector<types::particle_index> &ids)
775 if (!properties.empty())
779 for (
const auto &p : properties)
792 const auto n_global_properties =
796 const auto n_particles_per_proc =
800 std::vector<unsigned int> particle_start_indices(n_mpi_processes);
802 unsigned int particle_start_index = get_next_free_particle_index();
803 for (
unsigned int process = 0; process < particle_start_indices.size();
806 particle_start_indices[process] = particle_start_index;
807 particle_start_index += n_particles_per_proc[process];
811 const auto cells_positions_and_index_maps =
814 global_bounding_boxes);
818 const auto &local_cells_containing_particles =
819 std::get<0>(cells_positions_and_index_maps);
823 const auto &local_reference_positions =
824 std::get<1>(cells_positions_and_index_maps);
827 const auto &original_indices_of_local_particles =
828 std::get<2>(cells_positions_and_index_maps);
831 const auto &local_positions = std::get<3>(cells_positions_and_index_maps);
833 const auto &calling_process_indices =
834 std::get<4>(cells_positions_and_index_maps);
837 std::map<unsigned int, std::vector<unsigned int>>
838 original_process_to_local_particle_indices_tmp;
839 for (
unsigned int i_cell = 0;
840 i_cell < local_cells_containing_particles.size();
843 for (
unsigned int i_particle = 0;
844 i_particle < local_positions[i_cell].size();
847 const unsigned int local_id_on_calling_process =
848 original_indices_of_local_particles[i_cell][i_particle];
849 const unsigned int calling_process =
850 calling_process_indices[i_cell][i_particle];
852 original_process_to_local_particle_indices_tmp[calling_process]
853 .push_back(local_id_on_calling_process);
856 std::map<unsigned int, IndexSet> original_process_to_local_particle_indices;
857 for (
auto &process_and_particle_indices :
858 original_process_to_local_particle_indices_tmp)
860 const unsigned int calling_process = process_and_particle_indices.first;
861 original_process_to_local_particle_indices.insert(
862 {calling_process,
IndexSet(n_particles_per_proc[calling_process])});
863 std::sort(process_and_particle_indices.second.begin(),
864 process_and_particle_indices.second.end());
865 original_process_to_local_particle_indices[calling_process].add_indices(
866 process_and_particle_indices.second.begin(),
867 process_and_particle_indices.second.end());
868 original_process_to_local_particle_indices[calling_process].compress();
876 std::map<unsigned int, std::vector<std::vector<double>>>
877 locally_owned_properties_from_other_processes;
884 std::map<unsigned int, std::vector<types::particle_index>>
885 locally_owned_ids_from_other_processes;
887 if (n_global_properties > 0 || !ids.empty())
892 comm, original_process_to_local_particle_indices);
895 if (n_global_properties > 0)
897 std::map<unsigned int, std::vector<std::vector<double>>>
898 non_locally_owned_properties;
900 for (
const auto &it : send_to_cpu)
902 std::vector<std::vector<double>> properties_to_send(
903 it.second.n_elements(),
904 std::vector<double>(n_properties_per_particle()));
905 unsigned int index = 0;
906 for (
const auto el : it.second)
907 properties_to_send[index++] = properties[el];
908 non_locally_owned_properties.insert(
909 {it.first, properties_to_send});
914 locally_owned_properties_from_other_processes =
918 locally_owned_properties_from_other_processes.size(),
919 original_process_to_local_particle_indices.size());
924 std::map<unsigned int, std::vector<types::particle_index>>
925 non_locally_owned_ids;
926 for (
const auto &it : send_to_cpu)
928 std::vector<types::particle_index> ids_to_send(
929 it.second.n_elements());
930 unsigned int index = 0;
931 for (
const auto el : it.second)
932 ids_to_send[index++] = ids[el];
933 non_locally_owned_ids.insert({it.first, ids_to_send});
938 locally_owned_ids_from_other_processes =
942 original_process_to_local_particle_indices.size());
947 for (
unsigned int i_cell = 0;
948 i_cell < local_cells_containing_particles.size();
951 for (
unsigned int i_particle = 0;
952 i_particle < local_positions[i_cell].size();
955 const unsigned int local_id_on_calling_process =
956 original_indices_of_local_particles[i_cell][i_particle];
958 const unsigned int calling_process =
959 calling_process_indices[i_cell][i_particle];
961 const unsigned int index_within_set =
962 original_process_to_local_particle_indices[calling_process]
963 .index_within_set(local_id_on_calling_process);
965 const unsigned int particle_id =
967 local_id_on_calling_process +
968 particle_start_indices[calling_process] :
969 locally_owned_ids_from_other_processes[calling_process]
973 insert_particle(local_positions[i_cell][i_particle],
974 local_reference_positions[i_cell][i_particle],
976 local_cells_containing_particles[i_cell]);
978 if (n_global_properties > 0)
980 particle_it->set_properties(
981 locally_owned_properties_from_other_processes
982 [calling_process][index_within_set]);
987 update_cached_numbers();
989 return original_process_to_local_particle_indices;
994 template <
int dim,
int spacedim>
995 std::map<unsigned int, IndexSet>
999 &global_bounding_boxes)
1003 std::vector<Point<spacedim>> positions;
1004 std::vector<std::vector<double>> properties;
1005 std::vector<types::particle_index> ids;
1006 positions.resize(particles.size());
1007 ids.resize(particles.size());
1008 if (n_properties_per_particle() > 0)
1009 properties.resize(particles.size(),
1010 std::vector<double>(n_properties_per_particle()));
1013 for (
const auto &p : particles)
1015 positions[i] = p.get_location();
1016 ids[i] = p.get_id();
1017 if (p.has_properties())
1018 properties[i] = {p.get_properties().begin(),
1019 p.get_properties().end()};
1023 return insert_global_particles(positions,
1024 global_bounding_boxes,
1031 template <
int dim,
int spacedim>
1035 return global_number_of_particles;
1040 template <
int dim,
int spacedim>
1044 return global_max_particles_per_cell;
1049 template <
int dim,
int spacedim>
1053 return number_of_locally_owned_particles;
1058 template <
int dim,
int spacedim>
1062 return property_pool->n_properties_per_slot();
1067 template <
int dim,
int spacedim>
1071 return next_free_particle_index;
1076 template <
int dim,
int spacedim>
1080 IndexSet set(get_next_free_particle_index());
1081 std::vector<types::particle_index> indices;
1082 indices.reserve(n_locally_owned_particles());
1083 for (
const auto &p : *
this)
1084 indices.push_back(p.get_id());
1092 template <
int dim,
int spacedim>
1096 return property_pool->n_slots();
1101 template <
int dim,
int spacedim>
1105 const bool add_to_output_vector)
1111 for (
auto it = begin(); it != end(); ++it, ++i)
1113 if (add_to_output_vector)
1114 positions[i] = positions[i] + it->get_location();
1116 positions[i] = it->get_location();
1122 template <
int dim,
int spacedim>
1126 const bool displace_particles)
1132 for (
auto it = begin(); it != end(); ++it, ++i)
1135 if (displace_particles)
1136 location += new_positions[i];
1138 location = new_positions[i];
1140 sort_particles_into_subdomains_and_cells();
1145 template <
int dim,
int spacedim>
1149 const bool displace_particles)
1156 for (
auto &particle : *
this)
1159 function.
vector_value(particle_location, new_position);
1160 if (displace_particles)
1161 for (
unsigned int d = 0; d < spacedim; ++d)
1162 particle_location[d] += new_position[d];
1164 for (
unsigned int d = 0; d < spacedim; ++d)
1165 particle_location[d] = new_position[d];
1167 sort_particles_into_subdomains_and_cells();
1172 template <
int dim,
int spacedim>
1176 return *property_pool;
1194 compare_particle_association(
1195 const unsigned int a,
1196 const unsigned int b,
1200 const double scalar_product_a = center_directions[a] * particle_direction;
1201 const double scalar_product_b = center_directions[b] * particle_direction;
1206 return (scalar_product_a > scalar_product_b);
1212 template <
int dim,
int spacedim>
1228 std::vector<particle_iterator> particles_out_of_cell;
1233 particles_out_of_cell.reserve(n_locally_owned_particles() / 4);
1236 std::vector<Point<spacedim>> real_locations;
1237 std::vector<Point<dim>> reference_locations;
1238 real_locations.reserve(global_max_particles_per_cell);
1239 reference_locations.reserve(global_max_particles_per_cell);
1241 for (
const auto &cell :
triangulation->active_cell_iterators())
1248 if (cell->is_locally_owned() ==
false)
1253 const unsigned int n_pic = n_particles_in_cell(cell);
1254 auto pic = particles_in_cell(cell);
1256 real_locations.clear();
1257 for (
const auto &particle : pic)
1258 real_locations.push_back(particle.get_location());
1260 reference_locations.resize(n_pic);
1261 mapping->transform_points_real_to_unit_cell(cell,
1263 reference_locations);
1265 auto particle = pic.begin();
1266 for (
const auto &p_unit : reference_locations)
1270 tolerance_inside_cell))
1271 particle->set_reference_location(p_unit);
1273 particles_out_of_cell.push_back(particle);
1285 std::map<types::subdomain_id, std::vector<particle_iterator>>
1289 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1297 using vector_size =
typename std::vector<particle_iterator>::size_type;
1299 std::set<types::subdomain_id> ghost_owners;
1300 if (
const auto parallel_triangulation =
1303 ghost_owners = parallel_triangulation->ghost_owners();
1308 for (
const auto &ghost_owner : ghost_owners)
1309 moved_particles[ghost_owner].reserve(particles_out_of_cell.size() / 4);
1310 for (
const auto &ghost_owner : ghost_owners)
1311 moved_cells[ghost_owner].reserve(particles_out_of_cell.size() / 4);
1316 std::set<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1317 &vertex_to_cells = triangulation_cache->get_vertex_to_cell_map();
1321 const std::vector<std::vector<Tensor<1, spacedim>>>
1322 &vertex_to_cell_centers =
1323 triangulation_cache->get_vertex_to_cell_centers_directions();
1325 std::vector<unsigned int> search_order;
1333 for (
auto &out_particle : particles_out_of_cell)
1338 auto current_cell = out_particle->get_surrounding_cell();
1340 real_locations[0] = out_particle->get_location();
1343 bool found_cell =
false;
1347 const unsigned int closest_vertex =
1348 GridTools::find_closest_vertex_of_cell<dim, spacedim>(
1349 current_cell, out_particle->get_location(), *mapping);
1350 const unsigned int closest_vertex_index =
1351 current_cell->vertex_index(closest_vertex);
1353 const auto &candidate_cells = vertex_to_cells[closest_vertex_index];
1354 const unsigned int n_candidate_cells = candidate_cells.size();
1358 search_order.resize(n_candidate_cells);
1359 for (
unsigned int i = 0; i < n_candidate_cells; ++i)
1360 search_order[i] = i;
1366 out_particle->get_location() - current_cell->vertex(closest_vertex);
1371 1e4 * std::numeric_limits<double>::epsilon() *
1372 std::numeric_limits<double>::epsilon() *
1373 vertex_to_cell_centers[closest_vertex_index][0].norm_square())
1375 vertex_to_particle /= vertex_to_particle.
norm();
1376 const auto &vertex_to_cells =
1377 vertex_to_cell_centers[closest_vertex_index];
1379 std::sort(search_order.begin(),
1381 [&vertex_to_particle,
1382 &vertex_to_cells](
const unsigned int a,
1383 const unsigned int b) {
1384 return compare_particle_association(
1385 a, b, vertex_to_particle, vertex_to_cells);
1391 for (
unsigned int i = 0; i < n_candidate_cells; ++i)
1395 const_iterator candidate_cell = candidate_cells.begin();
1397 std::advance(candidate_cell, search_order[i]);
1398 mapping->transform_points_real_to_unit_cell(*candidate_cell,
1400 reference_locations);
1403 tolerance_inside_cell))
1405 current_cell = *candidate_cell;
1421#if defined(DEAL_II_WITH_BOOST_BUNDLED) || \
1422 !(defined(__clang_major__) && __clang_major__ >= 16) || \
1423 BOOST_VERSION >= 108100
1425 std::vector<std::pair<Point<spacedim>,
unsigned int>>
1426 closest_vertex_in_domain;
1427 triangulation_cache->get_used_vertices_rtree().query(
1428 boost::geometry::index::nearest(out_particle->get_location(),
1430 std::back_inserter(closest_vertex_in_domain));
1434 const unsigned int closest_vertex_index_in_domain =
1435 closest_vertex_in_domain[0].second;
1437 const unsigned int closest_vertex_index_in_domain =
1440 out_particle->get_location());
1445 for (
const auto &cell :
1446 vertex_to_cells[closest_vertex_index_in_domain])
1448 mapping->transform_points_real_to_unit_cell(
1449 cell, real_locations, reference_locations);
1452 reference_locations[0], tolerance_inside_cell))
1454 current_cell = cell;
1466 signals.particle_lost(out_particle,
1467 out_particle->get_surrounding_cell());
1473 out_particle->set_reference_location(reference_locations[0]);
1477 if (current_cell->is_locally_owned())
1480 out_particle->particles_in_cell
1481 ->particles[out_particle->particle_index_within_cell];
1484 const auto old_value = old;
1488 insert_particle(old_value, current_cell);
1492 moved_particles[current_cell->subdomain_id()].push_back(
1494 moved_cells[current_cell->subdomain_id()].push_back(current_cell);
1500#ifdef DEAL_II_WITH_MPI
1501 if (
const auto parallel_triangulation =
1506 parallel_triangulation->get_mpi_communicator()) > 1)
1507 send_recv_particles(moved_particles, moved_cells);
1512 remove_particles(particles_out_of_cell);
1515 std::vector<typename PropertyPool<dim, spacedim>::Handle> unsorted_handles;
1516 unsorted_handles.reserve(property_pool->n_registered_slots());
1519 for (
auto &particles_in_cell : particles)
1520 for (
auto &particle : particles_in_cell.particles)
1522 unsorted_handles.push_back(particle);
1523 particle = sorted_handle++;
1526 property_pool->sort_memory_slots(unsorted_handles);
1532 template <
int dim,
int spacedim>
1535 const bool enable_cache)
1538 const auto parallel_triangulation =
1541 if (parallel_triangulation !=
nullptr)
1544 parallel_triangulation->get_mpi_communicator()) == 1)
1550#ifndef DEAL_II_WITH_MPI
1554 for (
const auto &cell :
triangulation->active_cell_iterators())
1555 if (cell->is_ghost() &&
1556 cells_to_particle_cache[cell->active_cell_index()] != particles.end())
1558 Assert(cells_to_particle_cache[cell->active_cell_index()]->cell ==
1562 for (
auto &ghost_particle :
1563 cells_to_particle_cache[cell->active_cell_index()]->particles)
1564 property_pool->deregister_particle(ghost_particle);
1567 particles.erase(cells_to_particle_cache[cell->active_cell_index()]);
1568 cells_to_particle_cache[cell->active_cell_index()] = particles.end();
1572 ghost_particles_cache.ghost_particles_by_domain.clear();
1573 ghost_particles_cache.valid =
false;
1580 const std::map<unsigned int, std::set<types::subdomain_id>>
1582 triangulation_cache->get_vertices_with_ghost_neighbors();
1584 const std::set<types::subdomain_id> ghost_owners =
1585 parallel_triangulation->ghost_owners();
1586 for (
const auto ghost_owner : ghost_owners)
1587 ghost_particles_cache.ghost_particles_by_domain[ghost_owner].reserve(
1588 n_locally_owned_particles() / 4);
1590 const std::vector<std::set<unsigned int>> vertex_to_neighbor_subdomain =
1591 triangulation_cache->get_vertex_to_neighbor_subdomain();
1593 for (
const auto &cell :
triangulation->active_cell_iterators())
1595 if (cell->is_locally_owned())
1597 std::set<unsigned int> cell_to_neighbor_subdomain;
1598 for (
const unsigned int v : cell->vertex_indices())
1600 const auto vertex_ghost_neighbors =
1602 if (vertex_ghost_neighbors !=
1605 cell_to_neighbor_subdomain.insert(
1606 vertex_ghost_neighbors->second.begin(),
1607 vertex_ghost_neighbors->second.end());
1611 if (cell_to_neighbor_subdomain.size() > 0)
1614 particles_in_cell(cell);
1616 for (
const auto domain : cell_to_neighbor_subdomain)
1618 for (
typename particle_iterator_range::iterator particle =
1619 particle_range.begin();
1620 particle != particle_range.end();
1622 ghost_particles_cache.ghost_particles_by_domain[domain]
1623 .push_back(particle);
1629 send_recv_particles(
1630 ghost_particles_cache.ghost_particles_by_domain,
1641 template <
int dim,
int spacedim>
1646 const auto parallel_triangulation =
1649 if (parallel_triangulation ==
nullptr ||
1651 parallel_triangulation->get_mpi_communicator()) == 1)
1657#ifdef DEAL_II_WITH_MPI
1660 Assert(ghost_particles_cache.valid,
1662 "Ghost particles cannot be updated if they first have not been "
1663 "exchanged at least once with the cache enabled"));
1666 send_recv_particles_properties_and_location(
1667 ghost_particles_cache.ghost_particles_by_domain);
1673#ifdef DEAL_II_WITH_MPI
1674 template <
int dim,
int spacedim>
1683 const bool build_cache)
1689 ghost_particles_cache.valid = build_cache;
1691 const auto parallel_triangulation =
1694 Assert(parallel_triangulation,
1695 ExcMessage(
"This function is only implemented for "
1696 "parallel::TriangulationBase objects."));
1699 const std::set<types::subdomain_id> ghost_owners =
1700 parallel_triangulation->ghost_owners();
1701 const std::vector<types::subdomain_id> neighbors(ghost_owners.begin(),
1702 ghost_owners.end());
1703 const unsigned int n_neighbors = neighbors.size();
1705 if (send_cells.size() != 0)
1711 particles_to_send.end(),
1716 for (
auto send_particles = particles_to_send.begin();
1717 send_particles != particles_to_send.end();
1719 Assert(ghost_owners.find(send_particles->first) != ghost_owners.end(),
1722 std::size_t n_send_particles = 0;
1723 for (
auto send_particles = particles_to_send.begin();
1724 send_particles != particles_to_send.end();
1726 n_send_particles += send_particles->second.size();
1732 std::vector<unsigned int> n_send_data(n_neighbors, 0);
1733 std::vector<unsigned int> send_offsets(n_neighbors, 0);
1734 std::vector<char> send_data;
1739 const unsigned int individual_particle_data_size =
1741 (size_callback ? size_callback() : 0);
1743 const unsigned int individual_total_particle_data_size =
1744 individual_particle_data_size + cellid_size;
1749 if (n_send_particles > 0)
1752 send_data.resize(n_send_particles *
1753 individual_total_particle_data_size);
1755 void *
data =
static_cast<void *
>(&send_data.front());
1758 for (
unsigned int i = 0; i < n_neighbors; ++i)
1760 send_offsets[i] =
reinterpret_cast<std::size_t
>(
data) -
1761 reinterpret_cast<std::size_t
>(&send_data.front());
1763 const unsigned int n_particles_to_send =
1764 particles_to_send.at(neighbors[i]).size();
1766 Assert(
static_cast<std::size_t
>(n_particles_to_send) *
1767 individual_total_particle_data_size ==
1768 static_cast<std::size_t
>(
1769 n_particles_to_send *
1770 individual_total_particle_data_size),
1771 ExcMessage(
"Overflow when trying to send particle "
1774 for (
unsigned int j = 0; j < n_particles_to_send; ++j)
1780 if (send_cells.empty())
1781 cell = particles_to_send.at(neighbors[i])[j]
1782 ->get_surrounding_cell();
1784 cell = send_cells.at(neighbors[i])[j];
1787 cell->id().template to_binary<dim>();
1788 memcpy(
data, &cellid, cellid_size);
1789 data =
static_cast<char *
>(
data) + cellid_size;
1791 data = particles_to_send.at(neighbors[i])[j]
1792 ->write_particle_data_to_memory(
data);
1795 store_callback(particles_to_send.at(neighbors[i])[j],
data);
1797 n_send_data[i] = n_particles_to_send;
1802 std::vector<unsigned int> n_recv_data(n_neighbors);
1803 std::vector<unsigned int> recv_offsets(n_neighbors);
1809 std::vector<MPI_Request> n_requests(2 * n_neighbors);
1810 for (
unsigned int i = 0; i < n_neighbors; ++i)
1813 MPI_Irecv(&(n_recv_data[i]),
1818 parallel_triangulation->get_mpi_communicator(),
1819 &(n_requests[2 * i]));
1822 for (
unsigned int i = 0; i < n_neighbors; ++i)
1825 MPI_Isend(&(n_send_data[i]),
1830 parallel_triangulation->get_mpi_communicator(),
1831 &(n_requests[2 * i + 1]));
1835 MPI_Waitall(2 * n_neighbors, n_requests.data(), MPI_STATUSES_IGNORE);
1840 unsigned int total_recv_data = 0;
1841 for (
unsigned int neighbor_id = 0; neighbor_id < n_neighbors; ++neighbor_id)
1843 recv_offsets[neighbor_id] = total_recv_data;
1845 n_recv_data[neighbor_id] * individual_total_particle_data_size;
1849 std::vector<char> recv_data(total_recv_data);
1853 std::vector<MPI_Request> requests(2 * n_neighbors);
1854 unsigned int send_ops = 0;
1855 unsigned int recv_ops = 0;
1860 for (
unsigned int i = 0; i < n_neighbors; ++i)
1861 if (n_recv_data[i] > 0)
1864 MPI_Irecv(&(recv_data[recv_offsets[i]]),
1865 n_recv_data[i] * individual_total_particle_data_size,
1869 parallel_triangulation->get_mpi_communicator(),
1870 &(requests[send_ops]));
1875 for (
unsigned int i = 0; i < n_neighbors; ++i)
1876 if (n_send_data[i] > 0)
1879 MPI_Isend(&(send_data[send_offsets[i]]),
1880 n_send_data[i] * individual_total_particle_data_size,
1884 parallel_triangulation->get_mpi_communicator(),
1885 &(requests[send_ops + recv_ops]));
1890 MPI_Waitall(send_ops + recv_ops, requests.data(), MPI_STATUSES_IGNORE);
1896 const void *recv_data_it =
static_cast<const void *
>(recv_data.data());
1899 auto &ghost_particles_iterators =
1900 ghost_particles_cache.ghost_particles_iterators;
1904 ghost_particles_iterators.clear();
1906 auto &send_pointers_particles = ghost_particles_cache.send_pointers;
1907 send_pointers_particles.assign(n_neighbors + 1, 0);
1909 for (
unsigned int i = 0; i < n_neighbors; ++i)
1910 send_pointers_particles[i + 1] =
1911 send_pointers_particles[i] +
1912 n_send_data[i] * individual_particle_data_size;
1914 auto &recv_pointers_particles = ghost_particles_cache.recv_pointers;
1915 recv_pointers_particles.assign(n_neighbors + 1, 0);
1917 for (
unsigned int i = 0; i < n_neighbors; ++i)
1918 recv_pointers_particles[i + 1] =
1919 recv_pointers_particles[i] +
1920 n_recv_data[i] * individual_particle_data_size;
1922 ghost_particles_cache.neighbors = neighbors;
1924 ghost_particles_cache.send_data.resize(
1925 ghost_particles_cache.send_pointers.back());
1926 ghost_particles_cache.recv_data.resize(
1927 ghost_particles_cache.recv_pointers.back());
1930 while (
reinterpret_cast<std::size_t
>(recv_data_it) -
1931 reinterpret_cast<std::size_t
>(recv_data.data()) <
1935 memcpy(&binary_cellid, recv_data_it, cellid_size);
1936 const CellId id(binary_cellid);
1937 recv_data_it =
static_cast<const char *
>(recv_data_it) + cellid_size;
1942 insert_particle(property_pool->register_particle(), cell);
1943 const typename particle_container::iterator &cache =
1944 cells_to_particle_cache[cell->active_cell_index()];
1949 cache->particles.size() - 1);
1952 particle_it->read_particle_data_from_memory(recv_data_it);
1955 recv_data_it = load_callback(particle_it, recv_data_it);
1958 ghost_particles_iterators.push_back(particle_it);
1961 AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
1963 "The amount of data that was read into new particles "
1964 "does not match the amount of data sent around."));
1970#ifdef DEAL_II_WITH_MPI
1971 template <
int dim,
int spacedim>
1977 const auto parallel_triangulation =
1981 parallel_triangulation,
1983 "This function is only implemented for parallel::TriangulationBase "
1986 const auto &neighbors = ghost_particles_cache.neighbors;
1987 const auto &send_pointers = ghost_particles_cache.send_pointers;
1988 const auto &recv_pointers = ghost_particles_cache.recv_pointers;
1990 std::vector<char> &send_data = ghost_particles_cache.send_data;
1993 if (send_pointers.back() > 0)
1995 void *
data =
static_cast<void *
>(&send_data.front());
1998 for (
const auto i : neighbors)
1999 for (
const auto &p : particles_to_send.at(i))
2001 data = p->write_particle_data_to_memory(
data);
2007 std::vector<char> &recv_data = ghost_particles_cache.recv_data;
2011 std::vector<MPI_Request> requests(2 * neighbors.size());
2012 unsigned int send_ops = 0;
2013 unsigned int recv_ops = 0;
2018 for (
unsigned int i = 0; i < neighbors.size(); ++i)
2019 if ((recv_pointers[i + 1] - recv_pointers[i]) > 0)
2022 MPI_Irecv(recv_data.data() + recv_pointers[i],
2023 recv_pointers[i + 1] - recv_pointers[i],
2027 parallel_triangulation->get_mpi_communicator(),
2028 &(requests[send_ops]));
2033 for (
unsigned int i = 0; i < neighbors.size(); ++i)
2034 if ((send_pointers[i + 1] - send_pointers[i]) > 0)
2037 MPI_Isend(send_data.data() + send_pointers[i],
2038 send_pointers[i + 1] - send_pointers[i],
2042 parallel_triangulation->get_mpi_communicator(),
2043 &(requests[send_ops + recv_ops]));
2048 MPI_Waitall(send_ops + recv_ops, requests.data(), MPI_STATUSES_IGNORE);
2054 const void *recv_data_it =
static_cast<const void *
>(recv_data.data());
2057 auto &ghost_particles_iterators =
2058 ghost_particles_cache.ghost_particles_iterators;
2060 for (
auto &recv_particle : ghost_particles_iterators)
2065 recv_particle->read_particle_data_from_memory(recv_data_it);
2067 Assert(recv_particle->particles_in_cell->cell->is_ghost(),
2071 recv_data_it = load_callback(
2074 recv_particle->particle_index_within_cell),
2078 AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
2080 "The amount of data that was read into new particles "
2081 "does not match the amount of data sent around."));
2085 template <
int dim,
int spacedim>
2088 const std::function<std::size_t()> &size_callb,
2093 size_callback = size_callb;
2094 store_callback = store_callb;
2095 load_callback = load_callb;
2099 template <
int dim,
int spacedim>
2104 for (
const auto &connection : tria_listeners)
2105 connection.disconnect();
2107 tria_listeners.clear();
2109 tria_listeners.push_back(
triangulation->signals.create.connect([&]() {
2110 this->initialize(*(this->triangulation),
2112 this->property_pool->n_properties_per_slot());
2115 this->tria_listeners.push_back(
2116 this->
triangulation->signals.clear.connect([&]() { this->clear(); }));
2122 tria_listeners.push_back(
2124 [&]() { this->post_mesh_change_action(); }));
2125 tria_listeners.push_back(
2126 triangulation->signals.post_distributed_repartition.connect(
2127 [&]() { this->post_mesh_change_action(); }));
2128 tria_listeners.push_back(
2130 [&]() { this->post_mesh_change_action(); }));
2134 tria_listeners.push_back(
triangulation->signals.post_refinement.connect(
2135 [&]() { this->post_mesh_change_action(); }));
2141 template <
int dim,
int spacedim>
2147 const bool distributed_triangulation =
2150 &(*triangulation)) !=
nullptr;
2151 (void)distributed_triangulation;
2154 distributed_triangulation || number_of_locally_owned_particles == 0,
2156 "Mesh refinement in a non-distributed triangulation is not supported "
2157 "by the ParticleHandler class. Either insert particles after mesh "
2158 "creation, or use a distributed triangulation."));
2162 if (number_of_locally_owned_particles == 0)
2163 cells_to_particle_cache.resize(
triangulation->n_active_cells(),
2169 template <
int dim,
int spacedim>
2173 register_data_attach();
2178 template <
int dim,
int spacedim>
2182 register_data_attach();
2187 template <
int dim,
int spacedim>
2191 const auto callback_function =
2195 return this->pack_callback(cell_iterator, cell_status);
2198 tria_attached_data_index =
2200 ->register_data_attach(callback_function,
2206 template <
int dim,
int spacedim>
2210 const bool serialization =
false;
2211 notify_ready_to_unpack(serialization);
2216 template <
int dim,
int spacedim>
2220 const bool serialization =
true;
2221 notify_ready_to_unpack(serialization);
2225 template <
int dim,
int spacedim>
2228 const bool serialization)
2238 register_data_attach();
2243 const auto callback_function =
2247 const boost::iterator_range<std::vector<char>::const_iterator>
2249 this->unpack_callback(cell_iterator, cell_status, range_iterator);
2253 ->notify_ready_to_unpack(tria_attached_data_index, callback_function);
2257 update_cached_numbers();
2263 template <
int dim,
int spacedim>
2269 std::vector<particle_iterator> stored_particles_on_cell;
2278 const unsigned int n_particles = n_particles_in_cell(cell);
2279 stored_particles_on_cell.reserve(n_particles);
2281 for (
unsigned int i = 0; i < n_particles; ++i)
2283 cells_to_particle_cache[cell->active_cell_index()],
2293 for (
const auto &child : cell->child_iterators())
2295 const unsigned int n_particles = n_particles_in_cell(child);
2297 stored_particles_on_cell.reserve(
2298 stored_particles_on_cell.size() + n_particles);
2300 const typename particle_container::iterator &cache =
2301 cells_to_particle_cache[child->active_cell_index()];
2302 for (
unsigned int i = 0; i < n_particles; ++i)
2303 stored_particles_on_cell.push_back(
2314 return pack_particles(stored_particles_on_cell);
2319 template <
int dim,
int spacedim>
2324 const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
2326 if (data_range.begin() == data_range.end())
2329 const auto cell_to_store_particles =
2333 if (data_range.begin() != data_range.end())
2335 const void *
data =
static_cast<const void *
>(&(*data_range.begin()));
2336 const void *end =
static_cast<const void *
>(
2337 &(*data_range.begin()) + (data_range.end() - data_range.begin()));
2341 const void *old_data =
data;
2342 const auto x = insert_particle(
data, cell_to_store_particles);
2346 const void *new_data =
data;
2351 x->serialized_size_in_bytes());
2356 "The particle data could not be deserialized successfully. "
2357 "Check that when deserializing the particles you expect "
2358 "the same number of properties that were serialized."));
2361 auto loaded_particles_on_cell = particles_in_cell(cell_to_store_particles);
2376 for (
auto &particle : loaded_particles_on_cell)
2379 mapping->transform_real_to_unit_cell(cell_to_store_particles,
2380 particle.get_location());
2381 particle.set_reference_location(p_unit);
2390 typename particle_container::iterator &cache =
2391 cells_to_particle_cache[cell_to_store_particles
2392 ->active_cell_index()];
2399 auto particle = loaded_particles_on_cell.begin();
2400 for (
unsigned int i = 0; i < cache->particles.size();)
2402 bool found_new_cell =
false;
2404 for (
const auto &child : cell->child_iterators())
2411 mapping->transform_real_to_unit_cell(
2412 child, particle->get_location());
2414 p_unit, tolerance_inside_cell))
2416 found_new_cell =
true;
2417 particle->set_reference_location(p_unit);
2421 if (child != cell_to_store_particles)
2424 insert_particle(cache->particles[i], child);
2426 cache->particles[i] = cache->particles.back();
2427 cache->particles.pop_back();
2444 if (found_new_cell ==
false)
2453 signals.particle_lost(particle,
2454 particle->get_surrounding_cell());
2455 if (cache->particles[i] !=
2457 property_pool->deregister_particle(cache->particles[i]);
2458 cache->particles[i] = cache->particles.back();
2459 cache->particles.pop_back();
2463 if (cache->particles.empty())
2465 particles.erase(cache);
2466 cache = particles.end();
2478#include "particle_handler.inst"
@ children_will_be_coarsened
std::array< unsigned int, 4 > binary_type
const unsigned int n_components
virtual void vector_value(const Point< dim > &p, Vector< RangeNumberType > &values) const
void add_indices(const ForwardIterator &begin, const ForwardIterator &end)
Abstract base class for mapping classes.
void register_additional_store_load_functions(const std::function< std::size_t()> &size_callback, const std::function< void *(const particle_iterator &, void *)> &store_callback, const std::function< const void *(const particle_iterator &, const void *)> &load_callback)
void exchange_ghost_particles(const bool enable_ghost_cache=false)
unsigned int tria_attached_data_index
types::particle_index n_global_particles() const
unsigned int global_max_particles_per_cell
void unpack_after_coarsening_and_refinement()
void register_data_attach()
internal::GhostParticlePartitioner< dim, spacedim > ghost_particles_cache
particle_container::iterator particle_container_ghost_begin() const
void prepare_for_serialization()
unsigned int n_properties_per_particle() const
types::particle_index global_number_of_particles
void get_particle_positions(VectorType &output_vector, const bool add_to_output_vector=false)
particle_container::iterator particle_container_owned_end() const
void update_cached_numbers()
void prepare_for_coarsening_and_refinement()
particle_container::iterator particle_container_ghost_end() const
boost::iterator_range< particle_iterator > particle_iterator_range
void post_mesh_change_action()
void send_recv_particles(const std::map< types::subdomain_id, std::vector< particle_iterator > > &particles_to_send, const std::map< types::subdomain_id, std::vector< typename Triangulation< dim, spacedim >::active_cell_iterator > > &new_cells_for_particles=std::map< types::subdomain_id, std::vector< typename Triangulation< dim, spacedim >::active_cell_iterator > >(), const bool enable_cache=false)
ObserverPointer< const Mapping< dim, spacedim >, ParticleHandler< dim, spacedim > > mapping
void send_recv_particles_properties_and_location(const std::map< types::subdomain_id, std::vector< particle_iterator > > &particles_to_send)
types::particle_index number_of_locally_owned_particles
PropertyPool< dim, spacedim > & get_property_pool() const
void initialize(const Triangulation< dim, spacedim > &tria, const Mapping< dim, spacedim > &mapping, const unsigned int n_properties=0)
std::unique_ptr< PropertyPool< dim, spacedim > > property_pool
types::particle_index get_max_local_particle_index() const
void reserve(const std::size_t n_particles)
std::map< unsigned int, IndexSet > insert_global_particles(const std::vector< Point< spacedim > > &positions, const std::vector< std::vector< BoundingBox< spacedim > > > &global_bounding_boxes, const std::vector< std::vector< double > > &properties={}, const std::vector< types::particle_index > &ids={})
void notify_ready_to_unpack(const bool serialization)
void connect_to_triangulation_signals()
std::enable_if_t< std::is_convertible_v< VectorType *, Function< spacedim > * >==false > set_particle_positions(const VectorType &input_vector, const bool displace_particles=true)
std::vector< char > pack_callback(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const CellStatus status) const
void insert_particles(const std::multimap< typename Triangulation< dim, spacedim >::active_cell_iterator, Particle< dim, spacedim > > &particles)
types::particle_index next_free_particle_index
void remove_particle(const particle_iterator &particle)
types::particle_index n_locally_owned_particles() const
void reset_particle_container(particle_container &particles)
types::particle_index n_particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell) const
void update_ghost_particles()
typename ParticleAccessor< dim, spacedim >::particle_container particle_container
ObserverPointer< const Triangulation< dim, spacedim >, ParticleHandler< dim, spacedim > > triangulation
particle_iterator_range particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell)
particle_iterator insert_particle(const Particle< dim, spacedim > &particle, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell)
void sort_particles_into_subdomains_and_cells()
void remove_particles(const std::vector< particle_iterator > &particles)
types::particle_index n_global_max_particles_per_cell() const
particle_container::iterator particle_container_owned_begin() const
void unpack_callback(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const CellStatus status, const boost::iterator_range< std::vector< char >::const_iterator > &data_range)
virtual ~ParticleHandler()
void copy_from(const ParticleHandler< dim, spacedim > &particle_handler)
types::particle_index get_next_free_particle_index() const
particle_container particles
IndexSet locally_owned_particle_ids() const
void set_property_pool(PropertyPool< dim, spacedim > &property_pool)
const Point< dim > & get_reference_location() const
const Point< spacedim > & get_location() const
std::size_t serialized_size_in_bytes() const
types::particle_index get_id() const
ArrayView< double > get_properties()
numbers::NumberTraits< Number >::real_type norm() const
constexpr numbers::NumberTraits< Number >::real_type norm_square() const
IteratorState::IteratorStates state() const
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrowMPI(error_code)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcPointNotAvailableHere()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
#define DEAL_II_ASSERT_UNREACHABLE()
std::vector< index_type > data
@ past_the_end
Iterator reached end of container.
@ valid
Iterator points to a valid object.
T sum(const T &t, const MPI_Comm mpi_communicator)
std::map< unsigned int, T > some_to_some(const MPI_Comm comm, const std::map< unsigned int, T > &objects_to_send)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
T max(const T &t, const MPI_Comm mpi_communicator)
std::vector< T > all_gather(const MPI_Comm comm, const T &object_to_send)
const types::subdomain_id artificial_subdomain_id
static const unsigned int invalid_unsigned_int
bool is_finite(const double x)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
unsigned int subdomain_id
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
std::map< unsigned int, std::set<::types::subdomain_id > > * vertices_with_ghost_neighbors
#define DEAL_II_PARTICLE_INDEX_MPI_TYPE
static bool is_inside_unit_cell(const Point< dim > &p)