std::pair<MPI_Request, const K*>* buildTwo(Prcndtnr* B, const MPI_Comm& comm) { static_assert(std::is_same<typename Prcndtnr::super&, decltype(*this)>::value || std::is_same<typename Prcndtnr::super::super&, decltype(*this)>::value, "Wrong preconditioner"); std::pair<MPI_Request, const K*>* ret = nullptr; constexpr unsigned short N = std::is_same<typename Prcndtnr::super&, decltype(*this)>::value ? 2 : 3; unsigned short allUniform[N + 1]; allUniform[0] = Subdomain<K>::_map.size(); const Option& opt = *Option::get(); unsigned short nu = allUniform[1] = (_co ? _co->getLocal() : static_cast<unsigned short>(opt["geneo_nu"])); allUniform[2] = static_cast<unsigned short>(~nu); if(N == 3) allUniform[3] = nu > 0 ? nu : std::numeric_limits<unsigned short>::max(); { MPI_Op op; #ifdef __MINGW32__ MPI_Op_create(&f<N>, 1, &op); #else auto f = [](void* in, void* inout, int*, MPI_Datatype*) -> void { HPDDM_LAMBDA_F(in, input, inout, output, N) }; MPI_Op_create(f, 1, &op); #endif MPI_Allreduce(MPI_IN_PLACE, allUniform, N + 1, MPI_UNSIGNED_SHORT, op, comm); MPI_Op_free(&op); } if(nu > 0 || allUniform[1] != 0 || allUniform[2] != std::numeric_limits<unsigned short>::max()) { if(!_co) { _co = new CoarseOperator; _co->setLocal(nu); } double construction = MPI_Wtime(); if(allUniform[1] == nu && allUniform[2] == static_cast<unsigned short>(~nu)) ret = _co->template construction<1, excluded>(Operator(*B, allUniform[0]), comm); else if(N == 3 && allUniform[1] == 0 && allUniform[2] == static_cast<unsigned short>(~allUniform[3])) ret = _co->template construction<2, excluded>(Operator(*B, allUniform[0]), comm); else ret = _co->template construction<0, excluded>(Operator(*B, allUniform[0]), comm); construction = MPI_Wtime() - construction; if(_co->getRank() == 0 && opt.val<int>("verbosity") > 0) { std::stringstream ss; ss << std::setprecision(2) << construction; std::string line = " --- coarse operator transferred and factorized by " + to_string(static_cast<int>(opt["master_p"])) + " process" + (static_cast<int>(opt["master_p"]) == 1 ? "" : "es") + " (in " + ss.str() + "s)"; std::cout << line << std::endl; std::cout << std::right << std::setw(line.size()) << "(criterion = " + to_string(allUniform[1] == nu && allUniform[2] == static_cast<unsigned short>(~nu) ? nu : (N == 3 && allUniform[2] == static_cast<unsigned short>(~allUniform[3]) ? -_co->getLocal() : 0)) + " -- topology = " + to_string(static_cast<int>(opt["master_topology"])) + " -- distribution = " + to_string(static_cast<int>(opt["master_distribution"])) + ")" << std::endl; std::cout.unsetf(std::ios_base::adjustfield); } } else { delete _co; _co = nullptr; } return ret; }
inline std::pair<MPI_Request, const K*>* buildTwo(Operator&& A, const MPI_Comm& comm, Container& parm) { static_assert(N == 2 || N == 3, "Wrong template parameter"); std::pair<MPI_Request, const K*>* ret = nullptr; unsigned short allUniform[N + 1]; allUniform[0] = Subdomain<K>::_map.size(); allUniform[1] = parm[NU]; allUniform[2] = static_cast<unsigned short>(~parm[NU]); if(N == 3) allUniform[3] = parm[NU] > 0 ? parm[NU] : std::numeric_limits<unsigned short>::max(); { MPI_Op op; #ifndef __MINGW32__ auto f = [](void* in, void* inout, int*, MPI_Datatype*) -> void { HPDDM_LAMBDA_F(in, input, inout, output, N) }; MPI_Op_create(f, 1, &op); #else MPI_Op_create(&f<N>, 1, &op); #endif MPI_Allreduce(MPI_IN_PLACE, allUniform, N + 1, MPI_UNSIGNED_SHORT, op, comm); MPI_Op_free(&op); } A.sparsity(allUniform[0]); if(parm[NU] > 0 || allUniform[1] != 0 || allUniform[2] != std::numeric_limits<unsigned short>::max()) { if(!_co) _co = new CoarseOperator; _co->setLocal(parm[NU]); double construction = MPI_Wtime(); if(allUniform[1] == parm[NU] && allUniform[2] == static_cast<unsigned short>(~parm[NU])) ret = _co->template construction<1, excluded>(A, comm, parm); else if(N == 3 && allUniform[1] == 0 && allUniform[2] == static_cast<unsigned short>(~allUniform[3])) ret = _co->template construction<2, excluded>(A, comm, parm); else ret = _co->template construction<0, excluded>(A, comm, parm); construction = MPI_Wtime() - construction; if(_co->getRank() == 0) { std::cout << " (" << parm[P] << " process" << (parm[P] > 1 ? "es" : "") << " -- topology = " << parm[TOPOLOGY] << " -- distribution = " << _co->getDistribution() << ")" << std::endl; std::cout << std::scientific << " --- coarse operator transferred and factorized (in " << construction << ")" << std::endl; std::cout << " (criterion: " << (allUniform[1] == parm[NU] && allUniform[2] == static_cast<unsigned short>(~parm[NU]) ? parm[NU] : (N == 3 && allUniform[2] == static_cast<unsigned short>(~allUniform[3]) ? -_co->getLocal() : 0)) << ")" << std::endl; } _uc = new K[_co->getSizeRHS()]; } return ret; }
namespace HPDDM { /* Class: Preconditioner * * A base class from which <Schwarz> and <Schur> inherit. * * Template Parameters: * Solver - Solver used for the factorization of local matrices. * CoarseOperator - Class of the coarse operator. * K - Scalar type. */ template<template<class> class Solver, class CoarseOperator, class K> class Preconditioner : public Subdomain<K> { #ifdef __MINGW32__ private: template<unsigned short N> static void __stdcall f(void* in, void* inout, int*, MPI_Datatype*) { HPDDM_LAMBDA_F(in, input, inout, output, N) } #endif protected: /* Variable: s * Solver used in <Schwarz::callNumfact> and <Schur::callNumfactPreconditioner> or <Schur::computeSchurComplement>. */ Solver<K> _s; /* Variable: co * Pointer to a <Coarse operator>. */ CoarseOperator* _co; /* Variable: ev * Array of deflation vectors as needed by <Preconditioner::co>. */ K** _ev; /* Variable: uc * Workspace array of size <Coarse operator::local>. */ mutable K* _uc;