Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #include "LibmeshPartitioner.h" 11 : 12 : #include "MooseApp.h" 13 : #include "MooseMeshUtils.h" 14 : 15 : #include "libmesh/linear_partitioner.h" 16 : #include "libmesh/centroid_partitioner.h" 17 : #include "libmesh/parmetis_partitioner.h" 18 : #include "libmesh/metis_partitioner.h" 19 : #include "libmesh/hilbert_sfc_partitioner.h" 20 : #include "libmesh/morton_sfc_partitioner.h" 21 : #include "libmesh/subdomain_partitioner.h" 22 : 23 : registerMooseObject("MooseApp", LibmeshPartitioner); 24 : 25 : InputParameters 26 14569 : LibmeshPartitioner::validParams() 27 : { 28 14569 : InputParameters params = MoosePartitioner::validParams(); 29 14569 : params.addClassDescription("Mesh partitioning using capabilities defined in libMesh."); 30 : MooseEnum partitioning( 31 14569 : "metis=-2 parmetis=-1 linear=0 centroid hilbert_sfc morton_sfc subdomain_partitioner"); 32 14569 : params.addRequiredParam<MooseEnum>( 33 : "partitioner", 34 : partitioning, 35 : "Specifies a mesh partitioner to use when splitting the mesh for a parallel computation."); 36 14569 : MooseEnum direction("x y z radial"); 37 14569 : params.addParam<MooseEnum>("centroid_partitioner_direction", 38 : direction, 39 : "Specifies the sort direction if using the centroid partitioner. " 40 : "Available options: x, y, z, radial"); 41 14569 : params.addParam<std::vector<std::vector<SubdomainName>>>( 42 : "blocks", {}, "Block is seperated by ;, and partition mesh block by block. "); 43 29138 : return params; 44 14569 : } 45 : 46 192 : LibmeshPartitioner::LibmeshPartitioner(const InputParameters & params) 47 : : MoosePartitioner(params), 48 192 : _partitioner_name(getParam<MooseEnum>("partitioner")), 49 384 : _subdomain_blocks(getParam<std::vector<std::vector<SubdomainName>>>("blocks")) 50 : { 51 192 : switch (_partitioner_name) 52 : { 53 0 : case -2: // metis 54 0 : _partitioner = std::make_unique<libMesh::MetisPartitioner>(); 55 0 : break; 56 0 : case -1: // parmetis 57 0 : _partitioner = std::make_unique<libMesh::ParmetisPartitioner>(); 58 0 : break; 59 : 60 72 : case 0: // linear 61 72 : _partitioner = std::make_unique<libMesh::LinearPartitioner>(); 62 72 : break; 63 0 : case 1: // centroid 64 : { 65 0 : if (!isParamValid("centroid_partitioner_direction")) 66 0 : mooseError( 67 : "If using the centroid partitioner you _must_ specify centroid_partitioner_direction!"); 68 : 69 0 : MooseEnum direction = getParam<MooseEnum>("centroid_partitioner_direction"); 70 : 71 0 : if (direction == "x") 72 : _partitioner = 73 0 : std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::X); 74 0 : else if (direction == "y") 75 : _partitioner = 76 0 : std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::Y); 77 0 : else if (direction == "z") 78 : _partitioner = 79 0 : std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::Z); 80 0 : else if (direction == "radial") 81 : _partitioner = 82 0 : std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::RADIAL); 83 0 : break; 84 0 : } 85 0 : case 2: // hilbert_sfc 86 0 : _partitioner = std::make_unique<libMesh::HilbertSFCPartitioner>(); 87 0 : break; 88 0 : case 3: // morton_sfc 89 0 : _partitioner = std::make_unique<libMesh::MortonSFCPartitioner>(); 90 0 : break; 91 120 : case 4: // subdomain_partitioner 92 120 : _partitioner = std::make_unique<libMesh::SubdomainPartitioner>(); 93 120 : break; 94 : } 95 192 : } 96 : 97 368 : LibmeshPartitioner::~LibmeshPartitioner() {} 98 : 99 : std::unique_ptr<Partitioner> 100 152 : LibmeshPartitioner::clone() const 101 : { 102 152 : switch (_partitioner_name) 103 : { 104 0 : case -2: // metis 105 0 : return std::make_unique<libMesh::MetisPartitioner>(); 106 : 107 0 : case -1: // parmetis 108 0 : return std::make_unique<libMesh::ParmetisPartitioner>(); 109 : 110 72 : case 0: // linear 111 72 : return std::make_unique<libMesh::LinearPartitioner>(); 112 : 113 0 : case 1: // centroid 114 : { 115 0 : if (!isParamValid("centroid_partitioner_direction")) 116 0 : mooseError( 117 : "If using the centroid partitioner you _must_ specify centroid_partitioner_direction!"); 118 : 119 0 : MooseEnum direction = getParam<MooseEnum>("centroid_partitioner_direction"); 120 : 121 0 : if (direction == "x") 122 0 : return std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::X); 123 0 : else if (direction == "y") 124 0 : return std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::Y); 125 0 : else if (direction == "z") 126 0 : return std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::Z); 127 0 : else if (direction == "radial") 128 0 : return std::make_unique<libMesh::CentroidPartitioner>(libMesh::CentroidPartitioner::RADIAL); 129 0 : break; 130 0 : } 131 0 : case 2: // hilbert_sfc 132 0 : return std::make_unique<libMesh::HilbertSFCPartitioner>(); 133 : 134 0 : case 3: // morton_sfc 135 0 : return std::make_unique<libMesh::MortonSFCPartitioner>(); 136 : 137 80 : case 4: // subdomain_partitioner 138 80 : return _app.getFactory().clone(*this); 139 : } 140 : // this cannot happen but I need to trick the compiler into 141 : // believing me 142 0 : mooseError("Error in LibmeshPartitioner: Supplied partitioner option causes error in clone()"); 143 : return std::make_unique<libMesh::MetisPartitioner>(); 144 : } 145 : 146 : void 147 36 : LibmeshPartitioner::prepareBlocksForSubdomainPartitioner( 148 : const MeshBase & mesh, libMesh::SubdomainPartitioner & subdomain_partitioner) 149 : { 150 : // For making sure all of the blocks exist 151 36 : std::set<subdomain_id_type> mesh_subdomain_ids; 152 36 : mesh.subdomain_ids(mesh_subdomain_ids); 153 : 154 : // Clear chunks before filling 155 36 : subdomain_partitioner.chunks.clear(); 156 : 157 : // Insert each chunk 158 100 : for (const auto & group : _subdomain_blocks) 159 : { 160 68 : const auto subdomain_ids = MooseMeshUtils::getSubdomainIDs(mesh, group); 161 324 : for (const auto id : subdomain_ids) 162 260 : if (!mesh_subdomain_ids.count(id)) 163 4 : paramError("blocks", "The block ", id, " was not found on the mesh"); 164 : 165 64 : std::set<subdomain_id_type> subdomain_ids_set(subdomain_ids.begin(), subdomain_ids.end()); 166 : 167 64 : subdomain_partitioner.chunks.push_back(subdomain_ids_set); 168 64 : } 169 32 : } 170 : 171 : void 172 36 : LibmeshPartitioner::partition(MeshBase & mesh, const unsigned int n) 173 : { 174 36 : if (_partitioner_name == "subdomain_partitioner") 175 : { 176 : mooseAssert(_partitioner.get(), "Partitioner is a NULL object"); 177 36 : prepareBlocksForSubdomainPartitioner( 178 36 : mesh, static_cast<libMesh::SubdomainPartitioner &>(*_partitioner.get())); 179 : } 180 : 181 32 : _partitioner->partition(mesh, n); 182 32 : } 183 : 184 : void 185 0 : LibmeshPartitioner::partition(MeshBase & mesh) 186 : { 187 0 : if (_partitioner_name == "subdomain_partitioner") 188 : { 189 : mooseAssert(_partitioner.get(), "Partitioner is a NULL object"); 190 0 : prepareBlocksForSubdomainPartitioner( 191 0 : mesh, static_cast<libMesh::SubdomainPartitioner &>(*_partitioner.get())); 192 : } 193 : 194 0 : _partitioner->partition(mesh); 195 0 : } 196 : 197 : void 198 0 : LibmeshPartitioner::_do_partition(MeshBase & /*mesh*/, const unsigned int /*n*/) 199 : { 200 0 : }