MGPoissonSolver.cpp 23.6 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;
gsell's avatar
gsell committed
109
    useRCB_m = false;
frey_m's avatar
frey_m committed
110
    if (Ippl::Info->getOutputLevel() > 3)
gsell's avatar
gsell committed
111 112 113 114
        verbose_m = true;
    else
        verbose_m = false;

115
    // Find CURRENT geometry
gsell's avatar
gsell committed
116
    currentGeometry = geometries_m[0];
frey_m's avatar
frey_m committed
117 118 119 120 121
    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
122
        } else if (currentGeometry->getTopology() == "BOXCORNER") {
frey_m's avatar
frey_m committed
123 124 125 126 127 128 129 130
            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
131
            bp_m->compute(itsBunch_m->get_hr());
gsell's avatar
gsell committed
132
        } else {
133 134
            throw OpalException("MGPoissonSolver::MGPoissonSolver",
                                "Geometry not known");
gsell's avatar
gsell committed
135
        }
136 137 138 139 140 141 142 143 144 145
    } 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
146 147
        bp_m = std::unique_ptr<IrregularDomain>(
            new ArbitraryDomain(currentGeometry, orig_nr_m, hr_m, interpl));
148
    }
149

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

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

    //all timers used here
172 173 174 175
    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
176
    FunctionTimer5_m = IpplTimings::getTimer("MueLu");
177 178 179
    FunctionTimer6_m = IpplTimings::getTimer("Setup");
    FunctionTimer7_m = IpplTimings::getTimer("CG");
    FunctionTimer8_m = IpplTimings::getTimer("LHS to IPPL");
gsell's avatar
gsell committed
180 181
}

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

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

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

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

        extrapolateLHS();
209 210
    }
}
gsell's avatar
gsell committed
211

212 213 214 215 216
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.
217
    //we also have to redistribute LHS
218

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

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

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

267

gsell's avatar
gsell committed
268 269
// 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
270
// XXX: use matrix stencil in computation directly (no Tpetra, define operators
gsell's avatar
gsell committed
271 272
// on IPPL GRID)
void MGPoissonSolver::computePotential(Field_t &rho, Vector_t hr) {
273

kraus's avatar
kraus committed
274
    Inform msg("OPAL ", INFORM_ALL_NODES);
gsell's avatar
gsell committed
275 276 277
    nr_m[0] = orig_nr_m[0];
    nr_m[1] = orig_nr_m[1];
    nr_m[2] = orig_nr_m[2];
278

frey_m's avatar
frey_m committed
279 280 281
    bp_m->setGlobalMeanR(itsBunch_m->getGlobalMeanR());
    bp_m->setGlobalToLocalQuaternion(itsBunch_m->getGlobalToLocalQuaternion());
    bp_m->setNr(nr_m);
282

283 284
    NDIndex<3> localId = layout_m->getLocalNDIndex();

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

    // Define the Map
kraus's avatar
kraus committed
292
    INFOMSG(level3 << "* Computing Map..." << endl);
293
    IpplTimings::startTimer(FunctionTimer2_m);
294
    computeMap(localId);
295
    IpplTimings::stopTimer(FunctionTimer2_m);
kraus's avatar
kraus committed
296
    INFOMSG(level3 << "* Done." << endl);
gsell's avatar
gsell committed
297

frey_m's avatar
frey_m committed
298
    // Allocate the RHS with the new Tpetra Map
299
    if (Teuchos::is_null(RHS))
300 301
        RHS = rcp(new TpetraVector_t(map_p));
    RHS->putScalar(0.0);
302

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

313

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

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

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

gsell's avatar
gsell committed
357
#ifdef DBG_STENCIL
frey_m's avatar
frey_m committed
358 359
    Tpetra::MatrixMarket::Writer<TpetraCrsMatrix_t>::writeSparseFile(
        "DiscrStencil.dat", A);
gsell's avatar
gsell committed
360
#endif
361

kraus's avatar
kraus committed
362
    INFOMSG(level3 << "* Computing Preconditioner..." << endl);
363
    IpplTimings::startTimer(FunctionTimer5_m);
frey_m's avatar
frey_m committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    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);
            MueLuList_m.set("reuse: type", "none");
            break;
        }
383
    }
384
    IpplTimings::stopTimer(FunctionTimer5_m);
kraus's avatar
kraus committed
385
    INFOMSG(level3 << "* Done." << endl);
386

gsell's avatar
gsell committed
387 388
    // setup preconditioned iterative solver
    // use old LHS solution as initial guess
kraus's avatar
kraus committed
389
    INFOMSG(level3 << "* Final Setup of Solver..." << endl);
390
    IpplTimings::startTimer(FunctionTimer6_m);
391 392 393 394 395 396 397
    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) {
398
            ERRORMSG("Belos::LinearProblem failed to set up correctly!" << endl);
399
        }
gsell's avatar
gsell committed
400
    }
401
    IpplTimings::stopTimer(FunctionTimer6_m);
kraus's avatar
kraus committed
402
    INFOMSG(level3 << "* Done." << endl);
403

gsell's avatar
gsell committed
404 405
    double time = MPI_Wtime();

kraus's avatar
kraus committed
406
    INFOMSG(level3 << "* Solving for Space Charge..." << endl);
407
    IpplTimings::startTimer(FunctionTimer7_m);
408
    solver_mp->solve();
409
    IpplTimings::stopTimer(FunctionTimer7_m);
kraus's avatar
kraus committed
410
    INFOMSG(level3 << "* Done." << endl);
gsell's avatar
gsell committed
411

kraus's avatar
kraus committed
412 413 414
    std::ofstream timings;
    if (true || verbose_m) {
        time = MPI_Wtime() - time;
415
        double minTime = 0, maxTime = 0, avgTime = 0;
416 417 418
        reduce(time, minTime, 1, std::less<double>());
        reduce(time, maxTime, 1, std::greater<double>());
        reduce(time, avgTime, 1, std::plus<double>());
419 420
        avgTime /= comm_mp->getSize();
        if (comm_mp->getRank() == 0) {
kraus's avatar
kraus committed
421
            char filename[50];
frey_m's avatar
frey_m committed
422 423
            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],
424
                    comm_mp->getSize(), recycleBlocks_m, numBlocks_m, nLHS_m);
frey_m's avatar
frey_m committed
425

kraus's avatar
kraus committed
426
            timings.open(filename, std::ios::app);
427
            timings << solver_mp->getNumIters() << "\t"
kraus's avatar
kraus committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441
                    //<< 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
442
    // Store new LHS in OldLHS
frey_m's avatar
frey_m committed
443 444
    if (nLHS_m > 1) OldLHS.push_front(*(LHS.get()));
    if (OldLHS.size() > nLHS_m) OldLHS.pop_back();
gsell's avatar
gsell committed
445 446

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

frey_m's avatar
frey_m committed
461
    if (itsBunch_m->getLocalTrackStep()+1 == (long long)Track::block->localTimeSteps.front()) {
462 463 464
        A = Teuchos::null;
        LHS = Teuchos::null;
        RHS = Teuchos::null;
465
        prec_mp = Teuchos::null;
466
    }
gsell's avatar
gsell committed
467 468 469
}


470
void MGPoissonSolver::redistributeWithRCB(NDIndex<3> localId) {
gsell's avatar
gsell committed
471 472 473

    int numMyGridPoints = 0;

474
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
475
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
kraus's avatar
kraus committed
476
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
477
                if (bp_m->isInside(idx, idy, idz))
gsell's avatar
gsell committed
478
                    numMyGridPoints++;
479
             }
gsell's avatar
gsell committed
480
        }
481
     }
gsell's avatar
gsell committed
482

483
    int indexbase = 0;
frey_m's avatar
frey_m committed
484 485 486 487
    Teuchos::RCP<TpetraMap_t> bmap = Teuchos::rcp(
        new TpetraMap_t(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),
                        numMyGridPoints, indexbase, comm_mp));

488 489
    Teuchos::RCP<const TpetraMultiVector_t> coords = Teuchos::rcp(
        new TpetraMultiVector_t(bmap, 3, false));
gsell's avatar
gsell committed
490

frey_m's avatar
frey_m committed
491
    size_t localRow = 0;
492
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
493
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
kraus's avatar
kraus committed
494
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
495
                if (bp_m->isInside(idx, idy, idz)) {
frey_m's avatar
frey_m committed
496 497 498 499
                    coords->replaceLocalValue(localRow, 0, idx);
                    coords->replaceLocalValue(localRow, 1, idy);
                    coords->replaceLocalValue(localRow, 2, idz);
                    localRow++;
gsell's avatar
gsell committed
500 501 502 503 504
                }
            }
        }
    }

frey_m's avatar
frey_m committed
505 506 507 508 509
//     Teuchos::ParameterList paramlist;
//     paramlist.set("Partitioning Method", "RCB");
//     Teuchos::ParameterList &sublist = paramlist.sublist("ZOLTAN");
//     sublist.set("RCB_RECTILINEAR_BLOCKS", "1");
//     sublist.set("DEBUG_LEVEL", "1");
gsell's avatar
gsell committed
510

511 512
    /*
     * FIXME
frey_m's avatar
frey_m committed
513 514 515
    Teuchos::RCP<Isorropia::Epetra::Partitioner> part = Teuchos::rcp(
        new Isorropia::Epetra::Partitioner(coords, paramlist));

gsell's avatar
gsell committed
516
    Isorropia::Epetra::Redistributor rd(part);
517
    Teuchos::RCP<TpetraMultiVector_t> newcoords = rd.redistribute(*coords);
gsell's avatar
gsell committed
518

519
    newcoords->extractView(&v, &stride);
gsell's avatar
gsell committed
520 521
    stride2 = 2 * stride;
    numMyGridPoints = 0;
522
    */
gsell's avatar
gsell committed
523
    std::vector<int> MyGlobalElements;
524 525
    /* FIXME
    for (unsigned int i = 0; i < newcoords->getLocalLength(); i++) {
frey_m's avatar
frey_m committed
526
        MyGlobalElements.push_back(bp_m->getIdx(v[0], v[stride], v[stride2]));
gsell's avatar
gsell committed
527 528 529
        v++;
        numMyGridPoints++;
    }
530 531 532
*/
    map_p = Teuchos::rcp(new TpetraMap_t(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),
                                         &MyGlobalElements[0], numMyGridPoints, indexbase, comm_mp));
gsell's avatar
gsell committed
533 534
}

535
void MGPoissonSolver::IPPLToMap3D(NDIndex<3> localId) {
536

gsell's avatar
gsell committed
537
    int NumMyElements = 0;
538
    std::vector<int> MyGlobalElements;
gsell's avatar
gsell committed
539

540
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
541
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
542
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
543 544
                if (bp_m->isInside(idx, idy, idz)) {
                    MyGlobalElements.push_back(bp_m->getIdx(idx, idy, idz));
gsell's avatar
gsell committed
545 546 547
                    NumMyElements++;
                }
            }
kraus's avatar
kraus committed
548
        }
549
    }
550 551 552
    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
553 554
}

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

frey_m's avatar
frey_m committed
557
    A->resumeFill();
558
    A->setAllToScalar(0.0);
559

560 561
    int NumMyElements = map_p->getNodeNumElements();
    auto MyGlobalElements = map_p->getMyGlobalIndices();
gsell's avatar
gsell committed
562

563 564
    std::vector<double> Values(6);
    std::vector<int> Indices(6);
gsell's avatar
gsell committed
565

frey_m's avatar
frey_m committed
566
    for (int i = 0 ; i < NumMyElements ; i++) {
gsell's avatar
gsell committed
567 568 569

        int NumEntries = 0;

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

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

frey_m's avatar
frey_m committed
576
        bp_m->getNeighbours(MyGlobalElements[i], W, E, S, N, F, B);
frey_m's avatar
frey_m committed
577
        if (E != -1) {
gsell's avatar
gsell committed
578 579 580
            Indices[NumEntries] = E;
            Values[NumEntries++] = EV;
        }
frey_m's avatar
frey_m committed
581
        if (W != -1) {
gsell's avatar
gsell committed
582 583 584
            Indices[NumEntries] = W;
            Values[NumEntries++] = WV;
        }
frey_m's avatar
frey_m committed
585
        if (S != -1) {
gsell's avatar
gsell committed
586 587 588
            Indices[NumEntries] = S;
            Values[NumEntries++] = SV;
        }
frey_m's avatar
frey_m committed
589
        if (N != -1) {
gsell's avatar
gsell committed
590 591 592
            Indices[NumEntries] = N;
            Values[NumEntries++] = NV;
        }
frey_m's avatar
frey_m committed
593
        if (F != -1) {
gsell's avatar
gsell committed
594 595 596
            Indices[NumEntries] = F;
            Values[NumEntries++] = FV;
        }
frey_m's avatar
frey_m committed
597
        if (B != -1) {
gsell's avatar
gsell committed
598 599 600 601
            Indices[NumEntries] = B;
            Values[NumEntries++] = BV;
        }

602
        // if matrix has already been filled (fillComplete()) we can only
gsell's avatar
gsell committed
603
        // replace entries
604

frey_m's avatar
fix bug  
frey_m committed
605
        if (isMatrixfilled_m) {
606
            // off-diagonal entries
607
            A->replaceGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
608
            // diagonal entry
609
            A->replaceGlobalValues(MyGlobalElements[i], 1, &CV, &MyGlobalElements[i]);
610
        } else {
gsell's avatar
gsell committed
611
            // off-diagonal entries
612
            A->insertGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
gsell's avatar
gsell committed
613
            // diagonal entry
614
            A->insertGlobalValues(MyGlobalElements[i], 1, &CV, &MyGlobalElements[i]);
615
        }
gsell's avatar
gsell committed
616 617
    }

618 619 620
    RCP<ParameterList_t> params = Teuchos::parameterList();
    params->set ("Optimize Storage", true);
    A->fillComplete(params);
frey_m's avatar
fix bug  
frey_m committed
621
    isMatrixfilled_m = true;
gsell's avatar
gsell committed
622 623 624 625 626
}

void MGPoissonSolver::printLoadBalanceStats() {

    //compute some load balance statistics
627 628
    size_t myNumPart = map_p->getNodeNumElements();
    size_t NumPart = map_p->getGlobalNumElements() * 1.0 / comm_mp->getSize();
gsell's avatar
gsell committed
629
    double imbalance = 1.0;
frey_m's avatar
frey_m committed
630
    if (myNumPart >= NumPart)
gsell's avatar
gsell committed
631 632 633 634 635
        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
636 637 638 639 640 641
    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
642

643
    avg /= comm_mp->getSize();
kraus's avatar
kraus committed
644 645
    *gmsg << "LBAL min = " << min << ", max = " << max << ", avg = " << avg << endl;
    *gmsg << "min nr gridpoints = " << minn << ", max nr gridpoints = " << maxn << endl;
gsell's avatar
gsell committed
646 647 648 649 650 651
}

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;
652
    return os;
gsell's avatar
gsell committed
653 654
}

655 656 657 658 659 660 661
// 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: