version 3.10-dev
boundaryflux.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_PNM_BOUNDARYFLUX_HH
13#define DUMUX_PNM_BOUNDARYFLUX_HH
14
15#include <algorithm>
16#include <numeric>
17#include <vector>
18#include <type_traits>
19#include <unordered_map>
20#include <string_view>
21#include <iostream>
22
23#include <dune/common/exceptions.hh>
26
27namespace Dumux::PoreNetwork {
28
34template<class GridVariables, class LocalResidual, class SolutionVector>
36{
37 using Problem = std::decay_t<decltype(std::declval<LocalResidual>().problem())>;
38 using GridGeometry = typename ProblemTraits<Problem>::GridGeometry;
39 using GridView = typename GridGeometry::GridView;
40 using Element = typename GridView::template Codim<0>::Entity;
41 using FVElementGeometry = typename GridGeometry::LocalView;
42 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
43 using BoundaryTypes = typename ProblemTraits<Problem>::BoundaryTypes;
45
46 using NumEqVector = typename SolutionVector::block_type;
47 static constexpr auto numEq = NumEqVector::dimension;
48
50 struct Result
51 {
52 NumEqVector totalFlux;
53 std::unordered_map<std::size_t, NumEqVector> fluxPerPore;
54
56 friend std::ostream& operator<< (std::ostream& stream, const Result& result)
57 {
58 stream << result.totalFlux;
59 return stream;
60 }
61
63 const auto& operator[] (int eqIdx) const
64 { return totalFlux[eqIdx]; }
65
67 operator NumEqVector() const
68 { return totalFlux; }
69 };
70
71public:
72 // export the Scalar type
73 using Scalar = typename GridVariables::Scalar;
74
75 BoundaryFlux(const GridVariables& gridVariables,
76 const LocalResidual& localResidual,
77 const SolutionVector& sol)
78 : localResidual_(localResidual)
79 , gridVariables_(gridVariables)
80 , sol_(sol)
81 , isStationary_(localResidual.isStationary())
82 {
83 const auto numDofs = localResidual_.problem().gridGeometry().numDofs();
84 isConsidered_.resize(numDofs, false);
85 boundaryFluxes_.resize(numDofs);
86 }
87
94 template<class Label>
95 Result getFlux(const std::vector<Label>& labels, const bool verbose = false) const
96 {
97 // helper lambda to decide which scvs to consider for flux calculation
98 auto restriction = [&] (const SubControlVolume& scv)
99 {
100 const Label poreLabel = localResidual_.problem().gridGeometry().poreLabel(scv.dofIndex());
101 return std::any_of(labels.begin(), labels.end(),
102 [&](const Label l){ return l == poreLabel; });
103 };
104
105 std::fill(boundaryFluxes_.begin(), boundaryFluxes_.end(), NumEqVector(0.0));
106 std::fill(isConsidered_.begin(), isConsidered_.end(), false);
107
108 // sum up the fluxes
109 for (const auto& element : elements(localResidual_.problem().gridGeometry().gridView()))
110 computeBoundaryFlux_(element, restriction, verbose);
111
112 Result result;
113 result.totalFlux = std::accumulate(boundaryFluxes_.begin(), boundaryFluxes_.end(), NumEqVector(0.0));;
114 for (int i = 0; i < isConsidered_.size(); ++i)
115 {
116 if (isConsidered_[i])
117 result.fluxPerPore[i] = boundaryFluxes_[i];
118 }
119
120 return result;
121 }
122
130 Result getFlux(std::string_view minMax, const int coord, const bool verbose = false) const
131 {
132 if (!(minMax == "min" || minMax == "max"))
133 DUNE_THROW(Dune::InvalidStateException,
134 "second argument must be either 'min' or 'max' (string) !");
135
136 const Scalar eps = 1e-6; //TODO
137 auto onMeasuringBoundary = [&] (const Scalar pos)
138 {
139 return ( (minMax == "min" && pos < localResidual_.problem().gridGeometry().bBoxMin()[coord] + eps) ||
140 (minMax == "max" && pos > localResidual_.problem().gridGeometry().bBoxMax()[coord] - eps) );
141 };
142
143 // helper lambda to decide which scvs to consider for flux calculation
144 auto restriction = [&] (const SubControlVolume& scv)
145 {
146 bool considerAllDirections = coord < 0 ? true : false;
147
148 //only consider SCVs on the boundary
149 bool considerScv = localResidual_.problem().gridGeometry().dofOnBoundary(scv.dofIndex()) && onMeasuringBoundary(scv.dofPosition()[coord]);
150
151 //check whether a vertex lies on a boundary and also check whether this boundary shall be
152 // considered for the flux calculation
153 if (considerScv && !considerAllDirections)
154 {
155 const auto& pos = scv.dofPosition();
156 if (!(pos[coord] < localResidual_.problem().gridGeometry().bBoxMin()[coord] + eps || pos[coord] > localResidual_.problem().gridGeometry().bBoxMax()[coord] -eps ))
157 considerScv = false;
158 }
159
160 return considerScv;
161 };
162
163 std::fill(boundaryFluxes_.begin(), boundaryFluxes_.end(), NumEqVector(0.0));
164 std::fill(isConsidered_.begin(), isConsidered_.end(), false);
165
166 // sum up the fluxes
167 for (const auto& element : elements(localResidual_.problem().gridGeometry().gridView()))
168 computeBoundaryFlux_(element, restriction, verbose);
169
170 Result result;
171 result.totalFlux = std::accumulate(boundaryFluxes_.begin(), boundaryFluxes_.end(), NumEqVector(0.0));;
172 for (int i = 0; i < isConsidered_.size(); ++i)
173 {
174 if (isConsidered_[i])
175 result.fluxPerPore[i] = boundaryFluxes_[i];
176 }
177
178 return result;
179 }
180
181private:
182
190 template<class RestrictingFunction>
191 void computeBoundaryFlux_(const Element& element,
192 RestrictingFunction considerScv,
193 const bool verbose = false) const
194 {
195 // by default, all coordinate directions are considered for the definition of a boundary
196
197 // make sure FVElementGeometry and volume variables are bound to the element
198 const auto fvGeometry = localView(localResidual_.problem().gridGeometry()).bind(element);
199 const auto curElemVolVars = localView(gridVariables_.curGridVolVars()).bind(element, fvGeometry, sol_);
200
201 auto prevElemVolVars = localView(gridVariables_.prevGridVolVars());
202 if (!isStationary_)
203 prevElemVolVars.bindElement(element, fvGeometry, sol_);
204
205 ElementBoundaryTypes elemBcTypes;
206 elemBcTypes.update(localResidual_.problem(), element, fvGeometry);
207 const auto elemFluxVarsCache = localView(gridVariables_.gridFluxVarsCache()).bindElement(element, fvGeometry, curElemVolVars);
208 auto residual = localResidual_.evalFluxAndSource(element, fvGeometry, curElemVolVars, elemFluxVarsCache, elemBcTypes);
209
210 if (!isStationary_)
211 residual += localResidual_.evalStorage(element, fvGeometry, prevElemVolVars, curElemVolVars);
212
213 for (auto&& scv : scvs(fvGeometry))
214 {
215 // compute the boundary flux using the local residual of the element's scv on the boundary
216 if (considerScv(scv))
217 {
218 isConsidered_[scv.dofIndex()] = true;
219
220 // get the type of the boundary condition on the scv
221 const auto& bcTypes = elemBcTypes.get(fvGeometry, scv);
222
223 NumEqVector flux(0.0);
224 for (int eqIdx = 0; eqIdx < NumEqVector::dimension; ++eqIdx)
225 {
226 // Check the type of the boundary condition.
227 // If BC is Dirichlet type, the flux is equal to the local residual of the element's scv on the boundary.
228 // Otherwise the flux is either zero or equal to a source term at the element's scv on the boundary.
229 // Technicaly, the PNM considers source terms instead of Neumann BCs.
230 if (!bcTypes.isDirichlet(eqIdx))
231 {
232 auto source = localResidual_.computeSource(localResidual_.problem(), element, fvGeometry, curElemVolVars, scv);
233 source *= scv.volume() * curElemVolVars[scv].extrusionFactor();
234 flux[eqIdx] = source[eqIdx];
235 }
236 else
237 flux[eqIdx] = residual[scv.indexInElement()][eqIdx];
238 }
239
240 // The flux must be subtracted:
241 // On an inlet boundary, the flux part of the local residual will be positive, since all fluxes will leave the SCV towards to interior domain.
242 // For the domain itself, however, the sign has to be negative, since mass is entering the system.
243 boundaryFluxes_[scv.dofIndex()] -= flux;
244
245 if (verbose)
246 std::cout << "SCV of element " << scv.elementIndex() << " at vertex " << scv.dofIndex() << " has flux: " << flux << std::endl;
247 }
248 }
249 }
250
251 const LocalResidual localResidual_; // store a copy of the local residual
252 const GridVariables& gridVariables_;
253 const SolutionVector& sol_;
254 bool isStationary_;
255 mutable std::vector<bool> isConsidered_;
256 mutable std::vector<NumEqVector> boundaryFluxes_;
257};
258
259} // end Dumux::PoreNetwork
260
261#endif
This class stores an array of BoundaryTypes objects.
Definition: cvfe/elementboundarytypes.hh:28
Class for the calculation of fluxes at the boundary of pore-network models.
Definition: boundaryflux.hh:36
BoundaryFlux(const GridVariables &gridVariables, const LocalResidual &localResidual, const SolutionVector &sol)
Definition: boundaryflux.hh:75
Result getFlux(std::string_view minMax, const int coord, const bool verbose=false) const
Returns the cumulative flux in , or of several pores at a given location on the boundary.
Definition: boundaryflux.hh:130
typename GridVariables::Scalar Scalar
Definition: boundaryflux.hh:73
Result getFlux(const std::vector< Label > &labels, const bool verbose=false) const
Returns the cumulative flux in , or of several pores for a given list of pore labels to consider.
Definition: boundaryflux.hh:95
Type traits for problem classes.
Boundary types gathered on an element.
typename NumEqVectorTraits< PrimaryVariables >::type NumEqVector
A vector with the same size as numbers of equations This is the default implementation and has to be ...
Definition: numeqvector.hh:34
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
Definition: discretization/porenetwork/fvelementgeometry.hh:24
auto operator<<(std::ostream &os, const T &t) -> std::enable_if_t< decltype(Detail::hasName(t))::value, std::ostream & >
Return the class name of the tagged type calling t.name()
Definition: tag.hh:48
std::decay_t< decltype(std::declval< Problem >().gridGeometry())> GridGeometry
Definition: common/typetraits/problem.hh:33
typename Detail::template ProblemTraits< Problem, typename GridGeometry::DiscretizationMethod >::BoundaryTypes BoundaryTypes
Definition: common/typetraits/problem.hh:34