MGPoissonSolver.cpp 23.7 KB
Newer Older
frey_m's avatar
frey_m committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
//
// 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,
//               2013 - 2015, Tülin Kaman, Paul Scherrer Institut, Villigen PSI, Switzerland
// All rights reserved
//
// Implemented as part of the PhD thesis
frey_m's avatar
frey_m committed
15
// "Toward massively parallel multi-objective optimization with application to
frey_m's avatar
frey_m committed
16 17 18 19 20 21 22 23 24 25 26 27
// particle accelerators" (https://doi.org/10.3929/ethz-a-009792359)
//
// 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/>.
//
28

29
//#define DBG_STENCIL
30

kraus's avatar
kraus committed
31
#include "Solvers/MGPoissonSolver.h"
32 33 34 35 36 37

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

38
#include "Track/Track.h"
gsell's avatar
gsell committed
39 40 41 42 43
#include "Physics/Physics.h"
#include "Utilities/OpalException.h"
#include "Attributes/Attributes.h"
#include "ValueDefinitions/RealVariable.h"
#include "AbstractObjects/OpalData.h"
44
#include "Utilities/Options.h"
45

46 47 48 49 50 51
// #include "Epetra_Operator.h"
// #include "EpetraExt_RowMatrixOut.h"
// #include "Epetra_Import.h"

#include <Tpetra_Import.hpp>
#include <BelosTpetraAdapter.hpp>
52 53 54 55 56

#include "Teuchos_CommandLineProcessor.hpp"

#include "BelosLinearProblem.hpp"
#include "BelosRCGSolMgr.hpp"
57
// #include "BelosEpetraAdapter.hpp"
58 59
#include "BelosBlockCGSolMgr.hpp"

60 61 62
#include <MueLu_CreateTpetraPreconditioner.hpp>
// #include <MueLu_TpetraOperator.hpp>

63 64 65 66
#include "ml_MultiLevelPreconditioner.h"
#include "ml_MultiLevelOperator.h"
#include "ml_epetra_utils.h"

67 68 69 70
// #include "Isorropia_Exception.hpp"
// #include "Isorropia_Epetra.hpp"
// #include "Isorropia_EpetraRedistributor.hpp"
// #include "Isorropia_EpetraPartitioner.hpp"
71

gsell's avatar
gsell committed
72 73
#include <algorithm>

74 75
using Teuchos::RCP;
using Teuchos::rcp;
gsell's avatar
gsell committed
76 77
using Physics::c;

78
MGPoissonSolver::MGPoissonSolver ( PartBunch *beam,
79 80 81 82 83 84 85
                                   Mesh_t *mesh,
                                   FieldLayout_t *fl,
                                   std::vector<BoundaryGeometry *> geometries,
                                   std::string itsolver,
                                   std::string interpl,
                                   double tol,
                                   int maxiters,
86 87 88 89 90 91 92 93 94
                                   std::string precmode)
    : geometries_m(geometries)
    , tol_m(tol)
    , maxiters_m(maxiters)
    , comm_mp(new Comm_t(Ippl::getComm()))
    , itsBunch_m(beam)
    , mesh_m(mesh)
    , layout_m(fl)
{
95

gsell's avatar
gsell committed
96 97
    domain_m = layout_m->getDomain();

98
    for (int i = 0; i < 3; i++) {
gsell's avatar
gsell committed
99 100 101 102
        hr_m[i] = mesh_m->get_meshSpacing(i);
        orig_nr_m[i] = domain_m[i].length();
    }

frey_m's avatar
frey_m committed
103 104 105
    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
106 107 108
    else throw OpalException("MGPoissonSolver", "No valid iterative solver selected!");

    precmode_m = STD_PREC;
frey_m's avatar
frey_m committed
109 110 111 112
    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
113 114 115 116 117 118

    tolerableIterationsCount_m = 2;
    numIter_m = -1;
    forcePreconditionerRecomputation_m = false;

    hasParallelDecompositionChanged_m = true;
119
    repartFreq_m = 1000;
gsell's avatar
gsell committed
120
    useRCB_m = false;
frey_m's avatar
frey_m committed
121
    if (Ippl::Info->getOutputLevel() > 3)
gsell's avatar
gsell committed
122 123 124 125
        verbose_m = true;
    else
        verbose_m = false;

126
    // Find CURRENT geometry
gsell's avatar
gsell committed
127
    currentGeometry = geometries_m[0];
frey_m's avatar
frey_m committed
128 129 130 131 132
    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
133
        } else if (currentGeometry->getTopology() == "BOXCORNER") {
frey_m's avatar
frey_m committed
134 135 136 137 138 139 140 141
            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
142
            bp_m->compute(itsBunch_m->get_hr());
gsell's avatar
gsell committed
143
        } else {
144 145
            throw OpalException("MGPoissonSolver::MGPoissonSolver",
                                "Geometry not known");
gsell's avatar
gsell committed
146
        }
147 148 149 150 151 152 153 154 155 156
    } 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
157 158
        bp_m = std::unique_ptr<IrregularDomain>(
            new ArbitraryDomain(currentGeometry, orig_nr_m, hr_m, interpl));
159
    }
160

161
    map_p = Teuchos::null;
gsell's avatar
gsell committed
162 163 164
    A = Teuchos::null;
    LHS = Teuchos::null;
    RHS = Teuchos::null;
165 166
    MueLuPrec = Teuchos::null;
    prec_mp = Teuchos::null;
167

gsell's avatar
gsell committed
168 169
    numBlocks_m = Options::numBlocks;
    recycleBlocks_m = Options::recycleBlocks;
170
    nLHS_m = Options::nLHS;
gsell's avatar
gsell committed
171 172
    SetupMLList();
    SetupBelosList();
173
    problem_mp = rcp(new Belos::LinearProblem<TpetraScalar_t, TpetraMultiVector_t, TpetraOperator_t>);
174
    // setup Belos solver
frey_m's avatar
frey_m committed
175
    if (numBlocks_m == 0 || recycleBlocks_m == 0)
176
        solver_mp = rcp(new Belos::BlockCGSolMgr<TpetraScalar_t, TpetraMultiVector_t, TpetraOperator_t>());
gsell's avatar
gsell committed
177
    else
178 179 180
        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
181 182 183
    convStatusTest->defineScaleForm(Belos::NormOfRHS, Belos::TwoNorm);

    //all timers used here
184 185 186 187 188 189 190 191
    FunctionTimer1_m = IpplTimings::getTimer("BGF-IndexCoordMap");
    FunctionTimer2_m = IpplTimings::getTimer("computeMap");
    FunctionTimer3_m = IpplTimings::getTimer("IPPL to RHS");
    FunctionTimer4_m = IpplTimings::getTimer("ComputeStencil");
    FunctionTimer5_m = IpplTimings::getTimer("ML");
    FunctionTimer6_m = IpplTimings::getTimer("Setup");
    FunctionTimer7_m = IpplTimings::getTimer("CG");
    FunctionTimer8_m = IpplTimings::getTimer("LHS to IPPL");
gsell's avatar
gsell committed
192 193
}

194
void MGPoissonSolver::deletePtr() {
195 196
    MueLuPrec = Teuchos::null;
    map_p  = Teuchos::null;
197 198 199
    A      = Teuchos::null;
    LHS    = Teuchos::null;
    RHS    = Teuchos::null;
200
    prec_mp = Teuchos::null;
201 202
}

203 204
MGPoissonSolver::~MGPoissonSolver() {
    deletePtr ();
205 206
    solver_mp = Teuchos::null;
    problem_mp = Teuchos::null;
gsell's avatar
gsell committed
207 208
}

209
void MGPoissonSolver::computePotential(Field_t& /*rho*/, Vector_t /*hr*/, double /*zshift*/) {
gsell's avatar
gsell committed
210 211 212
    throw OpalException("MGPoissonSolver", "not implemented yet");
}

213
void MGPoissonSolver::computeMap(NDIndex<3> localId) {
214
    if (itsBunch_m->getLocalTrackStep()%repartFreq_m == 0){
215
        deletePtr();
frey_m's avatar
frey_m committed
216
        if (useRCB_m)
217
            redistributeWithRCB(localId);
218
        else
219
            IPPLToMap3D(localId);
220 221

        extrapolateLHS();
222 223
    }
}
gsell's avatar
gsell committed
224

225 226 227 228 229
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.
230
    //we also have to redistribute LHS
231

232
    if (Teuchos::is_null(LHS)){
233 234
        LHS = rcp(new TpetraVector_t(map_p));
        LHS->putScalar(1.0);
235
    } else {
236 237 238
        RCP<TpetraVector_t> tmplhs = rcp(new TpetraVector_t(map_p));
        Tpetra::Import<> importer(map_p, LHS->getMap());
        tmplhs->doImport(*LHS, importer, Tpetra::CombineMode::ADD);
239 240
        LHS = tmplhs;
    }
gsell's avatar
gsell committed
241

242
    //...and all previously saved LHS
243
    std::deque< TpetraVector_t >::iterator it = OldLHS.begin();
frey_m's avatar
frey_m committed
244
    if (OldLHS.size() > 0) {
245
        int n = OldLHS.size();
frey_m's avatar
frey_m committed
246
        for (int i = 0; i < n; ++i) {
247 248 249
            TpetraVector_t tmplhs = TpetraVector_t(map_p);
            Tpetra::Import<> importer(map_p, it->getMap());
            tmplhs.doImport(*it, importer, Tpetra::CombineMode::ADD);
250 251 252 253
            *it = tmplhs;
            ++it;
        }
    }
gsell's avatar
gsell committed
254

255 256
    // extrapolate last OldLHS.size LHS to get a new start vector
    it = OldLHS.begin();
frey_m's avatar
frey_m committed
257
    if (nLHS_m == 0 || OldLHS.size()==0)
258
        LHS->putScalar(1.0);
frey_m's avatar
frey_m committed
259
    else if (OldLHS.size() == 1)
260
        *LHS = *it;
frey_m's avatar
frey_m committed
261
    else if (OldLHS.size() == 2)
262
        LHS->update(2.0, *it++, -1.0, *it, 0.0);
frey_m's avatar
frey_m committed
263
    else if (OldLHS.size() > 2) {
264
        int n = OldLHS.size();
265
        P_mp = rcp(new TpetraMultiVector_t(map_p, nLHS_m, false));
frey_m's avatar
frey_m committed
266
        for (int i = 0; i < n; ++i) {
267
           *(P_mp->getVectorNonConst(i)) = *it++;
268
        }
frey_m's avatar
frey_m committed
269 270
        for (int k = 1; k < n; ++k) {
           for (int i = 0; i < n - k; ++i) {
271
              P_mp->getVectorNonConst(i)->update(-(i + 1) / (float)k, *(P_mp->getVector(i + 1)), (i + k + 1) / (float)k);
272
           }
273
        }
274
        *LHS = *(P_mp->getVector(0));
275
     } else
frey_m's avatar
frey_m committed
276 277
        throw OpalException("MGPoissonSolver",
                            "Invalid number of old LHS: " + std::to_string(OldLHS.size()));
gsell's avatar
gsell committed
278 279
}

280

gsell's avatar
gsell committed
281 282 283 284 285
// 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
// XXX: use matrix stencil in computation directly (no Epetra, define operators
// on IPPL GRID)
void MGPoissonSolver::computePotential(Field_t &rho, Vector_t hr) {
286

kraus's avatar
kraus committed
287
    Inform msg("OPAL ", INFORM_ALL_NODES);
gsell's avatar
gsell committed
288 289 290
    nr_m[0] = orig_nr_m[0];
    nr_m[1] = orig_nr_m[1];
    nr_m[2] = orig_nr_m[2];
291

frey_m's avatar
frey_m committed
292 293 294
    bp_m->setGlobalMeanR(itsBunch_m->getGlobalMeanR());
    bp_m->setGlobalToLocalQuaternion(itsBunch_m->getGlobalToLocalQuaternion());
    bp_m->setNr(nr_m);
295

296 297
    NDIndex<3> localId = layout_m->getLocalNDIndex();

298
    IpplTimings::startTimer(FunctionTimer1_m);
299
    // Compute boundary intersections (only do on the first step)
frey_m's avatar
frey_m committed
300
    if (!itsBunch_m->getLocalTrackStep())
frey_m's avatar
frey_m committed
301
        bp_m->compute(hr, localId);
302
    IpplTimings::stopTimer(FunctionTimer1_m);
303 304

    // Define the Map
kraus's avatar
kraus committed
305
    INFOMSG(level3 << "* Computing Map..." << endl);
306
    IpplTimings::startTimer(FunctionTimer2_m);
307
    computeMap(localId);
308
    IpplTimings::stopTimer(FunctionTimer2_m);
kraus's avatar
kraus committed
309
    INFOMSG(level3 << "* Done." << endl);
gsell's avatar
gsell committed
310

311
    // Allocate the RHS with the new Epetra Map
312
    if (Teuchos::is_null(RHS))
313 314
        RHS = rcp(new TpetraVector_t(map_p));
    RHS->putScalar(0.0);
315

kraus's avatar
kraus committed
316 317 318 319 320 321
    // // get charge densities from IPPL field and store in Epetra vector (RHS)
    if (verbose_m) {
        Ippl::Comm->barrier();
        msg << "* Node:" << Ippl::myNode() << ", Filling RHS..." << endl;
        Ippl::Comm->barrier();
    }
322 323
    IpplTimings::startTimer(FunctionTimer3_m);
    int id = 0;
324
    float scaleFactor = itsBunch_m->getdT();
325

326

kraus's avatar
kraus committed
327
    if (verbose_m) {
frey_m's avatar
frey_m committed
328 329 330
        msg << "* Node:" << Ippl::myNode() << ", Rho for final element: "
            << rho[localId[0].last()][localId[1].last()][localId[2].last()].get()
            << endl;
331

kraus's avatar
kraus committed
332
        Ippl::Comm->barrier();
frey_m's avatar
frey_m committed
333 334 335 336 337
        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: "
338
            << RHS->getLocalLength() << endl;
frey_m's avatar
frey_m committed
339 340
        msg << "* Node:" << Ippl::myNode()
            << ", Number of reserved global elements in RHS: "
341
            << RHS->getGlobalLength() << endl;
kraus's avatar
kraus committed
342 343
        Ippl::Comm->barrier();
    }
344
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
345
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
kraus's avatar
kraus committed
346
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
347
                if (bp_m->isInside(idx, idy, idz))
348
                        RHS->getDataNonConst()[id++] = 4*M_PI*rho[idx][idy][idz].get()/scaleFactor;
gsell's avatar
gsell committed
349 350 351
            }
        }
    }
352

353
    IpplTimings::stopTimer(FunctionTimer3_m);
kraus's avatar
kraus committed
354 355
    if (verbose_m) {
        Ippl::Comm->barrier();
frey_m's avatar
frey_m committed
356 357
        msg << "* Node:" << Ippl::myNode()
            << ", Number of Local Inside Points " << id << endl;
kraus's avatar
kraus committed
358 359 360
        msg << "* Node:" << Ippl::myNode() << ", Done." << endl;
        Ippl::Comm->barrier();
    }
gsell's avatar
gsell committed
361
    // build discretization matrix
kraus's avatar
kraus committed
362
    INFOMSG(level3 << "* Building Discretization Matrix..." << endl);
363
    IpplTimings::startTimer(FunctionTimer4_m);
frey_m's avatar
frey_m committed
364
    if (Teuchos::is_null(A))
365
        A = rcp(new TpetraCrsMatrix_t(map_p,  7, Tpetra::StaticProfile));
366
    ComputeStencil(hr, RHS);
367
    IpplTimings::stopTimer(FunctionTimer4_m);
kraus's avatar
kraus committed
368
    INFOMSG(level3 << "* Done." << endl);
369

gsell's avatar
gsell committed
370 371 372
#ifdef DBG_STENCIL
    EpetraExt::RowMatrixToMatlabFile("DiscrStencil.dat", *A);
#endif
373

kraus's avatar
kraus committed
374
    INFOMSG(level3 << "* Computing Preconditioner..." << endl);
375
    /* FIXME
376
    IpplTimings::startTimer(FunctionTimer5_m);
377 378
    if (MueLuPrec == Teuchos::null) {
        MueLuPrec = MueLu::CreateTpetraPreconditioner(A, MLList_m);
379
    } else if (precmode_m == REUSE_HIERARCHY) {
380
        // FIXME MueLuPrec->ReComputePreconditioner();
381
    } else if (precmode_m == REUSE_PREC){
382
    }
383
    IpplTimings::stopTimer(FunctionTimer5_m);
384
    */
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 398 399 400
    problem_mp->setOperator(A);
    problem_mp->setLHS(LHS);
    problem_mp->setRHS(RHS);
    if (Teuchos::is_null(prec_mp))
        std::cout << "FIXME" << std::endl; //FIXME
//         prec_mp = MueLu::CreateTpetraPreconditioner(A, MLList_m);
    problem_mp->setLeftPrec(prec_mp);
    solver_mp->setProblem( problem_mp);
    if (!problem_mp->isProblemSet()) {
        if (problem_mp->setProblem() == false) {
401
            ERRORMSG("Belos::LinearProblem failed to set up correctly!" << endl);
402
        }
gsell's avatar
gsell committed
403
    }
404
    IpplTimings::stopTimer(FunctionTimer6_m);
kraus's avatar
kraus committed
405
    INFOMSG(level3 << "* Done." << endl);
406

gsell's avatar
gsell committed
407 408
    double time = MPI_Wtime();

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

kraus's avatar
kraus committed
415 416 417
    std::ofstream timings;
    if (true || verbose_m) {
        time = MPI_Wtime() - time;
418 419 420 421 422 423 424
        double minTime = 0, maxTime = 0, avgTime = 0;
        //FIXME
//         comm_mp->MinAll(&time, &minTime, 1);
//         comm_mp->MaxAll(&time, &maxTime, 1);
//         comm_mp->SumAll(&time, &avgTime, 1);
        avgTime /= comm_mp->getSize();
        if (comm_mp->getRank() == 0) {
kraus's avatar
kraus committed
425
            char filename[50];
frey_m's avatar
frey_m committed
426 427
            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],
428
                    comm_mp->getSize(), recycleBlocks_m, numBlocks_m, nLHS_m);
frey_m's avatar
frey_m committed
429

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

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

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


474
void MGPoissonSolver::redistributeWithRCB(NDIndex<3> localId) {
gsell's avatar
gsell committed
475 476 477

    int numMyGridPoints = 0;

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


488 489 490 491 492
    int indexbase = 0;
    Teuchos::RCP<TpetraMap_t> bmap = Teuchos::rcp(new TpetraMap_t(Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid(),
                                                                  numMyGridPoints, indexbase, comm_mp));
    Teuchos::RCP<const TpetraMultiVector_t> coords = Teuchos::rcp(
        new TpetraMultiVector_t(bmap, 3, false));
gsell's avatar
gsell committed
493

494 495 496 497
/*FIXME
    double *v;
    int stride = 0, stride2 = 0;
    coords->extractView(&v, &stride);
gsell's avatar
gsell committed
498 499
    stride2 = 2 * stride;

500
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
501
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
kraus's avatar
kraus committed
502
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
503
                if (bp_m->isInside(idx, idy, idz)) {
504 505 506
                    v[0] = (double)idx;
                    v[stride] = (double)idy;
                    v[stride2] = (double)idz;
gsell's avatar
gsell committed
507 508 509 510 511
                    v++;
                }
            }
        }
    }
512
    */
gsell's avatar
gsell committed
513 514 515 516 517 518 519

    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");

520 521
    /*
     * FIXME
frey_m's avatar
frey_m committed
522 523 524
    Teuchos::RCP<Isorropia::Epetra::Partitioner> part = Teuchos::rcp(
        new Isorropia::Epetra::Partitioner(coords, paramlist));

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

528
    newcoords->extractView(&v, &stride);
gsell's avatar
gsell committed
529 530
    stride2 = 2 * stride;
    numMyGridPoints = 0;
531
    */
gsell's avatar
gsell committed
532
    std::vector<int> MyGlobalElements;
533 534
    /* FIXME
    for (unsigned int i = 0; i < newcoords->getLocalLength(); i++) {
frey_m's avatar
frey_m committed
535
        MyGlobalElements.push_back(bp_m->getIdx(v[0], v[stride], v[stride2]));
gsell's avatar
gsell committed
536 537 538
        v++;
        numMyGridPoints++;
    }
539 540 541
*/
    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
542 543
}

544
void MGPoissonSolver::IPPLToMap3D(NDIndex<3> localId) {
545

gsell's avatar
gsell committed
546
    int NumMyElements = 0;
547
    std::vector<int> MyGlobalElements;
gsell's avatar
gsell committed
548

549
    for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
550
        for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
551
            for (int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
frey_m's avatar
frey_m committed
552 553
                if (bp_m->isInside(idx, idy, idz)) {
                    MyGlobalElements.push_back(bp_m->getIdx(idx, idy, idz));
gsell's avatar
gsell committed
554 555 556
                    NumMyElements++;
                }
            }
kraus's avatar
kraus committed
557
        }
558
    }
559 560 561
    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
562 563
}

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

566
    A->setAllToScalar(0.0);
567

568 569
    int NumMyElements = map_p->getNodeNumElements();
    auto MyGlobalElements = map_p->getMyGlobalIndices();
gsell's avatar
gsell committed
570

571 572
    std::vector<double> Values(6);
    std::vector<int> Indices(6);
gsell's avatar
gsell committed
573

frey_m's avatar
frey_m committed
574
    for (int i = 0 ; i < NumMyElements ; i++) {
gsell's avatar
gsell committed
575 576 577

        int NumEntries = 0;

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

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

frey_m's avatar
frey_m committed
584
        bp_m->getNeighbours(MyGlobalElements[i], W, E, S, N, F, B);
frey_m's avatar
frey_m committed
585
        if (E != -1) {
gsell's avatar
gsell committed
586 587 588
            Indices[NumEntries] = E;
            Values[NumEntries++] = EV;
        }
frey_m's avatar
frey_m committed
589
        if (W != -1) {
gsell's avatar
gsell committed
590 591 592
            Indices[NumEntries] = W;
            Values[NumEntries++] = WV;
        }
frey_m's avatar
frey_m committed
593
        if (S != -1) {
gsell's avatar
gsell committed
594 595 596
            Indices[NumEntries] = S;
            Values[NumEntries++] = SV;
        }
frey_m's avatar
frey_m committed
597
        if (N != -1) {
gsell's avatar
gsell committed
598 599 600
            Indices[NumEntries] = N;
            Values[NumEntries++] = NV;
        }
frey_m's avatar
frey_m committed
601
        if (F != -1) {
gsell's avatar
gsell committed
602 603 604
            Indices[NumEntries] = F;
            Values[NumEntries++] = FV;
        }
frey_m's avatar
frey_m committed
605
        if (B != -1) {
gsell's avatar
gsell committed
606 607 608 609
            Indices[NumEntries] = B;
            Values[NumEntries++] = BV;
        }

610
        // if matrix has already been filled (fillComplete()) we can only
gsell's avatar
gsell committed
611
        // replace entries
612

613
        if (A->isFillComplete()) {
614
            // off-diagonal entries
615
            A->replaceGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
616
            // diagonal entry
617
            A->replaceGlobalValues(MyGlobalElements[i], 1, &CV, &MyGlobalElements[i]);
618
        } else {
gsell's avatar
gsell committed
619
            // off-diagonal entries
620
            A->insertGlobalValues(MyGlobalElements[i], NumEntries, &Values[0], &Indices[0]);
gsell's avatar
gsell committed
621
            // diagonal entry
622
            A->insertGlobalValues(MyGlobalElements[i], 1, &CV, &MyGlobalElements[i]);
623
        }
gsell's avatar
gsell committed
624 625
    }

626 627 628
    RCP<ParameterList_t> params = Teuchos::parameterList();
    params->set ("Optimize Storage", true);
    A->fillComplete(params);
gsell's avatar
gsell committed
629 630 631 632 633
}

void MGPoissonSolver::printLoadBalanceStats() {

    //compute some load balance statistics
634 635
    size_t myNumPart = map_p->getNodeNumElements();
    size_t NumPart = map_p->getGlobalNumElements() * 1.0 / comm_mp->getSize();
gsell's avatar
gsell committed
636
    double imbalance = 1.0;
frey_m's avatar
frey_m committed
637
    if (myNumPart >= NumPart)
gsell's avatar
gsell committed
638 639 640 641 642 643 644 645 646 647 648 649
        imbalance += (myNumPart - NumPart) / NumPart;
    else
        imbalance += (NumPart - myNumPart) / NumPart;

    double max = 0.0, min = 0.0, avg = 0.0;
    int minn = 0, maxn = 0;
    MPI_Reduce(&imbalance, &min, 1, MPI_DOUBLE, MPI_MIN, 0, Ippl::getComm());
    MPI_Reduce(&imbalance, &max, 1, MPI_DOUBLE, MPI_MAX, 0, Ippl::getComm());
    MPI_Reduce(&imbalance, &avg, 1, MPI_DOUBLE, MPI_SUM, 0, Ippl::getComm());
    MPI_Reduce(&myNumPart, &minn, 1, MPI_INT, MPI_MIN, 0, Ippl::getComm());
    MPI_Reduce(&myNumPart, &maxn, 1, MPI_INT, MPI_MAX, 0, Ippl::getComm());

650
    avg /= comm_mp->getSize();
kraus's avatar
kraus committed
651 652
    *gmsg << "LBAL min = " << min << ", max = " << max << ", avg = " << avg << endl;
    *gmsg << "min nr gridpoints = " << minn << ", max nr gridpoints = " << maxn << endl;
gsell's avatar
gsell committed
653 654 655 656 657 658
}

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;
659
    return os;
gsell's avatar
gsell committed
660 661
}

662 663 664 665 666 667 668
// 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: