diff --git a/dune/mmdg/dg.hh b/dune/mmdg/dg.hh index 35acb2579cd8accc343403988b1fb2996dc4cb6a..83676e7aab71bd914fabbcf736bcde04119aaf6c 100644 --- a/dune/mmdg/dg.hh +++ b/dune/mmdg/dg.hh @@ -6,6 +6,7 @@ #include <dune/common/dynmatrix.hh> #include <dune/common/dynvector.hh> +#include <dune/grid/common/mcmgmapper.hh> #include <dune/grid/io/file/vtk.hh> #include <dune/geometry/quadraturerules.hh> @@ -16,10 +17,12 @@ #include <dune/mmdg/nonconformingp1vtkfunction.hh> -template<class GridView, class Mapper, class Problem> +template<class Grid, class GridView, class Mapper, class Problem> class DG -{ +{ //TODO: Ordnung (private / public) public: + //using GridView = typename Grid::LeafGridView; + //using Mapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<GridView>; using Scalar = typename GridView::ctype; static constexpr int dim = GridView::dimension; using Matrix = Dune::BCRSMatrix<Dune::FieldMatrix<Scalar,1,1>>; @@ -35,21 +38,23 @@ public: static constexpr auto edge = Dune::GeometryTypes::simplex(dim-1); //constructor - DG (const GridView& gridView, const Mapper& mapper, - const Problem& problem) : - gridView_(gridView), mapper_(mapper), problem_(problem), - dof((1 + dim) * gridView.size(0)) + DG (const Grid& grid, const GridView& gridView, const Mapper mapper, const Problem& problem) : + //NOTE: why does this not work? + //grid_(grid), gridView_(grid.leafGridView()), mapper_(*(new Mapper(gridView_, Dune::mcmgElementLayout()))), problem_(problem), dof_((1 + dim) * gridView_.size(0)) + grid_(grid), gridView_(gridView), mapper_(mapper), problem_(problem), + dof_((1 + dim) * gridView.size(0)) { //initialize stiffness matrix A, load vector b and solution vector d - A = std::make_shared<Matrix>(dof, dof, 10, 1, Matrix::implicit); //TODO - b = Vector(dof); - d = Vector(dof); + A = std::make_shared<Matrix>(dof_, dof_, 10, 1, Matrix::implicit); //TODO + b = Vector(dof_); + d = Vector(dof_); } const void operator() (const Scalar mu) { //assemble stiffness matrix A and load vector b assembleSLE(mu); + A->compress(); Dune::InverseOperatorResult result; Dune::UMFPack<Matrix> solver(*A); @@ -59,13 +64,25 @@ public: writeVTKoutput(); } + const Grid& grid_; const GridView& gridView_; const Mapper& mapper_; //element mapper for gridView_ const Problem& problem_; //the DG problem to be solved - const int dof; //degrees of freedom + const int dof_; + +protected: + DG (const Grid& grid, const GridView& gridView, const Mapper mapper, + const Problem& problem, const int dof) : + grid_(grid), gridView_(gridView), mapper_(mapper), problem_(problem), + dof_(dof) + { + //initialize stiffness matrix A, load vector b and solution vector d + A = std::make_shared<Matrix>(dof_, dof_, 10, 1, Matrix::implicit); //TODO + b = Vector(dof_); + d = Vector(dof_); + } -private: //assemble stiffness matrix A and load vector b void assembleSLE (const Scalar mu) { @@ -145,6 +162,14 @@ private: //iterate over all intersection with the boundary of elem for (const auto& intersct : intersections(gridView_, elem)) { + if constexpr (dim != 1) + { + if (grid_.isInterface(intersct)) + { + continue; + } + } + const auto& normal = intersct.centerUnitOuterNormal(); const auto& intersctGeo = intersct.geometry(); const double intersctVol = intersctGeo.volume(); @@ -377,7 +402,7 @@ private: // int_intersct (mu * phi_elem,i - K[:,i] * normal) * g ds //with K*grad(phi_elem,i) = K[:,i] for (int i = 0; i < dim; i++) - { + { b[elemIdxSLE + i + 1] += weight * integrationElem * (mu * qpGlobal[i] - (KEvaluation[i] * normal)) * boundaryEvaluation; @@ -423,8 +448,6 @@ private: } } } - - A->compress(); } //writes the solution to a vtk file @@ -433,8 +456,8 @@ private: //storage for pressure data, for each element we store the //pressure at the corners of the element, the VTKFunction will //create the output using a linear interpolation for each element - Dune::DynamicVector<Scalar> pressure(dof, 0.0); - Dune::DynamicVector<Scalar> exactPressure(dof, 0.0); + Dune::DynamicVector<Scalar> pressure(dof_, 0.0); + Dune::DynamicVector<Scalar> exactPressure(dof_, 0.0); for (const auto& elem : elements(gridView_)) { diff --git a/dune/mmdg/mmdg.hh b/dune/mmdg/mmdg.hh index e5f79b72ba5f852fc346544895e6236b590bea62..be1b24ac60acd88c0f047352fb0cc2b701049a16 100644 --- a/dune/mmdg/mmdg.hh +++ b/dune/mmdg/mmdg.hh @@ -1,6 +1,177 @@ #ifndef DUNE_MMDG_HH #define DUNE_MMDG_HH -// add your classes here +#include <dune/mmdg/dg.hh> -#endif // DUNE_MMDG_HH +template<class Grid, class GridView, class Mapper, class InterfaceGridView, + class InterfaceMapper, class Problem> +class MMDG : public DG<Grid, GridView, Mapper, Problem> +{ +public: + static constexpr int dim = GridView::dimension; + + using Base = DG<Grid, GridView, Mapper, Problem>; + using Scalar = typename Base::Scalar; + using Matrix = typename Base::Matrix; + using Vector = typename Base::Vector; + using Coordinate = Dune::FieldVector<Scalar, dim>; + using QRuleInterface = Base::QRuleEdge; + using QRulesInterface = Base::QRuleEdges; + static constexpr auto iSimplex = Dune::GeometryTypes::simplex(dim-1); + + //constructor + MMDG (const Grid& grid, const GridView& gridView, const Mapper& mapper, + const InterfaceGridView& iGridView, const InterfaceMapper& iMapper, + const Problem& problem) : + Base(grid, gridView, mapper, problem, + (1 + dim) * gridView.size(0) + dim * iGridView.size(0)), + iGridView_(iGridView), iMapper_(iMapper) {} + + const void operator() (const Scalar mu) + { + assembleSLE(mu); + Base::A->compress(); + } + + const InterfaceGridView& iGridView_; + const InterfaceMapper& iMapper_; + +private: + //assemble stiffness matrix A and load vector b + void assembleSLE (const Scalar mu) + { + //quadrature rules + const QRuleInterface& rule_qInterface = + QRulesInterface::rule(iSimplex, problem_.quadratureOrder_qInterface()); + + //we use the bulk basis + // phi_elem,0 (x) = indicator(elem); + // phi_elem,i (x) = x[i]*indicator(elem); + //for elem in elements(gridView) and i = 1,...,dim + + //we use the interface basis + // phi_iElem,0 (x) = indicator(elem); + // phi_iElem,i (x) = (x * tau_i)*indicator(elem); + //for iElem in elements(iGridView) and i = 1,...,dim-1 + //where {tau_i | i=1,...,dim-1} is the interface coordinate system given + //by the method interfaceFrame(normal) + + //in total we use the basis given by the union of + // { (phi_elem,i , 0) | elem in elements(gridView), i = 0,...,dim } + //and + // { (0 , phi_iElem,i ) | iElem in elements(iGridView), i = 0,...,dim-1 } + + //thus the stiffness matrix A and the load vector b exhibit the following + //block structure + // A = [ bulk, coupling b = [ bulk, + // coupling, interface], interface ] + + //call base class method for the assignment to fill stiffness matrix A + //and load vector b with bulk entries + Base::assembleSLE(mu); + + for (const auto& iElem : elements(iGridView_)) + { + const int iElemIdx = iMapper_.index(iElem); + const auto& iGeo = iElem.geometry(); + + //get basis of the interface coordinate system for evaluation of + //basis function phi_iElem,i with i=1,...,dim-1 + const std::array<Coordinate, dim-1> iFrame = interfaceFrame( + Base::grid_.asIntersection(iElem).centerUnitOuterNormal()); + + //in the total system of linear equations (SLE) Ad = b, + //the index iElemIdxSLE refers to the basis function (0, phi_iElem,0) + //and the indices iElemIdxSLE + i + 1, i = 1,...,dim-1, refer to the + //basis functions (0, phi_iElem,i) + const int iElemIdxSLE = (dim + 1)*Base::gridView_.size(0) + dim*iElemIdx; + + //fill load vector b with interface entries using a quadrature rule + for (const auto& ip : rule_qInterface) + { + //quadrature point in local and global coordinates + const auto& qpLocal = ip.position(); + const auto& qpGlobal = iGeo.global(qpLocal); + + const Scalar weight(ip.weight()); + const Scalar integrationElem(iGeo.integrationElement(qpLocal)); + const Scalar qInterfaceEvaluation(problem_.qInterface(qpGlobal)); + + //quadrature for int_elem q*phi_elem,0 dV + b[iElemIdxSLE] += weight * integrationElem * qEvaluation; + + //quadrature for int_elem q*phi_elem,i dV + for (int i = 0; i < dim - 1; i++) + { + b[iElemIdxSLE + i + 1] += + weight * integrationElem * (qpGlobal * iFrame[i]) * qEvaluation; + } + } + + //TODO: fill stiffness matrix A with interface entries + + //fill stiffness matrix A with coupling entries + for (const auto& elem : elements(Base::gridView_)) + { + //TODO + } + } + } + + //returns a basis of the interface coordinate system + //2d: tau = [ normal[1], + // -normal[0] ] + //3d: tau_1 ~ [ normal[1] + normal[2], tau_2 ~ [ -normal[1], + // -normal[0], normal[0] + normal[2] + // -normal[0] ], -normal[1] ] + std::array<Coordinate, dim-1> interfaceFrame(const Coordinate& normal) + { + for (int i = 0; i < dim - 1; i++) + { + Coordinate tau(0.0); + for (int j = 0; j < dim - 1; j++) + { + if (j == i) + { + continue; + } + + tau[i] += normal[j]; + tau[j] = -normal[i]; + } + tau /= tau.two_norm(); + + interfaceFrame[i] = tau; + } +/* //NOTE: which version is better? + if constexpr (dim == 2) + { + Coordinate tau; + tau[0] = normal[1]; + tau[1] = -normal[0]; + + interfaceFrame = {tau}; + } + else if constexpr (dim == 3) + { + Coordinate tau1; + tau1[0] = normal[1] + normal[2]; + tau1[1] = -normal[0]; + tau1[2] = -normal[0]; + Coordinate tau2; + tau2[0] = -normal[1]; + tau2[1] = normal[0] + normal[2]; + tau2[2] = -normal[1]; + interfaceFrame = {tau1, tau2}; + } + else + { + DUNE_THROW(Dune::Exception, + "Invalid dimension: dim = " + std::to_string(dim)); + }*/ + } + + +}; + +#endif diff --git a/dune/mmdg/problems/dgproblem.hh b/dune/mmdg/problems/dgproblem.hh index 64cc67fd5b9c163db702e1e184b8ccdbf0d13138..982015eaf089143a0fd010dba1fb30f72efa75d5 100644 --- a/dune/mmdg/problems/dgproblem.hh +++ b/dune/mmdg/problems/dgproblem.hh @@ -3,13 +3,11 @@ //abstract class providing an interface for a problem that is to be solved with //a discontinuous Galerkin scheme -template<class Coordinate, class ctype = double> +template<class Vector, class Scalar = double> class DGProblem { public: - using Scalar = ctype; - using Vector = Coordinate; - static constexpr int dimension = Coordinate::dimension; + static constexpr int dimension = Vector::dimension; using Matrix = Dune::FieldMatrix<Scalar, dimension, dimension>; //the exact solution at position pos diff --git a/src/dg.cc b/src/dg.cc index 8b160fec3ca62e53607e1a442eb1fd2c8e92d804..9f7f07c5cecb2f2a0ccacd6cf148c512350d824c 100644 --- a/src/dg.cc +++ b/src/dg.cc @@ -41,6 +41,8 @@ int main(int argc, char** argv) using GridView = typename Grid::LeafGridView; using Mapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<GridView>; using Coordinate = Dune::FieldVector<double, dim>; + using Problem = DGProblem<Coordinate>; + using DG = DG<Grid, GridView, Mapper, Problem>; //get parameters from file "parameterDG.ini" Dune::ParameterTree pt; @@ -50,15 +52,14 @@ int main(int argc, char** argv) const double mu = std::stod(pt["mu"]); //create a grid from .dgf file - GridFactory gridFactory( "grids/cube" + std::to_string(dim) + - "d.dgf" ); + GridFactory gridFactory( "grids/cube" + std::to_string(dim) + "d.dgf" ); const Grid& grid = *gridFactory.grid(); const GridView& gridView = grid.leafGridView(); //element mapper for the leaf grid view const Mapper mapper(gridView, Dune::mcmgElementLayout()); - DGProblem<Coordinate>* problem; //problem to be solved + Problem* problem; //problem to be solved //determine problem type if (pt["problem"] == "poisson") @@ -72,7 +73,8 @@ int main(int argc, char** argv) "parameterDG.ini (use 'poisson' or TODO)"); } - const DG dg(gridView, mapper, *problem); + //DG<GridView, Mapper, Problem> dg(gridView, mapper, *problem); + DG dg(grid, gridView, mapper, *problem); dg(mu); diff --git a/src/mmdg.cc b/src/mmdg.cc index 61ea9c46f1b6dd98d48505af1f71279d9678ee9e..aea7f9a8660c145c718a1f1a56addde93fccb578 100644 --- a/src/mmdg.cc +++ b/src/mmdg.cc @@ -1,30 +1,102 @@ -// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- -// vi: set et ts=4 sw=2 sts=2: - #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include <iostream> -#include <dune/common/parallel/mpihelper.hh> // An initializer of MPI -#include <dune/common/exceptions.hh> // We use exceptions + +#include <sys/stat.h> +#include <sys/types.h> +#include <type_traits> + +#include <dune/common/exceptions.hh> +#include <dune/common/parametertree.hh> +#include <dune/common/parametertreeparser.hh> + +#include <dune/grid/common/mcmgmapper.hh> +#include <dune/grid/io/file/dgfparser/dgfyasp.hh> +#include <dune/grid/io/file/dgfparser/dgfug.hh> + +#include <dune/mmesh/mmesh.hh> + +#include <dune/mmdg/mmdg.hh> +#include <dune/mmdg/clockhelper.hh> +#include <dune/mmdg/problems/dgproblem.hh> +#include <dune/mmdg/problems/poisson.hh> + int main(int argc, char** argv) { - try{ - // Maybe initialize MPI - Dune::MPIHelper& helper = Dune::MPIHelper::instance(argc, argv); - std::cout << "Hello World! This is dune-mmdg." << std::endl; - if(Dune::MPIHelper::isFake) - std::cout<< "This is a sequential program." << std::endl; + try + { + using Clock = std::chrono::steady_clock; + + //start run time measurement + const Clock::time_point timeInitial = Clock::now(); + + static constexpr int dim = GRIDDIM; + + using Grid = Dune::MovingMesh<dim>; + using GridFactory = Dune::DGFGridFactory<Grid>; + using GridView = typename Grid::LeafGridView; + using Mapper = typename Dune::MultipleCodimMultipleGeomTypeMapper<GridView>; + using IGrid = typename Grid::InterfaceGrid; + using IGridView = typename IGrid::LeafGridView; + using IMapper = + typename Dune::MultipleCodimMultipleGeomTypeMapper<IGridView>; + using Coordinate = Dune::FieldVector<double, dim>; + using Problem = DGProblem<Coordinate>; + using MMDG = MMDG<Grid, GridView, Mapper, IGridView, IMapper, Problem>; + + //get parameters from file "parameterDG.ini" + Dune::ParameterTree pt; + Dune::ParameterTreeParser::readINITree("parameterMMDG.ini", pt); + + //assume constant penalty parameter + const double mu = std::stod(pt["mu"]); + + //create a grid from .dgf file + GridFactory gridFactory( "grids/cube" + std::to_string(dim) + "d.dgf" ); + const Grid& grid = *gridFactory.grid(); + const GridView& gridView = grid.leafGridView(); + const IGrid& iGrid = grid.interfaceGrid(); + const IGridView& iGridView = iGrid.leafGridView(); + + //element mapper for the leaf grid views + const Mapper mapper(gridView, Dune::mcmgElementLayout()); + const IMapper iMapper(iGridView, Dune::mcmgElementLayout()); + + Problem* problem; //problem to be solved + + //determine problem type + if (pt["problem"] == "poisson") + { + problem = new Poisson<dim>(); + } else - std::cout<<"I am rank "<<helper.rank()<<" of "<<helper.size() - <<" processes!"<<std::endl; + { + DUNE_THROW(Dune::Exception, + "Invalid problem type or parameter 'problem' not specified in file " + "parameterDG.ini (use 'poisson' or TODO)"); + } + + MMDG mmdg(grid, gridView, mapper, iGridView, iMapper, *problem); + mmdg(mu); + + //print total run time + const double timeTotal = ClockHelper::elapsedRuntime(timeInitial); + std::cout << "Finished with a total run time of " << timeTotal << + " Seconds.\n"; + return 0; } - catch (Dune::Exception &e){ - std::cerr << "Dune reported error: " << e << std::endl; + catch (Dune::Exception& e) + { + std::cerr << "Dune reported error: " << e.what() << std::endl; + } + catch (std::exception& e) + { + std::cerr << "Error: " << e.what() << std::endl; } - catch (...){ + catch (...) + { std::cerr << "Unknown exception thrown!" << std::endl; } } diff --git a/src/parameterDG.ini b/src/parameterDG.ini index 808b309c788e7fb01abf6fe8127d74a91f0a991e..165571303cbed4b80a298d46af9b7007f682ed5d 100644 --- a/src/parameterDG.ini +++ b/src/parameterDG.ini @@ -1,3 +1,2 @@ -K = 1 mu = 1000 problem = poisson diff --git a/src/parameterMMDG.ini b/src/parameterMMDG.ini index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..165571303cbed4b80a298d46af9b7007f682ed5d 100644 --- a/src/parameterMMDG.ini +++ b/src/parameterMMDG.ini @@ -0,0 +1,2 @@ +mu = 1000 +problem = poisson