Hi, everyone I’m not familiar to ASPECT, could someone tell me how to get the data of ghost cells? In the ASPECT, I find that it is implemented through the following functions to obtain ghost particles in ~/aspect/source/particle/world.cc
template <int dim> std::map<types::subdomain_id,unsigned int> World<dim>::get_subdomain_id_to_neighbor_map() const { } template <int dim> void World<dim>::exchange_ghost_particles() { } template <int dim> void World<dim>::send_recv_particles (const std::vector<std::vector<std::pair<types::LevelInd,Particle <dim> > > > &send_particles, std::vector<std::pair<types::LevelInd, Particle<dim> > > &received_particles) { } *Presently, I just have a simple data(for example, an object of vector<valuetype> on each cell), which is not so complex like the particle, how can I realize this this easily?* Thanks very much! May modify directly in the following codes template <int dim> std::map<types::subdomain_id, unsigned int> World<dim>::get_subdomain_id_to_neighbor_map() const { std::map<types::subdomain_id, unsigned int> subdomain_id_to_neighbor_map; const std::set<types::subdomain_id> ghost_owners = this->get_triangulation().ghost_owners(); std::set<types::subdomain_id>::const_iterator ghost_owner = ghost_owners.begin(); for (unsigned int neighbor_id=0; neighbor_id<ghost_owners.size(); ++neighbor_id,++ghost_owner) { subdomain_id_to_neighbor_map.insert(std::make_pair(*ghost_owner,neighbor_id)); } return subdomain_id_to_neighbor_map; } template <int dim> void World<dim>::exchange_ghost_particles() { TimerOutput::Scope timer_section(this->get_computing_timer(), "Particles: Exchange ghosts"); // First clear the current ghost_particle information ghost_particles.clear(); const std::map<types::subdomain_id, unsigned int> subdomain_to_neighbor_map(get_subdomain_id_to_neighbor_map()); std::vector<std::vector<std::pair<types::LevelInd, Particle<dim> > > > ghost_particles_by_domain(subdomain_to_neighbor_map.size()); std::vector<std::set<unsigned int> > vertex_to_neighbor_subdomain(this->get_triangulation().n_vertices()); typename DoFHandler<dim>::active_cell_iterator cell = this->get_dof_handler().begin_active(), endc = this->get_dof_handler().end(); for (; cell != endc; ++cell) { if (cell->is_ghost()) for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v) vertex_to_neighbor_subdomain[cell->vertex_index(v)].insert(cell->subdomain_id()); } cell = this->get_triangulation().begin_active(); for (; cell != endc; ++cell) { if (!cell->is_ghost()) { std::set<unsigned int> cell_to_neighbor_subdomain; for (unsigned int v=0; v<GeometryInfo<dim>::vertices_per_cell; ++v) { cell_to_neighbor_subdomain.insert(vertex_to_neighbor_subdomain[cell->vertex_index(v)].begin(), vertex_to_neighbor_subdomain[cell->vertex_index(v)].end()); } if (cell_to_neighbor_subdomain.size() > 0) { const std::pair< const typename std::multimap<types::LevelInd,Particle <dim> >::iterator, const typename std::multimap<types::LevelInd,Particle <dim> >::iterator> particle_range_in_cell = particles.equal_range(std::make_pair(cell->level(),cell->index())); for (std::set<types::subdomain_id>::const_iterator domain=cell_to_neighbor_subdomain.begin(); domain != cell_to_neighbor_subdomain.end(); ++domain) { const unsigned int neighbor_id = subdomain_to_neighbor_map.find(*domain)->second; ghost_particles_by_domain[neighbor_id].insert( ghost_particles_by_domain[neighbor_id].end(), particle_range_in_cell.first, particle_range_in_cell.second); } } } } std::vector<std::pair<types::LevelInd, Particle<dim> > > received_ghost_particles; send_recv_particles(ghost_particles_by_domain, received_ghost_particles); ghost_particles.insert(received_ghost_particles.begin(), received_ghost_particles.end()); } *I'm not clear about the particles.equal_range().* *The following send_receive particles is mots difficult for me to understand* template <int dim> void World<dim>::send_recv_particles(const std::vector<std::vector<std::pair<types::LevelInd,Particle <dim> > > > &send_particles, std::vector<std::pair<types::LevelInd, Particle<dim> > > &received_particles) { // Determine the communication pattern const std::vector<types::subdomain_id> neighbors (this->get_triangulation().ghost_owners().begin(), this->get_triangulation().ghost_owners().end()); const unsigned int n_neighbors = neighbors.size(); Assert(n_neighbors == send_particles.size(), ExcMessage("The particles to send to other processes should be sorted into a vector " "containing as many vectors of particles as there are neighbor processes. This " "is not the case for an unknown reason. Contact the developers if you encounter " "this error.")); unsigned int n_send_particles = 0; for (unsigned int i=0; i<n_neighbors; ++i) n_send_particles += send_particles[i].size(); #if DEAL_II_VERSION_GTE(8,5,0) const unsigned int cellid_size = sizeof(CellId::binary_type); const unsigned int particle_size = property_manager->get_particle_size() + integrator->get_data_size() + cellid_size; #else const unsigned int particle_size = property_manager->get_particle_size() + integrator->get_data_size(); #endif // Determine the amount of data we will send to other processors std::vector<unsigned int> n_send_data(n_neighbors); std::vector<unsigned int> n_recv_data(n_neighbors); std::vector<unsigned int> send_offsets(n_neighbors); std::vector<unsigned int> recv_offsets(n_neighbors); // Allocate space for sending and receiving particle data std::vector<char> send_data(n_send_particles * particle_size); void *data = static_cast<void *> (&send_data.front()); for (types::subdomain_id neighbor_id = 0; neighbor_id < n_neighbors; ++neighbor_id) { send_offsets[neighbor_id] = reinterpret_cast<std::size_t> (data) - reinterpret_cast<std::size_t> (&send_data.front()); // Copy the particle data into the send array typename std::vector<std::pair<types::LevelInd,Particle <dim> > >::const_iterator cell_particle = send_particles[neighbor_id].begin(), end_particle = send_particles[neighbor_id].end(); for (; cell_particle != end_particle; ++cell_particle) { #if DEAL_II_VERSION_GTE(8,5,0) const typename parallel::distributed::Triangulation<dim>::cell_iterator cell (&this->get_triangulation(), cell_particle->first.first, cell_particle->first.second); const CellId::binary_type cellid = cell->id().template to_binary<dim>(); memcpy(data, &cellid, cellid_size); data = static_cast<char *>(data) + cellid_size; #endif cell_particle->second.write_data(data); data = integrator->write_data(data, cell_particle->second.get_id()); } n_send_data[neighbor_id] = reinterpret_cast<std::size_t> (data) - send_offsets[neighbor_id] - reinterpret_cast<std::size_t> (&send_data.front()); } // Notify other processors how many particles we will send std::vector<MPI_Request> n_requests(2*n_neighbors); for (unsigned int i=0; i<n_neighbors; ++i) MPI_Irecv(&(n_recv_data[i]), 1, MPI_INT, neighbors[i], 0, this->get_mpi_communicator(), &(n_requests[2*i])); for (unsigned int i=0; i<n_neighbors; ++i) MPI_Isend(&(n_send_data[i]), 1, MPI_INT, neighbors[i], 0, this->get_mpi_communicator(), &(n_requests[2*i+1])); MPI_Waitall(2*n_neighbors,&n_requests[0],MPI_STATUSES_IGNORE); // Determine how many particles and data we will receive unsigned int total_recv_data = 0; for (unsigned int neighbor_id=0; neighbor_id<n_neighbors; ++neighbor_id) { recv_offsets[neighbor_id] = total_recv_data; total_recv_data += n_recv_data[neighbor_id]; } // Set up the space for the received particle data std::vector<char> recv_data(total_recv_data); // Exchange the particle data between domains std::vector<MPI_Request> requests(2*n_neighbors); unsigned int send_ops = 0; unsigned int recv_ops = 0; for (unsigned int i=0; i<n_neighbors; ++i) if (n_recv_data[i] > 0) { MPI_Irecv(&(recv_data[recv_offsets[i]]), n_recv_data[i], MPI_CHAR, neighbors[i], 1, this->get_mpi_communicator(),&(requests[send_ops])); send_ops++; } for (unsigned int i=0; i<n_neighbors; ++i) if (n_send_data[i] > 0) { MPI_Isend(&(send_data[send_offsets[i]]), n_send_data[i], MPI_CHAR, neighbors[i], 1, this->get_mpi_communicator(),&(requests[send_ops+recv_ops])); recv_ops++; } MPI_Waitall(send_ops+recv_ops,&requests[0],MPI_STATUSES_IGNORE); // Put the received particles into the domain if they are in the triangulation const void *recv_data_it = static_cast<const void *> (&recv_data.front()); #if !DEAL_II_VERSION_GTE(8,5,0) const std::vector<std::set<typename Triangulation<dim>::active_cell_iterator> > vertex_to_cells(GridTools::vertex_to_cell_map(this->get_triangulation())); const std::vector<std::vector<Tensor<1,dim> > > vertex_to_cell_centers(vertex_to_cell_centers_directions(vertex_to_cells)); std::vector<unsigned int> neighbor_permutation; #endif while (reinterpret_cast<std::size_t> (recv_data_it) - reinterpret_cast<std::size_t> (&recv_data.front()) < total_recv_data) { #if DEAL_II_VERSION_GTE(8,5,0) CellId::binary_type binary_cellid; memcpy(&binary_cellid, recv_data_it, cellid_size); const CellId id(binary_cellid); recv_data_it = static_cast<const char *> (recv_data_it) + cellid_size; const typename parallel::distributed::Triangulation<dim>::active_cell_iterator cell = id.to_cell(this->get_triangulation()); const Particle<dim> recv_particle(recv_data_it,property_manager->get_particle_size()); recv_data_it = integrator->read_data(recv_data_it, recv_particle.get_id()); #else Particle<dim> recv_particle(recv_data_it,property_manager->get_particle_size()); recv_data_it = integrator->read_data(recv_data_it, recv_particle.get_id()); const std::pair<const typename parallel::distributed::Triangulation<dim>::active_cell_iterator, Point<dim> > current_cell_and_position = GridTools::find_active_cell_around_point<> (this->get_mapping(), this->get_triangulation(), recv_particle.get_location()); typename parallel::distributed::Triangulation<dim>::active_cell_iterator cell = current_cell_and_position.first; recv_particle.set_reference_location(current_cell_and_position.second); // GridTools::find_active_cell_around_point can find a different cell than // particle_is_in_cell if the particle is very close to the boundary // therefore, we might get a cell here that does not belong to us. // But then at least one of its neighbors belongs to us, and the particle // is extremely close to the boundary of these two cells. Look in the // neighbor cells for the particle. if (!cell->is_locally_owned()) { const unsigned int closest_vertex = get_closest_vertex_of_cell(cell,recv_particle.get_location()); const unsigned int closest_vertex_index = cell->vertex_index(closest_vertex); Tensor<1,dim> vertex_to_particle = recv_particle.get_location() - cell->vertex(closest_vertex); vertex_to_particle /= vertex_to_particle.norm(); const unsigned int n_neighbor_cells = vertex_to_cells[closest_vertex_index].size(); neighbor_permutation.resize(n_neighbor_cells); for (unsigned int i=0; i<n_neighbor_cells; ++i) neighbor_permutation[i] = i; std::sort(neighbor_permutation.begin(), neighbor_permutation.end(), std_cxx11::bind(&compare_particle_association<dim>, std_cxx11::_1, std_cxx11::_2, std_cxx11::cref(vertex_to_particle), std_cxx11::cref(vertex_to_cell_centers[closest_vertex_index]))); // Search all of the cells adjacent to the closest vertex of the previous cell // Most likely we will find the particle in them. for (unsigned int i=0; i<n_neighbor_cells; ++i) { try { typename std::set<typename Triangulation<dim>::active_cell_iterator>::const_iterator neighbor_cell = vertex_to_cells[closest_vertex_index].begin(); std::advance(neighbor_cell,neighbor_permutation[i]); const Point<dim> p_unit = this->get_mapping().transform_real_to_unit_cell(*neighbor_cell, recv_particle.get_location()); if (GeometryInfo<dim>::is_inside_unit_cell(p_unit)) { cell = *neighbor_cell; recv_particle.set_reference_location(p_unit); break; } } catch (typename Mapping<dim>::ExcTransformationFailed &) {} } } #endif const types::LevelInd found_cell = std::make_pair(cell->level(),cell->index()); received_particles.push_back(std::make_pair(found_cell, recv_particle)); } AssertThrow(recv_data_it == &recv_data.back()+1, ExcMessage("The amount of data that was read into new particles " "does not match the amount of data sent around.")); } Thanks so much! Best Jack > > Just for reference, Rene Gassmoeller implemented something similar for > particles recently: There, we store particles on every locally owned cell, > but > there are times when one also wants to access particles on ghost cells. > This > is implemented here: > https://github.com/geodynamics/aspect/pull/1216 > https://github.com/geodynamics/aspect/pull/1253 > > It's not terribly complicated because one just has to gather the > information > on cells that are ghosts on some other processor, and then send this > information to all relevant processors. > > Best > W. > > -- > ------------------------------------------------------------------------ > Wolfgang Bangerth email: bang...@colostate.edu > <javascript:> > www: http://www.math.colostate.edu/~bangerth/ > > -- The deal.II project is located at http://www.dealii.org/ For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en --- You received this message because you are subscribed to the Google Groups "deal.II User Group" group. To unsubscribe from this group and stop receiving emails from it, send an email to dealii+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.