// -*- 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 . * *****************************************************************************/ /*! * \file * \brief The free flow sub problem */ #ifndef DUMUX_STOKES_SUBPROBLEM_HH #define DUMUX_STOKES_SUBPROBLEM_HH #include #include namespace Dumux { /*! * \brief The free flow sub problem */ template class FreeFlowSubProblem : public NavierStokesProblem { using ParentType = NavierStokesProblem; using GridView = typename GetPropType::GridView; using Scalar = GetPropType; using Indices = typename GetPropType::Indices; using BoundaryTypes = GetPropType; using FVGridGeometry = GetPropType; using FVElementGeometry = typename FVGridGeometry::LocalView; using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; using Element = typename GridView::template Codim<0>::Entity; using GlobalPosition = typename Element::Geometry::GlobalCoordinate; using PrimaryVariables = GetPropType; using NumEqVector = GetPropType; using FluidSystem = GetPropType; using CouplingManager = GetPropType; public: FreeFlowSubProblem(std::shared_ptr fvGridGeometry, std::shared_ptr couplingManager) : ParentType(fvGridGeometry, "Stokes"), eps_(1e-6), couplingManager_(couplingManager) { deltaP_ = getParamFromGroup(this->paramGroup(), "Problem.PressureDifference"); } /*! * \name Problem parameters */ // \{ /*! * \brief Return the temperature within the domain in [K]. * * This problem assumes a temperature of 10 degrees Celsius. */ Scalar temperature() const { return 273.15 + 10; } // 10°C /*! * \brief Return the sources within the domain. * * \param globalPos The global position */ NumEqVector sourceAtPos(const GlobalPosition &globalPos) const { return NumEqVector(0.0); } // \} /*! * \name Boundary conditions */ // \{ /*! * \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.dofPosition(); // TODO: dumux-course-task 1.A // Change the boundary conditions here as described in the exercise if(onUpperBoundary_(globalPos)) { values.setDirichlet(Indices::velocityXIdx); values.setDirichlet(Indices::velocityYIdx); } // left/right wall if (onRightBoundary_(globalPos) || (onLeftBoundary_(globalPos))) { values.setDirichlet(Indices::velocityXIdx); values.setDirichlet(Indices::velocityYIdx); } // coupling interface if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf)) { values.setCouplingNeumann(Indices::conti0EqIdx); values.setCouplingNeumann(Indices::momentumYBalanceIdx); // TODO: dumux-course-task 1.B // Replace Dirichlet BC with Beavers-Joseph-Saffman slip condition for the tangential momentum balance values.setDirichlet(Indices::velocityXIdx); // assume no slip on interface // TODO: dumux-course-task 1.C // set the Beaver-Joseph-Saffman slip condition for the tangential momentum balance equation, // consider orientation of face automatically } return values; } /*! * \brief Evaluate the boundary conditions for a Dirichlet control volume. * * \param globalPos The global position */ PrimaryVariables dirichletAtPos(const GlobalPosition& globalPos) const { PrimaryVariables values(0.0); values = initialAtPos(globalPos); return values; } /*! * \brief Evaluate the boundary conditions for a Neumann control volume. * * \param element The element for which the Neumann boundary condition is set * \param fvGeomentry The fvGeometry * \param elemVolVars The element volume variables * \param elemFaceVars The element face variables * \param scvf The boundary sub control volume face */ template NumEqVector neumann(const Element& element, const FVElementGeometry& fvGeometry, const ElementVolumeVariables& elemVolVars, const ElementFaceVariables& elemFaceVars, const SubControlVolumeFace& scvf) const { NumEqVector values(0.0); if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf)) { values[Indices::conti0EqIdx] = couplingManager().couplingData().massCouplingCondition(element, fvGeometry, elemVolVars, elemFaceVars, scvf); values[Indices::momentumYBalanceIdx] = couplingManager().couplingData().momentumCouplingCondition(element, fvGeometry, elemVolVars, elemFaceVars, scvf); } return values; } // \} //! Set the coupling manager void setCouplingManager(std::shared_ptr cm) { couplingManager_ = cm; } //! Get the coupling manager const CouplingManager& couplingManager() const { return *couplingManager_; } /*! * \name Volume terms */ // \{ /*! * \brief Evaluate the initial value for a control volume. * * \param globalPos The global position */ PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const { PrimaryVariables values(0.0); values[Indices::velocityYIdx] = -1e-6 * globalPos[0] * (this->gridGeometry().bBoxMax()[0] - globalPos[0]); // TODO: dumux-course-task 1.A // Set fixed pressures on the left and right boundary return values; } /*! * \brief Returns the intrinsic permeability of required as input parameter for the Beavers-Joseph-Saffman boundary condition */ Scalar permeability(const Element& element, const SubControlVolumeFace& scvf) const { return couplingManager().couplingData().darcyPermeability(element, scvf); } /*! * \brief Returns the alpha value required as input parameter for the Beavers-Joseph-Saffman boundary condition */ Scalar alphaBJ(const SubControlVolumeFace& scvf) const { return couplingManager().problem(CouplingManager::darcyIdx).spatialParams().beaversJosephCoeffAtPos(scvf.center()); } /*! * \brief calculate the analytical velocity in x direction based on Beavers & Joseph (1967) */ void calculateAnalyticalVelocityX() const { analyticalVelocityX_.resize(this->gridGeometry().gridView().size(0)); using std::sqrt; const Scalar dPdX = -deltaP_ / (this->gridGeometry().bBoxMax()[0] - this->gridGeometry().bBoxMin()[0]); static const Scalar mu = FluidSystem::viscosity(temperature(), 1e5); static const Scalar alpha = getParam("Darcy.SpatialParams.AlphaBeaversJoseph"); static const Scalar K = getParam("Darcy.SpatialParams.Permeability"); static const Scalar sqrtK = sqrt(K); const Scalar sigma = (this->gridGeometry().bBoxMax()[1] - this->gridGeometry().bBoxMin()[1])/sqrtK; const Scalar uB = -K/(2.0*mu) * ((sigma*sigma + 2.0*alpha*sigma) / (1.0 + alpha*sigma)) * dPdX; for (const auto& element : elements(this->gridGeometry().gridView())) { const auto eIdx = this->gridGeometry().gridView().indexSet().index(element); const Scalar y = element.geometry().center()[1] - this->gridGeometry().bBoxMin()[1]; const Scalar u = uB*(1.0 + alpha/sqrtK*y) + 1.0/(2.0*mu) * (y*y + 2*alpha*y*sqrtK) * dPdX; analyticalVelocityX_[eIdx] = u; } } /*! * \brief Get the analytical velocity in x direction */ const std::vector& getAnalyticalVelocityX() const { if(analyticalVelocityX_.empty()) calculateAnalyticalVelocityX(); return analyticalVelocityX_; } // \} private: bool onLeftBoundary_(const GlobalPosition &globalPos) const { return globalPos[0] < this->gridGeometry().bBoxMin()[0] + eps_; } bool onRightBoundary_(const GlobalPosition &globalPos) const { return globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; } bool onLowerBoundary_(const GlobalPosition &globalPos) const { return globalPos[1] < this->gridGeometry().bBoxMin()[1] + eps_; } bool onUpperBoundary_(const GlobalPosition &globalPos) const { return globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_; } Scalar eps_; Scalar deltaP_; std::shared_ptr couplingManager_; mutable std::vector analyticalVelocityX_; }; } //end namespace Dumux #endif