MGPoissonSolver.cpp 21 KB
Newer Older
frey_m's avatar
frey_m committed
1 2 3 4 5 6 7 8 9 10
//
// Class MGPoissonSolver
//   This class contains methods for solving Poisson's equation for the
//   space charge portion of the calculation.
//
//   A smoothed aggregation based AMG preconditioned iterative solver for space charge
//   \see FFTPoissonSolver
//   \warning This solver is in an EXPERIMENTAL STAGE. For reliable simulations use the FFTPoissonSolver
//
// Copyright (c) 2010 - 2013, Yves Ineichen, ETH Zürich,
frey_m's avatar
frey_m committed
11 12
//               2013 - 2015, Tülin Kaman, Paul Scherrer Institut, Villigen PSI, Switzerland,
//                      2020, Matthias Frey, Paul Scherrer Institut, Villigen PSI, Switzerland
frey_m's avatar
frey_m committed
13 14 15
// All rights reserved
//
// Implemented as part of the PhD thesis
frey_m's avatar
frey_m committed
16
// "Toward massively parallel multi-objective optimization with application to
frey_m's avatar
frey_m committed
17 18
// particle accelerators" (https://doi.org/10.3929/ethz-a-009792359)
//
frey_m's avatar
frey_m committed
19
// In 2020, the code was ported to the second generation Trilinos packages,
frey_m's avatar
frey_m committed
20
// i.e., Epetra --> Tpetra, ML --> MueLu. See also issue #507.
frey_m's avatar
frey_m committed
21
//
frey_m's avatar
frey_m committed
22 23 24 25 26 27 28 29 30 31
// This file is part of OPAL.
//
// OPAL is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// You should have received a copy of the GNU General Public License
// along with OPAL. If not, see <https://www.gnu.org/licenses/>.
//
32

33
//#define DBG_STENCIL
34

kraus's avatar
kraus committed
35
#include "Solvers/MGPoissonSolver.h"
36 37 38 39 40 41

#include "Structure/BoundaryGeometry.h"
#include "ArbitraryDomain.h"
#include "EllipticDomain.h"
#include "BoxCornerDomain.h"

42
#include "Track/Track.h"
gsell's avatar
gsell committed
43 44 45 46 47
#include "Physics/Physics.h"
#include "Utilities/OpalException.h"
#include "Attributes/Attributes.h"
#include "ValueDefinitions/RealVariable.h"
#include "AbstractObjects/OpalData.h"
48
#include "Utilities/Options.h"
49

50 51
#include <Tpetra_Import.hpp>
#include <BelosTpetraAdapter.hpp>
52

frey_m's avatar
frey_m committed
53 54 55 56
#ifdef DBG_STENCIL
    #include "TpetraExt_MatrixMatrix.hpp"
#endif

57 58 59 60 61 62
#include "Teuchos_CommandLineProcessor.hpp"

#include "BelosLinearProblem.hpp"
#include "BelosRCGSolMgr.hpp"
#include "BelosBlockCGSolMgr.hpp"

63
#include <MueLu_CreateTpetraPreconditioner.hpp>
64

gsell's avatar
gsell committed
65 66
#include <algorithm>

67 68
using Teuchos::RCP;
using Teuchos::rcp;
gsell's avatar
gsell committed
69 70
using Physics::c;

71
MGPoissonSolver::MGPoissonSolver ( PartBunch *beam,
72 73 74 75 76 77 78
                                   Mesh_t *mesh,
                                   FieldLayout_t *fl,
                                   std::vector<BoundaryGeometry *> geometries,
                                   std::string itsolver,
                                   std::string interpl,
                                   double tol,
                                   int maxiters,
79
                                   std::string precmode)
frey_m's avatar
fix bug  
frey_m committed
80 81
    : isMatrixfilled_m(false)
    , geometries_m(geometries)
82 83 84 85 86 87 88
    , tol_m(tol)
    , maxiters_m(maxiters)
    , comm_mp(new Comm_t(Ippl::getComm()))
    , itsBunch_m(beam)
    , mesh_m(mesh)
    , layout_m(fl)
{
89

gsell's avatar
gsell committed
90 91
    domain_m = layout_m->getDomain();

92
    for (int i = 0; i < 3; i++) {
gsell's avatar
gsell committed
93 94 95 96
        hr_m[i] = mesh_m->get_meshSpacing(i);
        orig_nr_m[i] = domain_m[i].length();
    }

frey_m's avatar
frey_m committed
97 98 99
    if (itsolver == "CG") itsolver_m = AZ_cg;
    else if (itsolver == "BICGSTAB") itsolver_m = AZ_bicgstab;
    else if (itsolver == "GMRES") itsolver_m = AZ_gmres;
gsell's avatar
gsell committed
100 101 102
    else throw OpalException("MGPoissonSolver", "No valid iterative solver selected!");

    precmode_m = STD_PREC;
frey_m's avatar
frey_m committed
103 104 105 106
    if (precmode == "STD") precmode_m = STD_PREC;
    else if (precmode == "HIERARCHY") precmode_m = REUSE_HIERARCHY;
    else if (precmode == "REUSE") precmode_m = REUSE_PREC;
    else if (precmode == "NO") precmode_m = NO;
gsell's avatar
gsell committed
107

108
    repartFreq_m = 1000;
frey_m's avatar
frey_m committed
109
    if (Ippl::Info->getOutputLevel() > 3)
gsell's avatar
gsell committed
110 111 112 113
        verbose_m = true;
    else
        verbose_m = false;

114
    // Find CURRENT geometry
gsell's avatar
gsell committed
115
    currentGeometry = geometries_m[0];
frey_m's avatar
frey_m committed
116 117 118 119 120
    if (currentGeometry->getFilename() == "") {
        if (currentGeometry->getTopology() == "ELLIPTIC"){
            bp_m = std::unique_ptr<IrregularDomain>(
                new EllipticDomain(currentGeometry, orig_nr_m, hr_m, interpl));

kraus's avatar
kraus committed
121
        } else if (currentGeometry->getTopology() == "BOXCORNER") {
frey_m's avatar
frey_m committed
122 123 124 125 126 127 128 129
            bp_m = std::unique_ptr<IrregularDomain>(
                new BoxCornerDomain(currentGeometry->getA(),
                                    currentGeometry->getB(),
                                    currentGeometry->getC(),
                                    currentGeometry->getLength(),
                                    currentGeometry->getL1(),
                                    currentGeometry->getL2(),
                                    orig_nr_m, hr_m, interpl));
frey_m's avatar
frey_m committed
130
            bp_m->compute(itsBunch_m->get_hr());
gsell's avatar
gsell committed
131
        } else {
132 133
            throw OpalException("MGPoissonSolver::MGPoissonSolver",
                                "Geometry not known");
gsell's avatar
gsell committed
134
        }
135 136 137 138 139 140 141 142 143 144
    } else {
        NDIndex<3> localId = layout_m->getLocalNDIndex();
        if (localId[0].length() != domain_m[0].length() ||
            localId[1].length() != domain_m[1].length()) {
            throw OpalException("ArbitraryDomain::compute",
                                "The class ArbitraryDomain only works with parallelization\n"
                                "in z-direction.\n"
                                "Please set PARFFTX=FALSE, PARFFTY=FALSE, PARFFTT=TRUE in \n"
                                "the definition of the field solver in the input file.\n");
        }
frey_m's avatar
frey_m committed
145 146
        bp_m = std::unique_ptr<IrregularDomain>(
            new ArbitraryDomain(currentGeometry, orig_nr_m, hr_m, interpl));
147
    }
148

149
    map_p = Teuchos::null;
gsell's avatar
gsell committed
150 151 152
    A = Teuchos::null;
    LHS = Teuchos::null;
    RHS = Teuchos::null;
153
    prec_mp = Teuchos::null;
154

gsell's avatar
gsell committed
155 156
    numBlocks_m = Options::numBlocks;
    recycleBlocks_m = Options::recycleBlocks;
157
    nLHS_m = Options::nLHS;
frey_m's avatar
frey_m committed
158
    setupMueLuList();
frey_m's avatar
frey_m committed
159
    setupBelosList();
160
    problem_mp = rcp(new Belos::LinearProblem<TpetraScalar_t, TpetraMultiVector_t, TpetraOperator_t>);
161
    // setup Belos solver
frey_m's avatar
frey_m committed
162
    if (numBlocks_m == 0 || recycleBlocks_m == 0)
163
        solver_mp = rcp(new Belos::BlockCGSolMgr<TpetraScalar_t, TpetraMultiVector_t, TpetraOperator_t>());
gsell's avatar
gsell committed
164
    else
165 166 167
        solver_mp = rcp(new Belos::RCGSolMgr<TpetraScalar_t, TpetraMultiVector_t, TpetraOperator_t>());
    solver_mp->setParameters(rcp(&belosList, false));
    convStatusTest = rcp(new Belos::StatusTestGenResNorm<TpetraScalar_t, TpetraMultiVector_t, TpetraOperator_t> (tol));
gsell's avatar
gsell committed
168 169 170
    convStatusTest->defineScaleForm(Belos::NormOfRHS, Belos::TwoNorm);

    //all timers used here
171 172 173 174
    FunctionTimer1_m = IpplTimings::getTimer("BGF-IndexCoordMap");
    FunctionTimer2_m = IpplTimings::getTimer("computeMap");
    FunctionTimer3_m = IpplTimings::getTimer("IPPL to RHS");
    FunctionTimer4_m = IpplTimings::getTimer("ComputeStencil");
frey_m's avatar
frey_m committed
175
    FunctionTimer5_m = IpplTimings::getTimer("MueLu");
176 177 178
    FunctionTimer6_m = IpplTimings::getTimer("Setup");
    FunctionTimer7_m = IpplTimings::getTimer("CG");
    FunctionTimer8_m = IpplTimings::getTimer("LHS to IPPL");
gsell's avatar
gsell committed
179 180
}

181
void MGPoissonSolver::deletePtr() {
182
    map_p  = Teuchos::null;
183 184 185
    A      = Teuchos::null;
    LHS    = Teuchos::null;
    RHS    = Teuchos::null;
186
    prec_mp = Teuchos::null;
187 188
}

189 190
MGPoissonSolver::~MGPoissonSolver() {
    deletePtr ();
191 192
    solver_mp = Teuchos::null;
    problem_mp = Teuchos::null;
gsell's avatar
gsell committed
193 194
}

195
void MGPoissonSolver::computePotential(Field_t& /*rho*/, Vector_t /*hr*/, double /*zshift*/) {
gsell's avatar
gsell committed
196 197 198
    throw OpalException("MGPoissonSolver", "not implemented yet");
}

199
void MGPoissonSolver::computeMap(NDIndex<3> localId) {
200
    if (itsBunch_m->getLocalTrackStep()%repartFreq_m == 0){
201
        deletePtr();
frey_m's avatar
frey_m committed
202
        IPPLToMap3D(localId);
203 204

        extrapolateLHS();
205 206
    }
}
gsell's avatar
gsell committed
207

208 209 210 211 212
void MGPoissonSolver::extrapolateLHS() {
// Aitken-Neville
// Pi0 (x) := yi , i = 0 : n
// Pik (x) := (x − xi ) Pi+1,k−1(x) − (x − xi+k ) Pi,k−1(x) /(xi+k − xi )
// k = 1, . . . , n, i = 0, . . . , n − k.
213
    //we also have to redistribute LHS
214

215
    if (Teuchos::is_null(LHS)){
216 217
        LHS = rcp(new TpetraVector_t(map_p));
        LHS->putScalar(1.0);
218
    } else {
219 220 221
        RCP<TpetraVector_t> tmplhs = rcp(new TpetraVector_t(map_p));
        Tpetra::Import<> importer(map_p, LHS->getMap());
        tmplhs->doImport(*LHS, importer, Tpetra::CombineMode::ADD);
222 223
        LHS = tmplhs;
    }
gsell's avatar
gsell committed
224

225
    //...and all previously saved LHS
226
    std::deque< TpetraVector_t >::iterator it = OldLHS.begin();
frey_m's avatar
frey_m committed
227
    if (OldLHS.size() > 0) {
228
        int n = OldLHS.size();
frey_m's avatar
frey_m committed
229
        for (int i = 0; i < n; ++i) {
230 231 232
            TpetraVector_t tmplhs = TpetraVector_t(map_p);
            Tpetra::Import<> importer(map_p, it->getMap());
            tmplhs.doImport(*it, importer, Tpetra::CombineMode::ADD);
233 234 235 236
            *it = tmplhs;
            ++it;
        }
    }
gsell's avatar
gsell committed
237

238 239
    // extrapolate last OldLHS.size LHS to get a new start vector
    it = OldLHS.begin();
frey_m's avatar
frey_m committed
240
    if (nLHS_m == 0 || OldLHS.size()==0)
241
        LHS->putScalar(1.0);
frey_m's avatar
frey_m committed
242
    else if (OldLHS.size() == 1)
243
        *LHS = *it;
frey_m's avatar
frey_m committed
244
    else if (OldLHS.size() == 2)
245
        LHS->update(2.0, *it++, -1.0, *it, 0.0);
frey_m's avatar
frey_m committed
246
    else if (OldLHS.size() > 2) {
247
        int n = OldLHS.size();
248
        P_mp = rcp(new TpetraMultiVector_t(map_p, nLHS_m, false));
frey_m's avatar
frey_m committed
249
        for (int i = 0; i < n; ++i) {
250
           *(P_mp->getVectorNonConst(i)) = *it++;
251
        }
frey_m's avatar
frey_m committed
252 253
        for (int k = 1; k < n; ++k) {
           for (int i = 0; i < n - k; ++i) {
254
              P_mp->getVectorNonConst(i)->update(-(i + 1) / (float)k, *(P_mp->getVector(i + 1)), (i + k + 1) / (float)k);
255
           }
256
        }
257
        *LHS = *(P_mp->getVector(0));
258
     } else
frey_m's avatar
frey_m committed
259 260
        throw OpalException("MGPoissonSolver",
                            "Invalid number of old LHS: " + std::to_string(OldLHS.size()));
gsell's avatar
gsell committed
261 262
}

263

gsell's avatar
gsell committed
264 265
// given a charge-density field rho and a set of mesh spacings hr,
// compute the electric field and put in eg by solving the Poisson's equation
frey_m's avatar
frey_m committed
266
// XXX: use matrix stencil in computation directly (no Tpetra, define operators
gsell's avatar
gsell committed
267 268
// on IPPL GRID)
void MGPoissonSolver::computePotential(Field_t &rho, Vector_t hr) {
269

kraus's avatar
kraus committed
270
    Inform msg("OPAL ", INFORM_ALL_NODES);
gsell's avatar
gsell committed
271 272 273
    nr_m[0] = orig_nr_m[0];
    nr_m[1] = orig_nr_m[1];
    nr_m[2] = orig_nr_m[2];
274

frey_m's avatar
frey_m committed
275 276 277
    bp_m->setGlobalMeanR(itsBunch_m->getGlobalMeanR());
    bp_m->setGlobalToLocalQuaternion(itsBunch_m->getGlobalToLocalQuaternion());
    bp_m->setNr(nr_m);
278

279 280
    NDIndex<3> localId = layout_m->getLocalNDIndex();

281
    IpplTimings::startTimer(FunctionTimer1_m);
282
    // Compute boundary intersections (only do on the first step)
frey_m's avatar
frey_m committed
283
    if (!itsBunch_m->getLocalTrackStep())
frey_m's avatar
frey_m committed
284
        bp_m->compute(hr, localId);
285
    IpplTimings::stopTimer(FunctionTimer1_m);
286 287

    // Define the Map
kraus's avatar
kraus committed
288
    INFOMSG(level3 << "* Computing Map..." << endl);
289
    IpplTimings::startTimer(FunctionTimer2_m);
290
    computeMap(localId);
291
    IpplTimings::stopTimer(FunctionTimer2_m);
kraus's avatar
kraus committed
292
    INFOMSG(level3 << "* Done." << endl);
gsell's avatar
gsell committed
293

frey_m's avatar
frey_m committed
294
    // Allocate the RHS with the new Tpetra Map
295
    if (Teuchos::is_null(RHS))
296 297
        RHS = rcp(new TpetraVector_t(map_p));
    RHS->putScalar(0.0);
298

frey_m's avatar
frey_m committed
299
    // get charge densities from IPPL field and store in Tpetra vector (RHS)
kraus's avatar
kraus committed
300 301 302 303 304
    if (verbose_m) {
        Ippl::Comm->barrier();
        msg << "* Node:" << Ippl::myNode() << ", Filling RHS..." << endl;
        Ippl::Comm->barrier();
    }
305 306
    IpplTimings::startTimer(FunctionTimer3_m);
    int id = 0;
307
    float scaleFactor = itsBunch_m->getdT();
308

309

kraus's avatar
kraus committed
310
    if (verbose_m) {
frey_m's avatar
frey_m committed
311 312 313
        msg << "* Node:" << Ippl::myNode() << ", Rho for final element: "
            << rho[localId[0].last()][localId[1].last()][localId[2].last()].get()
            << endl;
314

kraus's avatar
kraus committed
315
        Ippl::Comm->barrier();
frey_m's avatar
frey_m committed
316 317 318 319 320
        msg << "* Node:" << Ippl::myNode() << ", Local nx*ny*nz = "
            <<  localId[2].last() *  localId[0].last() *  localId[1].last()
            << endl;
        msg << "* Node:" << Ippl::myNode()
            << ", Number of reserved local elements in RHS: "
321
            << RHS->getLocalLength() << endl;
frey_m's avatar
frey_m committed
322 323
        msg << "* Node:" << Ippl::myNode()
            << ", Number of reserved global elements in RHS: "
324
            << RHS->getGlobalLength() << endl;
kraus's avatar
kraus committed
325 326
        Ippl::Comm->barrier();
    }
327
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
328
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
kraus's avatar
kraus committed
329
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
330
                if (bp_m->isInside(idx, idy, idz))
331
                        RHS->getDataNonConst()[id++] = 4*M_PI*rho[idx][idy][idz].get()/scaleFactor;
gsell's avatar
gsell committed
332 333 334
            }
        }
    }
335

336
    IpplTimings::stopTimer(FunctionTimer3_m);
kraus's avatar
kraus committed
337 338
    if (verbose_m) {
        Ippl::Comm->barrier();
frey_m's avatar
frey_m committed
339 340
        msg << "* Node:" << Ippl::myNode()
            << ", Number of Local Inside Points " << id << endl;
kraus's avatar
kraus committed
341 342 343
        msg << "* Node:" << Ippl::myNode() << ", Done." << endl;
        Ippl::Comm->barrier();
    }
gsell's avatar
gsell committed
344
    // build discretization matrix
kraus's avatar
kraus committed
345
    INFOMSG(level3 << "* Building Discretization Matrix..." << endl);
346
    IpplTimings::startTimer(FunctionTimer4_m);
frey_m's avatar
frey_m committed
347
    if (Teuchos::is_null(A))
348
        A = rcp(new TpetraCrsMatrix_t(map_p,  7, Tpetra::StaticProfile));
349
    ComputeStencil(hr, RHS);
350
    IpplTimings::stopTimer(FunctionTimer4_m);
kraus's avatar
kraus committed
351
    INFOMSG(level3 << "* Done." << endl);
352

gsell's avatar
gsell committed
353
#ifdef DBG_STENCIL
frey_m's avatar
frey_m committed
354 355
    Tpetra::MatrixMarket::Writer<TpetraCrsMatrix_t>::writeSparseFile(
        "DiscrStencil.dat", A);
gsell's avatar
gsell committed
356
#endif
357

kraus's avatar
kraus committed
358
    INFOMSG(level3 << "* Computing Preconditioner..." << endl);
359
    IpplTimings::startTimer(FunctionTimer5_m);
frey_m's avatar
frey_m committed
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    if (Teuchos::is_null(prec_mp)) {
        Teuchos::RCP<TpetraOperator_t> At = Teuchos::rcp_dynamic_cast<TpetraOperator_t>(A);
        prec_mp = MueLu::CreateTpetraPreconditioner(At, MueLuList_m);
    }

    switch (precmode_m) {
        case REUSE_PREC:
        case REUSE_HIERARCHY: {
            MueLu::ReuseTpetraPreconditioner(A, *prec_mp);
            break;
        }
        case NO:
        case STD_PREC:
        default: {
            Teuchos::RCP<TpetraOperator_t> At = Teuchos::rcp_dynamic_cast<TpetraOperator_t>(A);
            prec_mp = MueLu::CreateTpetraPreconditioner(At, MueLuList_m);
            break;
        }
378
    }
379
    IpplTimings::stopTimer(FunctionTimer5_m);
kraus's avatar
kraus committed
380
    INFOMSG(level3 << "* Done." << endl);
381

gsell's avatar
gsell committed
382 383
    // setup preconditioned iterative solver
    // use old LHS solution as initial guess
kraus's avatar
kraus committed
384
    INFOMSG(level3 << "* Final Setup of Solver..." << endl);
385
    IpplTimings::startTimer(FunctionTimer6_m);
386 387 388 389 390 391 392
    problem_mp->setOperator(A);
    problem_mp->setLHS(LHS);
    problem_mp->setRHS(RHS);
    problem_mp->setLeftPrec(prec_mp);
    solver_mp->setProblem( problem_mp);
    if (!problem_mp->isProblemSet()) {
        if (problem_mp->setProblem() == false) {
393
            ERRORMSG("Belos::LinearProblem failed to set up correctly!" << endl);
394
        }
gsell's avatar
gsell committed
395
    }
396
    IpplTimings::stopTimer(FunctionTimer6_m);
kraus's avatar
kraus committed
397
    INFOMSG(level3 << "* Done." << endl);
398

gsell's avatar
gsell committed
399 400
    double time = MPI_Wtime();

kraus's avatar
kraus committed
401
    INFOMSG(level3 << "* Solving for Space Charge..." << endl);
402
    IpplTimings::startTimer(FunctionTimer7_m);
403
    solver_mp->solve();
404
    IpplTimings::stopTimer(FunctionTimer7_m);
kraus's avatar
kraus committed
405
    INFOMSG(level3 << "* Done." << endl);
gsell's avatar
gsell committed
406

kraus's avatar
kraus committed
407 408 409
    std::ofstream timings;
    if (true || verbose_m) {
        time = MPI_Wtime() - time;
410
        double minTime = 0, maxTime = 0, avgTime = 0;
411 412 413
        reduce(time, minTime, 1, std::less<double>());
        reduce(time, maxTime, 1, std::greater<double>());
        reduce(time, avgTime, 1, std::plus<double>());
414 415
        avgTime /= comm_mp->getSize();
        if (comm_mp->getRank() == 0) {
kraus's avatar
kraus committed
416
            char filename[50];
frey_m's avatar
frey_m committed
417 418
            sprintf(filename, "timing_MX%d_MY%d_MZ%d_nProc%d_recB%d_numB%d_nLHS%d",
                    orig_nr_m[0], orig_nr_m[1], orig_nr_m[2],
419
                    comm_mp->getSize(), recycleBlocks_m, numBlocks_m, nLHS_m);
frey_m's avatar
frey_m committed
420

kraus's avatar
kraus committed
421
            timings.open(filename, std::ios::app);
422
            timings << solver_mp->getNumIters() << "\t"
kraus's avatar
kraus committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436
                    //<< time <<" "<<
                    << minTime << "\t"
                    << maxTime << "\t"
                    << avgTime << "\t"
                    << numBlocks_m << "\t"
                    << recycleBlocks_m << "\t"
                    << nLHS_m << "\t"
                    //<< OldLHS.size() <<"\t"<<
                    << std::endl;

            timings.close();
        }

    }
gsell's avatar
gsell committed
437
    // Store new LHS in OldLHS
frey_m's avatar
frey_m committed
438 439
    if (nLHS_m > 1) OldLHS.push_front(*(LHS.get()));
    if (OldLHS.size() > nLHS_m) OldLHS.pop_back();
gsell's avatar
gsell committed
440 441

    //now transfer solution back to IPPL grid
442 443
    IpplTimings::startTimer(FunctionTimer8_m);
    id = 0;
gsell's avatar
gsell committed
444
    rho = 0.0;
445
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
446
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
kraus's avatar
kraus committed
447
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
448
                  NDIndex<3> l(Index(idx, idx), Index(idy, idy), Index(idz, idz));
frey_m's avatar
frey_m committed
449
                  if (bp_m->isInside(idx, idy, idz))
450
                     rho.localElement(l) = LHS->getData()[id++] * scaleFactor;
gsell's avatar
gsell committed
451 452 453
            }
        }
    }
454
    IpplTimings::stopTimer(FunctionTimer8_m);
455

frey_m's avatar
frey_m committed
456
    if (itsBunch_m->getLocalTrackStep()+1 == (long long)Track::block->localTimeSteps.front()) {
457 458 459
        A = Teuchos::null;
        LHS = Teuchos::null;
        RHS = Teuchos::null;
460
        prec_mp = Teuchos::null;
461
    }
gsell's avatar
gsell committed
462 463 464
}


465
void MGPoissonSolver::IPPLToMap3D(NDIndex<3> localId) {
466

gsell's avatar
gsell committed
467
    int NumMyElements = 0;
468
    std::vector<int> MyGlobalElements;
gsell's avatar
gsell committed
469

470
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
471
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
472
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
473 474
                if (bp_m->isInside(idx, idy, idz)) {
                    MyGlobalElements.push_back(bp_m->getIdx(idx, idy, idz));
gsell's avatar
gsell committed
475 476 477
                    NumMyElements++;
                }
            }
kraus's avatar
kraus committed
478
        }
479
    }
480 481 482
    int indexbase = 0;
    map_p = Teuchos::rcp(new TpetraMap_t(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),
                                         &MyGlobalElements[0], NumMyElements, indexbase, comm_mp));
gsell's avatar
gsell committed
483 484
}

485
void MGPoissonSolver::ComputeStencil(Vector_t /*hr*/, Teuchos::RCP<TpetraVector_t> RHS) {
gsell's avatar
gsell committed
486

frey_m's avatar
frey_m committed
487
    A->resumeFill();
488
    A->setAllToScalar(0.0);
489

490 491
    int NumMyElements = map_p->getNodeNumElements();
    auto MyGlobalElements = map_p->getMyGlobalIndices();
gsell's avatar
gsell committed
492

493 494
    std::vector<double> Values(6);
    std::vector<int> Indices(6);
gsell's avatar
gsell committed
495

frey_m's avatar
frey_m committed
496
    for (int i = 0 ; i < NumMyElements ; i++) {
gsell's avatar
gsell committed
497 498 499

        int NumEntries = 0;

500
        double WV, EV, SV, NV, FV, BV, CV, scaleFactor=1.0;
501
        int W, E, S, N, F, B;
gsell's avatar
gsell committed
502

frey_m's avatar
frey_m committed
503
        bp_m->getBoundaryStencil(MyGlobalElements[i], WV, EV, SV, NV, FV, BV, CV, scaleFactor);
504
        RHS->scale(scaleFactor);
gsell's avatar
gsell committed
505

frey_m's avatar
frey_m committed
506
        bp_m->getNeighbours(MyGlobalElements[i], W, E, S, N, F, B);
frey_m's avatar
frey_m committed
507
        if (E != -1) {
gsell's avatar
gsell committed
508 509 510
            Indices[NumEntries] = E;
            Values[NumEntries++] = EV;
        }
frey_m's avatar
frey_m committed
511
        if (W != -1) {
gsell's avatar
gsell committed
512 513 514
            Indices[NumEntries] = W;
            Values[NumEntries++] = WV;
        }
frey_m's avatar
frey_m committed
515
        if (S != -1) {
gsell's avatar
gsell committed
516 517 518
            Indices[NumEntries] = S;
            Values[NumEntries++] = SV;
        }
frey_m's avatar
frey_m committed
519
        if (N != -1) {
gsell's avatar
gsell committed
520 521 522
            Indices[NumEntries] = N;
            Values[NumEntries++] = NV;
        }
frey_m's avatar
frey_m committed
523
        if (F != -1) {
gsell's avatar
gsell committed
524 525 526
            Indices[NumEntries] = F;
            Values[NumEntries++] = FV;
        }
frey_m's avatar
frey_m committed
527
        if (B != -1) {
gsell's avatar
gsell committed
528 529 530 531
            Indices[NumEntries] = B;
            Values[NumEntries++] = BV;
        }

532
        // if matrix has already been filled (fillComplete()) we can only
gsell's avatar
gsell committed
533
        // replace entries
534

frey_m's avatar
fix bug  
frey_m committed
535
        if (isMatrixfilled_m) {
536
            // off-diagonal entries
537
            A->replaceGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
538
            // diagonal entry
539
            A->replaceGlobalValues(MyGlobalElements[i], 1, &CV, &MyGlobalElements[i]);
540
        } else {
gsell's avatar
gsell committed
541
            // off-diagonal entries
542
            A->insertGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
gsell's avatar
gsell committed
543
            // diagonal entry
544
            A->insertGlobalValues(MyGlobalElements[i], 1, &CV, &MyGlobalElements[i]);
545
        }
gsell's avatar
gsell committed
546 547
    }

548 549 550
    RCP<ParameterList_t> params = Teuchos::parameterList();
    params->set ("Optimize Storage", true);
    A->fillComplete(params);
frey_m's avatar
fix bug  
frey_m committed
551
    isMatrixfilled_m = true;
gsell's avatar
gsell committed
552 553 554 555 556
}

void MGPoissonSolver::printLoadBalanceStats() {

    //compute some load balance statistics
557 558
    size_t myNumPart = map_p->getNodeNumElements();
    size_t NumPart = map_p->getGlobalNumElements() * 1.0 / comm_mp->getSize();
gsell's avatar
gsell committed
559
    double imbalance = 1.0;
frey_m's avatar
frey_m committed
560
    if (myNumPart >= NumPart)
gsell's avatar
gsell committed
561 562 563 564 565
        imbalance += (myNumPart - NumPart) / NumPart;
    else
        imbalance += (NumPart - myNumPart) / NumPart;

    double max = 0.0, min = 0.0, avg = 0.0;
frey_m's avatar
frey_m committed
566 567 568 569 570 571
    size_t minn = 0, maxn = 0;
    reduce(imbalance, min, 1, std::less<double>());
    reduce(imbalance, max, 1, std::greater<double>());
    reduce(imbalance, avg, 1, std::plus<double>());
    reduce(myNumPart, minn, 1, std::less<size_t>());
    reduce(myNumPart, maxn, 1, std::greater<size_t>());
gsell's avatar
gsell committed
572

573
    avg /= comm_mp->getSize();
kraus's avatar
kraus committed
574 575
    *gmsg << "LBAL min = " << min << ", max = " << max << ", avg = " << avg << endl;
    *gmsg << "min nr gridpoints = " << minn << ", max nr gridpoints = " << maxn << endl;
gsell's avatar
gsell committed
576 577 578 579 580 581
}

Inform &MGPoissonSolver::print(Inform &os) const {
    os << "* *************** M G P o i s s o n S o l v e r ************************************ " << endl;
    os << "* h " << hr_m << '\n';
    os << "* ********************************************************************************** " << endl;
582
    return os;
gsell's avatar
gsell committed
583 584
}

585 586 587 588 589 590 591
// vi: set et ts=4 sw=4 sts=4:
// Local Variables:
// mode:c
// c-basic-offset: 4
// indent-tabs-mode: nil
// require-final-newline: nil
// End: