📄 partitioner.c
字号:
// $Id: partitioner.C 2895 2008-06-26 13:41:06Z benkirk $// The libMesh Finite Element Library.// Copyright (C) 2002-2007 Benjamin S. Kirk, John W. Peterson // This library is free software; you can redistribute it and/or// modify it under the terms of the GNU Lesser General Public// License as published by the Free Software Foundation; either// version 2.1 of the License, or (at your option) any later version. // This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU// Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public// License along with this library; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA// C++ Includes -----------------------------------// Local Includes -----------------------------------#include "elem.h"#include "mesh_base.h"#include "parallel.h"#include "partitioner.h"#include "mesh_tools.h"#include "mesh_communication.h"#include "libmesh_logging.h"// ------------------------------------------------------------// Partitioner static dataconst unsigned int Partitioner::communication_blocksize = 1000000;// ------------------------------------------------------------// Partitioner implementationvoid Partitioner::partition (MeshBase& mesh, const unsigned int n){ // BSK - temporary fix while redistribution is integrated 6/26/2008 // Uncomment this to not repartition in parallel if (!mesh.is_serial()) return; // we cannot partition into more pieces than we have // active elements! const unsigned int n_parts = std::min(mesh.n_active_elem(), n); // Set the number of partitions in the mesh mesh.set_n_partitions()=n_parts; if (n_parts == 1) { this->single_partition (mesh); return; } // First assign a temporary partitioning to any unpartitioned elements Partitioner::partition_unpartitioned_elements(mesh, n_parts); // Call the partitioning function this->_do_partition(mesh,n_parts); // Set the parent's processor ids Partitioner::set_parent_processor_ids(mesh); // Set the node's processor ids Partitioner::set_node_processor_ids(mesh);}void Partitioner::repartition (MeshBase& mesh, const unsigned int n){ // we cannot partition into more pieces than we have // active elements! const unsigned int n_parts = std::min(mesh.n_active_elem(), n); // Set the number of partitions in the mesh mesh.set_n_partitions()=n_parts; if (n_parts == 1) { this->single_partition (mesh); return; } // First assign a temporary partitioning to any unpartitioned elements Partitioner::partition_unpartitioned_elements(mesh, n_parts); // Call the partitioning function this->_do_repartition(mesh,n_parts); // Set the parent's processor ids Partitioner::set_parent_processor_ids(mesh); // Set the node's processor ids Partitioner::set_node_processor_ids(mesh);}void Partitioner::single_partition (MeshBase& mesh){ START_LOG("single_partition()","Partitioner"); // Loop over all the elements and assign them to processor 0. MeshBase::element_iterator elem_it = mesh.elements_begin(); const MeshBase::element_iterator elem_end = mesh.elements_end(); for ( ; elem_it != elem_end; ++elem_it) (*elem_it)->processor_id() = 0; // For a single partition, all the nodes are on processor 0 MeshBase::node_iterator node_it = mesh.nodes_begin(); const MeshBase::node_iterator node_end = mesh.nodes_end(); for ( ; node_it != node_end; ++node_it) (*node_it)->processor_id() = 0; STOP_LOG("single_partition()","Partitioner");}void Partitioner::partition_unpartitioned_elements (MeshBase &mesh, const unsigned int n_subdomains){ MeshBase::const_element_iterator it = mesh.unpartitioned_elements_begin(); const MeshBase::const_element_iterator end = mesh.unpartitioned_elements_end(); const unsigned int n_unpartitioned_elements = MeshTools::n_elem (it, end); // the unpartitioned elements must exist on all processors. If the range is empty on one // it is empty on all, and we can quit right here. if (!n_unpartitioned_elements) return; // find the target subdomain sizes std::vector<unsigned int> subdomain_bounds(libMesh::n_processors()); for (unsigned int pid=0; pid<libMesh::n_processors(); pid++) { unsigned int tgt_subdomain_size = 0; // watch out for the case that n_subdomains < n_processors if (pid < n_subdomains) { tgt_subdomain_size = n_unpartitioned_elements/n_subdomains; if (pid < n_unpartitioned_elements%n_subdomains) tgt_subdomain_size++; } //std::cout << "pid, #= " << pid << ", " << tgt_subdomain_size << std::endl; if (pid == 0) subdomain_bounds[0] = tgt_subdomain_size; else subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size; } libmesh_assert (subdomain_bounds.back() == n_unpartitioned_elements); // create the unique mapping for all unpartitioned elements independent of partitioning // determine the global indexing for all the unpartitoned elements std::vector<unsigned int> global_indices; // Calling this on all processors a unique range in [0,n_unpartitioned_elements) is constructed. // Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (MeshTools::bounding_box(mesh), it, end, global_indices); for (unsigned int cnt=0; it != end; ++it) { Elem *elem = *it; libmesh_assert (cnt < global_indices.size()); const unsigned int global_index = global_indices[cnt++]; libmesh_assert (global_index < subdomain_bounds.back()); libmesh_assert (global_index < n_unpartitioned_elements); const unsigned int subdomain_id = std::distance(subdomain_bounds.begin(), std::upper_bound(subdomain_bounds.begin(), subdomain_bounds.end(), global_index)); libmesh_assert (subdomain_id < n_subdomains); elem->processor_id() = subdomain_id; //std::cout << "assigning " << global_index << " to " << subdomain_id << std::endl; }}void Partitioner::set_parent_processor_ids(MeshBase& mesh){ START_LOG("set_parent_processor_ids()","Partitioner"); // If the mesh is serial we have access to all the elements, // in particular all the active ones. We can therefore set // the parent processor ids indirecly through their children. // By convention a parent is assigned to the minimum processor // of all its children. if (mesh.is_serial()) { // Loop over all the active elements in the mesh MeshBase::element_iterator it = mesh.active_elements_begin(); const MeshBase::element_iterator end = mesh.active_elements_end(); for ( ; it!=end; ++it) {#ifdef ENABLE_AMR Elem *child = *it; Elem *parent = child->parent(); while (parent) { // invalidate the parent id, otherwise the min below // will not work if the current parent id is less // than all the children! parent->invalidate_processor_id(); for(unsigned int c=0; c<parent->n_children(); c++) { child = parent->child(c); libmesh_assert(child); libmesh_assert(!child->is_remote()); libmesh_assert(child->processor_id() != DofObject::invalid_processor_id); parent->processor_id() = std::min(parent->processor_id(), child->processor_id()); } parent = parent->parent(); }#else libmesh_assert ((*it)->level() == 0);#endif } } // When the mesh is parallel we cannot guarantee that parents have access to // all their children. else { // We will use a brute-force approach here. Each processor finds its parent // elements and sets the parent pid to the minimum of its local children. // A global reduction is then performed to make sure the true minimum is found. // As noted, this is required because we cannot guarantee that a parent has // access to all its children on any single processor. parallel_only(); libmesh_assert(MeshTools::n_elem(mesh.unpartitioned_elements_begin(), mesh.unpartitioned_elements_end()) == 0); const unsigned int max_elem_id = mesh.max_elem_id(); std::vector<unsigned short int> parent_processor_ids (std::min(communication_blocksize, max_elem_id));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -