Reference documentation for deal.II version 9.1.0-pre
particle_handler.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2017 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/std_cxx14/memory.h>
17 
18 #include <deal.II/grid/grid_tools.h>
19 #include <deal.II/grid/grid_tools_cache.h>
20 
21 #include <deal.II/particles/particle_handler.h>
22 
23 #include <utility>
24 
25 DEAL_II_NAMESPACE_OPEN
26 
27 #ifdef DEAL_II_WITH_P4EST
28 
29 namespace Particles
30 {
31  template <int dim, int spacedim>
33  : triangulation()
34  , particles()
35  , ghost_particles()
36  , global_number_of_particles(0)
37  , global_max_particles_per_cell(0)
38  , next_free_particle_index(0)
39  , property_pool(new PropertyPool(0))
40  , size_callback()
41  , store_callback()
42  , load_callback()
43  , handle(numbers::invalid_unsigned_int)
44  {}
45 
46 
47 
48  template <int dim, int spacedim>
52  const unsigned int n_properties)
53  : triangulation(&triangulation, typeid(*this).name())
54  , mapping(&mapping, typeid(*this).name())
55  , particles()
56  , ghost_particles()
60  , property_pool(new PropertyPool(n_properties))
61  , size_callback()
62  , store_callback()
63  , load_callback()
64  , handle(numbers::invalid_unsigned_int)
65  {}
66 
67 
68 
69  template <int dim, int spacedim>
71  {}
72 
73 
74 
75  template <int dim, int spacedim>
76  void
79  const Mapping<dim, spacedim> & mapp,
80  const unsigned int n_properties)
81  {
82  triangulation = &tria;
83  mapping = &mapp;
84 
85  // Create the memory pool that will store all particle properties
86  property_pool = std_cxx14::make_unique<PropertyPool>(n_properties);
87  }
88 
89 
90 
91  template <int dim, int spacedim>
92  void
94  {
99  }
100 
101 
102 
103  template <int dim, int spacedim>
104  void
106  {
107  particles.clear();
108  }
109 
110 
111 
112  template <int dim, int spacedim>
113  void
115  {
116  types::particle_index locally_highest_index = 0;
117  unsigned int local_max_particles_per_cell = 0;
118  unsigned int current_particles_per_cell = 0;
120  triangulation->begin_active();
121 
122  for (particle_iterator particle = begin(); particle != end(); ++particle)
123  {
124  locally_highest_index =
125  std::max(locally_highest_index, particle->get_id());
126 
127  if (particle->get_surrounding_cell(*triangulation) != current_cell)
128  {
129  current_particles_per_cell = 0;
130  current_cell = particle->get_surrounding_cell(*triangulation);
131  }
132 
133  ++current_particles_per_cell;
134  local_max_particles_per_cell =
135  std::max(local_max_particles_per_cell, current_particles_per_cell);
136  }
137 
139  ::Utilities::MPI::sum(particles.size(),
140  triangulation->get_communicator());
142  ::Utilities::MPI::max(locally_highest_index,
143  triangulation->get_communicator()) +
144  1;
146  ::Utilities::MPI::max(local_max_particles_per_cell,
147  triangulation->get_communicator());
148  }
149 
150 
151 
152  template <int dim, int spacedim>
155  {
156  return (const_cast<ParticleHandler<dim, spacedim> *>(this))->begin();
157  }
158 
159 
160 
161  template <int dim, int spacedim>
164  {
165  return particle_iterator(particles, particles.begin());
166  }
167 
168 
169 
170  template <int dim, int spacedim>
173  {
174  return (const_cast<ParticleHandler<dim, spacedim> *>(this))->end();
175  }
176 
177 
178 
179  template <int dim, int spacedim>
182  {
183  return particle_iterator(particles, particles.end());
184  }
185 
186 
187 
188  template <int dim, int spacedim>
191  {
192  return (const_cast<ParticleHandler<dim, spacedim> *>(this))->begin_ghost();
193  }
194 
195 
196 
197  template <int dim, int spacedim>
200  {
202  }
203 
204 
205 
206  template <int dim, int spacedim>
209  {
210  return (const_cast<ParticleHandler<dim, spacedim> *>(this))->end_ghost();
211  }
212 
213 
214 
215  template <int dim, int spacedim>
218  {
220  }
221 
222 
223 
224  template <int dim, int spacedim>
228  const
229  {
230  return (const_cast<ParticleHandler<dim, spacedim> *>(this))
231  ->particles_in_cell(cell);
232  }
233 
234 
235 
236  template <int dim, int spacedim>
240  {
241  const internal::LevelInd level_index =
242  std::make_pair<int, int>(cell->level(), cell->index());
243 
244  if (cell->is_ghost())
245  {
246  const auto particles_in_cell = ghost_particles.equal_range(level_index);
247  return boost::make_iterator_range(
250  }
251 
252  const auto particles_in_cell = particles.equal_range(level_index);
253  return boost::make_iterator_range(
256  }
257 
258 
259 
260  template <int dim, int spacedim>
261  void
264  {
265  particles.erase(particle->particle);
266  }
267 
268 
269 
270  template <int dim, int spacedim>
273  const Particle<dim, spacedim> & particle,
275  {
276  typename std::multimap<internal::LevelInd,
277  Particle<dim, spacedim>>::iterator it =
278  particles.insert(
279  std::make_pair(internal::LevelInd(cell->level(), cell->index()),
280  particle));
281 
282  particle_iterator particle_it(particles, it);
283  particle_it->set_property_pool(*property_pool);
284 
285  if (particle.has_properties())
286  for (unsigned int n = 0; n < particle.get_properties().size(); ++n)
287  particle_it->get_properties()[n] = particle.get_properties()[n];
288 
289  return particle_it;
290  }
291 
292 
293 
294  template <int dim, int spacedim>
295  void
297  const std::multimap<
299  Particle<dim, spacedim>> &new_particles)
300  {
301  for (auto particle = new_particles.begin(); particle != new_particles.end();
302  ++particle)
303  particles.insert(
304  particles.end(),
305  std::make_pair(internal::LevelInd(particle->first->level(),
306  particle->first->index()),
307  particle->second));
308 
310  }
311 
312 
313 
314  template <int dim, int spacedim>
315  void
317  const std::vector<Point<spacedim>> &positions)
318  {
320 
321  // Determine the starting particle index of this process, which
322  // is the highest currently existing particle index plus the sum
323  // of the number of newly generated particles of all
324  // processes with a lower rank if in a parallel computation.
325  const types::particle_index local_next_particle_index =
327  types::particle_index local_start_index = 0;
328 
329 # ifdef DEAL_II_WITH_MPI
330  types::particle_index particles_to_add_locally = positions.size();
331  const int ierr = MPI_Scan(&particles_to_add_locally,
332  &local_start_index,
333  1,
334  PARTICLE_INDEX_MPI_TYPE,
335  MPI_SUM,
336  triangulation->get_communicator());
337  AssertThrowMPI(ierr);
338  local_start_index -= particles_to_add_locally;
339 # endif
340 
341  local_start_index += local_next_particle_index;
342 
344  auto point_locations = GridTools::compute_point_locations(cache, positions);
345 
346  auto &cells = std::get<0>(point_locations);
347  auto &local_positions = std::get<1>(point_locations);
348  auto &index_map = std::get<2>(point_locations);
349 
350  if (cells.size() == 0)
351  return;
352 
353  auto hint =
354  particles.find(std::make_pair(cells[0]->level(), cells[0]->index()));
355  for (unsigned int i = 0; i < cells.size(); ++i)
356  {
357  internal::LevelInd current_cell(cells[i]->level(), cells[i]->index());
358  for (unsigned int p = 0; p < local_positions[i].size(); ++p)
359  {
360  hint = particles.insert(
361  hint,
362  std::make_pair(current_cell,
363  Particle<dim, spacedim>(positions[index_map[i][p]],
364  local_positions[i][p],
365  local_start_index +
366  index_map[i][p])));
367  }
368  }
369 
371  }
372 
373 
374 
375  template <int dim, int spacedim>
378  {
380  }
381 
382 
383 
384  template <int dim, int spacedim>
387  {
389  }
390 
391 
392 
393  template <int dim, int spacedim>
396  {
397  return particles.size();
398  }
399 
400 
401 
402  template <int dim, int spacedim>
403  unsigned int
405  {
406  return property_pool->n_properties_per_slot();
407  }
408 
409 
410 
411  template <int dim, int spacedim>
412  unsigned int
415  const
416  {
417  const internal::LevelInd found_cell =
418  std::make_pair<int, int>(cell->level(), cell->index());
419 
420  if (cell->is_locally_owned())
421  return particles.count(found_cell);
422  else if (cell->is_ghost())
423  return ghost_particles.count(found_cell);
424  else if (cell->is_artificial())
425  AssertThrow(false, ExcInternalError());
426 
427  return 0;
428  }
429 
430 
431 
432  template <int dim, int spacedim>
435  {
437  }
438 
439 
440 
441  template <int dim, int spacedim>
442  PropertyPool &
444  {
445  return *property_pool;
446  }
447 
448 
449 
450  namespace
451  {
461  template <int dim>
462  bool
463  compare_particle_association(
464  const unsigned int a,
465  const unsigned int b,
466  const Tensor<1, dim> & particle_direction,
467  const std::vector<Tensor<1, dim>> &center_directions)
468  {
469  const double scalar_product_a = center_directions[a] * particle_direction;
470  const double scalar_product_b = center_directions[b] * particle_direction;
471 
472  // The function is supposed to return if a is before b. We are looking
473  // for the alignment of particle direction and center direction,
474  // therefore return if the scalar product of a is larger.
475  return (scalar_product_a > scalar_product_b);
476  }
477  } // namespace
478 
479 
480 
481  template <int dim, int spacedim>
482  void
484  {
485  // TODO: The current algorithm only works for particles that are in
486  // the local domain or in ghost cells, because it only knows the
487  // subdomain_id of ghost cells, but not of artificial cells. This
488  // can be extended using the distributed version of compute point
489  // locations.
490  // TODO: Extend this function to allow keeping particles on other
491  // processes around (with an invalid cell).
492 
493  std::vector<particle_iterator> particles_out_of_cell;
494  particles_out_of_cell.reserve(n_locally_owned_particles());
495 
496  // Now update the reference locations of the moved particles
497  for (particle_iterator it = begin(); it != end(); ++it)
498  {
499  const typename Triangulation<dim, spacedim>::cell_iterator cell =
500  it->get_surrounding_cell(*triangulation);
501 
502  try
503  {
504  const Point<dim> p_unit =
505  mapping->transform_real_to_unit_cell(cell, it->get_location());
507  {
508  it->set_reference_location(p_unit);
509  }
510  else
511  {
512  // The particle has left the cell
513  particles_out_of_cell.push_back(it);
514  }
515  }
516  catch (typename Mapping<dim>::ExcTransformationFailed &)
517  {
518  // The particle has left the cell
519  particles_out_of_cell.push_back(it);
520  }
521  }
522 
523  // There are three reasons why a particle is not in its old cell:
524  // It moved to another cell, to another subdomain or it left the mesh.
525  // Particles that moved to another cell are updated and stored inside the
526  // sorted_particles vector, particles that moved to another domain are
527  // collected in the moved_particles_domain vector. Particles that left
528  // the mesh completely are ignored and removed.
529  std::vector<std::pair<internal::LevelInd, Particle<dim, spacedim>>>
530  sorted_particles;
531  std::map<types::subdomain_id, std::vector<particle_iterator>>
532  moved_particles;
533  std::map<
535  std::vector<typename Triangulation<dim, spacedim>::active_cell_iterator>>
536  moved_cells;
537 
538  // We do not know exactly how many particles are lost, exchanged between
539  // domains, or remain on this process. Therefore we pre-allocate approximate
540  // sizes for these vectors. If more space is needed an automatic and
541  // relatively fast (compared to other parts of this algorithm)
542  // re-allocation will happen.
543  using vector_size = typename std::vector<particle_iterator>::size_type;
544  sorted_particles.reserve(
545  static_cast<vector_size>(particles_out_of_cell.size() * 1.25));
546 
547  const std::set<types::subdomain_id> ghost_owners =
548  triangulation->ghost_owners();
549 
550  for (auto ghost_domain_id = ghost_owners.begin();
551  ghost_domain_id != ghost_owners.end();
552  ++ghost_domain_id)
553  moved_particles[*ghost_domain_id].reserve(
554  static_cast<vector_size>(particles_out_of_cell.size() * 0.25));
555  for (auto ghost_domain_id = ghost_owners.begin();
556  ghost_domain_id != ghost_owners.end();
557  ++ghost_domain_id)
558  moved_cells[*ghost_domain_id].reserve(
559  static_cast<vector_size>(particles_out_of_cell.size() * 0.25));
560 
561  {
562  // Create a map from vertices to adjacent cells
563  const std::vector<
564  std::set<typename Triangulation<dim, spacedim>::active_cell_iterator>>
565  vertex_to_cells(GridTools::vertex_to_cell_map(*triangulation));
566 
567  // Create a corresponding map of vectors from vertex to cell center
568  const std::vector<std::vector<Tensor<1, spacedim>>>
569  vertex_to_cell_centers(
571  vertex_to_cells));
572 
573  std::vector<unsigned int> neighbor_permutation;
574 
575  // Find the cells that the particles moved to.
576  typename std::vector<particle_iterator>::iterator
577  it = particles_out_of_cell.begin(),
578  end_particle = particles_out_of_cell.end();
579 
580  for (; it != end_particle; ++it)
581  {
582  // The cell the particle is in
583  Point<dim> current_reference_position;
584  bool found_cell = false;
585 
586  // Check if the particle is in one of the old cell's neighbors
587  // that are adjacent to the closest vertex
589  current_cell = (*it)->get_surrounding_cell(*triangulation);
590 
591  const unsigned int closest_vertex =
592  GridTools::find_closest_vertex_of_cell<dim, spacedim>(
593  current_cell, (*it)->get_location());
594  Tensor<1, spacedim> vertex_to_particle =
595  (*it)->get_location() - current_cell->vertex(closest_vertex);
596  vertex_to_particle /= vertex_to_particle.norm();
597 
598  const unsigned int closest_vertex_index =
599  current_cell->vertex_index(closest_vertex);
600  const unsigned int n_neighbor_cells =
601  vertex_to_cells[closest_vertex_index].size();
602 
603  neighbor_permutation.resize(n_neighbor_cells);
604  for (unsigned int i = 0; i < n_neighbor_cells; ++i)
605  neighbor_permutation[i] = i;
606 
607  std::sort(neighbor_permutation.begin(),
608  neighbor_permutation.end(),
609  std::bind(&compare_particle_association<spacedim>,
610  std::placeholders::_1,
611  std::placeholders::_2,
612  std::cref(vertex_to_particle),
613  std::cref(
614  vertex_to_cell_centers[closest_vertex_index])));
615 
616  // Search all of the cells adjacent to the closest vertex of the
617  // previous cell Most likely we will find the particle in them.
618  for (unsigned int i = 0; i < n_neighbor_cells; ++i)
619  {
620  try
621  {
622  typename std::set<typename Triangulation<dim, spacedim>::
623  active_cell_iterator>::const_iterator
624  cell = vertex_to_cells[closest_vertex_index].begin();
625 
626  std::advance(cell, neighbor_permutation[i]);
627  const Point<dim> p_unit =
628  mapping->transform_real_to_unit_cell(*cell,
629  (*it)->get_location());
631  {
632  current_cell = *cell;
633  current_reference_position = p_unit;
634  found_cell = true;
635  break;
636  }
637  }
638  catch (typename Mapping<dim>::ExcTransformationFailed &)
639  {}
640  }
641 
642  if (!found_cell)
643  {
644  // The particle is not in a neighbor of the old cell.
645  // Look for the new cell in the whole local domain.
646  // This case is rare.
647  try
648  {
649  const std::pair<const typename Triangulation<dim, spacedim>::
650  active_cell_iterator,
651  Point<dim>>
652  current_cell_and_position =
653  GridTools::find_active_cell_around_point<>(
654  *mapping, *triangulation, (*it)->get_location());
655  current_cell = current_cell_and_position.first;
656  current_reference_position = current_cell_and_position.second;
657  }
658  catch (GridTools::ExcPointNotFound<spacedim> &)
659  {
660  // We can find no cell for this particle. It has left the
661  // domain due to an integration error or an open boundary.
662  continue;
663  }
664  }
665 
666  // If we are here, we found a cell and reference position for this
667  // particle
668  (*it)->set_reference_location(current_reference_position);
669 
670  // Reinsert the particle into our domain if we own its cell.
671  // Mark it for MPI transfer otherwise
672  if (current_cell->is_locally_owned())
673  {
674  sorted_particles.push_back(
675  std::make_pair(internal::LevelInd(current_cell->level(),
676  current_cell->index()),
677  (*it)->particle->second));
678  }
679  else
680  {
681  moved_particles[current_cell->subdomain_id()].push_back(*it);
682  moved_cells[current_cell->subdomain_id()].push_back(current_cell);
683  }
684  }
685  }
686 
687  // Sort the updated particles. This pre-sort speeds up inserting
688  // them into particles to O(N) complexity.
689  std::multimap<internal::LevelInd, Particle<dim, spacedim>>
690  sorted_particles_map;
691 
692  // Exchange particles between processors if we have more than one process
693 # ifdef DEAL_II_WITH_MPI
695  triangulation->get_communicator()) > 1)
696  send_recv_particles(moved_particles, sorted_particles_map, moved_cells);
697 # endif
698 
699  sorted_particles_map.insert(sorted_particles.begin(),
700  sorted_particles.end());
701 
702  for (unsigned int i = 0; i < particles_out_of_cell.size(); ++i)
703  remove_particle(particles_out_of_cell[i]);
704 
705  particles.insert(sorted_particles_map.begin(), sorted_particles_map.end());
707  }
708 
709 
710 
711  template <int dim, int spacedim>
712  void
714  {
715  // Nothing to do in serial computations
717  triangulation->get_communicator()) == 1)
718  return;
719 
720 # ifdef DEAL_II_WITH_MPI
721  // First clear the current ghost_particle information
722  ghost_particles.clear();
723 
724  std::map<types::subdomain_id, std::vector<particle_iterator>>
725  ghost_particles_by_domain;
726 
727  const std::set<types::subdomain_id> ghost_owners =
728  triangulation->ghost_owners();
729  for (auto ghost_domain_id = ghost_owners.begin();
730  ghost_domain_id != ghost_owners.end();
731  ++ghost_domain_id)
732  ghost_particles_by_domain[*ghost_domain_id].reserve(
733  static_cast<typename std::vector<particle_iterator>::size_type>(
734  particles.size() * 0.25));
735 
736  std::vector<std::set<unsigned int>> vertex_to_neighbor_subdomain(
737  triangulation->n_vertices());
738 
740  cell = triangulation->begin_active(),
741  endc = triangulation->end();
742  for (; cell != endc; ++cell)
743  {
744  if (cell->is_ghost())
745  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell;
746  ++v)
747  vertex_to_neighbor_subdomain[cell->vertex_index(v)].insert(
748  cell->subdomain_id());
749  }
750 
751  cell = triangulation->begin_active();
752  for (; cell != endc; ++cell)
753  {
754  if (!cell->is_ghost())
755  {
756  std::set<unsigned int> cell_to_neighbor_subdomain;
757  for (unsigned int v = 0; v < GeometryInfo<dim>::vertices_per_cell;
758  ++v)
759  {
760  cell_to_neighbor_subdomain.insert(
761  vertex_to_neighbor_subdomain[cell->vertex_index(v)].begin(),
762  vertex_to_neighbor_subdomain[cell->vertex_index(v)].end());
763  }
764 
765  if (cell_to_neighbor_subdomain.size() > 0)
766  {
767  const particle_iterator_range particle_range =
768  particles_in_cell(cell);
769 
770  for (std::set<types::subdomain_id>::const_iterator domain =
771  cell_to_neighbor_subdomain.begin();
772  domain != cell_to_neighbor_subdomain.end();
773  ++domain)
774  {
775  for (typename particle_iterator_range::iterator particle =
776  particle_range.begin();
777  particle != particle_range.end();
778  ++particle)
779  ghost_particles_by_domain[*domain].push_back(particle);
780  }
781  }
782  }
783  }
784 
785  send_recv_particles(ghost_particles_by_domain, ghost_particles);
786 # endif
787  }
788 
789 
790 
791 # ifdef DEAL_II_WITH_MPI
792  template <int dim, int spacedim>
793  void
795  const std::map<types::subdomain_id, std::vector<particle_iterator>>
796  &particles_to_send,
797  std::multimap<internal::LevelInd, Particle<dim, spacedim>>
798  &received_particles,
799  const std::map<
802  &send_cells)
803  {
804  // Determine the communication pattern
805  const std::set<types::subdomain_id> ghost_owners =
806  triangulation->ghost_owners();
807  const std::vector<types::subdomain_id> neighbors(ghost_owners.begin(),
808  ghost_owners.end());
809  const unsigned int n_neighbors = neighbors.size();
810 
811  if (send_cells.size() != 0)
812  Assert(particles_to_send.size() == send_cells.size(), ExcInternalError());
813 
814  // If we do not know the subdomain this particle needs to be send to, throw
815  // an error
816  Assert(particles_to_send.find(numbers::artificial_subdomain_id) ==
817  particles_to_send.end(),
818  ExcInternalError());
819 
820  // TODO: Implement the shipping of particles to processes that are not ghost
821  // owners of the local domain
822  for (auto send_particles = particles_to_send.begin();
823  send_particles != particles_to_send.end();
824  ++send_particles)
825  Assert(ghost_owners.find(send_particles->first) != ghost_owners.end(),
827 
828  unsigned int n_send_particles = 0;
829  for (auto send_particles = particles_to_send.begin();
830  send_particles != particles_to_send.end();
831  ++send_particles)
832  n_send_particles += send_particles->second.size();
833 
834  const unsigned int cellid_size = sizeof(CellId::binary_type);
835 
836  // Containers for the amount and offsets of data we will send
837  // to other processors and the data itself.
838  std::vector<unsigned int> n_send_data(n_neighbors, 0);
839  std::vector<unsigned int> send_offsets(n_neighbors, 0);
840  std::vector<char> send_data;
841 
842  // Only serialize things if there are particles to be send.
843  // We can not return early even if no particles
844  // are send, because we might receive particles from other processes
845  if (n_send_particles > 0)
846  {
847  // Allocate space for sending particle data
848  const unsigned int particle_size =
849  begin()->serialized_size_in_bytes() + cellid_size +
850  (size_callback ? size_callback() : 0);
851  send_data.resize(n_send_particles * particle_size);
852  void *data = static_cast<void *>(&send_data.front());
853 
854  // Serialize the data sorted by receiving process
855  for (unsigned int i = 0; i < n_neighbors; ++i)
856  {
857  send_offsets[i] = reinterpret_cast<std::size_t>(data) -
858  reinterpret_cast<std::size_t>(&send_data.front());
859 
860  for (unsigned int j = 0;
861  j < particles_to_send.at(neighbors[i]).size();
862  ++j)
863  {
864  // If no target cells are given, use the iterator information
866  cell;
867  if (send_cells.size() == 0)
868  cell =
869  particles_to_send.at(neighbors[i])[j]->get_surrounding_cell(
870  *triangulation);
871  else
872  cell = send_cells.at(neighbors[i])[j];
873 
874  const CellId::binary_type cellid =
875  cell->id().template to_binary<dim>();
876  memcpy(data, &cellid, cellid_size);
877  data = static_cast<char *>(data) + cellid_size;
878 
879  particles_to_send.at(neighbors[i])[j]->write_data(data);
880  if (store_callback)
881  data =
882  store_callback(particles_to_send.at(neighbors[i])[j], data);
883  }
884  n_send_data[i] = reinterpret_cast<std::size_t>(data) -
885  send_offsets[i] -
886  reinterpret_cast<std::size_t>(&send_data.front());
887  }
888  }
889 
890  // Containers for the data we will receive from other processors
891  std::vector<unsigned int> n_recv_data(n_neighbors);
892  std::vector<unsigned int> recv_offsets(n_neighbors);
893 
894  // Notify other processors how many particles we will send
895  {
896  std::vector<MPI_Request> n_requests(2 * n_neighbors);
897  for (unsigned int i = 0; i < n_neighbors; ++i)
898  {
899  const int ierr = MPI_Irecv(&(n_recv_data[i]),
900  1,
901  MPI_INT,
902  neighbors[i],
903  0,
904  triangulation->get_communicator(),
905  &(n_requests[2 * i]));
906  AssertThrowMPI(ierr);
907  }
908  for (unsigned int i = 0; i < n_neighbors; ++i)
909  {
910  const int ierr = MPI_Isend(&(n_send_data[i]),
911  1,
912  MPI_INT,
913  neighbors[i],
914  0,
915  triangulation->get_communicator(),
916  &(n_requests[2 * i + 1]));
917  AssertThrowMPI(ierr);
918  }
919  const int ierr =
920  MPI_Waitall(2 * n_neighbors, &n_requests[0], MPI_STATUSES_IGNORE);
921  AssertThrowMPI(ierr);
922  }
923 
924  // Determine how many particles and data we will receive
925  unsigned int total_recv_data = 0;
926  for (unsigned int neighbor_id = 0; neighbor_id < n_neighbors; ++neighbor_id)
927  {
928  recv_offsets[neighbor_id] = total_recv_data;
929  total_recv_data += n_recv_data[neighbor_id];
930  }
931 
932  // Set up the space for the received particle data
933  std::vector<char> recv_data(total_recv_data);
934 
935  // Exchange the particle data between domains
936  {
937  std::vector<MPI_Request> requests(2 * n_neighbors);
938  unsigned int send_ops = 0;
939  unsigned int recv_ops = 0;
940 
941  for (unsigned int i = 0; i < n_neighbors; ++i)
942  if (n_recv_data[i] > 0)
943  {
944  const int ierr = MPI_Irecv(&(recv_data[recv_offsets[i]]),
945  n_recv_data[i],
946  MPI_CHAR,
947  neighbors[i],
948  1,
949  triangulation->get_communicator(),
950  &(requests[send_ops]));
951  AssertThrowMPI(ierr);
952  send_ops++;
953  }
954 
955  for (unsigned int i = 0; i < n_neighbors; ++i)
956  if (n_send_data[i] > 0)
957  {
958  const int ierr = MPI_Isend(&(send_data[send_offsets[i]]),
959  n_send_data[i],
960  MPI_CHAR,
961  neighbors[i],
962  1,
963  triangulation->get_communicator(),
964  &(requests[send_ops + recv_ops]));
965  AssertThrowMPI(ierr);
966  recv_ops++;
967  }
968  const int ierr =
969  MPI_Waitall(send_ops + recv_ops, &requests[0], MPI_STATUSES_IGNORE);
970  AssertThrowMPI(ierr);
971  }
972 
973  // Put the received particles into the domain if they are in the
974  // triangulation
975  const void *recv_data_it = static_cast<const void *>(recv_data.data());
976 
977  while (reinterpret_cast<std::size_t>(recv_data_it) -
978  reinterpret_cast<std::size_t>(recv_data.data()) <
979  total_recv_data)
980  {
981  CellId::binary_type binary_cellid;
982  memcpy(&binary_cellid, recv_data_it, cellid_size);
983  const CellId id(binary_cellid);
984  recv_data_it = static_cast<const char *>(recv_data_it) + cellid_size;
985 
987  id.to_cell(*triangulation);
988 
989  typename std::multimap<internal::LevelInd,
990  Particle<dim, spacedim>>::iterator
991  recv_particle = received_particles.insert(std::make_pair(
992  internal::LevelInd(cell->level(), cell->index()),
993  Particle<dim, spacedim>(recv_data_it, property_pool.get())));
994 
995  if (load_callback)
996  recv_data_it =
997  load_callback(particle_iterator(received_particles, recv_particle),
998  recv_data_it);
999  }
1000 
1001  AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
1002  ExcMessage(
1003  "The amount of data that was read into new particles "
1004  "does not match the amount of data sent around."));
1005  }
1006 # endif
1007 
1008 
1009 
1010  template <int dim, int spacedim>
1011  void
1013  const std::function<std::size_t()> & size_callb,
1014  const std::function<void *(const particle_iterator &, void *)> &store_callb,
1015  const std::function<const void *(const particle_iterator &, const void *)>
1016  &load_callb)
1017  {
1018  size_callback = size_callb;
1019  store_callback = store_callb;
1020  load_callback = load_callb;
1021  }
1022 
1023 
1024 
1025  template <int dim, int spacedim>
1026  void
1028  {
1030  *non_const_triangulation =
1032  &(*triangulation));
1033 
1034  // Only save and load particles if there are any, we might get here for
1035  // example if somebody created a ParticleHandler but generated 0 particles.
1037 
1039  {
1040  const std::function<std::vector<char>(
1043  callback_function =
1045  std::cref(*this),
1046  std::placeholders::_1,
1047  std::placeholders::_2);
1048 
1049  handle = non_const_triangulation->register_data_attach(
1050  callback_function, /*returns_variable_size_data=*/false);
1051  }
1052  }
1053 
1054 
1055 
1056  template <int dim, int spacedim>
1057  void
1059  const bool serialization)
1060  {
1061  // All particles have been stored, when we reach this point. Empty the
1062  // particle data.
1063  clear_particles();
1064 
1066  *non_const_triangulation =
1068  &(*triangulation));
1069 
1070  // If we are resuming from a checkpoint, we first have to register the
1071  // store function again, to set the triangulation in the same state as
1072  // before the serialization. Only by this it knows how to deserialize the
1073  // data correctly. Only do this if something was actually stored.
1074  if (serialization && (global_max_particles_per_cell > 0))
1075  {
1076  const std::function<std::vector<char>(
1079  callback_function =
1081  std::cref(*this),
1082  std::placeholders::_1,
1083  std::placeholders::_2);
1084 
1085  handle = non_const_triangulation->register_data_attach(
1086  callback_function, /*returns_variable_size_data=*/false);
1087  }
1088 
1089  // Check if something was stored and load it
1091  {
1092  const std::function<void(
1095  const boost::iterator_range<std::vector<char>::const_iterator> &)>
1096  callback_function =
1098  std::ref(*this),
1099  std::placeholders::_1,
1100  std::placeholders::_2,
1101  std::placeholders::_3);
1102 
1103  non_const_triangulation->notify_ready_to_unpack(handle,
1104  callback_function);
1105 
1106  // Reset handle and update global number of particles. The number
1107  // can change because of discarded or newly generated particles
1110  }
1111  }
1112 
1113 
1114 
1115  template <int dim, int spacedim>
1116  std::vector<char>
1118  const typename Triangulation<dim, spacedim>::cell_iterator &cell,
1119  const typename Triangulation<dim, spacedim>::CellStatus status) const
1120  {
1121  // -------------------
1122  // HOTFIX: resize memory and static_cast std::vector to void*
1123  // TODO: Apply ParticleHandler to variable size transfer
1124 
1125  // ----- Copied from the old register_store_callback_function -----
1126  // Compute the size per serialized particle. This is simple if we own
1127  // particles, simply ask one of them. Otherwise create a temporary
1128  // particle, ask it for its size and add the size of its properties.
1129  const std::size_t size_per_particle =
1130  (particles.size() > 0) ?
1131  begin()->serialized_size_in_bytes() :
1132  Particle<dim, spacedim>().serialized_size_in_bytes() +
1133  property_pool->n_properties_per_slot() * sizeof(double);
1134 
1135  // We need to transfer the number of particles for this cell and
1136  // the particle data itself. If we are in the process of refinement
1137  // (i.e. not in serialization) we need to provide 2^dim times the
1138  // space for the data in case a cell is coarsened and all particles
1139  // of the children have to be stored in the parent cell.
1140  // (Note: In this hotfix we always reserve sufficient memory)
1141  const bool serialization = false;
1142  const std::size_t transfer_size_per_cell =
1143  sizeof(unsigned int) +
1144  (size_per_particle * global_max_particles_per_cell) *
1145  (serialization ? 1 : std::pow(2, dim));
1146 
1147  std::vector<char> data_vector(transfer_size_per_cell);
1148  void * data = static_cast<void *>(data_vector.data());
1149  // --------------------
1150 
1151  unsigned int n_particles(0);
1152 
1153  // If the cell persist or is refined store all particles of the current
1154  // cell.
1155  if (status ==
1157  status ==
1159  {
1160  const boost::iterator_range<particle_iterator> particle_range =
1161  particles_in_cell(cell);
1162  n_particles =
1163  std::distance(particle_range.begin(), particle_range.end());
1164 
1165  unsigned int *ndata = static_cast<unsigned int *>(data);
1166  *ndata = n_particles;
1167  data = static_cast<void *>(ndata + 1);
1168 
1169  for (particle_iterator particle = particle_range.begin();
1170  particle != particle_range.end();
1171  ++particle)
1172  {
1173  particle->write_data(data);
1174  }
1175  }
1176  // If this cell is the parent of children that will be coarsened, collect
1177  // the particles of all children.
1178  else if (status ==
1180  {
1181  for (unsigned int child_index = 0;
1182  child_index < GeometryInfo<dim>::max_children_per_cell;
1183  ++child_index)
1184  {
1185  const typename Triangulation<dim, spacedim>::cell_iterator child =
1186  cell->child(child_index);
1187  n_particles += n_particles_in_cell(child);
1188  }
1189 
1190  unsigned int *ndata = static_cast<unsigned int *>(data);
1191  *ndata = n_particles;
1192 
1193  data = static_cast<void *>(ndata + 1);
1194 
1195  for (unsigned int child_index = 0;
1196  child_index < GeometryInfo<dim>::max_children_per_cell;
1197  ++child_index)
1198  {
1199  const typename Triangulation<dim, spacedim>::cell_iterator child =
1200  cell->child(child_index);
1201  const boost::iterator_range<particle_iterator> particle_range =
1202  particles_in_cell(child);
1203 
1204  for (particle_iterator particle = particle_range.begin();
1205  particle != particle_range.end();
1206  ++particle)
1207  {
1208  particle->write_data(data);
1209  }
1210  }
1211  }
1212  else
1213  Assert(false, ExcInternalError());
1214 
1215  return data_vector;
1216  }
1217 
1218  template <int dim, int spacedim>
1219  void
1221  const typename Triangulation<dim, spacedim>::cell_iterator & cell,
1222  const typename Triangulation<dim, spacedim>::CellStatus status,
1223  const boost::iterator_range<std::vector<char>::const_iterator> &data_range)
1224  {
1225  // -------------------
1226  // HOTFIX: static_cast std::vector to void*
1227  // TODO: Apply ParticleHandler to variable size transfer
1228  // const void *data = static_cast<const void *>(data_vector.data());
1229  const void *data = static_cast<const void *>(&*(data_range.begin()));
1230  // -------------------
1231 
1232  const unsigned int *n_particles_in_cell_ptr =
1233  static_cast<const unsigned int *>(data);
1234  const void *pdata =
1235  reinterpret_cast<const void *>(n_particles_in_cell_ptr + 1);
1236 
1237  if (*n_particles_in_cell_ptr == 0)
1238  return;
1239 
1240  // Load all particles from the data stream and store them in the local
1241  // particle map.
1242  if (status ==
1244  {
1245  typename std::multimap<internal::LevelInd,
1246  Particle<dim, spacedim>>::iterator
1247  position_hint = particles.end();
1248  for (unsigned int i = 0; i < *n_particles_in_cell_ptr; ++i)
1249  {
1250  // Use std::multimap::emplace_hint to speed up insertion of
1251  // particles. This is a C++11 function, but not all compilers
1252  // that report a -std=c++11 (like gcc 4.6) implement it, so
1253  // require C++14 instead.
1254 # ifdef DEAL_II_WITH_CXX14
1255  position_hint = particles.emplace_hint(
1256  position_hint,
1257  std::make_pair(cell->level(), cell->index()),
1258  Particle<dim, spacedim>(pdata, property_pool.get()));
1259 # else
1260  position_hint = particles.insert(
1261  position_hint,
1262  std::make_pair(std::make_pair(cell->level(), cell->index()),
1264  property_pool.get())));
1265 # endif
1266  ++position_hint;
1267  }
1268  }
1269 
1270  else if (status ==
1272  {
1273  typename std::multimap<internal::LevelInd,
1274  Particle<dim, spacedim>>::iterator
1275  position_hint = particles.end();
1276  for (unsigned int i = 0; i < *n_particles_in_cell_ptr; ++i)
1277  {
1278  // Use std::multimap::emplace_hint to speed up insertion of
1279  // particles. This is a C++11 function, but not all compilers
1280  // that report a -std=c++11 (like gcc 4.6) implement it, so
1281  // require C++14 instead.
1282 # ifdef DEAL_II_WITH_CXX14
1283  position_hint = particles.emplace_hint(
1284  position_hint,
1285  std::make_pair(cell->level(), cell->index()),
1286  Particle<dim, spacedim>(pdata, property_pool.get()));
1287 # else
1288  position_hint = particles.insert(
1289  position_hint,
1290  std::make_pair(std::make_pair(cell->level(), cell->index()),
1292  property_pool.get())));
1293 # endif
1294  const Point<dim> p_unit = mapping->transform_real_to_unit_cell(
1295  cell, position_hint->second.get_location());
1296  position_hint->second.set_reference_location(p_unit);
1297  ++position_hint;
1298  }
1299  }
1300  else if (status ==
1302  {
1303  std::vector<typename std::multimap<internal::LevelInd,
1304  Particle<dim, spacedim>>::iterator>
1306  for (unsigned int child_index = 0;
1307  child_index < GeometryInfo<dim>::max_children_per_cell;
1308  ++child_index)
1309  {
1310  const typename Triangulation<dim, spacedim>::cell_iterator child =
1311  cell->child(child_index);
1312  position_hints[child_index] = particles.upper_bound(
1313  std::make_pair(child->level(), child->index()));
1314  }
1315 
1316  for (unsigned int i = 0; i < *n_particles_in_cell_ptr; ++i)
1317  {
1318  Particle<dim, spacedim> p(pdata, property_pool.get());
1319 
1320  for (unsigned int child_index = 0;
1321  child_index < GeometryInfo<dim>::max_children_per_cell;
1322  ++child_index)
1323  {
1325  child = cell->child(child_index);
1326 
1327  try
1328  {
1329  const Point<dim> p_unit =
1330  mapping->transform_real_to_unit_cell(child,
1331  p.get_location());
1333  {
1334  p.set_reference_location(p_unit);
1335  // Use std::multimap::emplace_hint to speed up insertion
1336  // of particles. This is a C++11 function, but not all
1337  // compilers that report a -std=c++11 (like gcc 4.6)
1338  // implement it, so require C++14 instead.
1339 # ifdef DEAL_II_WITH_CXX14
1340  position_hints[child_index] =
1341  particles.emplace_hint(position_hints[child_index],
1342  std::make_pair(child->level(),
1343  child->index()),
1344  std::move(p));
1345 # else
1346  position_hints[child_index] = particles.insert(
1347  position_hints[child_index],
1348  std::make_pair(
1349  std::make_pair(child->level(), child->index()), p));
1350 # endif
1351  ++position_hints[child_index];
1352  break;
1353  }
1354  }
1355  catch (typename Mapping<dim>::ExcTransformationFailed &)
1356  {}
1357  }
1358  }
1359  }
1360  }
1361 } // namespace Particles
1362 
1363 #endif
1364 
1365 DEAL_II_NAMESPACE_CLOSE
1366 
1367 DEAL_II_NAMESPACE_OPEN
1368 
1369 #ifdef DEAL_II_WITH_P4EST
1370 # include "particle_handler.inst"
1371 #endif
1372 
1373 DEAL_II_NAMESPACE_CLOSE
std::multimap< internal::LevelInd, Particle< dim, spacedim > > ghost_particles
unsigned int register_data_attach(const std::function< std::vector< char >(const cell_iterator &, const CellStatus)> &pack_callback, const bool returns_variable_size_data)
Definition: tria.cc:4342
static const unsigned int invalid_unsigned_int
Definition: types.h:173
types::particle_index n_global_max_particles_per_cell() const
void remove_particle(const particle_iterator &particle)
void initialize(const parallel::distributed::Triangulation< dim, spacedim > &tria, const Mapping< dim, spacedim > &mapping, const unsigned int n_properties=0)
particle_iterator begin_ghost() const
std::function< const void *(const particle_iterator &, const void *)> load_callback
particle_iterator insert_particle(const Particle< dim, spacedim > &particle, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell)
unsigned long long int particle_index
Definition: particle.h:43
std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > > vertex_to_cell_map(const Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:1919
types::particle_index next_free_particle_index
SmartPointer< const parallel::distributed::Triangulation< dim, spacedim >, ParticleHandler< dim, spacedim > > triangulation
const ArrayView< double > get_properties()
Definition: particle.cc:325
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1301
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
unsigned int global_max_particles_per_cell
std::array< unsigned int, 4 > binary_type
Definition: cell_id.h:73
void register_load_callback_function(const bool serialization)
static::ExceptionBase & ExcMessage(std::string arg1)
unsigned int subdomain_id
Definition: types.h:43
void insert_particles(const std::multimap< typename Triangulation< dim, spacedim >::active_cell_iterator, Particle< dim, spacedim >> &particles)
particle_iterator end_ghost() const
types::particle_index global_number_of_particles
#define Assert(cond, exc)
Definition: exceptions.h:1227
particle_iterator_range particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell)
std::function< std::size_t()> size_callback
Abstract base class for mapping classes.
Definition: dof_tools.h:57
particle_iterator begin() 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)
Definition: tria.cc:4372
particle_iterator end() const
PropertyPool & get_property_pool() const
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:69
Definition: cell_id.h:63
std::vector< std::vector< Tensor< 1, spacedim > > > vertex_to_cell_centers_directions(const Triangulation< dim, spacedim > &mesh, const std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator >> &vertex_to_cells)
Definition: grid_tools.cc:1436
std::unique_ptr< PropertyPool > property_pool
const types::subdomain_id artificial_subdomain_id
Definition: types.h:272
boost::iterator_range< particle_iterator > particle_iterator_range
ParticleIterator< dim, spacedim > particle_iterator
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1443
std::multimap< internal::LevelInd, Particle< dim, spacedim > > particles
std::function< void *(const particle_iterator &, void *)> store_callback
unsigned int n_properties_per_particle() const
types::particle_index n_locally_owned_particles() const
static::ExceptionBase & ExcNotImplemented()
return_type compute_point_locations(const Cache< dim, spacedim > &cache, const std::vector< Point< spacedim >> &points, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell_hint=typename Triangulation< dim, spacedim >::active_cell_iterator())
Definition: grid_tools.cc:3999
types::particle_index n_global_particles() const
std::vector< char > store_particles(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const typename Triangulation< dim, spacedim >::CellStatus status) const
SmartPointer< const Mapping< dim, spacedim >, ParticleHandler< dim, spacedim > > mapping
types::particle_index get_next_free_particle_index() const
unsigned int n_particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell) 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 >>())
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)
bool has_properties() const
Definition: particle.cc:336
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)
static::ExceptionBase & ExcInternalError()