32 template <
int dim,
int spacedim>
34 pack_particles(std::vector<Particle<dim, spacedim>> &particles)
36 std::vector<char> buffer;
38 if (particles.size() == 0)
41 buffer.resize(particles.size() *
42 particles.front().serialized_size_in_bytes());
43 void *current_data = buffer.data();
45 for (
const auto &particle : particles)
47 current_data = particle.write_particle_data_to_memory(current_data);
55 template <
int dim,
int spacedim>
56 std::vector<Particle<dim, spacedim>>
58 const boost::iterator_range<std::vector<char>::const_iterator>
60 PropertyPool<dim, spacedim> &property_pool)
62 std::vector<Particle<dim, spacedim>> particles;
64 if (data_range.empty())
67 Particle<dim, spacedim> particle;
68 particle.set_property_pool(property_pool);
69 const unsigned int particle_size = particle.serialized_size_in_bytes();
71 particles.reserve(data_range.size() / particle_size);
73 const void *data =
static_cast<const void *
>(&(*data_range.begin()));
75 while (data < &(*data_range.end()))
77 particles.emplace_back(data, &property_pool);
81 data == &(*data_range.end()),
83 "The particle data could not be deserialized successfully. "
84 "Check that when deserializing the particles you expect the same "
85 "number of properties that were serialized."));
91 template <
int dim,
int spacedim>
98 , global_number_of_particles(0)
99 , global_max_particles_per_cell(0)
100 , next_free_particle_index(0)
109 template <
int dim,
int spacedim>
113 const unsigned int n_properties)
115 , mapping(&mapping, typeid(*this).name())
116 , property_pool(
std::make_unique<
PropertyPool<dim, spacedim>>(n_properties))
119 , global_number_of_particles(0)
120 , global_max_particles_per_cell(0)
121 , next_free_particle_index(0)
133 template <
int dim,
int spacedim>
138 const unsigned int n_properties)
141 mapping = &new_mapping;
144 property_pool = std::make_unique<PropertyPool<dim, spacedim>>(n_properties);
148 triangulation_cache =
149 std::make_unique<GridTools::Cache<dim, spacedim>>(new_triangulation,
155 template <
int dim,
int spacedim>
162 const unsigned int n_properties =
167 property_pool->reserve(particle_handler.
particles.size() +
172 global_max_particles_per_cell =
178 ghost_particles_cache.ghost_particles_by_domain =
180 handle = particle_handler.
handle;
183 auto from_particle = particle_handler.
begin();
184 for (
auto &particle : *
this)
186 particle.set_property_pool(*property_pool);
191 for (
auto ghost = begin_ghost(); ghost != end_ghost();
192 ++ghost, ++from_ghost)
194 ghost->set_property_pool(*property_pool);
200 template <
int dim,
int spacedim>
205 global_number_of_particles = 0;
206 next_free_particle_index = 0;
207 global_max_particles_per_cell = 0;
212 template <
int dim,
int spacedim>
217 ghost_particles.clear();
221 property_pool->clear();
226 template <
int dim,
int spacedim>
231 unsigned int local_max_particles_per_cell = 0;
232 unsigned int current_particles_per_cell = 0;
236 for (
const auto &particle : *
this)
238 locally_highest_index =
239 std::max(locally_highest_index, particle.get_id());
241 if (particle.get_surrounding_cell(*
triangulation) != current_cell)
243 current_particles_per_cell = 0;
244 current_cell = particle.get_surrounding_cell(*
triangulation);
247 ++current_particles_per_cell;
248 local_max_particles_per_cell =
249 std::max(local_max_particles_per_cell, current_particles_per_cell);
252 if (
const auto parallel_triangulation =
257 particles.size(), parallel_triangulation->get_communicator());
258 next_free_particle_index =
259 global_number_of_particles == 0 ?
262 locally_highest_index,
263 parallel_triangulation->get_communicator()) +
266 local_max_particles_per_cell,
267 parallel_triangulation->get_communicator());
271 global_number_of_particles = particles.size();
272 next_free_particle_index =
273 global_number_of_particles == 0 ? 0 : locally_highest_index + 1;
274 global_max_particles_per_cell = local_max_particles_per_cell;
280 template <
int dim,
int spacedim>
287 std::make_pair(cell->level(), cell->index());
289 if (cell->is_locally_owned())
290 return particles.count(found_cell);
291 else if (cell->is_ghost())
292 return ghost_particles.count(found_cell);
295 ExcMessage(
"You can't ask for the particles on an artificial "
296 "cell since we don't know what exists on these "
304 template <
int dim,
int spacedim>
311 ->particles_in_cell(cell);
316 template <
int dim,
int spacedim>
322 std::make_pair(cell->level(), cell->index());
324 if (cell->is_ghost())
326 const auto particles_in_cell = ghost_particles.equal_range(level_index);
331 else if (cell->is_locally_owned())
333 const auto particles_in_cell = particles.equal_range(level_index);
340 ExcMessage(
"You can't ask for the particles on an artificial "
341 "cell since we don't know what exists on these "
349 template <
int dim,
int spacedim>
354 particles.erase(particle->particle);
359 template <
int dim,
int spacedim>
372 particle_it->set_property_pool(*property_pool);
375 for (
unsigned int n = 0; n < particle.
get_properties().size(); ++n)
383 template <
int dim,
int spacedim>
390 for (
const auto &particle : new_particles)
394 auto it = particles.insert(
397 particle.first->index()),
399 it->second.set_property_pool(*property_pool);
402 update_cached_numbers();
407 template <
int dim,
int spacedim>
412 update_cached_numbers();
419 get_next_free_particle_index();
422#ifdef DEAL_II_WITH_MPI
423 if (
const auto parallel_triangulation =
428 const int ierr = MPI_Scan(&particles_to_add_locally,
433 parallel_triangulation->get_communicator());
435 local_start_index -= particles_to_add_locally;
439 local_start_index += local_next_particle_index;
441 auto point_locations =
445 auto &cells = std::get<0>(point_locations);
446 auto &local_positions = std::get<1>(point_locations);
447 auto &index_map = std::get<2>(point_locations);
448 auto &missing_points = std::get<3>(point_locations);
454 (void)missing_points;
456 if (cells.size() == 0)
460 particles.find(std::make_pair(cells[0]->
level(), cells[0]->index()));
461 for (
unsigned int i = 0; i < cells.size(); ++i)
464 for (
unsigned int p = 0; p < local_positions[i].size(); ++p)
466 hint = particles.insert(
468 std::make_pair(current_cell,
470 local_positions[i][p],
474 hint->second.set_property_pool(*property_pool);
478 update_cached_numbers();
483 template <
int dim,
int spacedim>
484 std::map<unsigned int, IndexSet>
488 & global_bounding_boxes,
489 const std::vector<std::vector<double>> & properties,
490 const std::vector<types::particle_index> &ids)
492 if (!properties.empty())
496 for (
const auto &p : properties)
509 const auto n_global_properties =
513 const auto n_particles_per_proc =
519 unsigned int particle_start_index = get_next_free_particle_index();
520 for (
unsigned int process = 0; process < particle_start_indices.size();
523 particle_start_indices[process] = particle_start_index;
524 particle_start_index += n_particles_per_proc[process];
528 const auto cells_positions_and_index_maps =
531 global_bounding_boxes);
535 const auto &local_cells_containing_particles =
536 std::get<0>(cells_positions_and_index_maps);
540 const auto &local_reference_positions =
541 std::get<1>(cells_positions_and_index_maps);
544 const auto &original_indices_of_local_particles =
545 std::get<2>(cells_positions_and_index_maps);
548 const auto &local_positions = std::get<3>(cells_positions_and_index_maps);
550 const auto &calling_process_indices =
551 std::get<4>(cells_positions_and_index_maps);
554 std::map<unsigned int, std::vector<unsigned int>>
555 original_process_to_local_particle_indices_tmp;
556 for (
unsigned int i_cell = 0;
557 i_cell < local_cells_containing_particles.size();
560 for (
unsigned int i_particle = 0;
561 i_particle < local_positions[i_cell].size();
564 const unsigned int local_id_on_calling_process =
565 original_indices_of_local_particles[i_cell][i_particle];
566 const unsigned int calling_process =
567 calling_process_indices[i_cell][i_particle];
569 original_process_to_local_particle_indices_tmp[calling_process]
570 .push_back(local_id_on_calling_process);
573 std::map<unsigned int, IndexSet> original_process_to_local_particle_indices;
574 for (
auto &process_and_particle_indices :
575 original_process_to_local_particle_indices_tmp)
577 const unsigned int calling_process = process_and_particle_indices.first;
578 original_process_to_local_particle_indices.insert(
579 {calling_process,
IndexSet(n_particles_per_proc[calling_process])});
580 std::sort(process_and_particle_indices.second.begin(),
581 process_and_particle_indices.second.end());
582 original_process_to_local_particle_indices[calling_process].add_indices(
583 process_and_particle_indices.second.begin(),
584 process_and_particle_indices.second.end());
585 original_process_to_local_particle_indices[calling_process].compress();
593 std::map<unsigned int, std::vector<std::vector<double>>>
594 locally_owned_properties_from_other_processes;
601 std::map<unsigned int, std::vector<types::particle_index>>
602 locally_owned_ids_from_other_processes;
604 if (n_global_properties > 0 || !ids.empty())
609 comm, original_process_to_local_particle_indices);
612 if (n_global_properties > 0)
614 std::map<unsigned int, std::vector<std::vector<double>>>
615 non_locally_owned_properties;
617 for (
const auto &it : send_to_cpu)
619 std::vector<std::vector<double>> properties_to_send(
620 it.second.n_elements(),
621 std::vector<double>(n_properties_per_particle()));
622 unsigned int index = 0;
623 for (
const auto el : it.second)
624 properties_to_send[index++] = properties[el];
625 non_locally_owned_properties.insert(
626 {it.first, properties_to_send});
631 locally_owned_properties_from_other_processes =
635 locally_owned_properties_from_other_processes.size(),
636 original_process_to_local_particle_indices.size());
641 std::map<unsigned int, std::vector<types::particle_index>>
642 non_locally_owned_ids;
643 for (
const auto &it : send_to_cpu)
645 std::vector<types::particle_index> ids_to_send(
646 it.second.n_elements());
647 unsigned int index = 0;
648 for (
const auto el : it.second)
649 ids_to_send[index++] = ids[el];
650 non_locally_owned_ids.insert({it.first, ids_to_send});
655 locally_owned_ids_from_other_processes =
659 original_process_to_local_particle_indices.size());
665 std::multimap<typename Triangulation<dim, spacedim>::active_cell_iterator,
670 for (
unsigned int i_cell = 0;
671 i_cell < local_cells_containing_particles.size();
674 for (
unsigned int i_particle = 0;
675 i_particle < local_positions[i_cell].size();
678 const unsigned int local_id_on_calling_process =
679 original_indices_of_local_particles[i_cell][i_particle];
681 const unsigned int calling_process =
682 calling_process_indices[i_cell][i_particle];
684 const unsigned int index_within_set =
685 original_process_to_local_particle_indices[calling_process]
686 .index_within_set(local_id_on_calling_process);
688 const unsigned int particle_id =
690 local_id_on_calling_process +
691 particle_start_indices[calling_process] :
692 locally_owned_ids_from_other_processes[calling_process]
696 local_positions[i_cell][i_particle],
697 local_reference_positions[i_cell][i_particle],
702 if (n_global_properties > 0)
704 const auto &this_particle_properties =
705 locally_owned_properties_from_other_processes
706 [calling_process][index_within_set];
711 particles.emplace(local_cells_containing_particles[i_cell],
712 std::move(particle));
716 this->insert_particles(particles);
718 return original_process_to_local_particle_indices;
723 template <
int dim,
int spacedim>
724 std::map<unsigned int, IndexSet>
728 &global_bounding_boxes)
732 std::vector<Point<spacedim>> positions;
733 std::vector<std::vector<double>> properties;
734 std::vector<types::particle_index> ids;
735 positions.resize(particles.size());
736 ids.resize(particles.size());
737 if (n_properties_per_particle() > 0)
738 properties.resize(particles.size(),
739 std::vector<double>(n_properties_per_particle()));
742 for (
const auto &p : particles)
744 positions[i] = p.get_location();
746 if (p.has_properties())
747 properties[i] = {p.get_properties().begin(),
748 p.get_properties().end()};
752 return insert_global_particles(positions,
753 global_bounding_boxes,
760 template <
int dim,
int spacedim>
764 return global_number_of_particles;
769 template <
int dim,
int spacedim>
773 return global_max_particles_per_cell;
778 template <
int dim,
int spacedim>
782 return particles.size();
787 template <
int dim,
int spacedim>
791 return property_pool->n_properties_per_slot();
796 template <
int dim,
int spacedim>
800 return next_free_particle_index;
805 template <
int dim,
int spacedim>
810 for (
const auto &p : *
this)
811 set.add_index(p.get_id());
818 template <
int dim,
int spacedim>
822 const bool add_to_output_vector)
828 for (
auto it =
begin(); it !=
end(); ++it, ++i)
830 if (add_to_output_vector)
831 positions[i] = positions[i] + it->get_location();
833 positions[i] = it->get_location();
839 template <
int dim,
int spacedim>
843 const bool displace_particles)
849 for (
auto it =
begin(); it !=
end(); ++it, ++i)
851 if (displace_particles)
852 it->set_location(it->get_location() + new_positions[i]);
854 it->set_location(new_positions[i]);
856 sort_particles_into_subdomains_and_cells();
861 template <
int dim,
int spacedim>
865 const bool displace_particles)
872 for (
auto &particle : *
this)
876 if (displace_particles)
877 for (
unsigned int d = 0;
d < spacedim; ++
d)
878 particle_location[
d] += new_position[
d];
880 for (
unsigned int d = 0;
d < spacedim; ++
d)
881 particle_location[
d] = new_position[
d];
882 particle.set_location(particle_location);
884 sort_particles_into_subdomains_and_cells();
889 template <
int dim,
int spacedim>
893 return *property_pool;
911 compare_particle_association(
912 const unsigned int a,
913 const unsigned int b,
917 const double scalar_product_a = center_directions[a] * particle_direction;
918 const double scalar_product_b = center_directions[
b] * particle_direction;
923 return (scalar_product_a > scalar_product_b);
929 template <
int dim,
int spacedim>
941 std::vector<particle_iterator> particles_out_of_cell;
942 particles_out_of_cell.reserve(n_locally_owned_particles());
945 std::vector<Point<spacedim>> real_locations;
946 std::vector<Point<dim>> reference_locations;
947 for (
auto particle =
begin(); particle !=
end();)
949 const auto cell = particle->get_surrounding_cell(*
triangulation);
950 real_locations.clear();
957 for (
auto it = particle;
960 real_locations.push_back(it->get_location());
962 reference_locations.resize(real_locations.size());
964 reference_locations.size());
965 mapping->transform_points_real_to_unit_cell(cell,
969 for (
const auto &p_unit : reference_locations)
971 if (p_unit[0] == std::numeric_limits<double>::infinity() ||
973 particles_out_of_cell.push_back(particle);
975 particle->set_reference_location(p_unit);
986 std::vector<std::pair<internal::LevelInd, Particle<dim, spacedim>>>
988 std::map<types::subdomain_id, std::vector<particle_iterator>>
992 std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1001 sorted_particles.reserve(
1002 static_cast<vector_size
>(particles_out_of_cell.size() * 1.25));
1004 std::set<types::subdomain_id> ghost_owners;
1005 if (
const auto parallel_triangulation =
1008 ghost_owners = parallel_triangulation->ghost_owners();
1010 for (
const auto ghost_owner : ghost_owners)
1011 moved_particles[ghost_owner].reserve(
1012 static_cast<vector_size
>(particles_out_of_cell.size() * 0.25));
1013 for (
const auto ghost_owner : ghost_owners)
1014 moved_cells[ghost_owner].reserve(
1015 static_cast<vector_size
>(particles_out_of_cell.size() * 0.25));
1020 std::set<typename Triangulation<dim, spacedim>::active_cell_iterator>>
1021 vertex_to_cells = triangulation_cache->get_vertex_to_cell_map();
1025 std::vector<std::vector<Tensor<1, spacedim>>> vertex_to_cell_centers =
1026 triangulation_cache->get_vertex_to_cell_centers_directions();
1028 std::vector<unsigned int> neighbor_permutation;
1031 for (
auto &out_particle : particles_out_of_cell)
1035 bool found_cell =
false;
1040 current_cell = out_particle->get_surrounding_cell(*
triangulation);
1042 const unsigned int closest_vertex =
1043 GridTools::find_closest_vertex_of_cell<dim, spacedim>(
1044 current_cell, out_particle->get_location(), *mapping);
1046 out_particle->get_location() - current_cell->vertex(closest_vertex);
1047 vertex_to_particle /= vertex_to_particle.
norm();
1049 const unsigned int closest_vertex_index =
1050 current_cell->vertex_index(closest_vertex);
1051 const unsigned int n_neighbor_cells =
1052 vertex_to_cells[closest_vertex_index].size();
1054 neighbor_permutation.resize(n_neighbor_cells);
1055 for (
unsigned int i = 0; i < n_neighbor_cells; ++i)
1056 neighbor_permutation[i] = i;
1058 const auto cell_centers =
1059 vertex_to_cell_centers[closest_vertex_index];
1060 std::sort(neighbor_permutation.begin(),
1061 neighbor_permutation.end(),
1062 [&vertex_to_particle, &cell_centers](
const unsigned int a,
1063 const unsigned int b) {
1064 return compare_particle_association(a,
1073 const auto previous_cell_of_particle = current_cell;
1077 for (
unsigned int i = 0; i < n_neighbor_cells; ++i)
1081 typename std::set<typename Triangulation<dim, spacedim>::
1082 active_cell_iterator>::const_iterator
1083 cell = vertex_to_cells[closest_vertex_index].
begin();
1087 mapping->transform_real_to_unit_cell(
1088 *cell, out_particle->get_location());
1091 current_cell = *cell;
1092 current_reference_position = p_unit;
1106 const std::pair<const typename Triangulation<dim, spacedim>::
1107 active_cell_iterator,
1109 current_cell_and_position =
1110 GridTools::find_active_cell_around_point<>(
1111 *triangulation_cache, out_particle->get_location());
1112 current_cell = current_cell_and_position.first;
1113 current_reference_position = current_cell_and_position.second;
1120 signals.particle_lost(out_particle,
1121 previous_cell_of_particle);
1128 out_particle->set_reference_location(current_reference_position);
1132 if (current_cell->is_locally_owned())
1134 sorted_particles.push_back(
1136 current_cell->index()),
1137 out_particle->particle->second));
1141 moved_particles[current_cell->subdomain_id()].push_back(
1143 moved_cells[current_cell->subdomain_id()].push_back(current_cell);
1150 std::multimap<internal::LevelInd, Particle<dim, spacedim>>
1151 sorted_particles_map;
1154#ifdef DEAL_II_WITH_MPI
1155 if (
const auto parallel_triangulation =
1160 parallel_triangulation->get_communicator()) > 1)
1161 send_recv_particles(moved_particles,
1162 sorted_particles_map,
1167 sorted_particles_map.insert(sorted_particles.begin(),
1168 sorted_particles.end());
1170 for (
unsigned int i = 0; i < particles_out_of_cell.size(); ++i)
1171 remove_particle(particles_out_of_cell[i]);
1173 particles.insert(sorted_particles_map.begin(), sorted_particles_map.end());
1174 update_cached_numbers();
1179 template <
int dim,
int spacedim>
1182 const bool enable_cache)
1185 const auto parallel_triangulation =
1188 if (parallel_triangulation !=
nullptr)
1191 parallel_triangulation->get_communicator()) == 1)
1197#ifndef DEAL_II_WITH_MPI
1201 ghost_particles.clear();
1204 ghost_particles_cache.ghost_particles_by_domain.clear();
1205 ghost_particles_cache.valid =
false;
1208 const std::set<types::subdomain_id> ghost_owners =
1209 parallel_triangulation->ghost_owners();
1210 for (
const auto ghost_owner : ghost_owners)
1211 ghost_particles_cache.ghost_particles_by_domain[ghost_owner].reserve(
1213 particles.size() * 0.25));
1215 const std::vector<std::set<unsigned int>> vertex_to_neighbor_subdomain =
1216 triangulation_cache->get_vertex_to_neighbor_subdomain();
1218 for (
const auto &cell :
triangulation->active_cell_iterators())
1220 if (cell->is_locally_owned())
1222 std::set<unsigned int> cell_to_neighbor_subdomain;
1223 for (
const unsigned int v : cell->vertex_indices())
1225 cell_to_neighbor_subdomain.insert(
1226 vertex_to_neighbor_subdomain[cell->vertex_index(v)].begin(),
1227 vertex_to_neighbor_subdomain[cell->vertex_index(v)].end());
1230 if (cell_to_neighbor_subdomain.size() > 0)
1233 particles_in_cell(cell);
1235 for (
const auto domain : cell_to_neighbor_subdomain)
1237 for (
typename particle_iterator_range::iterator particle =
1238 particle_range.begin();
1239 particle != particle_range.end();
1241 ghost_particles_cache.ghost_particles_by_domain[domain]
1242 .push_back(particle);
1248 send_recv_particles(
1249 ghost_particles_cache.ghost_particles_by_domain,
1259 template <
int dim,
int spacedim>
1264 const auto parallel_triangulation =
1267 if (parallel_triangulation ==
nullptr ||
1269 parallel_triangulation->get_communicator()) == 1)
1275#ifdef DEAL_II_WITH_MPI
1279 ghost_particles_cache.valid,
1281 "Ghost particles cannot be updated if they first have not been exchanged at least once with the cache enabled"));
1284 send_recv_particles_properties_and_location(
1285 ghost_particles_cache.ghost_particles_by_domain, ghost_particles);
1291#ifdef DEAL_II_WITH_MPI
1292 template <
int dim,
int spacedim>
1298 &received_particles,
1303 const bool build_cache)
1305 ghost_particles_cache.valid = build_cache;
1307 const auto parallel_triangulation =
1311 parallel_triangulation,
1313 "This function is only implemented for parallel::TriangulationBase objects."));
1316 const std::set<types::subdomain_id> ghost_owners =
1317 parallel_triangulation->ghost_owners();
1318 const std::vector<types::subdomain_id> neighbors(ghost_owners.begin(),
1319 ghost_owners.end());
1320 const unsigned int n_neighbors = neighbors.size();
1322 if (send_cells.size() != 0)
1328 particles_to_send.end(),
1333 for (
auto send_particles = particles_to_send.begin();
1334 send_particles != particles_to_send.end();
1336 Assert(ghost_owners.find(send_particles->first) != ghost_owners.end(),
1339 std::size_t n_send_particles = 0;
1340 for (
auto send_particles = particles_to_send.begin();
1341 send_particles != particles_to_send.end();
1343 n_send_particles += send_particles->second.size();
1349 std::vector<unsigned int> n_send_data(n_neighbors, 0);
1350 std::vector<unsigned int> send_offsets(n_neighbors, 0);
1351 std::vector<char> send_data;
1353 const unsigned int individual_particle_data_size =
1355 ((
begin()->serialized_size_in_bytes() +
1356 (size_callback ? size_callback() : 0))) :
1358 parallel_triangulation->get_communicator());
1360 const unsigned int individual_total_particle_data_size =
1361 individual_particle_data_size + cellid_size;
1366 if (n_send_particles > 0)
1369 send_data.resize(n_send_particles *
1370 individual_total_particle_data_size);
1372 void *data =
static_cast<void *
>(&send_data.front());
1375 for (
unsigned int i = 0; i < n_neighbors; ++i)
1377 send_offsets[i] =
reinterpret_cast<std::size_t
>(data) -
1378 reinterpret_cast<std::size_t
>(&send_data.front());
1380 const unsigned int n_particles_to_send =
1381 particles_to_send.at(neighbors[i]).size();
1383 Assert(
static_cast<std::size_t
>(n_particles_to_send) *
1384 individual_total_particle_data_size ==
1385 static_cast<std::size_t
>(
1386 n_particles_to_send *
1387 individual_total_particle_data_size),
1388 ExcMessage(
"Overflow when trying to send particle data"));
1390 for (
unsigned int j = 0; j < n_particles_to_send; ++j)
1395 if (send_cells.size() == 0)
1397 particles_to_send.at(neighbors[i])[j]->get_surrounding_cell(
1400 cell = send_cells.at(neighbors[i])[j];
1403 cell->id().template to_binary<dim>();
1404 memcpy(data, &cellid, cellid_size);
1405 data =
static_cast<char *
>(data) + cellid_size;
1407 data = particles_to_send.at(neighbors[i])[j]
1408 ->write_particle_data_to_memory(data);
1411 store_callback(particles_to_send.at(neighbors[i])[j], data);
1413 n_send_data[i] = n_particles_to_send;
1418 std::vector<unsigned int> n_recv_data(n_neighbors);
1419 std::vector<unsigned int> recv_offsets(n_neighbors);
1425 std::vector<MPI_Request> n_requests(2 * n_neighbors);
1426 for (
unsigned int i = 0; i < n_neighbors; ++i)
1428 const int ierr = MPI_Irecv(&(n_recv_data[i]),
1433 parallel_triangulation->get_communicator(),
1434 &(n_requests[2 * i]));
1437 for (
unsigned int i = 0; i < n_neighbors; ++i)
1439 const int ierr = MPI_Isend(&(n_send_data[i]),
1444 parallel_triangulation->get_communicator(),
1445 &(n_requests[2 * i + 1]));
1449 MPI_Waitall(2 * n_neighbors, n_requests.data(), MPI_STATUSES_IGNORE);
1454 unsigned int total_recv_data = 0;
1455 for (
unsigned int neighbor_id = 0; neighbor_id < n_neighbors; ++neighbor_id)
1457 recv_offsets[neighbor_id] = total_recv_data;
1459 n_recv_data[neighbor_id] * individual_total_particle_data_size;
1463 std::vector<char> recv_data(total_recv_data);
1467 std::vector<MPI_Request> requests(2 * n_neighbors);
1468 unsigned int send_ops = 0;
1469 unsigned int recv_ops = 0;
1474 for (
unsigned int i = 0; i < n_neighbors; ++i)
1475 if (n_recv_data[i] > 0)
1478 MPI_Irecv(&(recv_data[recv_offsets[i]]),
1479 n_recv_data[i] * individual_total_particle_data_size,
1483 parallel_triangulation->get_communicator(),
1484 &(requests[send_ops]));
1489 for (
unsigned int i = 0; i < n_neighbors; ++i)
1490 if (n_send_data[i] > 0)
1493 MPI_Isend(&(send_data[send_offsets[i]]),
1494 n_send_data[i] * individual_total_particle_data_size,
1498 parallel_triangulation->get_communicator(),
1499 &(requests[send_ops + recv_ops]));
1504 MPI_Waitall(send_ops + recv_ops, requests.data(), MPI_STATUSES_IGNORE);
1510 const void *recv_data_it =
static_cast<const void *
>(recv_data.data());
1513 auto &ghost_particles_iterators =
1514 ghost_particles_cache.ghost_particles_iterators;
1518 ghost_particles_iterators.clear();
1520 auto &send_pointers_particles = ghost_particles_cache.send_pointers;
1521 send_pointers_particles.assign(n_neighbors + 1, 0);
1523 for (
unsigned int i = 0; i < n_neighbors; ++i)
1524 send_pointers_particles[i + 1] =
1525 send_pointers_particles[i] +
1526 n_send_data[i] * individual_particle_data_size;
1528 auto &recv_pointers_particles = ghost_particles_cache.recv_pointers;
1529 recv_pointers_particles.assign(n_neighbors + 1, 0);
1531 for (
unsigned int i = 0; i < n_neighbors; ++i)
1532 recv_pointers_particles[i + 1] =
1533 recv_pointers_particles[i] +
1534 n_recv_data[i] * individual_particle_data_size;
1536 ghost_particles_cache.neighbors = neighbors;
1538 ghost_particles_cache.send_data.resize(
1539 ghost_particles_cache.send_pointers.back());
1540 ghost_particles_cache.recv_data.resize(
1541 ghost_particles_cache.recv_pointers.back());
1544 while (
reinterpret_cast<std::size_t
>(recv_data_it) -
1545 reinterpret_cast<std::size_t
>(recv_data.data()) <
1549 memcpy(&binary_cellid, recv_data_it, cellid_size);
1550 const CellId id(binary_cellid);
1551 recv_data_it =
static_cast<const char *
>(recv_data_it) + cellid_size;
1558 recv_particle = received_particles.insert(std::make_pair(
1568 ghost_particles_iterators.push_back(recv_particle);
1571 AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
1573 "The amount of data that was read into new particles "
1574 "does not match the amount of data sent around."));
1580#ifdef DEAL_II_WITH_MPI
1581 template <
int dim,
int spacedim>
1589 const auto &neighbors = ghost_particles_cache.neighbors;
1590 const auto &send_pointers = ghost_particles_cache.send_pointers;
1591 const auto &recv_pointers = ghost_particles_cache.recv_pointers;
1593 const auto parallel_triangulation =
1597 parallel_triangulation,
1599 "This function is only implemented for parallel::TriangulationBase objects."));
1601 std::vector<char> &send_data = ghost_particles_cache.send_data;
1604 if (send_pointers.back() > 0)
1606 void *data =
static_cast<void *
>(&send_data.front());
1609 for (
const auto i : neighbors)
1610 for (
const auto &p : particles_to_send.at(i))
1612 data = p->write_particle_data_to_memory(data);
1614 data = store_callback(p, data);
1618 std::vector<char> &recv_data = ghost_particles_cache.recv_data;
1622 std::vector<MPI_Request> requests(2 * neighbors.size());
1623 unsigned int send_ops = 0;
1624 unsigned int recv_ops = 0;
1629 for (
unsigned int i = 0; i < neighbors.size(); ++i)
1630 if ((recv_pointers[i + 1] - recv_pointers[i]) > 0)
1633 MPI_Irecv(recv_data.data() + recv_pointers[i],
1634 recv_pointers[i + 1] - recv_pointers[i],
1638 parallel_triangulation->get_communicator(),
1639 &(requests[send_ops]));
1644 for (
unsigned int i = 0; i < neighbors.size(); ++i)
1645 if ((send_pointers[i + 1] - send_pointers[i]) > 0)
1648 MPI_Isend(send_data.data() + send_pointers[i],
1649 send_pointers[i + 1] - send_pointers[i],
1653 parallel_triangulation->get_communicator(),
1654 &(requests[send_ops + recv_ops]));
1659 MPI_Waitall(send_ops + recv_ops, requests.data(), MPI_STATUSES_IGNORE);
1665 const void *recv_data_it =
static_cast<const void *
>(recv_data.data());
1668 auto &ghost_particles_iterators =
1669 ghost_particles_cache.ghost_particles_iterators;
1671 for (
auto &recv_particle : ghost_particles_iterators)
1676 recv_particle->second.read_particle_data_from_memory(recv_data_it);
1684 AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
1686 "The amount of data that was read into new particles "
1687 "does not match the amount of data sent around."));
1691 template <
int dim,
int spacedim>
1694 const std::function<std::size_t()> & size_callb,
1699 size_callback = size_callb;
1700 store_callback = store_callb;
1701 load_callback = load_callb;
1706 template <
int dim,
int spacedim>
1711 *non_const_triangulation =
1714 *
>(&(*triangulation)));
1715 (void)non_const_triangulation;
1719#ifdef DEAL_II_WITH_P4EST
1723 update_cached_numbers();
1725 if (global_max_particles_per_cell > 0)
1727 const auto callback_function =
1732 return this->store_particles(cell_iterator, cell_status);
1736 callback_function,
true);
1743 template <
int dim,
int spacedim>
1746 const bool serialization)
1753 *non_const_triangulation =
1756 *
>(&(*triangulation)));
1757 (void)non_const_triangulation;
1761#ifdef DEAL_II_WITH_P4EST
1766 if (serialization && (global_max_particles_per_cell > 0))
1768 const auto callback_function =
1773 return this->store_particles(cell_iterator, cell_status);
1777 callback_function,
true);
1783 const auto callback_function =
1788 const boost::iterator_range<std::vector<char>::const_iterator>
1790 this->load_particles(cell_iterator, cell_status, range_iterator);
1799 update_cached_numbers();
1802 (void)serialization;
1808 template <
int dim,
int spacedim>
1814 std::vector<Particle<dim, spacedim>> stored_particles_on_cell;
1823 unsigned int n_particles = 0;
1827 const auto particles_in_cell =
1828 (cell->is_ghost() ? ghost_particles.equal_range(level_index) :
1829 particles.equal_range(level_index));
1831 n_particles = n_particles_in_cell(cell);
1832 stored_particles_on_cell.reserve(n_particles);
1835 particles_in_cell.first,
1836 particles_in_cell.second,
1837 [&stored_particles_on_cell](
1840 stored_particles_on_cell.push_back(particle.second);
1851 unsigned int n_particles = 0;
1853 for (
const auto &child : cell->child_iterators())
1855 n_particles += n_particles_in_cell(child);
1858 stored_particles_on_cell.reserve(n_particles);
1860 for (
const auto &child : cell->child_iterators())
1864 const auto particles_in_cell =
1865 (child->is_ghost() ?
1866 ghost_particles.equal_range(level_index) :
1867 particles.equal_range(level_index));
1870 particles_in_cell.first,
1871 particles_in_cell.second,
1872 [&stored_particles_on_cell](
1875 stored_particles_on_cell.push_back(particle.second);
1888 return pack_particles(stored_particles_on_cell);
1893 template <
int dim,
int spacedim>
1898 const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
1902 std::vector<Particle<dim, spacedim>> loaded_particles_on_cell =
1903 unpack_particles<dim, spacedim>(data_range, *property_pool);
1908 for (
auto &particle : loaded_particles_on_cell)
1909 particle.set_property_pool(*property_pool);
1915 auto position_hint = particles.
end();
1916 for (
const auto &particle : loaded_particles_on_cell)
1921 particles.emplace_hint(position_hint,
1922 std::make_pair(cell->level(),
1924 std::move(particle));
1937 position_hint = particles.end();
1938 for (
auto &particle : loaded_particles_on_cell)
1941 mapping->transform_real_to_unit_cell(cell,
1942 particle.get_location());
1943 particle.set_reference_location(p_unit);
1947 particles.emplace_hint(position_hint,
1948 std::make_pair(cell->level(),
1950 std::move(particle));
1965 for (
unsigned int child_index = 0;
1966 child_index < GeometryInfo<dim>::max_children_per_cell;
1970 child = cell->child(child_index);
1971 position_hints[child_index] = particles.upper_bound(
1972 std::make_pair(child->level(), child->index()));
1975 for (
auto &particle : loaded_particles_on_cell)
1977 for (
unsigned int child_index = 0;
1978 child_index < GeometryInfo<dim>::max_children_per_cell;
1982 child = cell->child(child_index);
1987 mapping->transform_real_to_unit_cell(
1988 child, particle.get_location());
1991 particle.set_reference_location(p_unit);
1994 position_hints[child_index] =
1995 particles.emplace_hint(
1996 position_hints[child_index],
1997 std::make_pair(child->level(), child->index()),
1998 std::move(particle));
2002 ++position_hints[child_index];
2020#include "particle_handler.inst"
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 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)
types::particle_index n_global_particles() const
std::multimap< internal::LevelInd, Particle< dim, spacedim > > particles
unsigned int global_max_particles_per_cell
internal::GhostParticlePartitioner< dim, spacedim > ghost_particles_cache
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)
void update_cached_numbers()
boost::iterator_range< particle_iterator > particle_iterator_range
std::multimap< internal::LevelInd, Particle< dim, spacedim > > ghost_particles
particle_iterator begin_ghost() const
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
particle_iterator begin() const
void send_recv_particles_properties_and_location(const std::map< types::subdomain_id, std::vector< particle_iterator > > &particles_to_send, std::multimap< internal::LevelInd, Particle< dim, spacedim > > &received_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 register_load_callback_function(const bool serialization)
std::vector< char > store_particles(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const typename Triangulation< dim, spacedim >::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 register_store_callback_function()
void remove_particle(const particle_iterator &particle)
types::particle_index n_locally_owned_particles() const
types::particle_index n_particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell) const
void update_ghost_particles()
particle_iterator_range particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell)
void load_particles(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const typename Triangulation< dim, spacedim >::CellStatus status, const boost::iterator_range< std::vector< char >::const_iterator > &data_range)
SmartPointer< const Triangulation< dim, spacedim >, ParticleHandler< dim, spacedim > > triangulation
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()
types::particle_index n_global_max_particles_per_cell() const
void copy_from(const ParticleHandler< dim, spacedim > &particle_handler)
SmartPointer< const Mapping< dim, spacedim >, ParticleHandler< dim, spacedim > > mapping
std::unique_ptr< GridTools::Cache< dim, spacedim > > triangulation_cache
std::enable_if< std::is_convertible< VectorType *, Function< spacedim > * >::value==false >::type set_particle_positions(const VectorType &input_vector, const bool displace_particles=true)
types::particle_index get_next_free_particle_index() const
void send_recv_particles(const std::map< types::subdomain_id, std::vector< particle_iterator > > &particles_to_send, std::multimap< internal::LevelInd, Particle< dim, spacedim > > &received_particles, 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)
IndexSet locally_owned_particle_ids() const
void set_property_pool(PropertyPool< dim, spacedim > &property_pool)
bool has_properties() const
const ArrayView< double > get_properties()
void set_properties(const ArrayView< const double > &new_properties)
numbers::NumberTraits< Number >::real_type norm() const
cell_iterator begin(const unsigned int level=0) const
cell_iterator end() const
void notify_ready_to_unpack(const unsigned int handle, const std::function< void(const cell_iterator &, const CellStatus, const boost::iterator_range< std::vector< char >::const_iterator > &)> &unpack_callback)
unsigned int register_data_attach(const std::function< std::vector< char >(const cell_iterator &, const CellStatus)> &pack_callback, const bool returns_variable_size_data)
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_NAMESPACE_CLOSE
__global__ void set(Number *val, const Number s, const size_type N)
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)
IteratorRange< BaseIterator > make_iterator_range(const BaseIterator &begin, const typename identity< BaseIterator >::type &end)
@ valid
Iterator points to a valid object.
types::global_dof_index size_type
std::pair< int, int > LevelInd
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
VectorType::value_type * end(VectorType &V)
VectorType::value_type * begin(VectorType &V)
std::vector< T > all_gather(const MPI_Comm &comm, const T &object_to_send)
T sum(const T &t, const MPI_Comm &mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
T max(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)
const types::subdomain_id artificial_subdomain_id
static const unsigned int invalid_unsigned_int
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
unsigned int subdomain_id
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
*braid_SplitCommworld & comm
#define DEAL_II_PARTICLE_INDEX_MPI_TYPE
void advance(std::tuple< I1, I2 > &t, const unsigned int n)