[de061d] | 1 | /*
|
---|
| 2 | * vmg - a versatile multigrid solver
|
---|
| 3 | * Copyright (C) 2012 Institute for Numerical Simulation, University of Bonn
|
---|
| 4 | *
|
---|
| 5 | * vmg is free software: you can redistribute it and/or modify
|
---|
| 6 | * it under the terms of the GNU General Public License as published by
|
---|
| 7 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 8 | * (at your option) any later version.
|
---|
| 9 | *
|
---|
| 10 | * vmg is distributed in the hope that it will be useful,
|
---|
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 13 | * GNU General Public License for more details.
|
---|
| 14 | *
|
---|
| 15 | * You should have received a copy of the GNU General Public License
|
---|
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 17 | */
|
---|
| 18 |
|
---|
| 19 | /**
|
---|
| 20 | * @file settings.cpp
|
---|
| 21 | * @author Julian Iseringhausen <isering@ins.uni-bonn.de>
|
---|
| 22 | * @date Mon Jan 2 18:45:22 2012
|
---|
| 23 | *
|
---|
| 24 | * @brief Computes several MPI-related settings.
|
---|
| 25 | *
|
---|
| 26 | */
|
---|
| 27 |
|
---|
| 28 | #ifdef HAVE_CONFIG_H
|
---|
| 29 | #include <libvmg_config.h>
|
---|
| 30 | #endif
|
---|
| 31 |
|
---|
| 32 | #ifdef HAVE_MPI
|
---|
| 33 | #include <mpi.h>
|
---|
| 34 | #ifdef HAVE_MARMOT
|
---|
| 35 | #include <enhancempicalls.h>
|
---|
| 36 | #include <sourceinfompicalls.h>
|
---|
| 37 | #endif
|
---|
| 38 | #else
|
---|
| 39 | #error MPI is needed to compile CommMPISettings
|
---|
| 40 | #endif
|
---|
| 41 |
|
---|
| 42 | #include <cassert>
|
---|
| 43 | #include <sstream>
|
---|
| 44 | #include <string>
|
---|
| 45 |
|
---|
| 46 | #include "base/index.hpp"
|
---|
| 47 | #include "comm/comm.hpp"
|
---|
| 48 | #include "comm/mpi/settings.hpp"
|
---|
| 49 | #include "discretization/boundary_value_setter.hpp"
|
---|
| 50 | #include "grid/multigrid.hpp"
|
---|
| 51 | #include "grid/tempgrid.hpp"
|
---|
| 52 | #include "mg.hpp"
|
---|
| 53 |
|
---|
| 54 | using namespace VMG;
|
---|
| 55 |
|
---|
| 56 | Grid& VMG::MPI::Settings::FinerGrid(const Grid& grid)
|
---|
| 57 | {
|
---|
| 58 | assert(finer_grids.find(&grid) != finer_grids.end());
|
---|
| 59 | return *finer_grids.find(&grid)->second;
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | Grid& VMG::MPI::Settings::CoarserGrid(const Grid& grid)
|
---|
| 63 | {
|
---|
| 64 | assert(coarser_grids.find(&grid) != coarser_grids.end());
|
---|
| 65 | return *coarser_grids.find(&grid)->second;
|
---|
| 66 | }
|
---|
| 67 |
|
---|
| 68 | MPI_Comm VMG::MPI::Settings::CommunicatorGlobal(const Grid& grid) const
|
---|
| 69 | {
|
---|
| 70 | assert(communicators_global.find(grid.Level()) != communicators_global.end());
|
---|
| 71 | return communicators_global.find(grid.Level())->second;
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | MPI_Comm VMG::MPI::Settings::CommunicatorLocal(const Grid& grid) const
|
---|
| 75 | {
|
---|
| 76 | KeyUnsorted k(grid, 0);
|
---|
| 77 | assert(communicators_local.find(k) != communicators_local.end());
|
---|
| 78 | return communicators_local.find(k)->second;
|
---|
| 79 | }
|
---|
| 80 |
|
---|
| 81 | VMG::MPI::DatatypesGlobal& VMG::MPI::Settings::DatatypesGlobal(const Grid& grid_old, const Grid& grid_new, const int& direction)
|
---|
| 82 | {
|
---|
| 83 | KeyUnsorted k(grid_old, grid_new, direction);
|
---|
| 84 | assert(datatypes_global.find(k) != datatypes_global.end());
|
---|
| 85 | return datatypes_global.find(k)->second;
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | VMG::MPI::DatatypesLocal& VMG::MPI::Settings::DatatypesLocal(const Grid& grid)
|
---|
| 89 | {
|
---|
| 90 | KeyUnsorted k(grid, 0);
|
---|
| 91 | assert(datatypes_local.find(k) != datatypes_local.end());
|
---|
| 92 | return datatypes_local.find(k)->second;
|
---|
| 93 | }
|
---|
| 94 |
|
---|
| 95 | void VMG::MPI::Settings::ComputeSettings(Multigrid& sol, Multigrid& rhs, MPI_Comm& comm_global)
|
---|
| 96 | {
|
---|
| 97 |
|
---|
| 98 | std::map<const Grid*, Grid*>::const_iterator grid_iter;
|
---|
| 99 |
|
---|
| 100 | Comm& comm = *MG::GetComm();
|
---|
| 101 |
|
---|
| 102 | /*
|
---|
| 103 | * Create coarser grids
|
---|
| 104 | */
|
---|
| 105 | for (int i=sol.MaxLevel(); i>sol.MinLevel(); --i) {
|
---|
| 106 |
|
---|
| 107 | TempGrid* temp_grid = new TempGrid();
|
---|
| 108 | temp_grid->SetPropertiesToCoarser(sol(i), comm.BoundaryConditions());
|
---|
| 109 |
|
---|
| 110 | if (temp_grid->Global().LocalBegin().IsComponentwiseGreaterOrEqual(sol(i-1).Global().LocalBegin()) &&
|
---|
| 111 | temp_grid->Global().LocalEnd().IsComponentwiseLessOrEqual(sol(i-1).Global().LocalEnd())) {
|
---|
| 112 | delete temp_grid;
|
---|
| 113 | coarser_grids.insert(std::make_pair(&sol(i), &sol(i-1)));
|
---|
| 114 | }else {
|
---|
| 115 | coarser_grids.insert(std::make_pair(&sol(i), temp_grid));
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | //FIXME
|
---|
| 121 | for (int i=rhs.MaxLevel(); i>rhs.MinLevel(); --i) {
|
---|
| 122 |
|
---|
| 123 | TempGrid* temp_grid = new TempGrid();
|
---|
| 124 | temp_grid->SetPropertiesToCoarser(rhs(i), comm.BoundaryConditions());
|
---|
| 125 |
|
---|
| 126 | if (temp_grid->Global().LocalBegin().IsComponentwiseGreaterOrEqual(rhs(i-1).Global().LocalBegin()) &&
|
---|
| 127 | temp_grid->Global().LocalEnd().IsComponentwiseLessOrEqual(rhs(i-1).Global().LocalEnd())) {
|
---|
| 128 | delete temp_grid;
|
---|
| 129 | coarser_grids.insert(std::make_pair(&rhs(i), &rhs(i-1)));
|
---|
| 130 | }else {
|
---|
| 131 | coarser_grids.insert(std::make_pair(&rhs(i), temp_grid));
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 | /*
|
---|
| 137 | * Create finer grids
|
---|
| 138 | */
|
---|
| 139 | for (int i=sol.MinLevel(); i<sol.MaxLevel(); ++i) {
|
---|
| 140 |
|
---|
| 141 | TempGrid* temp_grid = new TempGrid();
|
---|
| 142 | temp_grid->SetPropertiesToFiner(sol(i), comm.BoundaryConditions());
|
---|
| 143 | if (temp_grid->Global().LocalBegin() == sol(i+1).Global().LocalBegin() &&
|
---|
| 144 | temp_grid->Global().LocalEnd() == sol(i+1).Global().LocalEnd()) {
|
---|
| 145 | delete temp_grid;
|
---|
| 146 | finer_grids.insert(std::make_pair(&sol(i), &sol(i+1)));
|
---|
| 147 | }else {
|
---|
| 148 | finer_grids.insert(std::make_pair(&sol(i), temp_grid));
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 | }
|
---|
| 152 |
|
---|
| 153 | for (int i=rhs.MinLevel(); i<rhs.MaxLevel(); ++i) {
|
---|
| 154 |
|
---|
| 155 | TempGrid* temp_grid = new TempGrid();
|
---|
| 156 | temp_grid->SetPropertiesToFiner(rhs(i), comm.BoundaryConditions());
|
---|
| 157 | if (temp_grid->Global().LocalBegin() == rhs(i+1).Global().LocalBegin() &&
|
---|
| 158 | temp_grid->Global().LocalEnd() == rhs(i+1).Global().LocalEnd()) {
|
---|
| 159 | delete temp_grid;
|
---|
| 160 | finer_grids.insert(std::make_pair(&rhs(i), &rhs(i+1)));
|
---|
| 161 | }else {
|
---|
| 162 | finer_grids.insert(std::make_pair(&rhs(i), temp_grid));
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | }
|
---|
| 166 |
|
---|
| 167 | /*
|
---|
| 168 | * Create global communicators
|
---|
| 169 | */
|
---|
| 170 | for (int i=sol.MinLevel()+1; i<sol.MaxLevel(); ++i)
|
---|
| 171 | CreateGlobalCommunicator(comm_global, &sol(i), &CoarserGrid(sol(i+1)), &FinerGrid(sol(i-1)));
|
---|
| 172 |
|
---|
| 173 | CreateGlobalCommunicator(comm_global, &sol(sol.MinLevel()), &CoarserGrid(sol(sol.MinLevel()+1)));
|
---|
| 174 | CreateGlobalCommunicator(comm_global, &sol(sol.MaxLevel()), &FinerGrid(sol(sol.MaxLevel()-1)));
|
---|
| 175 |
|
---|
| 176 | MPI_Comm my_comm_global;
|
---|
| 177 | MPI_Comm_dup(comm_global, &my_comm_global);
|
---|
| 178 | communicators_global.insert(std::make_pair(0, my_comm_global));
|
---|
| 179 |
|
---|
| 180 | /*
|
---|
| 181 | * Create local communicators
|
---|
| 182 | */
|
---|
| 183 | for (int i=sol.MinLevel(); i<=sol.MaxLevel(); ++i)
|
---|
| 184 | CreateLocalCommunicator(comm_global, sol(i));
|
---|
| 185 |
|
---|
| 186 | for (int i=sol.MinLevel(); i<sol.MaxLevel(); ++i)
|
---|
| 187 | CreateLocalCommunicator(comm_global, FinerGrid(sol(i)));
|
---|
| 188 |
|
---|
| 189 | for (int i=sol.MaxLevel(); i>sol.MinLevel(); --i)
|
---|
| 190 | CreateLocalCommunicator(comm_global, CoarserGrid(sol(i)));
|
---|
| 191 |
|
---|
| 192 | if (MG::GetFactory().TestObject("PARTICLE_NEAR_FIELD_CELLS"))
|
---|
| 193 | CreateLocalCommunicator(comm_global, comm.GetParticleGrid());
|
---|
| 194 |
|
---|
| 195 | /*
|
---|
| 196 | * Create single grid datatypes
|
---|
| 197 | */
|
---|
| 198 | for (int i=sol.MinLevel(); i<=sol.MaxLevel(); ++i)
|
---|
| 199 | datatypes_local.insert(std::make_pair(KeyUnsorted(sol(i), 0), VMG::MPI::DatatypesLocal(sol(i), CommunicatorLocal(sol(i)), true)));
|
---|
| 200 |
|
---|
| 201 | for (grid_iter=finer_grids.begin(); grid_iter!=finer_grids.end(); ++grid_iter)
|
---|
| 202 | datatypes_local.insert(std::make_pair(KeyUnsorted(*grid_iter->second, 0), VMG::MPI::DatatypesLocal(*grid_iter->second, CommunicatorLocal(*grid_iter->second), true)));
|
---|
| 203 |
|
---|
| 204 | for (grid_iter=coarser_grids.begin(); grid_iter!=coarser_grids.end(); ++grid_iter)
|
---|
| 205 | datatypes_local.insert(std::make_pair(KeyUnsorted(*grid_iter->second, 0), VMG::MPI::DatatypesLocal(*grid_iter->second, CommunicatorLocal(*grid_iter->second), true)));
|
---|
| 206 |
|
---|
| 207 | if (MG::GetFactory().TestObject("PARTICLE_NEAR_FIELD_CELLS"))
|
---|
| 208 | datatypes_local.insert(std::make_pair(KeyUnsorted(comm.GetParticleGrid(), 0), VMG::MPI::DatatypesLocal(comm.GetParticleGrid(), CommunicatorLocal(comm.GetParticleGrid()), true)));
|
---|
| 209 |
|
---|
| 210 | /*
|
---|
| 211 | * Create two grid datatypes
|
---|
| 212 | */
|
---|
| 213 | for (int i=sol.MinLevel(); i<sol.MaxLevel(); ++i) {
|
---|
| 214 | AddDatatypeGlobal(sol(i), CoarserGrid(sol(i+1)), 0);
|
---|
| 215 | AddDatatypeGlobal(CoarserGrid(sol(i+1)), sol(i), 1);
|
---|
| 216 | }
|
---|
| 217 |
|
---|
| 218 | for (int i=sol.MaxLevel(); i>sol.MinLevel(); --i) {
|
---|
| 219 | AddDatatypeGlobal(sol(i), FinerGrid(sol(i-1)), 0);
|
---|
| 220 | AddDatatypeGlobal(FinerGrid(sol(i-1)), sol(i), 1);
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | InitializeBoundaryValues();
|
---|
| 224 | }
|
---|
| 225 |
|
---|
| 226 | void VMG::MPI::Settings::CreateGlobalCommunicator(MPI_Comm& comm_global, const Grid* grid_1, const Grid* grid_2, const Grid* grid_3)
|
---|
| 227 | {
|
---|
| 228 | int rank;
|
---|
| 229 | MPI_Comm comm_new;
|
---|
| 230 |
|
---|
| 231 | const bool in_communicator = (grid_1->Global().LocalSize().Product() > 0) ||
|
---|
| 232 | (grid_2 && grid_2->Global().LocalSize().Product() > 0) ||
|
---|
| 233 | (grid_3 && grid_3->Global().LocalSize().Product() > 0);
|
---|
| 234 |
|
---|
| 235 | MPI_Comm_rank(comm_global, &rank);
|
---|
| 236 |
|
---|
| 237 | if (in_communicator) {
|
---|
| 238 | Index dims, periods, coords;
|
---|
| 239 | MPI_Comm comm_temp;
|
---|
| 240 | MPI_Cart_get(comm_global, 3, dims.vec(), periods.vec(), coords.vec());
|
---|
| 241 | MPI_Comm_split(comm_global, 1, rank, &comm_temp);
|
---|
| 242 | dims = GlobalDims(comm_temp, coords);
|
---|
| 243 | MPI_Cart_create(comm_temp, 3, dims.vec(), periods.vec(), 0, &comm_new);
|
---|
| 244 | MPI_Comm_free(&comm_temp);
|
---|
| 245 | }else {
|
---|
| 246 | MPI_Comm_split(comm_global, MPI_UNDEFINED, rank, &comm_new);
|
---|
| 247 | }
|
---|
| 248 |
|
---|
| 249 | communicators_global.insert(std::make_pair(grid_1->Level(), comm_new));
|
---|
| 250 | }
|
---|
| 251 |
|
---|
| 252 | void VMG::MPI::Settings::CreateLocalCommunicator(MPI_Comm& comm_global, const Grid& grid)
|
---|
| 253 | {
|
---|
| 254 | int rank, comm_equal;
|
---|
| 255 | MPI_Comm comm_new;
|
---|
| 256 | std::set<MPI_Comm>::iterator iter;
|
---|
| 257 |
|
---|
| 258 | MPI_Comm_rank(comm_global, &rank);
|
---|
| 259 |
|
---|
| 260 | if (grid.Global().LocalSize().Product() > 0) {
|
---|
| 261 | Index dims, periods, coords;
|
---|
| 262 | MPI_Comm comm_temp;
|
---|
| 263 | MPI_Cart_get(comm_global, 3, dims.vec(), periods.vec(), coords.vec());
|
---|
| 264 | MPI_Comm_split(comm_global, 1, rank, &comm_temp);
|
---|
| 265 | dims = GlobalDims(comm_temp, coords);
|
---|
| 266 | MPI_Cart_create(comm_temp, 3, dims.vec(), periods.vec(), 0, &comm_new);
|
---|
| 267 | MPI_Comm_free(&comm_temp);
|
---|
| 268 | }else {
|
---|
| 269 | MPI_Comm_split(comm_global, MPI_UNDEFINED, rank, &comm_new);
|
---|
| 270 | }
|
---|
| 271 |
|
---|
| 272 | if (comm_new != MPI_COMM_NULL) {
|
---|
| 273 | for (iter=communicators_local_unique.begin(); iter!=communicators_local_unique.end(); ++iter) {
|
---|
| 274 | if (*iter != MPI_COMM_NULL) {
|
---|
| 275 | MPI_Comm_compare(comm_new, *iter, &comm_equal);
|
---|
| 276 | assert(comm_equal != MPI_SIMILAR);
|
---|
| 277 | if (comm_equal == MPI_IDENT || comm_equal == MPI_CONGRUENT) {
|
---|
| 278 | MPI_Comm_free(&comm_new);
|
---|
| 279 | comm_new = *iter;
|
---|
| 280 | break;
|
---|
| 281 | }
|
---|
| 282 | }
|
---|
| 283 | }
|
---|
| 284 | }
|
---|
| 285 |
|
---|
| 286 | std::pair<std::set<MPI_Comm>::iterator, bool> insert_result = communicators_local_unique.insert(comm_new);
|
---|
| 287 | communicators_local.insert(std::make_pair(KeyUnsorted(grid, 0), *insert_result.first));
|
---|
| 288 | }
|
---|
| 289 |
|
---|
| 290 | void VMG::MPI::Settings::AddDatatypeGlobal(const Grid& grid_old, const Grid& grid_new, const int& direction)
|
---|
| 291 | {
|
---|
| 292 | MPI_Comm comm = CommunicatorGlobal(grid_old);
|
---|
| 293 |
|
---|
| 294 | // Insert into map
|
---|
| 295 | std::pair< std::map<VMG::MPI::KeyUnsorted, VMG::MPI::DatatypesGlobal>::iterator, bool > insert_result =
|
---|
| 296 | datatypes_global.insert(std::make_pair(VMG::MPI::KeyUnsorted(grid_old, grid_new, direction), VMG::MPI::DatatypesGlobal()));
|
---|
| 297 | VMG::MPI::DatatypesGlobal& dt_global = insert_result.first->second;
|
---|
| 298 | bool dt_is_new = insert_result.second;
|
---|
| 299 |
|
---|
| 300 |
|
---|
| 301 | if (comm != MPI_COMM_NULL) {
|
---|
| 302 |
|
---|
| 303 | Index begin, end, offset_old, offset_new;
|
---|
| 304 | int rank, size;
|
---|
| 305 |
|
---|
| 306 | MPI_Comm_rank(comm, &rank);
|
---|
| 307 | MPI_Comm_size(comm, &size);
|
---|
| 308 |
|
---|
| 309 | std::vector<int> buffer;
|
---|
| 310 | buffer.resize(6*size);
|
---|
| 311 |
|
---|
| 312 | // Compute local offset for ghost cells
|
---|
| 313 | for (int i=0; i<3; ++i) {
|
---|
| 314 | offset_old[i] = (grid_old.Local().HaloSize1()[i] > 0 ? grid_old.Local().Begin()[i] : 0);
|
---|
| 315 | offset_new[i] = (grid_new.Local().HaloSize1()[i] > 0 ? grid_new.Local().Begin()[i] : 0);
|
---|
| 316 | }
|
---|
| 317 |
|
---|
| 318 | // Publish which grid part this process can offer
|
---|
| 319 | if (&grid_old == &grid_new) {
|
---|
| 320 | for (int i=0; i<6; ++i)
|
---|
| 321 | buffer[6*rank+i] = 0;
|
---|
| 322 | }else {
|
---|
| 323 | for (int i=0; i<3; ++i) {
|
---|
| 324 | buffer[6*rank+i] = grid_old.Global().LocalBegin()[i];
|
---|
| 325 | buffer[6*rank+i+3] = grid_old.Global().LocalEnd()[i];
|
---|
| 326 | }
|
---|
| 327 | }
|
---|
| 328 |
|
---|
| 329 | MPI_Allgather(MPI_IN_PLACE, 6, MPI_INT, &buffer.front(), 6, MPI_INT, comm);
|
---|
| 330 |
|
---|
| 331 | if (dt_is_new) {
|
---|
| 332 |
|
---|
| 333 | // Decide who offers a useful grid part
|
---|
| 334 | for (int i=0; i<size; ++i) {
|
---|
| 335 | for (int j=0; j<3; ++j) {
|
---|
| 336 | begin[j] = buffer[6*i+j];
|
---|
| 337 | end[j] = buffer[6*i+j+3];
|
---|
| 338 | }
|
---|
| 339 |
|
---|
| 340 | begin = begin.Clamp(grid_new.Global().LocalBegin(), grid_new.Global().LocalEnd());
|
---|
| 341 | end = end.Clamp(grid_new.Global().LocalBegin(), grid_new.Global().LocalEnd());
|
---|
| 342 |
|
---|
| 343 | if ((end-begin).Product() > 0) {
|
---|
| 344 | // This process has a useful part
|
---|
| 345 | dt_global.Receive().push_back(VMG::MPI::Datatype(grid_new.Local().SizeTotal(),
|
---|
| 346 | end - begin,
|
---|
| 347 | begin - grid_new.Global().LocalBegin() + offset_new,
|
---|
| 348 | i, 0, 0, true));
|
---|
| 349 | }
|
---|
| 350 | }
|
---|
| 351 | }
|
---|
| 352 |
|
---|
| 353 | // Publish which grid parts this process needs
|
---|
| 354 | for (int i=0; i<3; ++i) {
|
---|
| 355 | buffer[6*rank+i] = grid_new.Global().LocalBegin()[i];
|
---|
| 356 | buffer[6*rank+i+3] = grid_new.Global().LocalEnd()[i];
|
---|
| 357 | }
|
---|
| 358 |
|
---|
| 359 | MPI_Allgather(MPI_IN_PLACE, 6, MPI_INT, &buffer.front(), 6, MPI_INT, comm);
|
---|
| 360 |
|
---|
| 361 | if (dt_is_new) {
|
---|
| 362 |
|
---|
| 363 | // Decide who needs a part of my grid
|
---|
| 364 | for (int i=0; i<size; ++i) {
|
---|
| 365 |
|
---|
| 366 | if ((i == rank) && (&grid_old == &grid_new))
|
---|
| 367 | continue;
|
---|
| 368 |
|
---|
| 369 | for (int j=0; j<3; ++j) {
|
---|
| 370 | begin[j] = buffer[6*i+j];
|
---|
| 371 | end[j] = buffer[6*i+j+3];
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | begin = begin.Clamp(grid_old.Global().LocalBegin(), grid_old.Global().LocalEnd());
|
---|
| 375 | end = end.Clamp(grid_old.Global().LocalBegin(), grid_old.Global().LocalEnd());
|
---|
| 376 |
|
---|
| 377 | if ((end-begin).Product() > 0) {
|
---|
| 378 | // This process needs one of my parts
|
---|
| 379 | dt_global.Send().push_back(VMG::MPI::Datatype(grid_old.Local().SizeTotal(),
|
---|
| 380 | end - begin,
|
---|
| 381 | begin - grid_old.Global().LocalBegin() + offset_old,
|
---|
| 382 | i, 0, 0, true));
|
---|
| 383 | }
|
---|
| 384 | }
|
---|
| 385 | }
|
---|
| 386 | }
|
---|
| 387 | }
|
---|
| 388 |
|
---|
| 389 | MPI_Datatype& VMG::MPI::Settings::Datatype(const Index& begin, const Index& end,
|
---|
| 390 | const Index& size_local, const Index& size_global,
|
---|
| 391 | const int& level)
|
---|
| 392 | {
|
---|
| 393 | KeyUnsorted k(begin, end, size_local, size_global, level, 0);
|
---|
| 394 | std::map<KeyUnsorted, MPI_Datatype>::iterator iter = datatypes.find(k);
|
---|
| 395 |
|
---|
| 396 | if (iter != datatypes.end())
|
---|
| 397 | return iter->second;
|
---|
| 398 |
|
---|
| 399 | MPI_Datatype dt;
|
---|
| 400 | Index sizes = size_local;
|
---|
| 401 | Index subsizes = end - begin;
|
---|
| 402 | Index starts = begin;
|
---|
| 403 |
|
---|
| 404 | MPI_Type_create_subarray(3, sizes.vec(), subsizes.vec(), starts.vec(), MPI_ORDER_C, MPI_DOUBLE, &dt);
|
---|
| 405 | MPI_Type_commit(&dt);
|
---|
| 406 |
|
---|
| 407 | return datatypes.insert(std::make_pair(k, dt)).first->second;
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | Index VMG::MPI::Settings::GlobalDims(MPI_Comm comm, Index pos)
|
---|
| 411 | {
|
---|
| 412 | std::set<int> unique_set[3];
|
---|
| 413 | Index dims;
|
---|
| 414 |
|
---|
| 415 | int size;
|
---|
| 416 | MPI_Comm_size(comm, &size);
|
---|
| 417 |
|
---|
| 418 | int* coordinates = new int[3*size];
|
---|
| 419 |
|
---|
| 420 | MPI_Allgather(pos.vec(), 3, MPI_INT, coordinates, 3, MPI_INT, comm);
|
---|
| 421 |
|
---|
| 422 | for (int i=0; i<size; ++i)
|
---|
| 423 | for (int j=0; j<3; ++j)
|
---|
| 424 | unique_set[j].insert(coordinates[3*i+j]);
|
---|
| 425 |
|
---|
| 426 | for (int j=0; j<3; ++j)
|
---|
| 427 | dims[j] = static_cast<int>(unique_set[j].size());
|
---|
| 428 |
|
---|
| 429 | delete [] coordinates;
|
---|
| 430 |
|
---|
| 431 | return dims;
|
---|
| 432 | }
|
---|
| 433 |
|
---|
| 434 | void VMG::MPI::Settings::InitializeBoundaryValues()
|
---|
| 435 | {
|
---|
| 436 | assert(bv_ranks.size() == 0);
|
---|
| 437 |
|
---|
| 438 | if (MG::GetFactory().TestObject("BOUNDARY_VALUE_SETTER")) {
|
---|
| 439 |
|
---|
| 440 | Index coord;
|
---|
| 441 |
|
---|
| 442 | const int level_index = MG::GetRhs()->MaxLevel() - MG::GetRhs()->GlobalMaxLevel();
|
---|
| 443 | const std::vector<BoundaryValue>& bvs = MG::GetBoundaryValueSetter()->BoundaryValues();
|
---|
| 444 | const std::map<Index, std::vector<GlobalIndices> >& global = MG::GetComm()->DecomposedGlobal();
|
---|
| 445 |
|
---|
| 446 | assert(global.find(0)->second[level_index].BoundaryType() == GlobalMax);
|
---|
| 447 |
|
---|
| 448 | MPI_Comm comm = CommunicatorLocal((*MG::GetRhs())(MG::GetRhs()->GlobalMaxLevel()));
|
---|
| 449 |
|
---|
| 450 | bv_ranks.reserve(bvs.size());
|
---|
| 451 |
|
---|
| 452 | for (std::vector<BoundaryValue>::const_iterator iter_b = bvs.begin(); iter_b != bvs.end(); ++iter_b) {
|
---|
| 453 | for (std::map<Index, std::vector<GlobalIndices> >::const_iterator iter_g = global.begin(); iter_g != global.end(); ++iter_g) {
|
---|
| 454 | if (iter_b->GetIndex().IsComponentwiseGreaterOrEqual(iter_g->second[level_index].LocalBegin()) &&
|
---|
| 455 | iter_b->GetIndex().IsComponentwiseLess(iter_g->second[level_index].LocalEnd())) {
|
---|
| 456 | bv_ranks.push_back(0);
|
---|
| 457 | coord = iter_g->first;
|
---|
| 458 | MPI_Cart_rank(comm, coord.vec(), &bv_ranks.back());
|
---|
| 459 | break;
|
---|
| 460 | }
|
---|
| 461 | }
|
---|
| 462 | }
|
---|
| 463 | }
|
---|
| 464 | }
|
---|
| 465 |
|
---|
| 466 | std::string VMG::MPI::Settings::ToString() const
|
---|
| 467 | {
|
---|
| 468 | std::stringstream str;
|
---|
| 469 | std::map<KeyUnsorted, VMG::MPI::DatatypesGlobal>::const_iterator iter_global;
|
---|
| 470 | std::map<KeyUnsorted, VMG::MPI::DatatypesLocal>::const_iterator iter_local;
|
---|
| 471 |
|
---|
| 472 | str << "#### MPI_SETTINGS ####" << std::endl;
|
---|
| 473 |
|
---|
| 474 | for (iter_global = datatypes_global.begin(); iter_global != datatypes_global.end(); ++iter_global)
|
---|
| 475 | str << iter_global->second << std::endl;
|
---|
| 476 |
|
---|
| 477 | for (iter_local = datatypes_local.begin(); iter_local != datatypes_local.end(); ++iter_local)
|
---|
| 478 | str << iter_local->second << std::endl;
|
---|
| 479 |
|
---|
| 480 | str << "######################";
|
---|
| 481 |
|
---|
| 482 | return str.str();
|
---|
| 483 | }
|
---|
| 484 |
|
---|
| 485 | std::ostream& VMG::MPI::operator<<(std::ostream& out, const VMG::MPI::Settings& settings)
|
---|
| 486 | {
|
---|
| 487 | return out << settings.ToString();
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 | VMG::MPI::Settings::Settings()
|
---|
| 491 | {
|
---|
| 492 | }
|
---|
| 493 |
|
---|
| 494 | VMG::MPI::Settings::~Settings()
|
---|
| 495 | {
|
---|
| 496 | std::map<int, MPI_Comm>::iterator iter_comm_global;
|
---|
| 497 | for (iter_comm_global=communicators_global.begin(); iter_comm_global!=communicators_global.end(); ++iter_comm_global)
|
---|
| 498 | if (iter_comm_global->second != MPI_COMM_NULL)
|
---|
| 499 | MPI_Comm_free(&iter_comm_global->second);
|
---|
| 500 |
|
---|
| 501 | /*
|
---|
| 502 | * We simply copied some communicators so we have to make sure that we free
|
---|
| 503 | * each communicator exactly once
|
---|
| 504 | */
|
---|
| 505 | std::set<MPI_Comm>::iterator iter_comm_set;
|
---|
| 506 | for (iter_comm_set=communicators_local_unique.begin(); iter_comm_set!=communicators_local_unique.end(); ++iter_comm_set)
|
---|
| 507 | if (*iter_comm_set != MPI_COMM_NULL) {
|
---|
| 508 | MPI_Comm comm_temp = *iter_comm_set;
|
---|
| 509 | MPI_Comm_free(&comm_temp);
|
---|
| 510 | }
|
---|
| 511 |
|
---|
| 512 | std::map<KeyUnsorted, MPI_Datatype>::iterator iter_dt;
|
---|
| 513 | for (iter_dt=datatypes.begin(); iter_dt!=datatypes.end(); ++iter_dt)
|
---|
| 514 | if (iter_dt->second != MPI_DATATYPE_NULL)
|
---|
| 515 | MPI_Type_free(&iter_dt->second);
|
---|
| 516 |
|
---|
| 517 | std::map<const Grid*, Grid*>::iterator iter_grid;
|
---|
| 518 | for (iter_grid=finer_grids.begin(); iter_grid!=finer_grids.end(); ++iter_grid)
|
---|
| 519 | if (iter_grid->second->Father() == NULL)
|
---|
| 520 | delete iter_grid->second;
|
---|
| 521 |
|
---|
| 522 | for (iter_grid=coarser_grids.begin(); iter_grid!=coarser_grids.end(); ++iter_grid)
|
---|
| 523 | if (iter_grid->second->Father() == NULL)
|
---|
| 524 | delete iter_grid->second;
|
---|
| 525 | }
|
---|