From c8a947857caec88d6d3d10b185e2425b6a694bd7 Mon Sep 17 00:00:00 2001 From: Timo Koch <timo.koch@iws.uni-stuttgart.de> Date: Mon, 9 Jul 2018 18:50:10 +0200 Subject: [PATCH] [test][boundary] Add 1p1p darcy-darcy test with tpfa (domain decomposition) --- test/multidomain/CMakeLists.txt | 1 + test/multidomain/boundary/CMakeLists.txt | 1 + .../boundary/darcydarcy/1p_1p/CMakeLists.txt | 22 ++ .../boundary/darcydarcy/1p_1p/main.cc | 353 ++++++++++++++++++ .../boundary/darcydarcy/1p_1p/problem.hh | 163 ++++++++ .../darcydarcy/1p_1p/spatialparams.hh | 114 ++++++ .../1p_1p/test_boundary_equaldim_1p_1p.input | 34 ++ .../boundary/darcydarcy/CMakeLists.txt | 1 + 8 files changed, 689 insertions(+) create mode 100644 test/multidomain/boundary/CMakeLists.txt create mode 100644 test/multidomain/boundary/darcydarcy/1p_1p/CMakeLists.txt create mode 100644 test/multidomain/boundary/darcydarcy/1p_1p/main.cc create mode 100644 test/multidomain/boundary/darcydarcy/1p_1p/problem.hh create mode 100644 test/multidomain/boundary/darcydarcy/1p_1p/spatialparams.hh create mode 100644 test/multidomain/boundary/darcydarcy/1p_1p/test_boundary_equaldim_1p_1p.input create mode 100644 test/multidomain/boundary/darcydarcy/CMakeLists.txt diff --git a/test/multidomain/CMakeLists.txt b/test/multidomain/CMakeLists.txt index fe1923bdc7..d6f0a545fe 100644 --- a/test/multidomain/CMakeLists.txt +++ b/test/multidomain/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(embedded) add_subdirectory(poromechanics) +add_subdirectory(boundary) diff --git a/test/multidomain/boundary/CMakeLists.txt b/test/multidomain/boundary/CMakeLists.txt new file mode 100644 index 0000000000..51f43731d8 --- /dev/null +++ b/test/multidomain/boundary/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(darcydarcy) diff --git a/test/multidomain/boundary/darcydarcy/1p_1p/CMakeLists.txt b/test/multidomain/boundary/darcydarcy/1p_1p/CMakeLists.txt new file mode 100644 index 0000000000..510844ae3d --- /dev/null +++ b/test/multidomain/boundary/darcydarcy/1p_1p/CMakeLists.txt @@ -0,0 +1,22 @@ +dune_add_test(NAME test_boundary_equaldim_1p_1p_half + SOURCES main.cc + COMPILE_DEFINITIONS DOMAINSPLIT=0 + COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py + CMD_ARGS --script fuzzy + --files ${CMAKE_SOURCE_DIR}/test/references/1ptestcc-reference.vtu + ${CMAKE_CURRENT_BINARY_DIR}/md_1p_half_combined.vtu + --command "${CMAKE_CURRENT_BINARY_DIR}/test_boundary_equaldim_1p_1p_half test_boundary_equaldim_1p_1p.input \ + -Problem.Name md_1p_half") + +dune_add_test(NAME test_boundary_equaldim_1p_1p_lens + SOURCES main.cc + COMPILE_DEFINITIONS DOMAINSPLIT=1 + COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py + CMAKE_GUARD dune-subgrid_FOUND + CMD_ARGS --script fuzzy + --files ${CMAKE_SOURCE_DIR}/test/references/1ptestcc-reference.vtu + ${CMAKE_CURRENT_BINARY_DIR}/md_1p_lens_combined.vtu + --command "${CMAKE_CURRENT_BINARY_DIR}/test_boundary_equaldim_1p_1p_lens test_boundary_equaldim_1p_1p.input \ + -Problem.Name md_1p_lens") + +dune_symlink_to_source_files(FILES "test_boundary_equaldim_1p_1p.input") diff --git a/test/multidomain/boundary/darcydarcy/1p_1p/main.cc b/test/multidomain/boundary/darcydarcy/1p_1p/main.cc new file mode 100644 index 0000000000..3d7be9226f --- /dev/null +++ b/test/multidomain/boundary/darcydarcy/1p_1p/main.cc @@ -0,0 +1,353 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * + * \brief Test for the equal dimension boundary coupling model + */ +#include <config.h> + +#include <ctime> +#include <iostream> +#include <fstream> + +#include <dune/common/parallel/mpihelper.hh> +#include <dune/common/timer.hh> + +#include <dumux/common/properties.hh> +#include <dumux/common/parameters.hh> +#include <dumux/common/dumuxmessage.hh> +#include <dumux/linear/seqsolverbackend.hh> +#include <dumux/assembly/diffmethod.hh> +#include <dumux/discretization/methods.hh> +#include <dumux/io/vtkoutputmodule.hh> +#include <dumux/io/grid/gridmanager.hh> +#include <dumux/io/grid/subgridgridcreator.hh> + +#include <dumux/porousmediumflow/1p/model.hh> +#include <dumux/material/components/simpleh2o.hh> +#include <dumux/material/fluidsystems/1pliquid.hh> +#include <dumux/discretization/cellcentered/tpfa/properties.hh> +#include <dumux/discretization/cellcentered/tpfa/fvgridgeometry.hh> + +#include <dumux/multidomain/traits.hh> +#include <dumux/multidomain/fvassembler.hh> +#include <dumux/multidomain/newtonsolver.hh> +#include <dumux/multidomain/boundary/darcydarcy/couplingmanager.hh> + +#include "problem.hh" + +#ifndef DOMAINSPLIT +#define DOMAINSPLIT 0 +#endif + +namespace Dumux { +namespace Properties { + +NEW_TYPE_TAG(OnePSubTypeTag, INHERITS_FROM(CCTpfaModel, OneP)); +// differentiate between the two subproblems +NEW_TYPE_TAG(OnePSubTypeTag0, INHERITS_FROM(OnePSubTypeTag)); +NEW_TYPE_TAG(OnePSubTypeTag1, INHERITS_FROM(OnePSubTypeTag)); + +// the coupling manager +SET_TYPE_PROP(OnePSubTypeTag, CouplingManager, + DarcyDarcyBoundaryCouplingManager<MultiDomainTraits<TTAG(OnePSubTypeTag0), TTAG(OnePSubTypeTag1)>>); + +// Set the grid type +#if DOMAINSPLIT==1 +SET_PROP(OnePSubTypeTag, Grid) +{ + using FullDomainGrid = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; + using type = Dune::SubGrid<FullDomainGrid::dimension, FullDomainGrid>; +}; +#elif DOMAINSPLIT==0 +SET_PROP(OnePSubTypeTag, Grid) +{ + using FullDomainGrid = Dune::YaspGrid<2, Dune::EquidistantOffsetCoordinates<double, 2>>; + using type = FullDomainGrid; +}; +#endif + +// set the spatial params +SET_TYPE_PROP(OnePSubTypeTag, SpatialParams, OnePTestSpatialParams<typename GET_PROP_TYPE(TypeTag, FVGridGeometry), + typename GET_PROP_TYPE(TypeTag, Scalar)>); + +// the fluid system +SET_PROP(OnePSubTypeTag, FluidSystem) +{ + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using type = FluidSystems::OnePLiquid<Scalar, Components::SimpleH2O<Scalar> >; +}; + +// differentiate between the two subproblems +SET_TYPE_PROP(OnePSubTypeTag0, Problem, OnePTestProblem<TypeTag, 0>); +SET_TYPE_PROP(OnePSubTypeTag1, Problem, OnePTestProblem<TypeTag, 1>); + +} // end namespace Properties +} // end namespace Dumux + +int main(int argc, char** argv) try +{ + using namespace Dumux; + + // initialize MPI, finalize is done automatically on exit + const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv); + + // print dumux start message + if (mpiHelper.rank() == 0) + DumuxMessage::print(/*firstCall=*/true); + + // parse command line arguments and input file + Parameters::init(argc, argv); + + // Define the sub problem type tags + using TypeTag = TTAG(OnePSubTypeTag); + using SubTypeTag0 = TTAG(OnePSubTypeTag0); + using SubTypeTag1 = TTAG(OnePSubTypeTag1); + + // create the full grid that we are gonna split for the output + using FullDomainGrid = typename GET_PROP(TypeTag, Grid)::FullDomainGrid; + GridManager<FullDomainGrid> gridManager; + gridManager.init(); + + // get the lens + using GlobalPosition = typename FullDomainGrid::template Codim<0>::Geometry::GlobalCoordinate; + const auto lensLowerLeft = getParam<GlobalPosition>("SpatialParams.LensLowerLeft"); + const auto lensUpperRight = getParam<GlobalPosition>("SpatialParams.LensUpperRight"); + +/////////////////////////////////////////////////////////////////////////////////////////// +// split the domains by creating two separate grids for lens and the rest (using sub-grid) +/////////////////////////////////////////////////////////////////////////////////////////// +#if DOMAINSPLIT==1 + + // create subgrids coinciding with the lens + auto elementSelector0 = [&lensLowerLeft, &lensUpperRight](const auto& element) + { return LensSpatialParams::pointInLens(element.geometry().center(), lensLowerLeft, lensUpperRight); }; + auto elementSelector1 = [&lensLowerLeft, &lensUpperRight](const auto& element) + { return !LensSpatialParams::pointInLens(element.geometry().center(), lensLowerLeft, lensUpperRight); }; + + auto subGrid0 = SubgridGridCreator<FullDomainGrid>::makeGrid(gridManager.grid(), elementSelector0); + auto subGrid1 = SubgridGridCreator<FullDomainGrid>::makeGrid(gridManager.grid(), elementSelector1); + + //////////////////////////////////////////////////////////// + // run instationary non-linear problem on this grid + //////////////////////////////////////////////////////////// + + // we compute on the leaf grid views + const auto& gridView0 = subGrid0->leafGridView(); + const auto& gridView1 = subGrid1->leafGridView(); + +////////////////////////////////////////////////////////////////////////////////// +// split the domains by creating two separate grids for the lower and upper half +////////////////////////////////////////////////////////////////////////////////// +#elif DOMAINSPLIT==0 + + // create an upper half and lower half grid + GridManager<typename GET_PROP_TYPE(TypeTag, Grid)> gridManager0, gridManager1; + gridManager0.init("1"); + gridManager1.init("2"); + + // we compute on the leaf grid views + const auto& gridView0 = gridManager0.grid().leafGridView(); + const auto& gridView1 = gridManager1.grid().leafGridView(); + +#endif + + //////////////////////////////////////////////// + // run the multidomain simulation on two grids + //////////////////////////////////////////////// + + // create the finite volume grid geometries + using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); + auto fvGridGeometry0 = std::make_shared<FVGridGeometry>(gridView0); + auto fvGridGeometry1 = std::make_shared<FVGridGeometry>(gridView1); + fvGridGeometry0->update(); + fvGridGeometry1->update(); + + // the mixed dimension type traits + using Traits = MultiDomainTraits<SubTypeTag0, SubTypeTag1>; + constexpr auto domain0Idx = Traits::template DomainIdx<0>(); + constexpr auto domain1Idx = Traits::template DomainIdx<1>(); + + // the coupling manager + using CouplingManager = typename GET_PROP_TYPE(TypeTag, CouplingManager); + auto couplingManager = std::make_shared<CouplingManager>(); + + // the problem (initial and boundary conditions) + using Problem0 = typename GET_PROP_TYPE(SubTypeTag0, Problem); + auto problem0 = std::make_shared<Problem0>(fvGridGeometry0, couplingManager, "1"); + problem0->spatialParams().setLens(lensLowerLeft, lensUpperRight); + using Problem1 = typename GET_PROP_TYPE(SubTypeTag1, Problem); + auto problem1 = std::make_shared<Problem1>(fvGridGeometry1, couplingManager, "2"); + problem1->spatialParams().setLens(lensLowerLeft, lensUpperRight); + + // the solution vector + Traits::SolutionVector sol; + sol[domain0Idx].resize(fvGridGeometry0->numDofs()); + sol[domain1Idx].resize(fvGridGeometry1->numDofs()); + problem0->applyInitialSolution(sol[domain0Idx]); + problem1->applyInitialSolution(sol[domain1Idx]); + auto oldSol = sol; + + // compute the coupling map + couplingManager->init(problem0, problem1, sol); + + // the grid variables + using GridVariables0 = typename GET_PROP_TYPE(SubTypeTag0, GridVariables); + auto gridVariables0 = std::make_shared<GridVariables0>(problem0, fvGridGeometry0); + using GridVariables1 = typename GET_PROP_TYPE(SubTypeTag1, GridVariables); + auto gridVariables1 = std::make_shared<GridVariables1>(problem1, fvGridGeometry1); + gridVariables0->init(sol[domain0Idx], oldSol[domain0Idx]); + gridVariables1->init(sol[domain1Idx], oldSol[domain1Idx]); + + // get some time loop parameters + using Scalar = Traits::Scalar; + const auto tEnd = getParam<Scalar>("TimeLoop.TEnd"); + const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize"); + auto dt = getParam<Scalar>("TimeLoop.DtInitial"); + + // intialize the vtk output module + VtkOutputModule<SubTypeTag0> vtkWriter0(*problem0, *fvGridGeometry0, *gridVariables0, sol[domain0Idx], problem0->name()); + GET_PROP_TYPE(SubTypeTag0, VtkOutputFields)::init(vtkWriter0); + vtkWriter0.write(0.0); + + VtkOutputModule<SubTypeTag1> vtkWriter1(*problem1, *fvGridGeometry1, *gridVariables1, sol[domain1Idx], problem1->name()); + GET_PROP_TYPE(SubTypeTag1, VtkOutputFields)::init(vtkWriter1); + vtkWriter1.write(0.0); + + // instantiate time loop + auto timeLoop = std::make_shared<TimeLoop<Scalar>>(0.0, dt, tEnd); + timeLoop->setMaxTimeStepSize(maxDt); + + // the assembler with time loop for instationary problem + using Assembler = MultiDomainFVAssembler<Traits, CouplingManager, DiffMethod::numeric>; + auto assembler = std::make_shared<Assembler>(std::make_tuple(problem0, problem1), + std::make_tuple(fvGridGeometry0, fvGridGeometry1), + std::make_tuple(gridVariables0, gridVariables1), + couplingManager, timeLoop); + + // the linear solver + using LinearSolver = ILU0BiCGSTABBackend; + auto linearSolver = std::make_shared<LinearSolver>(); + + // the non-linear solver + using NewtonSolver = MultiDomainNewtonSolver<Assembler, LinearSolver, CouplingManager>; + NewtonSolver nonLinearSolver(assembler, linearSolver, couplingManager); + + // time loop + timeLoop->start(); + while (!timeLoop->finished()) + { + // set previous solution for storage evaluations + assembler->setPreviousSolution(oldSol); + + // solve the non-linear system with time step control + nonLinearSolver.solve(sol, *timeLoop); + + // make the new solution the old solution + oldSol = sol; + gridVariables0->advanceTimeStep(); + gridVariables1->advanceTimeStep(); + + // advance to the time loop to the next step + timeLoop->advanceTimeStep(); + + // write vtk output + vtkWriter0.write(timeLoop->time()); + vtkWriter1.write(timeLoop->time()); + + // report statistics of this time step + timeLoop->reportTimeStep(); + + // set new dt as suggested by newton controller + timeLoop->setTimeStepSize(nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize())); + } + + timeLoop->finalize(mpiHelper.getCollectiveCommunication()); + + ////////////////////////////////////////////////////////////////////////// + // write out a combined vtu for vtu comparison in the testing framework + ////////////////////////////////////////////////////////////////////////// + + const auto& gridView = gridManager.grid().leafGridView(); + CCTpfaFVGridGeometry<typename FullDomainGrid::LeafGridView> fvGridGeometry(gridView); + const auto& bBoxTree = fvGridGeometry.boundingBoxTree(); + // copy data from the subdomains to full domain data vectors + std::vector<int> processRank(gridView.size(0), 0); // sequential simulation + std::vector<int> pressure(gridView.size(0)); + + for (const auto& element : elements(gridView0)) + { + const auto eIdx = fvGridGeometry0->elementMapper().index(element); + const auto eIdxHost = intersectingEntities(element.geometry().center(), bBoxTree)[0]; + pressure[eIdxHost] = sol[domain0Idx][eIdx][0]; + } + + for (const auto& element : elements(gridView1)) + { + const auto eIdx = fvGridGeometry1->elementMapper().index(element); + const auto eIdxHost = intersectingEntities(element.geometry().center(), bBoxTree)[0]; + pressure[eIdxHost] = sol[domain1Idx][eIdx][0]; + } + + Dune::VTKWriter<typename FullDomainGrid::LeafGridView> vtkWriter(gridView); + vtkWriter.addCellData(processRank, "process rank"); + vtkWriter.addCellData(pressure, "pressure"); + const auto filename = getParam<std::string>("Problem.Name") + "_combined"; + vtkWriter.write(filename); + + //////////////////////////////////////////////////////////// + // finalize, print dumux message to say goodbye + //////////////////////////////////////////////////////////// + + // print dumux end message + if (mpiHelper.rank() == 0) + { + Parameters::print(); + DumuxMessage::print(/*firstCall=*/false); + } + + return 0; +} + +// error handler +catch (Dumux::ParameterException &e) +{ + std::cerr << std::endl << e << " ---> Abort!" << std::endl; + return 1; +} +catch (Dune::DGFException & e) +{ + std::cerr << "DGF exception thrown (" << e << + "). Most likely, the DGF file name is wrong " + "or the DGF file is corrupted, " + "e.g. missing hash at end of file or wrong number (dimensions) of entries." + << " ---> Abort!" << std::endl; + return 2; +} +catch (Dune::Exception &e) +{ + std::cerr << "Dune reported error: " << e << " ---> Abort!" << std::endl; + return 3; +} +catch (...) +{ + std::cerr << "Unknown exception thrown! ---> Abort!" << std::endl; + return 4; +} diff --git a/test/multidomain/boundary/darcydarcy/1p_1p/problem.hh b/test/multidomain/boundary/darcydarcy/1p_1p/problem.hh new file mode 100644 index 0000000000..35f82fa8d2 --- /dev/null +++ b/test/multidomain/boundary/darcydarcy/1p_1p/problem.hh @@ -0,0 +1,163 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \ingroup OnePTests + * \brief The properties for the incompressible test + */ +#ifndef DUMUX_ONEP_SUB_TEST_PROBLEM_HH +#define DUMUX_ONEP_SUB_TEST_PROBLEM_HH + +#include <dumux/porousmediumflow/problem.hh> +#include "spatialparams.hh" + +namespace Dumux { + +/*! + * \ingroup OnePTests + * \brief Multidomain test problem for the incompressible one-phase model + * \todo doc me! + */ +template<class TypeTag, std::size_t tag> +class OnePTestProblem +: public PorousMediumFlowProblem<TypeTag> +{ + using ParentType = PorousMediumFlowProblem<TypeTag>; + using CouplingManager = typename GET_PROP_TYPE(TypeTag, CouplingManager); + using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); + using FVElementGeometry = typename FVGridGeometry::LocalView; + using SubControlVolumeFace = typename FVGridGeometry::SubControlVolumeFace; + using GridView = typename FVGridGeometry::GridView; + using Element = typename GridView::template Codim<0>::Entity; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using NumEqVector = typename GET_PROP_TYPE(TypeTag, NumEqVector); + using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices; + using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes); + static constexpr int dimWorld = GridView::dimensionworld; + using GlobalPosition = typename Element::Geometry::GlobalCoordinate; + static constexpr auto domainIdx = Dune::index_constant<tag>{}; + +public: + OnePTestProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry, + std::shared_ptr<CouplingManager> couplingManager, + const std::string& paramGroup = "") + : ParentType(fvGridGeometry, paramGroup) + , couplingManager_(couplingManager) + {} + + /*! + * \brief Specifies which kind of boundary condition should be + * used for which equation on a given boundary segment. + * + * \param element The finite element + * \param scvf The sub control volume face + */ + BoundaryTypes boundaryTypes(const Element &element, + const SubControlVolumeFace &scvf) const + { + BoundaryTypes values; + const auto& globalPos = scvf.ipGlobal(); + + if (globalPos[dimWorld-1] < this->fvGridGeometry().bBoxMin()[dimWorld-1] + eps_ + || globalPos[dimWorld-1] > this->fvGridGeometry().bBoxMax()[dimWorld-1] - eps_) + values.setAllDirichlet(); + else + values.setAllNeumann(); + + if (couplingManager_->isCoupled(domainIdx, scvf)) + values.setAllCouplingNeumann(); + + return values; + } + + /*! + * \brief Evaluate the boundary conditions for a neumann + * boundary segment. + * + * This is the method for the case where the Neumann condition is + * potentially solution dependent + * + * \param element The finite element + * \param fvGeometry The finite-volume geometry + * \param elemVolVars All volume variables for the element + * \param scvf The sub control volume face + * + * Negative values mean influx. + * E.g. for the mass balance that would the mass flux in \f$ [ kg / (m^2 \cdot s)] \f$. + */ + template<class ElementVolumeVariables> + NumEqVector neumann(const Element& element, + const FVElementGeometry& fvGeometry, + const ElementVolumeVariables& elemVolVars, + const SubControlVolumeFace& scvf) const + { + NumEqVector values(0.0); + const auto bcTypes = boundaryTypes(element, scvf); + if (bcTypes.hasCouplingNeumann()) + values[Indices::conti0EqIdx] = couplingManager_->advectiveFluxCoupling(domainIdx, element, fvGeometry, elemVolVars, scvf); + + return values; + } + + /*! + * \brief Evaluate the boundary conditions for a dirichlet + * control volume. + * + * \param values The dirichlet values for the primary variables + * \param globalPos The center of the finite volume which ought to be set. + * + * For this method, the \a values parameter stores primary variables. + */ + PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const + { + PrimaryVariables values(0.0); + values[0] = 1.0e+5*(2.0 - globalPos[dimWorld-1]); + return values; + } + + /*! + * \brief Returns the temperature \f$\mathrm{[K]}\f$ for an isothermal problem. + * + * This is not specific to the discretization. By default it just + * throws an exception so it must be overloaded by the problem if + * no energy equation is used. + */ + Scalar temperature() const + { + return 283.15; // 10°C + } + + /*! + * \brief Evaluate the initial value for a control volume. + * + * \param globalPos The global position + */ + PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const + { return dirichletAtPos(globalPos); } + + +private: + std::shared_ptr<CouplingManager> couplingManager_; + static constexpr Scalar eps_ = 1e-7; +}; + +} // end namespace Dumux + +#endif diff --git a/test/multidomain/boundary/darcydarcy/1p_1p/spatialparams.hh b/test/multidomain/boundary/darcydarcy/1p_1p/spatialparams.hh new file mode 100644 index 0000000000..9700bad520 --- /dev/null +++ b/test/multidomain/boundary/darcydarcy/1p_1p/spatialparams.hh @@ -0,0 +1,114 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program 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 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \ingroup OnePTests + * \brief The spatial params the incompressible test + */ +#ifndef DUMUX_INCOMPRESSIBLE_ONEP_TEST_SPATIAL_PARAMS_HH +#define DUMUX_INCOMPRESSIBLE_ONEP_TEST_SPATIAL_PARAMS_HH + +#include <limits> +#include <dumux/material/spatialparams/fv1p.hh> + +namespace Dumux { +namespace LensSpatialParams { +/*! + * \brief If a point is in a lens with a given bounding box + * + * \param globalPos the position of the point + * \param lensLowerLeft the lower left corner of the lens + * \param lensUpperRight the upper right corner of the lens + */ +template<class GlobalPosition> +bool pointInLens(const GlobalPosition& globalPos, + const GlobalPosition& lensLowerLeft, + const GlobalPosition& lensUpperRight) +{ + const auto eps = 1e-8*(lensUpperRight - lensLowerLeft).two_norm(); + for (int i = 0; i < GlobalPosition::size(); ++i) + if (globalPos[i] < lensLowerLeft[i] + eps || globalPos[i] > lensUpperRight[i] - eps) + return false; + + return true; +} +} // end namespace LensSpatialParams + +/*! + * \ingroup OnePTests + * \brief The spatial parameters class for the test problem using the + * incompressible 1p model + */ +template<class FVGridGeometry, class Scalar> +class OnePTestSpatialParams +: public FVSpatialParamsOneP<FVGridGeometry, Scalar, OnePTestSpatialParams<FVGridGeometry, Scalar>> +{ + using ThisType = OnePTestSpatialParams<FVGridGeometry, Scalar>; + using ParentType = FVSpatialParamsOneP<FVGridGeometry, Scalar, ThisType>; + using GridView = typename FVGridGeometry::GridView; + using Element = typename GridView::template Codim<0>::Entity; + using FVElementGeometry = typename FVGridGeometry::LocalView; + using SubControlVolume = typename FVElementGeometry::SubControlVolume; + + static constexpr int dimWorld = GridView::dimensionworld; + using GlobalPosition = typename Element::Geometry::GlobalCoordinate; + +public: + using PermeabilityType = Scalar; + OnePTestSpatialParams(std::shared_ptr<const FVGridGeometry> fvGridGeometry) + : ParentType(fvGridGeometry) + , lensLowerLeft_(std::numeric_limits<Scalar>::max()) + , lensUpperRight_(std::numeric_limits<Scalar>::lowest()) + { + permeability_ = getParam<Scalar>("SpatialParams.Permeability"); + permeabilityLens_ = getParam<Scalar>("SpatialParams.PermeabilityLens"); + } + + /*! + * \brief Function for defining the (intrinsic) permeability \f$[m^2]\f$. + * \return the intrinsic permeability + */ + PermeabilityType permeabilityAtPos(const GlobalPosition& globalPos) const + { return isInLens_(globalPos) ? permeabilityLens_ : permeability_; } + + /*! + * \brief Define the porosity \f$\mathrm{[-]}\f$. + * + * \param globalPos The global position + */ + Scalar porosityAtPos(const GlobalPosition& globalPos) const + { return 0.4; } + + /*! + * \brief Optionally set a lens + */ + void setLens(const GlobalPosition& lowerLeft, const GlobalPosition& upperRight) + { lensLowerLeft_ = lowerLeft; lensUpperRight_ = upperRight; } + +private: + bool isInLens_(const GlobalPosition &globalPos) const + { return LensSpatialParams::pointInLens(globalPos, lensLowerLeft_, lensUpperRight_); } + + GlobalPosition lensLowerLeft_, lensUpperRight_; + Scalar permeability_, permeabilityLens_; +}; + +} // end namespace Dumux + +#endif diff --git a/test/multidomain/boundary/darcydarcy/1p_1p/test_boundary_equaldim_1p_1p.input b/test/multidomain/boundary/darcydarcy/1p_1p/test_boundary_equaldim_1p_1p.input new file mode 100644 index 0000000000..4db37b49c2 --- /dev/null +++ b/test/multidomain/boundary/darcydarcy/1p_1p/test_boundary_equaldim_1p_1p.input @@ -0,0 +1,34 @@ +[TimeLoop] +TEnd = 1.0 +DtInitial = 1.0 + +[Problem] +EnableGravity = true + +[1.Problem] +Name = 1p_0 + +[2.Problem] +Name = 1p_1 + +[Grid] +LowerLeft = 0 0 +UpperRight = 1 1 +Cells = 10 10 + +[1.Grid] +LowerLeft = 0 0 +UpperRight = 1 0.5 +Cells = 10 5 + +[2.Grid] +LowerLeft = 0 0.5 +UpperRight = 1 1 +Cells = 10 5 + +[SpatialParams] +LensLowerLeft = 0.2 0.2 +LensUpperRight = 0.8 0.8 + +Permeability = 1e-10 # [m^2] +PermeabilityLens = 1e-12 # [m^2] diff --git a/test/multidomain/boundary/darcydarcy/CMakeLists.txt b/test/multidomain/boundary/darcydarcy/CMakeLists.txt new file mode 100644 index 0000000000..f62f49df14 --- /dev/null +++ b/test/multidomain/boundary/darcydarcy/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(1p_1p) -- GitLab