Line | Branch | Exec | Source |
---|---|---|---|
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 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup FacetCoupling | ||
10 | * \brief Modified upwind scheme for models using cell-centered schemes | ||
11 | * with coupling across element facets. | ||
12 | */ | ||
13 | #ifndef DUMUX_MIXEDDIMENSION_FACET_CC_UPWINDSCHEME_HH | ||
14 | #define DUMUX_MIXEDDIMENSION_FACET_CC_UPWINDSCHEME_HH | ||
15 | |||
16 | #include <dumux/common/properties.hh> | ||
17 | #include <dumux/common/parameters.hh> | ||
18 | #include <dumux/discretization/method.hh> | ||
19 | |||
20 | namespace Dumux { | ||
21 | |||
22 | /*! | ||
23 | * \ingroup FacetCoupling | ||
24 | * \brief The upwind scheme used for the advective fluxes. | ||
25 | * This is a modified scheme for models involving coupling | ||
26 | * with a lower-dimensional domain across the element facets. | ||
27 | */ | ||
28 | template<class GridGeometry> | ||
29 | class CCFacetCouplingUpwindScheme | ||
30 | { | ||
31 | using GridView = typename GridGeometry::GridView; | ||
32 | static constexpr int dim = GridView::dimension; | ||
33 | static constexpr int dimWorld = GridView::dimensionworld; | ||
34 | |||
35 | public: | ||
36 | // For surface and network grids (dim < dimWorld) we have to do a special upwind scheme | ||
37 | template<class FluxVariables, class UpwindTermFunction, class Scalar, int d = dim, int dw = dimWorld> | ||
38 | static typename std::enable_if<(d < dw), Scalar>::type | ||
39 | 27587296 | apply(const FluxVariables& fluxVars, | |
40 | const UpwindTermFunction& upwindTerm, | ||
41 | Scalar flux, int phaseIdx) | ||
42 | { | ||
43 |
4/6✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7875417 times.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
27587296 | static const Scalar upwindWeight = getParam<Scalar>("Flux.UpwindWeight"); |
44 | |||
45 | // the volume variables of the inside sub-control volume | ||
46 | 27587296 | const auto& scvf = fluxVars.scvFace(); | |
47 | 27587296 | const auto& elemVolVars = fluxVars.elemVolVars(); | |
48 | 32916388 | const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; | |
49 | |||
50 | // check if this is an interior boundary | ||
51 |
2/2✓ Branch 0 taken 242700 times.
✓ Branch 1 taken 7632724 times.
|
27587296 | const auto& cm = fluxVars.problem().couplingManager(); |
52 |
4/4✓ Branch 0 taken 242700 times.
✓ Branch 1 taken 7632724 times.
✓ Branch 2 taken 242700 times.
✓ Branch 3 taken 7632724 times.
|
55174592 | if (cm.isOnInteriorBoundary(fluxVars.element(), scvf)) |
53 | { | ||
54 | 919500 | const auto& outsideVolVars = cm.getLowDimVolVars(fluxVars.element(), scvf); | |
55 |
4/4✓ Branch 0 taken 57878 times.
✓ Branch 1 taken 184822 times.
✓ Branch 2 taken 57878 times.
✓ Branch 3 taken 184822 times.
|
1839000 | if (std::signbit(flux)) |
56 | 436034 | return flux*(upwindWeight*upwindTerm(outsideVolVars) | |
57 | 572298 | + (1.0 - upwindWeight)*upwindTerm(insideVolVars)); | |
58 | else | ||
59 | 483466 | return flux*(upwindWeight*upwindTerm(insideVolVars) | |
60 | 597942 | + (1.0 - upwindWeight)*upwindTerm(outsideVolVars)); | |
61 | } | ||
62 | else | ||
63 | { | ||
64 | // check if this is a branching point | ||
65 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 7632724 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7632724 times.
|
53335592 | if (scvf.numOutsideScvs() > 1) |
66 | { | ||
67 | // more complicated upwind scheme | ||
68 | // we compute a flux-weighted average of all inflowing branches | ||
69 | ✗ | Scalar branchingPointUpwindTerm = 0.0; | |
70 | ✗ | Scalar sumUpwindFluxes = 0.0; | |
71 | |||
72 | // if the inside flux is positive (outflow) do fully upwind and return flux | ||
73 | ✗ | if (!std::signbit(flux)) | |
74 | ✗ | return upwindTerm(insideVolVars)*flux; | |
75 | else | ||
76 | ✗ | sumUpwindFluxes += flux; | |
77 | |||
78 | ✗ | for (unsigned int i = 0; i < scvf.numOutsideScvs(); ++i) | |
79 | { | ||
80 | // compute the outside flux | ||
81 | ✗ | const auto& fvGeometry = fluxVars.fvGeometry(); | |
82 | ✗ | const auto outsideScvIdx = scvf.outsideScvIdx(i); | |
83 | ✗ | const auto outsideElement = fvGeometry.gridGeometry().element(outsideScvIdx); | |
84 | ✗ | const auto& flippedScvf = fvGeometry.flipScvf(scvf.index(), i); | |
85 | |||
86 | using AdvectionType = typename FluxVariables::AdvectionType; | ||
87 | ✗ | const auto outsideFlux = AdvectionType::flux(fluxVars.problem(), | |
88 | outsideElement, | ||
89 | fvGeometry, | ||
90 | elemVolVars, | ||
91 | flippedScvf, | ||
92 | phaseIdx, | ||
93 | fluxVars.elemFluxVarsCache()); | ||
94 | |||
95 | ✗ | if (!std::signbit(outsideFlux)) | |
96 | ✗ | branchingPointUpwindTerm += upwindTerm(elemVolVars[outsideScvIdx])*outsideFlux; | |
97 | else | ||
98 | ✗ | sumUpwindFluxes += outsideFlux; | |
99 | } | ||
100 | |||
101 | // the flux might be zero | ||
102 | ✗ | if (sumUpwindFluxes != 0.0) | |
103 | ✗ | branchingPointUpwindTerm /= -sumUpwindFluxes; | |
104 | else | ||
105 | branchingPointUpwindTerm = 0.0; | ||
106 | |||
107 | // upwind scheme (always do fully upwind at branching points) | ||
108 | // a weighting here would lead to an error since the derivation is based on a fully upwind scheme | ||
109 | // TODO How to implement a weight of e.g. 0.5 | ||
110 | ✗ | if (std::signbit(flux)) | |
111 | ✗ | return flux*branchingPointUpwindTerm; | |
112 | else | ||
113 | return flux*upwindTerm(insideVolVars); | ||
114 | } | ||
115 | // non-branching points and boundaries | ||
116 | else | ||
117 | { | ||
118 | 53335592 | const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()]; | |
119 |
4/4✓ Branch 0 taken 3659185 times.
✓ Branch 1 taken 3973539 times.
✓ Branch 2 taken 3659185 times.
✓ Branch 3 taken 3973539 times.
|
53335592 | if (std::signbit(flux)) |
120 | 12851503 | return flux*(upwindWeight*upwindTerm(outsideVolVars) | |
121 | 16645518 | + (1.0 - upwindWeight)*upwindTerm(insideVolVars)); | |
122 | else | ||
123 | 13816293 | return flux*(upwindWeight*upwindTerm(insideVolVars) | |
124 | 17842634 | + (1.0 - upwindWeight)*upwindTerm(outsideVolVars)); | |
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | // For grids with dim == dimWorld we use a simple upwinding scheme | ||
130 | template<class FluxVariables, class UpwindTermFunction, class Scalar, int d = dim, int dw = dimWorld> | ||
131 | static typename std::enable_if<(d == dw), Scalar>::type | ||
132 | 39136373 | apply(const FluxVariables& fluxVars, | |
133 | const UpwindTermFunction& upwindTerm, | ||
134 | Scalar flux, int phaseIdx) | ||
135 | { | ||
136 |
4/6✓ Branch 0 taken 23 times.
✓ Branch 1 taken 11102385 times.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
|
39136373 | static const Scalar upwindWeight = getParam<Scalar>("Flux.UpwindWeight"); |
137 | |||
138 | 39136373 | const auto& scvf = fluxVars.scvFace(); | |
139 | 39136373 | const auto& elemVolVars = fluxVars.elemVolVars(); | |
140 | 49197906 | const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; | |
141 | |||
142 | // check if this is an interior boundary | ||
143 |
2/2✓ Branch 0 taken 307956 times.
✓ Branch 1 taken 10794452 times.
|
39136373 | const auto& cm = fluxVars.problem().couplingManager(); |
144 |
4/4✓ Branch 0 taken 307956 times.
✓ Branch 1 taken 10794452 times.
✓ Branch 2 taken 307956 times.
✓ Branch 3 taken 10794452 times.
|
78272746 | if (cm.isOnInteriorBoundary(fluxVars.element(), scvf)) |
145 | { | ||
146 | // upwind scheme | ||
147 | 1604244 | const auto& outsideVolVars = cm.getLowDimVolVars(fluxVars.element(), scvf); | |
148 |
4/4✓ Branch 0 taken 56734 times.
✓ Branch 1 taken 251222 times.
✓ Branch 2 taken 56734 times.
✓ Branch 3 taken 251222 times.
|
3208488 | if (std::signbit(flux)) |
149 | 750598 | return flux*(upwindWeight*upwindTerm(outsideVolVars) | |
150 | 1255680 | + (1.0 - upwindWeight)*upwindTerm(insideVolVars)); | |
151 | else | ||
152 | 853646 | return flux*(upwindWeight*upwindTerm(insideVolVars) | |
153 | 1304280 | + (1.0 - upwindWeight)*upwindTerm(outsideVolVars)); | |
154 | } | ||
155 | else | ||
156 | { | ||
157 | 75064258 | const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()]; | |
158 | |||
159 |
4/4✓ Branch 0 taken 5088676 times.
✓ Branch 1 taken 5705776 times.
✓ Branch 2 taken 5088676 times.
✓ Branch 3 taken 5705776 times.
|
75064258 | if (std::signbit(flux)) // if sign of flux is negative |
160 | 18141912 | return flux*(upwindWeight*upwindTerm(outsideVolVars) | |
161 | 27479474 | + (1.0 - upwindWeight)*upwindTerm(insideVolVars)); | |
162 | else | ||
163 | 19390217 | return flux*(upwindWeight*upwindTerm(insideVolVars) | |
164 | 29279024 | + (1.0 - upwindWeight)*upwindTerm(outsideVolVars)); | |
165 | } | ||
166 | } | ||
167 | }; | ||
168 | |||
169 | } // end namespace Dumux | ||
170 | |||
171 | #endif | ||
172 |