34 template <
int dim,
int spacedim>
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>
78 template <
int dim,
int spacedim>
82 const unsigned int n_properties)
106 template <
int dim,
int spacedim>
112 connection.disconnect();
117 template <
int dim,
int spacedim>
122 const unsigned int n_properties)
132 property_pool = std::make_unique<PropertyPool<dim, spacedim>>(n_properties);
137 std::make_unique<GridTools::Cache<dim, spacedim>>(new_triangulation,
148 template <
int dim,
int spacedim>
153 const unsigned int n_properties =
159 property_pool = std::make_unique<PropertyPool<dim, spacedim>>(
181 if (!it->particles.empty())
191 template <
int dim,
int spacedim>
204 template <
int dim,
int spacedim>
226 template <
int dim,
int spacedim>
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);
256 ++given_particles.begin();
261 template <
int dim,
int spacedim>
266 bool sort_is_necessary =
false;
273 previous->cell > next->cell)
275 sort_is_necessary =
true;
281 if (sort_is_necessary)
299 for (
const auto &cell :
triangulation->active_cell_iterators())
300 if (!cell->is_artificial())
308 typename particle_container::iterator insert_position =
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 =
326 if (!it->particles.empty())
357 std::vector<typename particle_container::iterator> verify_cache(
360 if (!it->particles.empty())
361 verify_cache[it->cell->active_cell_index()] = it;
363 for (
unsigned int i = 0; i < verify_cache.size(); ++i)
413 template <
int dim,
int spacedim>
422 if (cell->is_artificial() ==
false)
432 ExcMessage(
"You can't ask for the particles on an artificial "
433 "cell since we don't know what exists on these "
441 template <
int dim,
int spacedim>
448 ->particles_in_cell(cell);
453 template <
int dim,
int spacedim>
458 const unsigned int active_cell_index = cell->active_cell_index();
460 if (cell->is_artificial() ==
false)
464 return boost::make_iterator_range(
470 const typename particle_container::iterator
471 particles_in_current_cell =
473 typename particle_container::iterator particles_in_next_cell =
474 particles_in_current_cell;
475 ++particles_in_next_cell;
476 return boost::make_iterator_range(
483 ExcMessage(
"You can't ask for the particles on an artificial "
484 "cell since we don't know what exists on these "
492 template <
int dim,
int spacedim>
510 const bool owned_cell = cell->is_locally_owned();
514 if (particles_on_cell.size() > 1)
517 std::move(particles_on_cell.back());
518 particles_on_cell.resize(particles_on_cell.size() - 1);
529 template <
int dim,
int spacedim>
533 &particles_to_remove)
546 bool particles_are_sorted =
true;
547 auto previous = particles_to_remove.begin();
548 for (
auto next = previous; next != particles_to_remove.end(); ++next)
550 if (check_greater(*previous, *next))
552 particles_are_sorted =
false;
557 if (particles_are_sorted)
560 for (
auto it = particles_to_remove.rbegin();
561 it != particles_to_remove.rend();
567 std::vector<ParticleHandler<dim, spacedim>::particle_iterator>
568 sorted_particles(particles_to_remove);
569 std::sort(sorted_particles.begin(),
570 sorted_particles.end(),
573 for (
const auto &particle : sorted_particles)
582 template <
int dim,
int spacedim>
597 template <
int dim,
int spacedim>
604 typename particle_container::iterator &cache =
608 const typename particle_container::iterator insert_position =
618 cache->particles.push_back(handle);
623 cache->particles.size() - 1);
628 template <
int dim,
int spacedim>
637 Assert(cell->is_locally_owned(),
638 ExcMessage(
"You tried to insert particles into a cell that is not "
639 "locally owned. This is not supported."));
653 template <
int dim,
int spacedim>
666 Assert(cell->is_locally_owned(),
667 ExcMessage(
"You tried to insert particles into a cell that is not "
668 "locally owned. This is not supported."));
675 particle_it->
set_id(particle_index);
677 if (properties.
size() != 0)
687 template <
int dim,
int spacedim>
695 for (
const auto &cell_and_particle : new_particles)
703 template <
int dim,
int spacedim>
721#ifdef DEAL_II_WITH_MPI
722 if (
const auto parallel_triangulation =
728 MPI_Scan(&particles_to_add_locally,
733 parallel_triangulation->get_mpi_communicator());
735 local_start_index -= particles_to_add_locally;
739 local_start_index += local_next_particle_index;
741 auto point_locations =
745 auto &cells = std::get<0>(point_locations);
746 auto &local_positions = std::get<1>(point_locations);
747 auto &index_map = std::get<2>(point_locations);
748 auto &missing_points = std::get<3>(point_locations);
754 (void)missing_points;
756 for (
unsigned int i = 0; i < cells.size(); ++i)
757 for (
unsigned int p = 0; p < local_positions[i].size(); ++p)
759 local_positions[i][p],
760 local_start_index + index_map[i][p],
768 template <
int dim,
int spacedim>
769 std::map<unsigned int, IndexSet>
773 &global_bounding_boxes,
774 const std::vector<std::vector<double>> &properties,
775 const std::vector<types::particle_index> &ids)
777 if (!properties.empty())
782 for (
const auto &p : properties)
795 const auto n_global_properties =
799 const auto n_particles_per_proc =
803 std::vector<unsigned int> particle_start_indices(n_mpi_processes);
806 for (
unsigned int process = 0; process < particle_start_indices.size();
809 particle_start_indices[process] = particle_start_index;
810 particle_start_index += n_particles_per_proc[process];
814 const auto cells_positions_and_index_maps =
817 global_bounding_boxes);
821 const auto &local_cells_containing_particles =
822 std::get<0>(cells_positions_and_index_maps);
826 const auto &local_reference_positions =
827 std::get<1>(cells_positions_and_index_maps);
830 const auto &original_indices_of_local_particles =
831 std::get<2>(cells_positions_and_index_maps);
834 const auto &local_positions = std::get<3>(cells_positions_and_index_maps);
836 const auto &calling_process_indices =
837 std::get<4>(cells_positions_and_index_maps);
840 std::map<unsigned int, std::vector<unsigned int>>
841 original_process_to_local_particle_indices_tmp;
842 for (
unsigned int i_cell = 0;
843 i_cell < local_cells_containing_particles.size();
846 for (
unsigned int i_particle = 0;
847 i_particle < local_positions[i_cell].size();
850 const unsigned int local_id_on_calling_process =
851 original_indices_of_local_particles[i_cell][i_particle];
852 const unsigned int calling_process =
853 calling_process_indices[i_cell][i_particle];
855 original_process_to_local_particle_indices_tmp[calling_process]
856 .push_back(local_id_on_calling_process);
859 std::map<unsigned int, IndexSet> original_process_to_local_particle_indices;
860 for (
auto &process_and_particle_indices :
861 original_process_to_local_particle_indices_tmp)
863 const unsigned int calling_process = process_and_particle_indices.first;
864 original_process_to_local_particle_indices.insert(
865 {calling_process,
IndexSet(n_particles_per_proc[calling_process])});
866 std::sort(process_and_particle_indices.second.begin(),
867 process_and_particle_indices.second.end());
868 original_process_to_local_particle_indices[calling_process].add_indices(
869 process_and_particle_indices.second.begin(),
870 process_and_particle_indices.second.end());
871 original_process_to_local_particle_indices[calling_process].compress();
879 std::map<unsigned int, std::vector<std::vector<double>>>
880 locally_owned_properties_from_other_processes;
887 std::map<unsigned int, std::vector<types::particle_index>>
888 locally_owned_ids_from_other_processes;
890 if (n_global_properties > 0 || !ids.empty())
895 comm, original_process_to_local_particle_indices);
898 if (n_global_properties > 0)
900 std::map<unsigned int, std::vector<std::vector<double>>>
901 non_locally_owned_properties;
903 for (
const auto &it : send_to_cpu)
905 std::vector<std::vector<double>> properties_to_send(
906 it.second.n_elements(),
908 unsigned int index = 0;
909 for (
const auto el : it.second)
910 properties_to_send[index++] = properties[el];
911 non_locally_owned_properties.insert(
912 {it.first, properties_to_send});
917 locally_owned_properties_from_other_processes =
921 locally_owned_properties_from_other_processes.size(),
922 original_process_to_local_particle_indices.size());
927 std::map<unsigned int, std::vector<types::particle_index>>
928 non_locally_owned_ids;
929 for (
const auto &it : send_to_cpu)
931 std::vector<types::particle_index> ids_to_send(
932 it.second.n_elements());
933 unsigned int index = 0;
934 for (
const auto el : it.second)
935 ids_to_send[index++] = ids[el];
936 non_locally_owned_ids.insert({it.first, ids_to_send});
941 locally_owned_ids_from_other_processes =
945 original_process_to_local_particle_indices.size());
950 for (
unsigned int i_cell = 0;
951 i_cell < local_cells_containing_particles.size();
954 for (
unsigned int i_particle = 0;
955 i_particle < local_positions[i_cell].size();
958 const unsigned int local_id_on_calling_process =
959 original_indices_of_local_particles[i_cell][i_particle];
961 const unsigned int calling_process =
962 calling_process_indices[i_cell][i_particle];
964 const unsigned int index_within_set =
965 original_process_to_local_particle_indices[calling_process]
966 .index_within_set(local_id_on_calling_process);
968 const unsigned int particle_id =
970 local_id_on_calling_process +
971 particle_start_indices[calling_process] :
972 locally_owned_ids_from_other_processes[calling_process]
977 local_reference_positions[i_cell][i_particle],
979 local_cells_containing_particles[i_cell]);
981 if (n_global_properties > 0)
983 particle_it->set_properties(
984 locally_owned_properties_from_other_processes
985 [calling_process][index_within_set]);
992 return original_process_to_local_particle_indices;
997 template <
int dim,
int spacedim>
998 std::map<unsigned int, IndexSet>
1002 &global_bounding_boxes)
1006 std::vector<Point<spacedim>> positions;
1007 std::vector<std::vector<double>> properties;
1008 std::vector<types::particle_index> ids;
1018 positions[i] = p.get_location();
1019 ids[i] = p.get_id();
1020 if (p.has_properties())
1021 properties[i] = {p.get_properties().begin(),
1022 p.get_properties().end()};
1027 global_bounding_boxes,
1034 template <
int dim,
int spacedim>
1043 template <
int dim,
int spacedim>
1052 template <
int dim,
int spacedim>
1061 template <
int dim,
int spacedim>
1070 template <
int dim,
int spacedim>
1079 template <
int dim,
int spacedim>
1084 std::vector<types::particle_index> indices;
1086 for (
const auto &p : *
this)
1087 indices.push_back(p.get_id());
1095 template <
int dim,
int spacedim>
1104 template <
int dim,
int spacedim>
1108 const bool add_to_output_vector)
1114 for (
auto it =
begin(); it !=
end(); ++it, ++i)
1116 if (add_to_output_vector)
1117 positions[i] = positions[i] + it->get_location();
1119 positions[i] = it->get_location();
1125 template <
int dim,
int spacedim>
1129 const bool displace_particles)
1135 for (
auto it =
begin(); it !=
end(); ++it, ++i)
1138 if (displace_particles)
1139 location += new_positions[i];
1141 location = new_positions[i];
1148 template <
int dim,
int spacedim>
1152 const bool displace_particles)
1159 for (
auto &particle : *
this)
1162 function.
vector_value(particle_location, new_position);
1163 if (displace_particles)
1164 for (
unsigned int d = 0; d < spacedim; ++d)
1165 particle_location[d] += new_position[d];
1167 for (
unsigned int d = 0; d < spacedim; ++d)
1168 particle_location[d] = new_position[d];
1175 template <
int dim,
int spacedim>
1197 compare_particle_association(
1198 const unsigned int a,
1199 const unsigned int b,
1203 const double scalar_product_a = center_directions[a] * particle_direction;
1204 const double scalar_product_b = center_directions[b] * particle_direction;
1209 return (scalar_product_a > scalar_product_b);
1215 template <
int dim,
int spacedim>
1231 std::vector<particle_iterator> particles_out_of_cell;
1239 std::vector<Point<spacedim>> real_locations;
1240 std::vector<Point<dim>> reference_locations;
1244 for (
const auto &cell :
triangulation->active_cell_iterators())
1251 if (cell->is_locally_owned() ==
false)
1259 real_locations.clear();
1260 for (
const auto &particle : pic)
1261 real_locations.push_back(particle.get_location());
1263 reference_locations.resize(n_pic);
1264 mapping->transform_points_real_to_unit_cell(cell,
1266 reference_locations);
1268 auto particle = pic.begin();
1269 for (
const auto &p_unit : reference_locations)
1272 cell->reference_cell().contains_point(p_unit,
1274 particle->set_reference_location(p_unit);
1276 particles_out_of_cell.push_back(particle);
1288 std::map<types::subdomain_id, std::vector<particle_iterator>>
1292 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1300 std::set<types::subdomain_id> ghost_owners;
1301 if (
const auto parallel_triangulation =
1304 ghost_owners = parallel_triangulation->ghost_owners();
1309 for (
const auto &ghost_owner : ghost_owners)
1310 moved_particles[ghost_owner].reserve(particles_out_of_cell.size() / 4);
1311 for (
const auto &ghost_owner : ghost_owners)
1312 moved_cells[ghost_owner].reserve(particles_out_of_cell.size() / 4);
1317 std::set<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1322 const std::vector<std::vector<Tensor<1, spacedim>>>
1323 &vertex_to_cell_centers =
1326 std::vector<unsigned int> search_order;
1334 for (
auto &out_particle : particles_out_of_cell)
1339 auto current_cell = out_particle->get_surrounding_cell();
1341 real_locations[0] = out_particle->get_location();
1344 bool found_cell =
false;
1348 const unsigned int closest_vertex =
1350 current_cell, out_particle->get_location(), *
mapping);
1351 const unsigned int closest_vertex_index =
1352 current_cell->vertex_index(closest_vertex);
1354 const auto &candidate_cells = vertex_to_cells[closest_vertex_index];
1355 const unsigned int n_candidate_cells = candidate_cells.size();
1359 search_order.resize(n_candidate_cells);
1360 for (
unsigned int i = 0; i < n_candidate_cells; ++i)
1361 search_order[i] = i;
1367 out_particle->get_location() - current_cell->vertex(closest_vertex);
1372 1e4 * std::numeric_limits<double>::epsilon() *
1373 std::numeric_limits<double>::epsilon() *
1374 vertex_to_cell_centers[closest_vertex_index][0].norm_square())
1376 vertex_to_particle /= vertex_to_particle.
norm();
1377 const auto &vertex_to_cells =
1378 vertex_to_cell_centers[closest_vertex_index];
1380 std::sort(search_order.begin(),
1382 [&vertex_to_particle,
1383 &vertex_to_cells](
const unsigned int a,
1384 const unsigned int b) {
1385 return compare_particle_association(
1386 a, b, vertex_to_particle, vertex_to_cells);
1392 for (
unsigned int i = 0; i < n_candidate_cells; ++i)
1396 const_iterator candidate_cell = candidate_cells.begin();
1398 std::advance(candidate_cell, search_order[i]);
1399 mapping->transform_points_real_to_unit_cell(*candidate_cell,
1401 reference_locations);
1403 if ((*candidate_cell)
1405 .contains_point(reference_locations[0],
1408 current_cell = *candidate_cell;
1424#if defined(DEAL_II_WITH_BOOST_BUNDLED) || \
1425 !(defined(__clang_major__) && __clang_major__ >= 16) || \
1426 BOOST_VERSION >= 108100
1428 std::vector<std::pair<Point<spacedim>,
unsigned int>>
1429 closest_vertex_in_domain;
1431 boost::geometry::index::nearest(out_particle->get_location(),
1433 std::back_inserter(closest_vertex_in_domain));
1437 const unsigned int closest_vertex_index_in_domain =
1438 closest_vertex_in_domain[0].second;
1440 const unsigned int closest_vertex_index_in_domain =
1443 out_particle->get_location());
1448 for (
const auto &cell :
1449 vertex_to_cells[closest_vertex_index_in_domain])
1451 mapping->transform_points_real_to_unit_cell(
1452 cell, real_locations, reference_locations);
1454 if (cell->reference_cell().contains_point(
1457 current_cell = cell;
1469 signals.particle_lost(out_particle,
1470 out_particle->get_surrounding_cell());
1476 out_particle->set_reference_location(reference_locations[0]);
1480 if (current_cell->is_locally_owned())
1483 out_particle->particles_in_cell
1484 ->particles[out_particle->particle_index_within_cell];
1487 const auto old_value = old;
1495 moved_particles[current_cell->subdomain_id()].push_back(
1497 moved_cells[current_cell->subdomain_id()].push_back(current_cell);
1503#ifdef DEAL_II_WITH_MPI
1504 if (
const auto parallel_triangulation =
1509 parallel_triangulation->get_mpi_communicator()) > 1)
1518 std::vector<typename PropertyPool<dim, spacedim>::Handle> unsorted_handles;
1519 unsorted_handles.reserve(
property_pool->n_registered_slots());
1525 unsorted_handles.push_back(particle);
1526 particle = sorted_handle++;
1535 template <
int dim,
int spacedim>
1538 const bool enable_cache)
1541 const auto parallel_triangulation =
1544 if (parallel_triangulation !=
nullptr)
1547 parallel_triangulation->get_mpi_communicator()) == 1)
1553#ifndef DEAL_II_WITH_MPI
1557 for (
const auto &cell :
triangulation->active_cell_iterators())
1558 if (cell->is_ghost() &&
1565 for (
auto &ghost_particle :
1583 const std::map<unsigned int, std::set<types::subdomain_id>>
1584 &vertices_with_ghost_neighbors =
1587 const std::set<types::subdomain_id> ghost_owners =
1588 parallel_triangulation->ghost_owners();
1589 for (
const auto ghost_owner : ghost_owners)
1593 const std::vector<std::set<unsigned int>> vertex_to_neighbor_subdomain =
1596 for (
const auto &cell :
triangulation->active_cell_iterators())
1598 if (cell->is_locally_owned())
1600 std::set<unsigned int> cell_to_neighbor_subdomain;
1601 for (
const unsigned int v : cell->vertex_indices())
1603 const auto vertex_ghost_neighbors =
1604 vertices_with_ghost_neighbors.find(cell->vertex_index(v));
1605 if (vertex_ghost_neighbors !=
1606 vertices_with_ghost_neighbors.end())
1608 cell_to_neighbor_subdomain.insert(
1609 vertex_ghost_neighbors->second.begin(),
1610 vertex_ghost_neighbors->second.end());
1614 if (cell_to_neighbor_subdomain.size() > 0)
1619 for (
const auto domain : cell_to_neighbor_subdomain)
1621 for (
typename particle_iterator_range::iterator particle =
1622 particle_range.begin();
1623 particle != particle_range.end();
1626 .push_back(particle);
1644 template <
int dim,
int spacedim>
1649 const auto parallel_triangulation =
1652 if (parallel_triangulation ==
nullptr ||
1654 parallel_triangulation->get_mpi_communicator()) == 1)
1660#ifdef DEAL_II_WITH_MPI
1665 "Ghost particles cannot be updated if they first have not been "
1666 "exchanged at least once with the cache enabled"));
1676#ifdef DEAL_II_WITH_MPI
1677 template <
int dim,
int spacedim>
1686 const bool build_cache)
1694 const auto parallel_triangulation =
1697 Assert(parallel_triangulation,
1698 ExcMessage(
"This function is only implemented for "
1699 "parallel::TriangulationBase objects."));
1702 const std::set<types::subdomain_id> ghost_owners =
1703 parallel_triangulation->ghost_owners();
1704 const std::vector<types::subdomain_id> neighbors(ghost_owners.begin(),
1705 ghost_owners.end());
1706 const unsigned int n_neighbors = neighbors.size();
1708 if (send_cells.size() != 0)
1714 particles_to_send.end(),
1719 for (
auto send_particles = particles_to_send.begin();
1720 send_particles != particles_to_send.end();
1722 Assert(ghost_owners.find(send_particles->first) != ghost_owners.end(),
1725 std::size_t n_send_particles = 0;
1726 for (
auto send_particles = particles_to_send.begin();
1727 send_particles != particles_to_send.end();
1729 n_send_particles += send_particles->second.size();
1735 std::vector<unsigned int> n_send_data(n_neighbors, 0);
1736 std::vector<unsigned int> send_offsets(n_neighbors, 0);
1737 std::vector<char> send_data;
1742 const unsigned int individual_particle_data_size =
1746 const unsigned int individual_total_particle_data_size =
1747 individual_particle_data_size + cellid_size;
1752 if (n_send_particles > 0)
1755 send_data.resize(n_send_particles *
1756 individual_total_particle_data_size);
1758 void *data =
static_cast<void *
>(&send_data.front());
1761 for (
unsigned int i = 0; i < n_neighbors; ++i)
1763 send_offsets[i] =
reinterpret_cast<std::size_t
>(data) -
1764 reinterpret_cast<std::size_t
>(&send_data.front());
1766 const unsigned int n_particles_to_send =
1767 particles_to_send.at(neighbors[i]).size();
1769 Assert(
static_cast<std::size_t
>(n_particles_to_send) *
1770 individual_total_particle_data_size ==
1771 static_cast<std::size_t
>(
1772 n_particles_to_send *
1773 individual_total_particle_data_size),
1774 ExcMessage(
"Overflow when trying to send particle "
1777 for (
unsigned int j = 0; j < n_particles_to_send; ++j)
1783 if (send_cells.empty())
1784 cell = particles_to_send.at(neighbors[i])[j]
1785 ->get_surrounding_cell();
1787 cell = send_cells.at(neighbors[i])[j];
1790 cell->id().template to_binary<dim>();
1791 memcpy(data, &cellid, cellid_size);
1792 data =
static_cast<char *
>(data) + cellid_size;
1794 data = particles_to_send.at(neighbors[i])[j]
1795 ->write_particle_data_to_memory(data);
1800 n_send_data[i] = n_particles_to_send;
1805 std::vector<unsigned int> n_recv_data(n_neighbors);
1806 std::vector<unsigned int> recv_offsets(n_neighbors);
1809 const int mpi_tag = Utilities::MPI::internal::Tags::
1810 particle_handler_send_recv_particles_setup;
1812 std::vector<MPI_Request> n_requests(2 * n_neighbors);
1813 for (
unsigned int i = 0; i < n_neighbors; ++i)
1816 MPI_Irecv(&(n_recv_data[i]),
1821 parallel_triangulation->get_mpi_communicator(),
1822 &(n_requests[2 * i]));
1825 for (
unsigned int i = 0; i < n_neighbors; ++i)
1828 MPI_Isend(&(n_send_data[i]),
1833 parallel_triangulation->get_mpi_communicator(),
1834 &(n_requests[2 * i + 1]));
1838 MPI_Waitall(2 * n_neighbors, n_requests.data(), MPI_STATUSES_IGNORE);
1843 unsigned int total_recv_data = 0;
1844 for (
unsigned int neighbor_id = 0; neighbor_id < n_neighbors; ++neighbor_id)
1846 recv_offsets[neighbor_id] = total_recv_data;
1848 n_recv_data[neighbor_id] * individual_total_particle_data_size;
1852 std::vector<char> recv_data(total_recv_data);
1856 std::vector<MPI_Request> requests(2 * n_neighbors);
1857 unsigned int send_ops = 0;
1858 unsigned int recv_ops = 0;
1860 const int mpi_tag = Utilities::MPI::internal::Tags::
1861 particle_handler_send_recv_particles_send;
1863 for (
unsigned int i = 0; i < n_neighbors; ++i)
1864 if (n_recv_data[i] > 0)
1867 MPI_Irecv(&(recv_data[recv_offsets[i]]),
1868 n_recv_data[i] * individual_total_particle_data_size,
1872 parallel_triangulation->get_mpi_communicator(),
1873 &(requests[send_ops]));
1878 for (
unsigned int i = 0; i < n_neighbors; ++i)
1879 if (n_send_data[i] > 0)
1882 MPI_Isend(&(send_data[send_offsets[i]]),
1883 n_send_data[i] * individual_total_particle_data_size,
1887 parallel_triangulation->get_mpi_communicator(),
1888 &(requests[send_ops + recv_ops]));
1893 MPI_Waitall(send_ops + recv_ops, requests.data(), MPI_STATUSES_IGNORE);
1899 const void *recv_data_it =
static_cast<const void *
>(recv_data.data());
1902 auto &ghost_particles_iterators =
1907 ghost_particles_iterators.clear();
1910 send_pointers_particles.assign(n_neighbors + 1, 0);
1912 for (
unsigned int i = 0; i < n_neighbors; ++i)
1913 send_pointers_particles[i + 1] =
1914 send_pointers_particles[i] +
1915 n_send_data[i] * individual_particle_data_size;
1918 recv_pointers_particles.assign(n_neighbors + 1, 0);
1920 for (
unsigned int i = 0; i < n_neighbors; ++i)
1921 recv_pointers_particles[i + 1] =
1922 recv_pointers_particles[i] +
1923 n_recv_data[i] * individual_particle_data_size;
1933 while (
reinterpret_cast<std::size_t
>(recv_data_it) -
1934 reinterpret_cast<std::size_t
>(recv_data.data()) <
1938 memcpy(&binary_cellid, recv_data_it, cellid_size);
1939 const CellId id(binary_cellid);
1940 recv_data_it =
static_cast<const char *
>(recv_data_it) + cellid_size;
1946 const typename particle_container::iterator &cache =
1952 cache->particles.size() - 1);
1961 ghost_particles_iterators.push_back(particle_it);
1964 AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
1966 "The amount of data that was read into new particles "
1967 "does not match the amount of data sent around."));
1973#ifdef DEAL_II_WITH_MPI
1974 template <
int dim,
int spacedim>
1980 const auto parallel_triangulation =
1984 parallel_triangulation,
1986 "This function is only implemented for parallel::TriangulationBase "
1996 if (send_pointers.back() > 0)
1998 void *data =
static_cast<void *
>(&send_data.front());
2001 for (
const auto i : neighbors)
2002 for (
const auto &p : particles_to_send.at(i))
2004 data = p->write_particle_data_to_memory(data);
2014 std::vector<MPI_Request> requests(2 * neighbors.size());
2015 unsigned int send_ops = 0;
2016 unsigned int recv_ops = 0;
2018 const int mpi_tag = Utilities::MPI::internal::Tags::
2019 particle_handler_send_recv_particles_send;
2021 for (
unsigned int i = 0; i < neighbors.size(); ++i)
2022 if ((recv_pointers[i + 1] - recv_pointers[i]) > 0)
2025 MPI_Irecv(recv_data.data() + recv_pointers[i],
2026 recv_pointers[i + 1] - recv_pointers[i],
2030 parallel_triangulation->get_mpi_communicator(),
2031 &(requests[send_ops]));
2036 for (
unsigned int i = 0; i < neighbors.size(); ++i)
2037 if ((send_pointers[i + 1] - send_pointers[i]) > 0)
2040 MPI_Isend(send_data.data() + send_pointers[i],
2041 send_pointers[i + 1] - send_pointers[i],
2045 parallel_triangulation->get_mpi_communicator(),
2046 &(requests[send_ops + recv_ops]));
2051 MPI_Waitall(send_ops + recv_ops, requests.data(), MPI_STATUSES_IGNORE);
2057 const void *recv_data_it =
static_cast<const void *
>(recv_data.data());
2060 auto &ghost_particles_iterators =
2063 for (
auto &recv_particle : ghost_particles_iterators)
2068 recv_particle->read_particle_data_from_memory(recv_data_it);
2070 Assert(recv_particle->particles_in_cell->cell->is_ghost(),
2077 recv_particle->particle_index_within_cell),
2081 AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
2083 "The amount of data that was read into new particles "
2084 "does not match the amount of data sent around."));
2088 template <
int dim,
int spacedim>
2091 const std::function<std::size_t()> &size_callb,
2102 template <
int dim,
int spacedim>
2108 connection.disconnect();
2113 this->initialize(*(this->triangulation),
2115 this->property_pool->n_properties_per_slot());
2118 this->tria_listeners.push_back(
2119 this->
triangulation->signals.clear.connect([&]() { this->clear(); }));
2127 [&]() { this->post_mesh_change_action(); }));
2129 triangulation->signals.post_distributed_repartition.connect(
2130 [&]() { this->post_mesh_change_action(); }));
2133 [&]() { this->post_mesh_change_action(); }));
2138 [&]() { this->post_mesh_change_action(); }));
2144 template <
int dim,
int spacedim>
2150 const bool distributed_triangulation =
2153 &(*triangulation)) !=
nullptr;
2154 (void)distributed_triangulation;
2159 "Mesh refinement in a non-distributed triangulation is not supported "
2160 "by the ParticleHandler class. Either insert particles after mesh "
2161 "creation, or use a distributed triangulation."));
2172 template <
int dim,
int spacedim>
2181 template <
int dim,
int spacedim>
2190 template <
int dim,
int spacedim>
2194 const auto callback_function =
2209 template <
int dim,
int spacedim>
2213 const bool serialization =
false;
2219 template <
int dim,
int spacedim>
2223 const bool serialization =
true;
2228 template <
int dim,
int spacedim>
2231 const bool serialization)
2246 const auto callback_function =
2250 const boost::iterator_range<std::vector<char>::const_iterator>
2266 template <
int dim,
int spacedim>
2272 std::vector<particle_iterator> stored_particles_on_cell;
2282 stored_particles_on_cell.reserve(n_particles);
2284 for (
unsigned int i = 0; i < n_particles; ++i)
2300 stored_particles_on_cell.reserve(
2301 stored_particles_on_cell.size() + n_particles);
2303 const typename particle_container::iterator &cache =
2305 for (
unsigned int i = 0; i < n_particles; ++i)
2306 stored_particles_on_cell.push_back(
2317 return pack_particles(stored_particles_on_cell);
2322 template <
int dim,
int spacedim>
2327 const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
2329 if (data_range.begin() == data_range.end())
2332 const auto cell_to_store_particles =
2336 if (data_range.begin() != data_range.end())
2338 const void *data =
static_cast<const void *
>(&(*data_range.begin()));
2339 const void *
end =
static_cast<const void *
>(
2340 &(*data_range.begin()) + (data_range.end() - data_range.begin()));
2344 const void *old_data = data;
2349 const void *new_data = data;
2354 x->serialized_size_in_bytes());
2359 "The particle data could not be deserialized successfully. "
2360 "Check that when deserializing the particles you expect "
2361 "the same number of properties that were serialized."));
2379 for (
auto &particle : loaded_particles_on_cell)
2382 mapping->transform_real_to_unit_cell(cell_to_store_particles,
2383 particle.get_location());
2384 particle.set_reference_location(p_unit);
2393 typename particle_container::iterator &cache =
2395 ->active_cell_index()];
2402 auto particle = loaded_particles_on_cell.begin();
2403 for (
unsigned int i = 0; i < cache->particles.size();)
2405 bool found_new_cell =
false;
2414 mapping->transform_real_to_unit_cell(
2415 child, particle->get_location());
2419 found_new_cell =
true;
2420 particle->set_reference_location(p_unit);
2424 if (child != cell_to_store_particles)
2429 cache->particles[i] = cache->particles.back();
2430 cache->particles.pop_back();
2447 if (found_new_cell ==
false)
2456 signals.particle_lost(particle,
2457 particle->get_surrounding_cell());
2458 if (cache->particles[i] !=
2461 cache->particles[i] = cache->particles.back();
2462 cache->particles.pop_back();
2466 if (cache->particles.empty())
2481#include "particles/particle_handler.inst"
@ children_will_be_coarsened
TriaIterator< CellAccessor< dim, spacedim > > child(const unsigned int i) const
bool is_locally_owned() const
boost::container::small_vector< TriaIterator< CellAccessor< dim, spacedim > >, GeometryInfo< dim >::max_children_per_cell > child_iterators() const
unsigned int active_cell_index() const
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.
particle_container::iterator particles_in_cell
unsigned int particle_index_within_cell
const void * read_particle_data_from_memory(const void *data)
const Triangulation< dim, spacedim >::cell_iterator & get_surrounding_cell() const
void set_location(const Point< spacedim > &new_location)
void set_reference_location(const Point< dim > &new_reference_location)
const PropertyPool< dim, spacedim >::Handle & get_handle() const
void set_properties(const std::vector< double > &new_properties)
void set_id(const types::particle_index &new_id)
std::function< void *(const particle_iterator &, void *)> store_callback
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
typename ParticleAccessor< dim, spacedim >::particle_container particle_container
const double tolerance_inside_cell
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)
ParticleIterator< dim, spacedim > particle_iterator
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)
particle_iterator begin() const
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::function< std::size_t()> size_callback
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
const particle_container::iterator owned_particles_end
particle_iterator end() const
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()
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
std::vector< boost::signals2::connection > tria_listeners
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()
std::vector< typename particle_container::iterator > cells_to_particle_cache
void copy_from(const ParticleHandler< dim, spacedim > &particle_handler)
std::function< const void *(const particle_iterator &, const void *)> load_callback
std::unique_ptr< GridTools::Cache< dim, spacedim > > triangulation_cache
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()
static const Handle invalid_handle
bool contains_point(const Point< dim > &p, const double tolerance=0) const
numbers::NumberTraits< Number >::real_type norm() const
constexpr numbers::NumberTraits< Number >::real_type norm_square() const
ReferenceCell reference_cell() const
IteratorState::IteratorStates state() const
#define DEAL_II_NAMESPACE_OPEN
constexpr bool running_in_debug_mode()
#define DEAL_II_NAMESPACE_CLOSE
#define DEAL_II_ASSERT_UNREACHABLE()
static ::ExceptionBase & ExcTransformationFailed()
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)
TriaActiveIterator< CellAccessor< dim, spacedim > > active_cell_iterator
TriaIterator< CellAccessor< dim, spacedim > > cell_iterator
@ 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 MPI_Datatype mpi_type_id_for_type
constexpr unsigned int invalid_unsigned_int
constexpr types::subdomain_id artificial_subdomain_id
bool is_finite(const double x)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
unsigned int subdomain_id
unsigned int particle_index
*braid_SplitCommworld & comm