Reference documentation for deal.II version 9.0.0
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 at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/particles/particle_handler.h>
17 
18 #include <deal.II/base/std_cxx14/memory.h>
19 #include <deal.II/grid/grid_tools.h>
20 #include <deal.II/grid/grid_tools_cache.h>
21 
22 #include <utility>
23 
24 DEAL_II_NAMESPACE_OPEN
25 
26 #ifdef DEAL_II_WITH_P4EST
27 
28 namespace Particles
29 {
30  template <int dim,int spacedim>
32  :
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  data_offset(numbers::invalid_unsigned_int)
44  {}
45 
46 
47 
48  template <int dim,int spacedim>
50  const Mapping<dim,spacedim> &mapping,
51  const unsigned int n_properties)
52  :
53  triangulation(&triangulation, typeid(*this).name()),
54  mapping(&mapping, typeid(*this).name()),
55  particles(),
56  ghost_particles(),
57  global_number_of_particles(0),
58  global_max_particles_per_cell(0),
59  next_free_particle_index(0),
60  property_pool(new PropertyPool(n_properties)),
61  size_callback(),
62  store_callback(),
63  load_callback(),
64  data_offset(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
78  const Mapping<dim,spacedim> &mapp,
79  const unsigned int n_properties)
80  {
81  triangulation = &tria;
82  mapping = &mapp;
83 
84  // Create the memory pool that will store all particle properties
85  property_pool = std_cxx14::make_unique<PropertyPool>(n_properties);
86  }
87 
88 
89 
90  template <int dim,int spacedim>
91  void
93  {
94  clear_particles();
95  global_number_of_particles = 0;
96  next_free_particle_index = 0;
97  global_max_particles_per_cell = 0;
98  }
99 
100 
101 
102  template <int dim,int spacedim>
103  void
105  {
106  particles.clear();
107  }
108 
109 
110 
111  template <int dim,int spacedim>
112  void
114  {
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;
119  typename Triangulation<dim,spacedim>::active_cell_iterator current_cell = triangulation->begin_active();
120 
121  for (particle_iterator particle = begin(); particle != end(); ++particle)
122  {
123  locally_highest_index = std::max(locally_highest_index,particle->get_id());
124 
125  if (particle->get_surrounding_cell(*triangulation) != current_cell)
126  {
127  current_particles_per_cell = 0;
128  current_cell = particle->get_surrounding_cell(*triangulation);
129  }
130 
131  ++current_particles_per_cell;
132  local_max_particles_per_cell = std::max(local_max_particles_per_cell,
133  current_particles_per_cell);
134  }
135 
136  global_number_of_particles = ::Utilities::MPI::sum (particles.size(), triangulation->get_communicator());
137  next_free_particle_index = ::Utilities::MPI::max (locally_highest_index, triangulation->get_communicator()) + 1;
138  global_max_particles_per_cell = ::Utilities::MPI::max(local_max_particles_per_cell,triangulation->get_communicator());
139  }
140 
141 
142 
143 
144  template <int dim,int spacedim>
147  {
148  return (const_cast<ParticleHandler<dim,spacedim> *> (this))->begin();
149  }
150 
151 
152 
153  template <int dim,int spacedim>
156  {
157  return particle_iterator(particles,particles.begin());
158  }
159 
160 
161 
162  template <int dim,int spacedim>
165  {
166  return (const_cast<ParticleHandler<dim,spacedim> *> (this))->end();
167  }
168 
169 
170 
171  template <int dim,int spacedim>
174  {
175  return particle_iterator(particles,particles.end());
176  }
177 
178 
179 
180  template <int dim,int spacedim>
183  {
184  return (const_cast<ParticleHandler<dim,spacedim> *> (this))->begin_ghost();
185  }
186 
187 
188 
189  template <int dim,int spacedim>
192  {
193  return particle_iterator(ghost_particles,ghost_particles.begin());
194  }
195 
196 
197 
198  template <int dim,int spacedim>
201  {
202  return (const_cast<ParticleHandler<dim,spacedim> *> (this))->end_ghost();
203  }
204 
205 
206 
207  template <int dim,int spacedim>
210  {
211  return particle_iterator(ghost_particles,ghost_particles.end());
212  }
213 
214 
215 
216  template <int dim,int spacedim>
219  {
220  return (const_cast<ParticleHandler<dim,spacedim> *> (this))->particles_in_cell(cell);
221  }
222 
223 
224 
225  template <int dim,int spacedim>
228  {
229  const internal::LevelInd level_index = std::make_pair<int, int> (cell->level(),cell->index());
230 
231  if (cell->is_ghost())
232  {
233  const auto particles_in_cell = ghost_particles.equal_range(level_index);
234  return boost::make_iterator_range(particle_iterator(ghost_particles,particles_in_cell.first),
235  particle_iterator(ghost_particles,particles_in_cell.second));
236  }
237 
238  const auto particles_in_cell = particles.equal_range(level_index);
239  return boost::make_iterator_range(particle_iterator(particles,particles_in_cell.first),
240  particle_iterator(particles,particles_in_cell.second));
241  }
242 
243 
244 
245  template <int dim,int spacedim>
246  void
248  {
249  particles.erase(particle->particle);
250  }
251 
252 
253 
254  template <int dim,int spacedim>
258  {
259  typename std::multimap<internal::LevelInd, Particle<dim,spacedim> >::iterator it =
260  particles.insert(std::make_pair(internal::LevelInd(cell->level(),cell->index()),particle));
261 
262  particle_iterator particle_it (particles,it);
263  particle_it->set_property_pool(*property_pool);
264 
265  if (particle.has_properties())
266  for (unsigned int n=0; n<particle.get_properties().size(); ++n)
267  particle_it->get_properties()[n] = particle.get_properties()[n];
268 
269  return particle_it;
270  }
271 
272 
273 
274  template <int dim,int spacedim>
275  void
277  Particle<dim,spacedim> > &new_particles)
278  {
279  for (auto particle = new_particles.begin(); particle != new_particles.end(); ++particle)
280  particles.insert(particles.end(),
281  std::make_pair(internal::LevelInd(particle->first->level(),particle->first->index()),
282  particle->second));
283 
284  update_cached_numbers();
285  }
286 
287 
288 
289  template <int dim,int spacedim>
290  void
292  {
293  update_cached_numbers();
294 
295  // Determine the starting particle index of this process, which
296  // is the highest currently existing particle index plus the sum
297  // of the number of newly generated particles of all
298  // processes with a lower rank if in a parallel computation.
299  const types::particle_index local_next_particle_index = get_next_free_particle_index();
300  types::particle_index local_start_index = 0;
301 
302 #ifdef DEAL_II_WITH_MPI
303  types::particle_index particles_to_add_locally = positions.size();
304  const int ierr = MPI_Scan(&particles_to_add_locally, &local_start_index, 1,
305  PARTICLE_INDEX_MPI_TYPE, MPI_SUM,
306  triangulation->get_communicator());
307  AssertThrowMPI(ierr);
308  local_start_index -= particles_to_add_locally;
309 #endif
310 
311  local_start_index += local_next_particle_index;
312 
313  GridTools::Cache<dim,spacedim> cache(*triangulation, *mapping);
314  auto point_locations = GridTools::compute_point_locations(cache, positions);
315 
316  auto &cells = std::get<0>(point_locations);
317  auto &local_positions = std::get<1>(point_locations);
318  auto &index_map = std::get<2>(point_locations);
319 
320  if (cells.size() == 0)
321  return;
322 
323  auto hint = particles.find(std::make_pair(cells[0]->level(),cells[0]->index()));
324  for (unsigned int i=0; i<cells.size(); ++i)
325  {
326  internal::LevelInd current_cell(cells[i]->level(),cells[i]->index());
327  for (unsigned int p=0; p<local_positions[i].size(); ++p)
328  {
329  hint = particles.insert(hint,
330  std::make_pair(current_cell,
331  Particle<dim,spacedim>(positions[index_map[i][p]],
332  local_positions[i][p],
333  local_start_index+index_map[i][p])));
334  }
335  }
336 
337  update_cached_numbers();
338  }
339 
340 
341 
342  template <int dim,int spacedim>
345  {
346  return global_number_of_particles;
347  }
348 
349 
350 
351  template <int dim,int spacedim>
354  {
355  return global_max_particles_per_cell;
356  }
357 
358 
359 
360  template <int dim,int spacedim>
363  {
364  return particles.size();
365  }
366 
367 
368 
369  template <int dim,int spacedim>
370  unsigned int
372  {
373  return property_pool->n_properties_per_slot();
374  }
375 
376 
377 
378  template <int dim,int spacedim>
379  unsigned int
381  {
382  const internal::LevelInd found_cell = std::make_pair<int, int> (cell->level(),cell->index());
383 
384  if (cell->is_locally_owned())
385  return particles.count(found_cell);
386  else if (cell->is_ghost())
387  return ghost_particles.count(found_cell);
388  else if (cell->is_artificial())
389  AssertThrow(false,ExcInternalError());
390 
391  return 0;
392  }
393 
394 
395 
396  template <int dim,int spacedim>
399  {
400  return next_free_particle_index;
401  }
402 
403 
404 
405  template <int dim, int spacedim>
406  PropertyPool &
408  {
409  return *property_pool;
410  }
411 
412 
413 
414  namespace
415  {
425  template <int dim>
426  bool
427  compare_particle_association(const unsigned int a,
428  const unsigned int b,
429  const Tensor<1,dim> &particle_direction,
430  const std::vector<Tensor<1,dim> > &center_directions)
431  {
432  const double scalar_product_a = center_directions[a] * particle_direction;
433  const double scalar_product_b = center_directions[b] * particle_direction;
434 
435  // The function is supposed to return if a is before b. We are looking
436  // for the alignment of particle direction and center direction,
437  // therefore return if the scalar product of a is larger.
438  return (scalar_product_a > scalar_product_b);
439  }
440  }
441 
442 
443 
444  template <int dim, int spacedim>
445  void
447  {
448  // TODO: The current algorithm only works for particles that are in
449  // the local domain or in ghost cells, because it only knows the
450  // subdomain_id of ghost cells, but not of artificial cells. This
451  // can be extended using the distributed version of compute point
452  // locations.
453  // TODO: Extend this function to allow keeping particles on other
454  // processes around (with an invalid cell).
455 
456  std::vector<particle_iterator> particles_out_of_cell;
457  particles_out_of_cell.reserve(n_locally_owned_particles());
458 
459  // Now update the reference locations of the moved particles
460  for (particle_iterator it=begin(); it!=end(); ++it)
461  {
462  const typename Triangulation<dim,spacedim>::cell_iterator cell = it->get_surrounding_cell(*triangulation);
463 
464  try
465  {
466  const Point<dim> p_unit = mapping->transform_real_to_unit_cell(cell, it->get_location());
468  {
469  it->set_reference_location(p_unit);
470  }
471  else
472  {
473  // The particle has left the cell
474  particles_out_of_cell.push_back(it);
475  }
476  }
477  catch (typename Mapping<dim>::ExcTransformationFailed &)
478  {
479  // The particle has left the cell
480  particles_out_of_cell.push_back(it);
481  }
482  }
483 
484  // There are three reasons why a particle is not in its old cell:
485  // It moved to another cell, to another subdomain or it left the mesh.
486  // Particles that moved to another cell are updated and stored inside the
487  // sorted_particles vector, particles that moved to another domain are
488  // collected in the moved_particles_domain vector. Particles that left
489  // the mesh completely are ignored and removed.
490  std::vector<std::pair<internal::LevelInd, Particle<dim,spacedim> > > sorted_particles;
491  std::map<types::subdomain_id, std::vector<particle_iterator> > moved_particles;
492  std::map<types::subdomain_id, std::vector<typename Triangulation<dim,spacedim>::active_cell_iterator> > moved_cells;
493 
494  // We do not know exactly how many particles are lost, exchanged between
495  // domains, or remain on this process. Therefore we pre-allocate approximate
496  // sizes for these vectors. If more space is needed an automatic and
497  // relatively fast (compared to other parts of this algorithm)
498  // re-allocation will happen.
499  typedef typename std::vector<particle_iterator>::size_type vector_size;
500  sorted_particles.reserve(static_cast<vector_size> (particles_out_of_cell.size()*1.25));
501 
502  const std::set<types::subdomain_id> ghost_owners = triangulation->ghost_owners();
503 
504  for (auto ghost_domain_id = ghost_owners.begin(); ghost_domain_id != ghost_owners.end(); ++ghost_domain_id)
505  moved_particles[*ghost_domain_id].reserve(static_cast<vector_size> (particles_out_of_cell.size()*0.25));
506  for (auto ghost_domain_id = ghost_owners.begin(); ghost_domain_id != ghost_owners.end(); ++ghost_domain_id)
507  moved_cells[*ghost_domain_id].reserve(static_cast<vector_size> (particles_out_of_cell.size()*0.25));
508 
509  {
510  // Create a map from vertices to adjacent cells
511  const std::vector<std::set<typename Triangulation<dim,spacedim>::active_cell_iterator> >
512  vertex_to_cells(GridTools::vertex_to_cell_map(*triangulation));
513 
514  // Create a corresponding map of vectors from vertex to cell center
515  const std::vector<std::vector<Tensor<1,spacedim> > >
516  vertex_to_cell_centers(GridTools::vertex_to_cell_centers_directions(*triangulation,vertex_to_cells));
517 
518  std::vector<unsigned int> neighbor_permutation;
519 
520  // Find the cells that the particles moved to.
521  typename std::vector<particle_iterator>::iterator it = particles_out_of_cell.begin(),
522  end_particle = particles_out_of_cell.end();
523 
524  for (; it!=end_particle; ++it)
525  {
526  // The cell the particle is in
527  Point<dim> current_reference_position;
528  bool found_cell = false;
529 
530  // Check if the particle is in one of the old cell's neighbors
531  // that are adjacent to the closest vertex
532  typename Triangulation<dim,spacedim>::active_cell_iterator current_cell = (*it)->get_surrounding_cell(*triangulation);
533 
534  const unsigned int closest_vertex = GridTools::find_closest_vertex_of_cell<dim,spacedim>(current_cell,(*it)->get_location());
535  Tensor<1,spacedim> vertex_to_particle = (*it)->get_location() - current_cell->vertex(closest_vertex);
536  vertex_to_particle /= vertex_to_particle.norm();
537 
538  const unsigned int closest_vertex_index = current_cell->vertex_index(closest_vertex);
539  const unsigned int n_neighbor_cells = vertex_to_cells[closest_vertex_index].size();
540 
541  neighbor_permutation.resize(n_neighbor_cells);
542  for (unsigned int i=0; i<n_neighbor_cells; ++i)
543  neighbor_permutation[i] = i;
544 
545  std::sort(neighbor_permutation.begin(),
546  neighbor_permutation.end(),
547  std::bind(&compare_particle_association<spacedim>,
548  std::placeholders::_1,
549  std::placeholders::_2,
550  std::cref(vertex_to_particle),
551  std::cref(vertex_to_cell_centers[closest_vertex_index])));
552 
553  // Search all of the cells adjacent to the closest vertex of the previous cell
554  // Most likely we will find the particle in them.
555  for (unsigned int i=0; i<n_neighbor_cells; ++i)
556  {
557  try
558  {
559  typename std::set<typename Triangulation<dim,spacedim>::active_cell_iterator>::const_iterator
560  cell = vertex_to_cells[closest_vertex_index].begin();
561 
562  std::advance(cell,neighbor_permutation[i]);
563  const Point<dim> p_unit = mapping->transform_real_to_unit_cell(*cell,
564  (*it)->get_location());
566  {
567  current_cell = *cell;
568  current_reference_position = p_unit;
569  found_cell = true;
570  break;
571  }
572  }
573  catch (typename Mapping<dim>::ExcTransformationFailed &)
574  {}
575  }
576 
577  if (!found_cell)
578  {
579  // The particle is not in a neighbor of the old cell.
580  // Look for the new cell in the whole local domain.
581  // This case is rare.
582  try
583  {
584  const std::pair<const typename Triangulation<dim,spacedim>::active_cell_iterator,
585  Point<dim> > current_cell_and_position =
586  GridTools::find_active_cell_around_point<> (*mapping,
587  *triangulation,
588  (*it)->get_location());
589  current_cell = current_cell_and_position.first;
590  current_reference_position = current_cell_and_position.second;
591  }
592  catch (GridTools::ExcPointNotFound<spacedim> &)
593  {
594  // We can find no cell for this particle. It has left the
595  // domain due to an integration error or an open boundary.
596  continue;
597  }
598  }
599 
600  // If we are here, we found a cell and reference position for this particle
601  (*it)->set_reference_location(current_reference_position);
602 
603  // Reinsert the particle into our domain if we own its cell.
604  // Mark it for MPI transfer otherwise
605  if (current_cell->is_locally_owned())
606  {
607  sorted_particles.push_back(std::make_pair(internal::LevelInd(current_cell->level(),current_cell->index()),
608  (*it)->particle->second));
609  }
610  else
611  {
612  moved_particles[current_cell->subdomain_id()].push_back(*it);
613  moved_cells[current_cell->subdomain_id()].push_back(current_cell);
614  }
615  }
616  }
617 
618  // Sort the updated particles. This pre-sort speeds up inserting
619  // them into particles to O(N) complexity.
620  std::multimap<internal::LevelInd,Particle <dim,spacedim> > sorted_particles_map;
621 
622  // Exchange particles between processors if we have more than one process
623 #ifdef DEAL_II_WITH_MPI
624  if (::Utilities::MPI::n_mpi_processes(triangulation->get_communicator()) > 1)
625  send_recv_particles(moved_particles,sorted_particles_map,moved_cells);
626 #endif
627 
628  sorted_particles_map.insert(sorted_particles.begin(),sorted_particles.end());
629 
630  for (unsigned int i=0; i<particles_out_of_cell.size(); ++i)
631  remove_particle(particles_out_of_cell[i]);
632 
633  particles.insert(sorted_particles_map.begin(),sorted_particles_map.end());
634  update_cached_numbers();
635  }
636 
637 
638 
639  template <int dim, int spacedim>
640  void
642  {
643  // Nothing to do in serial computations
644  if (::Utilities::MPI::n_mpi_processes(triangulation->get_communicator()) == 1)
645  return;
646 
647 #ifdef DEAL_II_WITH_MPI
648  // First clear the current ghost_particle information
649  ghost_particles.clear();
650 
651  std::map<types::subdomain_id, std::vector<particle_iterator> > ghost_particles_by_domain;
652 
653  const std::set<types::subdomain_id> ghost_owners = triangulation->ghost_owners();
654  for (auto ghost_domain_id = ghost_owners.begin(); ghost_domain_id != ghost_owners.end(); ++ghost_domain_id)
655  ghost_particles_by_domain[*ghost_domain_id].reserve(static_cast<typename std::vector<particle_iterator>::size_type> (particles.size()*0.25));
656 
657  std::vector<std::set<unsigned int> > vertex_to_neighbor_subdomain(triangulation->n_vertices());
658 
660  cell = triangulation->begin_active(),
661  endc = triangulation->end();
662  for (; cell != endc; ++cell)
663  {
664  if (cell->is_ghost())
665  for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v)
666  vertex_to_neighbor_subdomain[cell->vertex_index(v)].insert(cell->subdomain_id());
667  }
668 
669  cell = triangulation->begin_active();
670  for (; cell != endc; ++cell)
671  {
672  if (!cell->is_ghost())
673  {
674  std::set<unsigned int> cell_to_neighbor_subdomain;
675  for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v)
676  {
677  cell_to_neighbor_subdomain.insert(vertex_to_neighbor_subdomain[cell->vertex_index(v)].begin(),
678  vertex_to_neighbor_subdomain[cell->vertex_index(v)].end());
679  }
680 
681  if (cell_to_neighbor_subdomain.size() > 0)
682  {
683  const particle_iterator_range particle_range = particles_in_cell(cell);
684 
685  for (std::set<types::subdomain_id>::const_iterator domain=cell_to_neighbor_subdomain.begin();
686  domain != cell_to_neighbor_subdomain.end(); ++domain)
687  {
688  for (typename particle_iterator_range::iterator particle = particle_range.begin(); particle != particle_range.end(); ++particle)
689  ghost_particles_by_domain[*domain].push_back(particle);
690  }
691  }
692  }
693  }
694 
695  send_recv_particles(ghost_particles_by_domain,
696  ghost_particles);
697 #endif
698  }
699 
700 
701 
702 #ifdef DEAL_II_WITH_MPI
703  template <int dim, int spacedim>
704  void
705  ParticleHandler<dim,spacedim>::send_recv_particles(const std::map<types::subdomain_id, std::vector<particle_iterator> > &particles_to_send,
706  std::multimap<internal::LevelInd,Particle <dim,spacedim> > &received_particles,
707  const std::map<types::subdomain_id, std::vector<typename Triangulation<dim,spacedim>::active_cell_iterator> > &send_cells)
708  {
709  // Determine the communication pattern
710  const std::set<types::subdomain_id> ghost_owners = triangulation->ghost_owners();
711  const std::vector<types::subdomain_id> neighbors (ghost_owners.begin(),
712  ghost_owners.end());
713  const unsigned int n_neighbors = neighbors.size();
714 
715  if (send_cells.size() != 0)
716  Assert (particles_to_send.size() == send_cells.size(),ExcInternalError());
717 
718  // If we do not know the subdomain this particle needs to be send to, throw an error
719  Assert (particles_to_send.find(numbers::artificial_subdomain_id) == particles_to_send.end(),
720  ExcInternalError());
721 
722  // TODO: Implement the shipping of particles to processes that are not ghost owners of the local domain
723  for (auto send_particles = particles_to_send.begin(); send_particles != particles_to_send.end(); ++send_particles)
724  Assert(ghost_owners.find(send_particles->first) != ghost_owners.end(),
726 
727  unsigned int n_send_particles = 0;
728  for (auto send_particles = particles_to_send.begin(); send_particles != particles_to_send.end(); ++send_particles)
729  n_send_particles += send_particles->second.size();
730 
731  const unsigned int cellid_size = sizeof(CellId::binary_type);
732 
733  // Containers for the amount and offsets of data we will send
734  // to other processors and the data itself.
735  std::vector<unsigned int> n_send_data(n_neighbors,0);
736  std::vector<unsigned int> send_offsets(n_neighbors,0);
737  std::vector<char> send_data;
738 
739  // Only serialize things if there are particles to be send.
740  // We can not return early even if no particles
741  // are send, because we might receive particles from other processes
742  if (n_send_particles > 0)
743  {
744  // Allocate space for sending particle data
745  const unsigned int particle_size = begin()->serialized_size_in_bytes() + cellid_size + (size_callback ? size_callback() : 0);
746  send_data.resize(n_send_particles * particle_size);
747  void *data = static_cast<void *> (&send_data.front());
748 
749  // Serialize the data sorted by receiving process
750  for (unsigned int i = 0; i<n_neighbors; ++i)
751  {
752  send_offsets[i] = reinterpret_cast<std::size_t> (data) - reinterpret_cast<std::size_t> (&send_data.front());
753 
754  for (unsigned int j=0; j<particles_to_send.at(neighbors[i]).size(); ++j)
755  {
756  // If no target cells are given, use the iterator information
758  if (send_cells.size() == 0)
759  cell = particles_to_send.at(neighbors[i])[j]->get_surrounding_cell(*triangulation);
760  else
761  cell = send_cells.at(neighbors[i])[j];
762 
763  const CellId::binary_type cellid = cell->id().template to_binary<dim>();
764  memcpy(data, &cellid, cellid_size);
765  data = static_cast<char *>(data) + cellid_size;
766 
767  particles_to_send.at(neighbors[i])[j]->write_data(data);
768  if (store_callback)
769  data = store_callback(particles_to_send.at(neighbors[i])[j],data);
770  }
771  n_send_data[i] = reinterpret_cast<std::size_t> (data) - send_offsets[i] - reinterpret_cast<std::size_t> (&send_data.front());
772  }
773  }
774 
775  // Containers for the data we will receive from other processors
776  std::vector<unsigned int> n_recv_data(n_neighbors);
777  std::vector<unsigned int> recv_offsets(n_neighbors);
778 
779  // Notify other processors how many particles we will send
780  {
781  std::vector<MPI_Request> n_requests(2*n_neighbors);
782  for (unsigned int i=0; i<n_neighbors; ++i)
783  {
784  const int ierr = MPI_Irecv(&(n_recv_data[i]), 1, MPI_INT, neighbors[i],
785  0, triangulation->get_communicator(), &(n_requests[2*i]));
786  AssertThrowMPI(ierr);
787  }
788  for (unsigned int i=0; i<n_neighbors; ++i)
789  {
790  const int ierr = MPI_Isend(&(n_send_data[i]), 1, MPI_INT, neighbors[i],
791  0, triangulation->get_communicator(), &(n_requests[2*i+1]));
792  AssertThrowMPI(ierr);
793  }
794  const int ierr = MPI_Waitall(2*n_neighbors,&n_requests[0],MPI_STATUSES_IGNORE);
795  AssertThrowMPI(ierr);
796  }
797 
798  // Determine how many particles and data we will receive
799  unsigned int total_recv_data = 0;
800  for (unsigned int neighbor_id=0; neighbor_id<n_neighbors; ++neighbor_id)
801  {
802  recv_offsets[neighbor_id] = total_recv_data;
803  total_recv_data += n_recv_data[neighbor_id];
804  }
805 
806  // Set up the space for the received particle data
807  std::vector<char> recv_data(total_recv_data);
808 
809  // Exchange the particle data between domains
810  {
811  std::vector<MPI_Request> requests(2*n_neighbors);
812  unsigned int send_ops = 0;
813  unsigned int recv_ops = 0;
814 
815  for (unsigned int i=0; i<n_neighbors; ++i)
816  if (n_recv_data[i] > 0)
817  {
818  const int ierr = MPI_Irecv(&(recv_data[recv_offsets[i]]), n_recv_data[i], MPI_CHAR,
819  neighbors[i], 1, triangulation->get_communicator(),
820  &(requests[send_ops]));
821  AssertThrowMPI(ierr);
822  send_ops++;
823  }
824 
825  for (unsigned int i=0; i<n_neighbors; ++i)
826  if (n_send_data[i] > 0)
827  {
828  const int ierr = MPI_Isend(&(send_data[send_offsets[i]]), n_send_data[i], MPI_CHAR,
829  neighbors[i], 1, triangulation->get_communicator(),
830  &(requests[send_ops+recv_ops]));
831  AssertThrowMPI(ierr);
832  recv_ops++;
833  }
834  const int ierr = MPI_Waitall(send_ops+recv_ops,&requests[0],MPI_STATUSES_IGNORE);
835  AssertThrowMPI(ierr);
836  }
837 
838  // Put the received particles into the domain if they are in the triangulation
839  const void *recv_data_it = static_cast<const void *> (recv_data.data());
840 
841  while (reinterpret_cast<std::size_t> (recv_data_it) - reinterpret_cast<std::size_t> (recv_data.data()) < total_recv_data)
842  {
843  CellId::binary_type binary_cellid;
844  memcpy(&binary_cellid, recv_data_it, cellid_size);
845  const CellId id(binary_cellid);
846  recv_data_it = static_cast<const char *> (recv_data_it) + cellid_size;
847 
848  const typename Triangulation<dim,spacedim>::active_cell_iterator cell = id.to_cell(*triangulation);
849 
850  typename std::multimap<internal::LevelInd,Particle <dim,spacedim> >::iterator recv_particle =
851  received_particles.insert(std::make_pair(internal::LevelInd(cell->level(),cell->index()),
852  Particle<dim,spacedim>(recv_data_it,property_pool.get())));
853 
854  if (load_callback)
855  recv_data_it = load_callback(particle_iterator(received_particles,recv_particle),
856  recv_data_it);
857  }
858 
859  AssertThrow(recv_data_it == recv_data.data() + recv_data.size(),
860  ExcMessage("The amount of data that was read into new particles "
861  "does not match the amount of data sent around."));
862  }
863 #endif
864 
865 
866 
867  template <int dim, int spacedim>
868  void
869  ParticleHandler<dim,spacedim>::register_additional_store_load_functions(const std::function<std::size_t ()> &size_callb,
870  const std::function<void *(const particle_iterator &,
871  void *)> &store_callb,
872  const std::function<const void *(const particle_iterator &,
873  const void *)> &load_callb)
874  {
875  size_callback = size_callb;
876  store_callback = store_callb;
877  load_callback = load_callb;
878  }
879 
880 
881 
882  template <int dim, int spacedim>
883  void
885  {
886  parallel::distributed::Triangulation<dim,spacedim> *non_const_triangulation =
887  const_cast<parallel::distributed::Triangulation<dim,spacedim> *> (&(*triangulation));
888 
889  // Only save and load particles if there are any, we might get here for
890  // example if somebody created a ParticleHandler but generated 0 particles.
891  update_cached_numbers();
892 
893  if (global_max_particles_per_cell > 0)
894  {
895  const std::function<void(const typename Triangulation<dim,spacedim>::cell_iterator &,
896  const typename Triangulation<dim,spacedim>::CellStatus, void *) > callback_function
898  std::cref(*this),
899  std::placeholders::_1,
900  std::placeholders::_2,
901  std::placeholders::_3);
902 
903  // Compute the size per serialized particle. This is simple if we own
904  // particles, simply ask one of them. Otherwise create a temporary particle,
905  // ask it for its size and add the size of its properties.
906  const std::size_t size_per_particle = (particles.size() > 0)
907  ?
908  begin()->serialized_size_in_bytes()
909  :
910  Particle<dim,spacedim>().serialized_size_in_bytes()
911  + property_pool->n_properties_per_slot() * sizeof(double);
912 
913  // We need to transfer the number of particles for this cell and
914  // the particle data itself. If we are in the process of refinement
915  // (i.e. not in serialization) we need to provide 2^dim times the
916  // space for the data in case a cell is coarsened and all particles
917  // of the children have to be stored in the parent cell.
918  const std::size_t transfer_size_per_cell = sizeof (unsigned int) +
919  (size_per_particle * global_max_particles_per_cell) *
920  (serialization ?
921  1
922  :
923  std::pow(2,dim));
924 
925  data_offset = non_const_triangulation->register_data_attach(transfer_size_per_cell,callback_function);
926  }
927  }
928 
929 
930 
931  template <int dim, int spacedim>
932  void
934  {
935  // All particles have been stored, when we reach this point. Empty the
936  // particle data.
937  clear_particles();
938 
939  parallel::distributed::Triangulation<dim,spacedim> *non_const_triangulation =
940  const_cast<parallel::distributed::Triangulation<dim,spacedim> *> (&(*triangulation));
941 
942  // If we are resuming from a checkpoint, we first have to register the
943  // store function again, to set the triangulation in the same state as
944  // before the serialization. Only by this it knows how to deserialize the
945  // data correctly. Only do this if something was actually stored.
946  if (serialization && (global_max_particles_per_cell > 0))
947  {
948  const std::function<void(const typename Triangulation<dim,spacedim>::cell_iterator &,
949  const typename Triangulation<dim,spacedim>::CellStatus, void *) > callback_function
951  std::cref(*this),
952  std::placeholders::_1,
953  std::placeholders::_2,
954  std::placeholders::_3);
955 
956  // Compute the size per serialized particle. This is simple if we own
957  // particles, simply ask one of them. Otherwise create a temporary particle,
958  // ask it for its size and add the size of its properties.
959  const std::size_t size_per_particle = (particles.size() > 0)
960  ?
961  begin()->serialized_size_in_bytes()
962  :
963  Particle<dim,spacedim>().serialized_size_in_bytes()
964  + property_pool->n_properties_per_slot() * sizeof(double);
965 
966  // We need to transfer the number of particles for this cell and
967  // the particle data itself and we need to provide 2^dim times the
968  // space for the data in case a cell is coarsened
969  const std::size_t transfer_size_per_cell = sizeof (unsigned int) +
970  (size_per_particle * global_max_particles_per_cell);
971  data_offset = non_const_triangulation->register_data_attach(transfer_size_per_cell,callback_function);
972  }
973 
974  // Check if something was stored and load it
975  if (data_offset != numbers::invalid_unsigned_int)
976  {
977  const std::function<void(const typename Triangulation<dim,spacedim>::cell_iterator &,
979  const void *) > callback_function
981  std::ref(*this),
982  std::placeholders::_1,
983  std::placeholders::_2,
984  std::placeholders::_3);
985 
986  non_const_triangulation->notify_ready_to_unpack(data_offset,callback_function);
987 
988  // Reset offset and update global number of particles. The number
989  // can change because of discarded or newly generated particles
990  data_offset = numbers::invalid_unsigned_int;
991  update_cached_numbers();
992  }
993  }
994 
995 
996 
997  template <int dim, int spacedim>
998  void
1000  const typename Triangulation<dim,spacedim>::CellStatus status,
1001  void *data) const
1002  {
1003  unsigned int n_particles(0);
1004 
1005  // If the cell persist or is refined store all particles of the current cell.
1008  {
1009  const boost::iterator_range<particle_iterator> particle_range
1010  = particles_in_cell(cell);
1011  n_particles = std::distance(particle_range.begin(),particle_range.end());
1012 
1013  unsigned int *ndata = static_cast<unsigned int *> (data);
1014  *ndata = n_particles;
1015  data = static_cast<void *> (ndata + 1);
1016 
1017  for (particle_iterator particle = particle_range.begin();
1018  particle != particle_range.end(); ++particle)
1019  {
1020  particle->write_data(data);
1021  }
1022  }
1023  // If this cell is the parent of children that will be coarsened, collect
1024  // the particles of all children.
1026  {
1027  for (unsigned int child_index = 0; child_index < GeometryInfo<dim>::max_children_per_cell; ++child_index)
1028  {
1029  const typename Triangulation<dim,spacedim>::cell_iterator child = cell->child(child_index);
1030  n_particles += n_particles_in_cell(child);
1031  }
1032 
1033  unsigned int *ndata = static_cast<unsigned int *> (data);
1034  *ndata = n_particles;
1035 
1036  data = static_cast<void *> (ndata + 1);
1037 
1038  for (unsigned int child_index = 0; child_index < GeometryInfo<dim>::max_children_per_cell; ++child_index)
1039  {
1040  const typename Triangulation<dim,spacedim>::cell_iterator child = cell->child(child_index);
1041  const boost::iterator_range<particle_iterator> particle_range
1042  = particles_in_cell(child);
1043 
1044  for (particle_iterator particle = particle_range.begin();
1045  particle != particle_range.end(); ++particle)
1046  {
1047  particle->write_data(data);
1048  }
1049  }
1050  }
1051  else
1052  Assert (false, ExcInternalError());
1053 
1054  }
1055 
1056  template <int dim, int spacedim>
1057  void
1059  const typename Triangulation<dim,spacedim>::CellStatus status,
1060  const void *data)
1061  {
1062  const unsigned int *n_particles_in_cell_ptr = static_cast<const unsigned int *> (data);
1063  const void *pdata = reinterpret_cast<const void *> (n_particles_in_cell_ptr + 1);
1064 
1065  if (*n_particles_in_cell_ptr == 0)
1066  return;
1067 
1068  // Load all particles from the data stream and store them in the local
1069  // particle map.
1071  {
1072  typename std::multimap<internal::LevelInd,Particle<dim,spacedim> >::iterator position_hint = particles.end();
1073  for (unsigned int i = 0; i < *n_particles_in_cell_ptr; ++i)
1074  {
1075  // Use std::multimap::emplace_hint to speed up insertion of
1076  // particles. This is a C++11 function, but not all compilers
1077  // that report a -std=c++11 (like gcc 4.6) implement it, so
1078  // require C++14 instead.
1079 #ifdef DEAL_II_WITH_CXX14
1080  position_hint = particles.emplace_hint(position_hint,
1081  std::make_pair(cell->level(),cell->index()),
1082  Particle<dim,spacedim>(pdata,property_pool.get()));
1083 #else
1084  position_hint = particles.insert(position_hint,
1085  std::make_pair(std::make_pair(cell->level(),cell->index()),
1086  Particle<dim,spacedim>(pdata,property_pool.get())));
1087 #endif
1088  ++position_hint;
1089  }
1090  }
1091 
1093  {
1094  typename std::multimap<internal::LevelInd,Particle<dim,spacedim> >::iterator position_hint = particles.end();
1095  for (unsigned int i = 0; i < *n_particles_in_cell_ptr; ++i)
1096  {
1097  // Use std::multimap::emplace_hint to speed up insertion of
1098  // particles. This is a C++11 function, but not all compilers
1099  // that report a -std=c++11 (like gcc 4.6) implement it, so
1100  // require C++14 instead.
1101 #ifdef DEAL_II_WITH_CXX14
1102  position_hint = particles.emplace_hint(position_hint,
1103  std::make_pair(cell->level(),cell->index()),
1104  Particle<dim,spacedim>(pdata,property_pool.get()));
1105 #else
1106  position_hint = particles.insert(position_hint,
1107  std::make_pair(std::make_pair(cell->level(),cell->index()),
1108  Particle<dim,spacedim>(pdata,property_pool.get())));
1109 #endif
1110  const Point<dim> p_unit = mapping->transform_real_to_unit_cell(cell, position_hint->second.get_location());
1111  position_hint->second.set_reference_location(p_unit);
1112  ++position_hint;
1113  }
1114  }
1116  {
1117  std::vector<typename std::multimap<internal::LevelInd, Particle<dim,spacedim> >::iterator > position_hints(GeometryInfo<dim>::max_children_per_cell);
1118  for (unsigned int child_index=0; child_index<GeometryInfo<dim>::max_children_per_cell; ++child_index)
1119  {
1120  const typename Triangulation<dim,spacedim>::cell_iterator child = cell->child(child_index);
1121  position_hints[child_index] = particles.upper_bound(std::make_pair(child->level(),child->index()));
1122  }
1123 
1124  for (unsigned int i = 0; i < *n_particles_in_cell_ptr; ++i)
1125  {
1126  Particle<dim,spacedim> p (pdata,property_pool.get());
1127 
1128  for (unsigned int child_index = 0; child_index < GeometryInfo<dim>::max_children_per_cell; ++child_index)
1129  {
1130  const typename Triangulation<dim,spacedim>::cell_iterator child = cell->child(child_index);
1131 
1132  try
1133  {
1134  const Point<dim> p_unit = mapping->transform_real_to_unit_cell(child,
1135  p.get_location());
1137  {
1138  p.set_reference_location(p_unit);
1139  // Use std::multimap::emplace_hint to speed up insertion of
1140  // particles. This is a C++11 function, but not all compilers
1141  // that report a -std=c++11 (like gcc 4.6) implement it, so
1142  // require C++14 instead.
1143 #ifdef DEAL_II_WITH_CXX14
1144  position_hints[child_index] = particles.emplace_hint(position_hints[child_index],
1145  std::make_pair(child->level(),child->index()),
1146  std::move(p));
1147 #else
1148  position_hints[child_index] = particles.insert(position_hints[child_index],
1149  std::make_pair(std::make_pair(child->level(),child->index()),
1150  p));
1151 #endif
1152  ++position_hints[child_index];
1153  break;
1154  }
1155  }
1156  catch (typename Mapping<dim>::ExcTransformationFailed &)
1157  {}
1158  }
1159  }
1160  }
1161  }
1162 }
1163 
1164 #endif
1165 
1166 DEAL_II_NAMESPACE_CLOSE
1167 
1168 DEAL_II_NAMESPACE_OPEN
1169 
1170 #ifdef DEAL_II_WITH_P4EST
1171 #include "particle_handler.inst"
1172 #endif
1173 
1174 DEAL_II_NAMESPACE_CLOSE
types::particle_index n_global_particles() const
static const unsigned int invalid_unsigned_int
Definition: types.h:173
types::particle_index n_locally_owned_particles() const
unsigned int particle_index
Definition: particle.h:64
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)
types::particle_index n_global_max_particles_per_cell() const
particle_iterator insert_particle(const Particle< dim, spacedim > &particle, const typename Triangulation< dim, spacedim >::active_cell_iterator &cell)
std::vector< std::set< typename Triangulation< dim, spacedim >::active_cell_iterator > > vertex_to_cell_map(const Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:1978
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 ArrayView< double > get_properties()
Definition: particle.cc:309
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
numbers::NumberTraits< Number >::real_type norm() const
Definition: tensor.h:1273
unsigned int register_data_attach(const std::size_t size, const std::function< void(const cell_iterator &, const CellStatus, void *)> &pack_callback)
Definition: tria.cc:3224
void register_load_callback_function(const bool serialization)
void store_particles(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const typename Triangulation< dim, spacedim >::CellStatus status, void *data) const
static ::ExceptionBase & ExcMessage(std::string arg1)
particle_iterator begin_ghost() const
unsigned int n_properties_per_particle() const
#define Assert(cond, exc)
Definition: exceptions.h:1142
particle_iterator_range particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell)
void insert_particles(const std::multimap< typename Triangulation< dim, spacedim >::active_cell_iterator, Particle< dim, spacedim > > &particles)
Abstract base class for mapping classes.
Definition: dof_tools.h:46
void notify_ready_to_unpack(const unsigned int handle, const std::function< void(const cell_iterator &, const CellStatus, const void *)> &unpack_callback)
Definition: tria.cc:3248
particle_iterator begin() const
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:3841
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:1557
unsigned int subdomain_id
Definition: types.h:42
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:65
Definition: cell_id.h:61
const types::subdomain_id artificial_subdomain_id
Definition: types.h:264
void load_particles(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const typename Triangulation< dim, spacedim >::CellStatus status, const void *data)
types::particle_index get_next_free_particle_index() const
bool has_properties() const
Definition: particle.cc:321
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1314
std::array< unsigned int, 4 > binary_type
Definition: cell_id.h:71
PropertyPool & get_property_pool() const
void register_store_callback_function(const bool serialization)
static ::ExceptionBase & ExcNotImplemented()
boost::iterator_range< particle_iterator > particle_iterator_range
particle_iterator end_ghost() const
particle_iterator end() 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)
unsigned int n_particles_in_cell(const typename Triangulation< dim, spacedim >::active_cell_iterator &cell) const
static ::ExceptionBase & ExcInternalError()