Skip to content
Snippets Groups Projects
multilevelpatches.cc 16.6 KiB
Newer Older
podlesny's avatar
podlesny committed
#include <config.h>

#include <cmath>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>

/*
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <dune/grid/uggrid/ugwrapper.hh>
#pragma GCC diagnostic pop
*/

#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/parametertree.hh>
#include <dune/common/parametertreeparser.hh>
#include <dune/common/timer.hh>

// dune-istl includes
#include <dune/istl/bcrsmatrix.hh>
#include <dune/istl/matrix.hh>

// dune-fufem includes
#include <dune/fufem/assemblers/localassemblers/l2functionalassembler.hh>

// dune-grid includes
#include <dune/grid/uggrid.hh>
#include <dune/grid/io/file/vtk/vtkwriter.hh>

// dune-solver includes
#include <dune/solvers/norms/energynorm.hh>
#include <dune/solvers/norms/twonorm.hh>

// dune-faultnetworks includes
#include <dune/faultnetworks/utils/matrixreader.hh>
#include <dune/faultnetworks/utils/vectorreader.hh>
#include <dune/faultnetworks/utils/levelinterfacenetworkwriter.hh>
#include <dune/faultnetworks/utils/debugutils.hh>

#include <dune/faultnetworks/assemblers/interfaceoperatorassembler.hh>
#include <dune/faultnetworks/assemblers/intersectionjumpmassassembler.hh>
#include <dune/faultnetworks/assemblers/osclocalassembler.hh>

#include <dune/faultnetworks/solvers/osccgsolver.hh>

#include <dune/faultnetworks/preconditioners/multilevelpatchpreconditioner.hh>

#include <dune/faultnetworks/faultp1nodalbasis.hh>
#include <dune/faultnetworks/levelinterfacenetwork.hh>
#include <dune/faultnetworks/faultinterface.hh>
#include <dune/faultnetworks/levelinterfacenetworkproblem.hh>

#include <dune/faultnetworks/dgmgtransfer.hh>
#include <dune/faultnetworks/compressedmultigridtransfer.hh>

#include <dune/faultnetworks/oscdata.hh>
#include <dune/faultnetworks/oscdatahierarchy.hh>
#include <dune/faultnetworks/oscrhs.hh>

#include <dune/faultnetworks/faultfactories/multileveluniformfaultfactory.hh>


int main(int argc, char** argv) try
{
    MPIHelper::instance(argc, argv);

    const int dim = 2;
    //typedef double ctype;


    typedef typename Dune::FieldVector<double, dim> WorldVectorType;
    typedef typename Dune::BlockVector<Dune::FieldVector<double,1>> VectorType;
    typedef typename Dune::BitSetVector<1> BitVector;
    typedef typename Dune::BCRSMatrix<Dune::FieldMatrix<double, 1, 1>> MatrixType;


    #if HAVE_UG
    typedef typename Dune::UGGrid<dim> GridType;
    #else
    #error No UG!
    #endif


    typedef typename GridType::LevelGridView GV;

    typedef FaultP1NodalBasis<GV, double> DGBasis;
    typedef typename DGBasis::LocalFiniteElement DGFE;

    typedef OscLocalAssembler<GridType, DGFE, DGFE> LocalOscAssembler;
    typedef IntersectionJumpMassAssembler<GV, DGFE, DGFE> LocalInterfaceAssembler;
 
  // parse parameter file
    ParameterTree parameterSet;
    if (argc==2)
        ParameterTreeParser::readINITree(argv[1], parameterSet);
    else
        ParameterTreeParser::readINITree("/home/mi/podlesny/software/dune/faultnetworks/src/uniformfaultnetworks/multilevelpatches.parset", parameterSet);

    const std::string path = parameterSet.get<std::string>("path");
    const std::string resultPath = parameterSet.get<std::string>("resultPath");

    int problemCount = 0;
    while (parameterSet.hasSub("problem" + std::to_string(problemCount))) {
	
    ParameterTree& problemParameters = parameterSet.sub("problem" + std::to_string(problemCount));

    const std::string oscDataFile = problemParameters.get<std::string>("oscDataFile");

    const int coarseResolution = problemParameters.get<int>("coarseResolution");
    const int fineResolution = problemParameters.get<int>("fineResolution");
    const int exactResolution = problemParameters.get<int>("exactResolution");

    const int faultCount = problemParameters.get<int>("faultCount");

    const double penaltyFactor = problemParameters.get<double>("penaltyFactor");
    const int patchDepth = problemParameters.get<int>("patchDepth");

    const int maxIterations = problemParameters.get<int>("maxIterations");
    const double solverTolerance = problemParameters.get<double>("tol");
    //const bool useExactSol = problemParameters.get<bool>("useExactSol");

    //const int coarseGridN = std::pow(2, coarseResolution);
    const int fineGridN = std::pow(2, fineResolution);


    std::ofstream out(resultPath + oscDataFile + "_" + std::to_string(coarseResolution) + "_" + std::to_string(fineResolution) + "_" + std::to_string(exactResolution) + "_" + std::to_string(faultCount) + ".log");
    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buf
    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!


    std::cout << std::endl;
    std::cout << "Parameter file read successfully!" << std::endl;

    typedef Dune::Matrix<Dune::FieldMatrix<double,1,1>, std::allocator<Dune::FieldMatrix<double,1,1>>> OscMatrixType;
    OscMatrixType matrix;

    // interface integral jump penalty, B:
    OscMatrixType B(2,2);
    B[0][0] = 1;
    B[1][1] = 1;
    B[0][1] = -1;
    B[1][0] = -1;

    MatrixReader<OscMatrixType> matrixReader(path + oscDataFile);
    matrixReader.read(matrix);

    const int oscGridN = matrix.N();
    const int oscGridLevelIdx = std::round(std::log2(oscGridN)) - coarseResolution;

    if (oscGridN>fineGridN)
        DUNE_THROW(Dune::Exception, "Provided oscData too large!");

    std::cout << "OscData file read successfully!" << std::endl << std::endl;

    const int fineLevelIdx = fineResolution - coarseResolution;
    const int exactLevelIdx = exactResolution - coarseResolution;

    std::vector<int> faultToLevel(faultCount);
    for (size_t i=0; i<faultToLevel.size(); ) {
        for (int j=fineLevelIdx; j>0 && i<faultToLevel.size(); j--) {
            faultToLevel[i] = j;
            i++;
        }

        for (int j=0; j<fineLevelIdx && i<faultToLevel.size(); j++) {
            faultToLevel[i] = j;
            i++;
        }
    }

    print(faultToLevel, "faultToLevel: ");

    MultilevelUniformFaultFactory<GridType> faultFactory(faultCount, faultToLevel, coarseResolution, exactLevelIdx);
    faultFactory.prolongToAll();

    const GridType& grid = faultFactory.grid();
    const InterfaceNetwork<GridType>& interfaceNetwork = faultFactory.interfaceNetwork();

    int writeLevel = fineLevelIdx;
    LevelInterfaceNetworkWriter networkWriter(resultPath + "levelinterfacenetwork_" + std::to_string(writeLevel) + ".tikz");
    networkWriter.write(interfaceNetwork.levelInterfaceNetwork(writeLevel));

    OscData<GridType, OscMatrixType> oscData(grid, oscGridLevelIdx);
    oscData.set(matrix);
    OscDataHierarchy<GridType, OscMatrixType> oscDataHierarchy(oscData);
    
    Timer totalTimer;
    totalTimer.reset();
    totalTimer.start();


    // ----------------------------------------------------------------
    // ---              compute initial iterate                     ---
    // ----------------------------------------------------------------
    std::cout << std::endl;
    std::cout << "Computing initial iterate!" << std::endl;

    const LevelInterfaceNetwork<GV>& coarseLevelInterfaceNetwork = interfaceNetwork.levelInterfaceNetwork(0);
    LevelInterfaceNetworkProblem<DGBasis, MatrixType, VectorType> coarseGlobalAssembler(coarseLevelInterfaceNetwork);
    LocalOscAssembler coarseLocalAssembler(oscDataHierarchy[0]->data(), oscDataHierarchy[0]->mapper());

    OscRhs<WorldVectorType, Dune::FieldVector<double,1>> f;
    L2FunctionalAssembler<GridType, DGFE> l2FunctionalAssembler(f);

    std::vector<std::shared_ptr<LocalInterfaceAssembler>> coarseLocalInterfaceAssemblers(coarseLevelInterfaceNetwork.size());
    for (size_t i=0; i<coarseLocalInterfaceAssemblers.size(); i++) {
        //const double pen = penaltyFactor;
        const double pen = penaltyFactor*std::pow(2.0, coarseResolution);
        coarseLocalInterfaceAssemblers[i] = std::make_shared<LocalInterfaceAssembler>(B, 2, pen);
    }

    coarseGlobalAssembler.assemble(coarseLocalAssembler, coarseLocalInterfaceAssemblers, l2FunctionalAssembler);
    coarseGlobalAssembler.solve();

    const VectorType& coarseSol = coarseGlobalAssembler.getSol();
    const DGBasis& coarseBasis = coarseGlobalAssembler.basis();

    // ----------------------------------------------------------------
    // ---              compute exact solution                      ---
    // ----------------------------------------------------------------
    std::cout << std::endl;
    std::cout << "Computing exact solution!" << std::endl;

    const LevelInterfaceNetwork<GV>& exactLevelInterfaceNetwork = interfaceNetwork.levelInterfaceNetwork(exactLevelIdx);
    LevelInterfaceNetworkProblem<DGBasis, MatrixType, VectorType> exactGlobalAssembler(exactLevelInterfaceNetwork);
    LocalOscAssembler exactLocalAssembler(oscDataHierarchy[exactLevelIdx]->data(), oscDataHierarchy[exactLevelIdx]->mapper());

    std::vector<std::shared_ptr<LocalInterfaceAssembler>> exactLocalInterfaceAssemblers(exactLevelInterfaceNetwork.size());
    for (size_t i=0; i<exactLocalInterfaceAssemblers.size(); i++) {
        //const double pen = penaltyFactor;
        const double pen = penaltyFactor*std::pow(2.0, coarseResolution + exactLevelInterfaceNetwork.getIntersectionsLevels().at(i));
        exactLocalInterfaceAssemblers[i] = std::make_shared<LocalInterfaceAssembler>(B, 2, pen);
    }

    exactGlobalAssembler.assemble(exactLocalAssembler, exactLocalInterfaceAssemblers, l2FunctionalAssembler);
    exactGlobalAssembler.solve();

    const VectorType& exactSol = exactGlobalAssembler.getSol();
    const DGBasis& exactBasis = exactGlobalAssembler.basis();

    EnergyNorm<MatrixType, VectorType> exactEnergyNorm(exactGlobalAssembler.matrix());


    // ----------------------------------------------------------------
    // ---                set up cg solver                          ---
    // ----------------------------------------------------------------
    std::cout << std::endl;
    std::cout << "---------------------------------------------" << std::endl; 
    std::cout << "Setting up the fine level CG solver:" << std::endl; 
    std::cout << "---------------------------------------------" << std::endl << std::endl;

    const LevelInterfaceNetwork<GV>& fineLevelInterfaceNetwork = interfaceNetwork.levelInterfaceNetwork(fineLevelIdx);
    LevelInterfaceNetworkProblem<DGBasis, MatrixType, VectorType> fineGlobalAssembler(fineLevelInterfaceNetwork);
    LocalOscAssembler fineLocalAssembler(oscDataHierarchy[fineLevelIdx]->data(), oscDataHierarchy[fineLevelIdx]->mapper());

    std::vector<std::shared_ptr<LocalInterfaceAssembler>> fineLocalInterfaceAssemblers(fineLevelInterfaceNetwork.size());
    for (size_t i=0; i<fineLocalInterfaceAssemblers.size(); i++) {
        //const double pen = penaltyFactor;
        const double pen = penaltyFactor*std::pow(2.0, coarseResolution + fineLevelInterfaceNetwork.getIntersectionsLevels().at(i));
        fineLocalInterfaceAssemblers[i] = std::make_shared<LocalInterfaceAssembler>(B, 2, pen);
    }

    fineGlobalAssembler.assemble(fineLocalAssembler, fineLocalInterfaceAssemblers, l2FunctionalAssembler);
    fineGlobalAssembler.solve();

    const VectorType& fineSol = fineGlobalAssembler.getSol();
    const VectorType& fineRhs = fineGlobalAssembler.rhs();
    const DGBasis& fineBasis = fineGlobalAssembler.basis();

    EnergyNorm<MatrixType, VectorType> fineEnergyNorm(fineGlobalAssembler.matrix());

    // ---------------------------------------------------------------
    // multilevel transfer
    // ---------------------------------------------------------------
    DGMGTransfer<DGBasis> coarseFineTransfer(coarseBasis, fineBasis);

    std::cout << "Setting up the preconditioner!" << std::endl;

    BitVector activeLevels(fineLevelIdx+1, true);
    //activeLevels[0][0] = true;
    //activeLevels[1][0] = false;
    //activeLevels[2][0] = false;
    //activeLevels[fineLevelIdx][0] = true;

    std::vector<std::shared_ptr<LocalOscAssembler>> localAssemblers;
    std::vector<std::vector<std::shared_ptr<LocalInterfaceAssembler>>> localIntersectionAssemblers;

    localAssemblers.resize(activeLevels.size());
    localIntersectionAssemblers.resize(activeLevels.size());

    for (size_t i=0; i<activeLevels.size(); i++) {
        localAssemblers[i] = std::make_shared<LocalOscAssembler>(oscDataHierarchy[i]->data(), oscDataHierarchy[i]->mapper());

        const LevelInterfaceNetwork<GV>& levelInterfaceNetwork = interfaceNetwork.levelInterfaceNetwork(i);
        std::vector<std::shared_ptr<LocalInterfaceAssembler>>& levelLocalIntersectionAssemblers = localIntersectionAssemblers[i];
        levelLocalIntersectionAssemblers.resize(levelInterfaceNetwork.size());
        for (size_t j=0; j<levelLocalIntersectionAssemblers.size(); j++) {
            //const double pen = penaltyFactor;
            const double pen = penaltyFactor*std::pow(2.0, coarseResolution + levelInterfaceNetwork.getIntersectionsLevels().at(j));
            levelLocalIntersectionAssemblers[j] = std::make_shared<LocalInterfaceAssembler>(B, 2, pen);
        }
    }

    typedef MultilevelPatchPreconditioner<DGBasis, LocalOscAssembler, LocalInterfaceAssembler, MatrixType, VectorType> MultilevelPatchPreconditioner;
    typedef typename MultilevelPatchPreconditioner::LevelPatchPreconditionerType LevelPatchPreconditioner;
    //typedef typename MultilevelPatchPreconditioner::LevelGlobalPreconditionerType LevelGlobalPreconditioner;
    MultilevelPatchPreconditioner::Mode preconditionerMode = MultilevelPatchPreconditioner::Mode::additive;

    MultilevelPatchPreconditioner preconditioner(interfaceNetwork, activeLevels, localAssemblers, localIntersectionAssemblers, preconditionerMode);
    for (size_t i=0; i<preconditioner.size()-1; i++) {
        LevelPatchPreconditioner& levelFaultPreconditioner = *preconditioner.levelPatchPreconditioner(i);

        levelFaultPreconditioner.setPatchDepth(patchDepth);
        levelFaultPreconditioner.setBoundaryMode(LevelPatchPreconditioner::BoundaryMode::homogeneous);
    }
    preconditioner.build();

    std::cout << "Setup complete, starting preconditioned cg iteration!" << std::endl;
    std::cout << std::endl << std::endl;
    
    /*Dune::BlockVector<Dune::FieldVector<double,1>> initialError(fineX.size());
    initialError = initialX;
    initialError -= fineX;
    std::cout << "Initial error in energy norm: " << energyNorm.operator()(initialError) << std::endl;
    std::cout << "Initial error in two norm: " << initialError.two_norm() << std::endl << std::endl;*/


    VectorType initialX;
    coarseFineTransfer.prolong(coarseSol, initialX);

    VectorType initialXCopy(initialX);
    VectorType fineRhsCopy(fineRhs);
    VectorType rhs(fineRhs);

    //print(initialX, "initialX");
    //print(fineRhs, "fineRhs");
    //print(exactSol, "exactSol");
    //print(fineSol, "fineSol");
    
    /* Basis fineContBasis(fineGridView);
    std::cout << "fineContBasis.size(): " << fineContBasis.size() << std::endl;
    DGMGTransfer<Basis> contMGTransfer(coarseBasis, fineContBasis);

    Basis exactContBasis(exactGridView);
    std::cout << "exactContBasis.size(): " << exactContBasis.size() << std::endl; */

    DGMGTransfer<DGBasis> discMGTransfer(fineBasis, exactBasis);

    // solve
    OscCGSolver<MatrixType, VectorType, DGBasis>
    solver(fineBasis, &fineGlobalAssembler.matrix(), &initialX, &rhs, &preconditioner,
                    maxIterations, solverTolerance, &exactEnergyNorm,
                    Solver::FULL, &exactSol, &fineSol, discMGTransfer, 1.0, true); //((oscGridN+0.0)/fineGridN)
    solver.check();
    solver.preprocess();
    solver.solve();


    /*
    VectorType finalError(fineSol.size());
    finalError = initialX;
    finalError -= fineSol;
    std::cout << "Final error in energy norm: " << fineEnergyNorm.operator()(finalError) << std::endl;
    std::cout << "Final error in two norm: " << finalError.two_norm() << std::endl << std::endl;*/

    std::cout << std::endl;
    std::cout << "Total time: " << totalTimer.elapsed() << " seconds." << std::endl; 

    // regular unpreconditioned cg solver for comparisson
/*
    std::cout << "Setup complete, starting cg iteration!" << std::endl;
    std::cout << std::endl;
    
    // solve
    OscCGSolver<MatrixType, VectorType, DGBasis >
    regSolver(fineBasis, &fineGlobalAssembler.matrix(), &initialXCopy, &fineRhsCopy, nullptr,
                    maxIterations, solverTolerance, &exactEnergyNorm,
                    Solver::FULL, &exactSol, &fineSol, discMGTransfer, 1.0, true);
    regSolver.check();
    regSolver.preprocess();
    regSolver.solve();
*/
    // TODO: use once debugging finished
    std::cout.rdbuf(coutbuf); //reset to standard output again

    std::cout << "Problem " << problemCount << " done!" << std::endl;
    problemCount++;
    }
} catch (Dune::Exception e) {

    std::cout << e << std::endl;

}