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 | #ifndef DUMUX_EXAMPLE_BLOODFLOW_SOLVER_HH | ||
9 | #define DUMUX_EXAMPLE_BLOODFLOW_SOLVER_HH | ||
10 | |||
11 | #include <memory> | ||
12 | |||
13 | #include <dune/foamgrid/foamgrid.hh> | ||
14 | |||
15 | #include <dumux/common/exceptions.hh> | ||
16 | #include <dumux/common/parameters.hh> | ||
17 | #include <dumux/common/properties.hh> | ||
18 | #include <dumux/common/numeqvector.hh> | ||
19 | #include <dumux/common/reorderingdofmapper.hh> | ||
20 | |||
21 | #include <dumux/io/format.hh> | ||
22 | |||
23 | #include <dumux/discretization/cctpfa.hh> | ||
24 | |||
25 | #include <dumux/porousmediumflow/problem.hh> | ||
26 | #include <dumux/porousmediumflow/1p/model.hh> | ||
27 | #include <dumux/porousmediumflow/1p/incompressiblelocalresidual.hh> | ||
28 | #include <dumux/porousmediumflow/fvspatialparams1p.hh> | ||
29 | |||
30 | #include <dumux/material/components/constant.hh> | ||
31 | #include <dumux/material/fluidsystems/1pliquid.hh> | ||
32 | |||
33 | #include <dumux/linear/istlsolvers.hh> | ||
34 | #include <dumux/linear/linearsolvertraits.hh> | ||
35 | #include <dumux/linear/linearalgebratraits.hh> | ||
36 | #include <dumux/assembly/fvassembler.hh> | ||
37 | #include <dumux/nonlinear/newtonsolver.hh> | ||
38 | |||
39 | namespace Dumux::BloodFlowSolver { | ||
40 | |||
41 | template<class TypeTag> | ||
42 | class BloodFlowProblem : public PorousMediumFlowProblem<TypeTag> | ||
43 | { | ||
44 | using ParentType = PorousMediumFlowProblem<TypeTag>; | ||
45 | |||
46 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
47 | using PointSource = GetPropType<TypeTag, Properties::PointSource>; | ||
48 | using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices; | ||
49 | using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>; | ||
50 | using BoundaryTypes = Dumux::BoundaryTypes<PrimaryVariables::size()>; | ||
51 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
52 | using GridView = typename GridGeometry::GridView; | ||
53 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
54 | using SubControlVolume = typename GridGeometry::SubControlVolume; | ||
55 | using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace; | ||
56 | using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>; | ||
57 | using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; | ||
58 | using Element = typename GridView::template Codim<0>::Entity; | ||
59 | using GlobalPosition = typename Element::Geometry::GlobalCoordinate; | ||
60 | using NumEqVector = Dumux::NumEqVector<PrimaryVariables>; | ||
61 | static constexpr int dim = GridView::dimension; | ||
62 | |||
63 | public: | ||
64 | template<class GridData> | ||
65 | 1 | BloodFlowProblem(std::shared_ptr<const GridGeometry> gridGeometry, | |
66 | std::shared_ptr<GridData> gridData) | ||
67 |
8/22✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
|
3 | : ParentType(gridGeometry) |
68 | { | ||
69 | // read spatial parameters | ||
70 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
3 | this->spatialParams().readGridParams(*gridData); |
71 | |||
72 | // mapping from element index to boundaryFlag | ||
73 |
1/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1 | referencePressure_ = getParam<Scalar>("Problem.ReferencePressure", 0.0); |
74 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | setBoundaryDomainMarker_(*gridData); |
75 | 1 | } | |
76 | |||
77 | ✗ | PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const | |
78 | 3470 | { return { 0.0 }; } | |
79 | |||
80 | ///////////////////////////////////////////////////////////////////////////////// | ||
81 | /////// CC Tpfa ///////////////////////////////////////////////////////////////// | ||
82 | ✗ | BoundaryTypes boundaryTypes(const Element& element, const SubControlVolumeFace& scvf) const | |
83 | { | ||
84 |
3/10✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 252 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 252 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 504 times.
✗ Branch 9 not taken.
|
1008 | BoundaryTypes bcTypes; |
85 |
3/10✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 252 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 252 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 504 times.
✗ Branch 9 not taken.
|
1008 | bcTypes.setAllDirichlet(); |
86 | ✗ | return bcTypes; | |
87 | } | ||
88 | |||
89 | ✗ | PrimaryVariables dirichlet(const Element& element, const SubControlVolumeFace& scvf) const | |
90 | { | ||
91 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
504 | PrimaryVariables values(0.0); |
92 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
504 | values[Indices::pressureIdx] = this->bloodPressureBoundaryScvf(scvf.index()); |
93 | ✗ | return values; | |
94 | } | ||
95 | |||
96 | //! blood pressure for boundary sub control volume faces | ||
97 | 504 | Scalar bloodPressureBoundaryScvf(std::size_t scvfIndex) const | |
98 | { | ||
99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 504 times.
|
504 | const auto p = bloodPressureBoundary_[scvfIndex]; |
100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 504 times.
|
504 | if (std::isnan(p)) |
101 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Invalid scvf index for boundary pressure!"); | |
102 | 504 | return p; | |
103 | } | ||
104 | |||
105 | // compute volume fluxes as input for the transport model | ||
106 | 1 | std::vector<Scalar> computeVolumeFluxes(const SolutionVector& sol, const GridVariables& gridVars) | |
107 | { | ||
108 | 1 | const auto& gg = this->gridGeometry(); | |
109 | 3 | std::vector<Scalar> volumeFlux(gg.numScvf(), 0.0); | |
110 | |||
111 | using FluxVariables = GetPropType<TypeTag, Properties::FluxVariables>; | ||
112 | 13410 | auto upwindTerm = [](const auto& volVars) { return volVars.mobility(Indices::conti0EqIdx); }; | |
113 | |||
114 | 1 | auto fvGeometry = localView(gg); | |
115 | 3 | auto elemVolVars = localView(gridVars.curGridVolVars()); | |
116 | 2 | auto elemFluxVars = localView(gridVars.gridFluxVarsCache()); | |
117 |
6/6✓ Branch 2 taken 1735 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1735 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1734 times.
✓ Branch 7 taken 1 times.
|
1737 | for (const auto& element : elements(gg.gridView())) |
118 | { | ||
119 |
2/2✓ Branch 0 taken 1734 times.
✓ Branch 1 taken 1 times.
|
1735 | fvGeometry.bind(element); |
120 |
1/2✓ Branch 1 taken 1735 times.
✗ Branch 2 not taken.
|
1735 | elemVolVars.bind(element, fvGeometry, sol); |
121 | 1735 | elemFluxVars.bind(element, fvGeometry, elemVolVars); | |
122 | |||
123 |
6/6✓ Branch 0 taken 3470 times.
✓ Branch 1 taken 1735 times.
✓ Branch 2 taken 3470 times.
✓ Branch 3 taken 1735 times.
✓ Branch 4 taken 3344 times.
✓ Branch 5 taken 126 times.
|
6940 | for (const auto& scvf : scvfs(fvGeometry)) |
124 | { | ||
125 | 3470 | const auto scvfIdx = scvf.index(); | |
126 | |||
127 |
2/2✓ Branch 0 taken 3344 times.
✓ Branch 1 taken 126 times.
|
3470 | if (!scvf.boundary()) |
128 | { | ||
129 |
1/2✓ Branch 1 taken 3344 times.
✗ Branch 2 not taken.
|
3344 | FluxVariables fluxVars; |
130 |
1/2✓ Branch 1 taken 3344 times.
✗ Branch 2 not taken.
|
3344 | fluxVars.init(*this, element, fvGeometry, elemVolVars, scvf, elemFluxVars); |
131 |
1/2✓ Branch 1 taken 3344 times.
✗ Branch 2 not taken.
|
3344 | volumeFlux[scvfIdx] = fluxVars.advectiveFlux(Indices::conti0EqIdx, upwindTerm); |
132 | } | ||
133 | else | ||
134 | { | ||
135 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | const auto bcTypes = boundaryTypes(element, scvf); |
136 |
2/4✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
|
252 | if (bcTypes.hasOnlyDirichlet()) // Dirichlet |
137 | { | ||
138 |
1/2✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
|
126 | FluxVariables fluxVars; |
139 |
1/2✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
|
126 | fluxVars.init(*this, element, fvGeometry, elemVolVars, scvf, elemFluxVars); |
140 |
1/2✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
|
126 | volumeFlux[scvfIdx] = fluxVars.advectiveFlux(Indices::conti0EqIdx, upwindTerm); |
141 | } | ||
142 | |||
143 | else // Neumann | ||
144 | { | ||
145 | ✗ | volumeFlux[scvfIdx] = this->neumann(element, fvGeometry, elemVolVars, 0.0, scvf)[Indices::pressureIdx] | |
146 | ✗ | * scvf.area() * elemVolVars[0].extrusionFactor() | |
147 | ✗ | / elemVolVars[0].density(); // volume flux from mass flux | |
148 | } | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | 1 | return volumeFlux; | |
154 | } | ||
155 | |||
156 | private: | ||
157 | template<class GridData> | ||
158 | 1 | void setBoundaryDomainMarker_(const GridData& gridData) | |
159 | { | ||
160 | 1 | const auto& gg = this->gridGeometry(); | |
161 | |||
162 | // this is a bit difficult as we need to map from vertex to scvf. | ||
163 | // maybe an scvf specialization for 1d could help containing the vertex index? | ||
164 | 2 | bloodPressureBoundary_.resize(gg.numScvf(), std::numeric_limits<Scalar>::quiet_NaN()); | |
165 | 2 | bloodPressureVertex_.resize(gg.gridView().size(GridView::dimension), std::numeric_limits<Scalar>::quiet_NaN()); | |
166 | 1 | auto fvGeometry = localView(gg); | |
167 | 1 | std::size_t count = 0; | |
168 |
6/6✓ Branch 2 taken 1735 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1735 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1734 times.
✓ Branch 7 taken 1 times.
|
3472 | for (const auto& element : elements(gg.gridView())) |
169 | { | ||
170 |
2/2✓ Branch 0 taken 1734 times.
✓ Branch 1 taken 1 times.
|
1735 | fvGeometry.bindElement(element); |
171 |
4/6✓ Branch 4 taken 5535 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 126 times.
✓ Branch 11 taken 3674 times.
✓ Branch 13 taken 3800 times.
✗ Branch 14 not taken.
|
14336 | for (const auto& intersection : intersections(gg.gridView(), element)) |
172 | { | ||
173 |
4/4✓ Branch 0 taken 126 times.
✓ Branch 1 taken 3674 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 3674 times.
|
7600 | if (intersection.boundary()) |
174 | { | ||
175 | // go up to the 0 level vertex | ||
176 | auto level0element = intersection.inside(); | ||
177 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
|
252 | while (level0element.hasFather()) |
178 | ✗ | level0element = level0element.father(); | |
179 | |||
180 | 126 | const auto scvfIdxGlobal = [&]() | |
181 | { | ||
182 |
3/6✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
|
252 | for (const auto& scvf : scvfs(fvGeometry)) |
183 | { | ||
184 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | if (scvf.boundary()) |
185 |
3/4✓ Branch 1 taken 42 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 126 times.
✗ Branch 4 not taken.
|
294 | if (Dune::FloatCmp::eq(scvf.unitOuterNormal() * intersection.centerUnitOuterNormal(), 1.0, eps_)) |
186 | 126 | return scvf.index(); | |
187 | } | ||
188 | |||
189 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Boundary scvf not found!"); | |
190 | |||
191 |
1/2✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
|
126 | }(); |
192 | |||
193 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
|
126 | const auto vertex = level0element.template subEntity<dim>(intersection.indexInInside()); |
194 |
2/4✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 126 times.
✗ Branch 7 not taken.
|
126 | bloodPressureVertex_[gg.vertexMapper().index(vertex)] = gridData.parameters(vertex)[0] - referencePressure_; |
195 |
1/2✓ Branch 1 taken 126 times.
✗ Branch 2 not taken.
|
126 | bloodPressureBoundary_[scvfIdxGlobal] = gridData.parameters(vertex)[0] - referencePressure_; |
196 | 126 | count++; | |
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 |
2/6✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
1 | std::cout << Fmt::format("Extracted boundary data at {} boundary facets.\n", count); |
202 | 1 | } | |
203 | |||
204 | static constexpr Scalar eps_ = 1e-7; | ||
205 | Scalar referencePressure_; | ||
206 | std::vector<Scalar> bloodPressureBoundary_; // blood pressure on boundary (Reichold/Schmid/Weber/Jenny) | ||
207 | std::vector<Scalar> bloodPressureVertex_; // blood pressure on boundary (Reichold/Schmid/Weber/Jenny) | ||
208 | }; | ||
209 | |||
210 | } //end namespace Dumux | ||
211 | |||
212 | namespace Dumux::BloodFlowSolver { | ||
213 | |||
214 | template<class GridGeometry, class Scalar> | ||
215 | class BloodFlowSpatialParams | ||
216 | : public FVPorousMediumFlowSpatialParamsOneP<GridGeometry, Scalar, BloodFlowSpatialParams<GridGeometry, Scalar>> | ||
217 | { | ||
218 | using ThisType = BloodFlowSpatialParams<GridGeometry, Scalar>; | ||
219 | using ParentType = FVPorousMediumFlowSpatialParamsOneP<GridGeometry, Scalar, ThisType>; | ||
220 | using GridView = typename GridGeometry::GridView; | ||
221 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
222 | using SubControlVolume = typename GridGeometry::SubControlVolume; | ||
223 | using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace; | ||
224 | using Element = typename GridView::template Codim<0>::Entity; | ||
225 | using GlobalPosition = typename Element::Geometry::GlobalCoordinate; | ||
226 | static constexpr int dim = GridView::dimension; | ||
227 | |||
228 | public: | ||
229 | // export permeability type | ||
230 | using PermeabilityType = Scalar; | ||
231 | |||
232 | 1 | BloodFlowSpatialParams(std::shared_ptr<const GridGeometry> gridGeometry) | |
233 |
2/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
4 | : ParentType(gridGeometry) |
234 | 1 | {} | |
235 | |||
236 | template<class ElementSolution> | ||
237 | ✗ | Scalar extrusionFactor(const Element& element, | |
238 | const SubControlVolume& scv, | ||
239 | const ElementSolution& elemSol) const | ||
240 | { | ||
241 | ✗ | const auto radius = this->radius(scv.elementIndex()); | |
242 | ✗ | return M_PI*radius*radius; | |
243 | } | ||
244 | |||
245 | ✗ | Scalar porosityAtPos(const GlobalPosition& globalPos) const | |
246 | ✗ | { return 1.0; } | |
247 | |||
248 | template<class ElementSolution> | ||
249 | ✗ | PermeabilityType permeability(const Element& element, | |
250 | const SubControlVolume& scv, | ||
251 | const ElementSolution& elemSol) const | ||
252 | { | ||
253 | ✗ | return permeability_[scv.elementIndex()]; | |
254 | } | ||
255 | |||
256 | // Return the radius of the circular pipe | ||
257 | Scalar radius(std::size_t eIdxGlobal) const | ||
258 | ✗ | { return radius_[eIdxGlobal];} | |
259 | |||
260 | //! Get the radii for e.g. output | ||
261 | const std::vector<Scalar>& getRadii() const | ||
262 | ✗ | { return radius_; } | |
263 | |||
264 | //! Get the viscosity factors for e.g. output | ||
265 | const std::vector<Scalar>& getViscosityFactors() const | ||
266 | ✗ | { return viscosityFactor_; } | |
267 | |||
268 | //! Read params from dgf | ||
269 | template<class GridData> | ||
270 | 1 | void readGridParams(const GridData& gridData) | |
271 | { | ||
272 | 1 | const auto& gg = this->gridGeometry(); | |
273 | 2 | auto numElements = gg.gridView().size(0); | |
274 | 1 | radius_.resize(numElements); | |
275 | 1 | permeability_.resize(numElements); | |
276 | 1 | viscosityFactor_.resize(numElements); | |
277 | |||
278 | // gridView is a leafGridView. Parameters are only set on level 0. | ||
279 | // elements have to inherit spatial parameters from their father. | ||
280 |
4/4✓ Branch 2 taken 1735 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1735 times.
✓ Branch 5 taken 1 times.
|
3472 | for (const auto& element : elements(gg.gridView())) |
281 | { | ||
282 | 1735 | auto level0element = element; | |
283 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1735 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1735 times.
|
3470 | while (level0element.hasFather()) |
284 | ✗ | level0element = level0element.father(); | |
285 | |||
286 | 3470 | auto eIdx = gg.elementMapper().index(element); | |
287 | 1735 | const auto& params = gridData.parameters(level0element); | |
288 | 1735 | radius_[eIdx] = params[0]; | |
289 | |||
290 | 1735 | constexpr Scalar dischargeHematocrit = 0.45; | |
291 | 1735 | viscosityFactor_[eIdx] = etaVivo_(radius_[eIdx], dischargeHematocrit); | |
292 | 1735 | constexpr Scalar gamma = 2; // quadratic velocity profile (Poiseuille flow) | |
293 | 3470 | permeability_[eIdx] = radius_[eIdx]*radius_[eIdx] | |
294 | 1735 | /(2.0*viscosityFactor_[eIdx]*(2.0+gamma)); | |
295 | } | ||
296 | 1 | } | |
297 | |||
298 | ✗ | Scalar temperatureAtPos(const GlobalPosition& globalPos) const | |
299 | ✗ | { return 273.15 + 37.0; } // Body temperature | |
300 | |||
301 | private: | ||
302 | 1735 | Scalar etaVivo_(const Scalar radius, const Scalar dischargeHematocrit) | |
303 | { | ||
304 | 1735 | const auto D = 2*radius*1e6*1.187; // times rat blood factor (55fl RBC), convert to µm | |
305 | 1735 | const auto scaling = (D/(D - 1.1))*(D/(D - 1.1)); | |
306 | 1735 | const auto C = corrFactor_(D); | |
307 | using std::exp; using std::pow; | ||
308 | 1735 | return scaling*(1.0 + scaling*(etaVivoH45_(D) - 1.0)*(pow(1.0 - dischargeHematocrit, C) - 1.0)/(pow(1.0 - 0.45, C) - 1.0)); | |
309 | } | ||
310 | |||
311 | ✗ | Scalar etaVivoH45_(const Scalar D) // in µm | |
312 | { | ||
313 | using std::exp; using std::pow; | ||
314 | ✗ | return 6.0*exp(-0.085*D) - 2.44*exp(-0.06*pow(D, 0.645)) + 3.2; | |
315 | } | ||
316 | |||
317 | ✗ | Scalar corrFactor_(const Scalar D) // in µm | |
318 | { | ||
319 | using std::exp; using std::pow; | ||
320 | ✗ | const auto scaling = 1.0/(1.0 + 1e-11*pow(D, 12)); | |
321 | ✗ | return (0.8 + exp(-0.075*D))*(scaling - 1.0) + scaling; | |
322 | } | ||
323 | |||
324 | std::vector<Scalar> radius_; | ||
325 | std::vector<Scalar> permeability_; | ||
326 | std::vector<Scalar> viscosityFactor_; | ||
327 | }; | ||
328 | |||
329 | } // end namespace Dumux | ||
330 | |||
331 | namespace Dumux::Properties { | ||
332 | namespace TTag { struct BloodFlowCCTpfa { using InheritsFrom = std::tuple<OneP, CCTpfaModel>; }; } | ||
333 | |||
334 | template<class TypeTag> struct EnableGridGeometryCache<TypeTag, TTag::BloodFlowCCTpfa> { static constexpr bool value = true; }; | ||
335 | template<class TypeTag> struct EnableGridVolumeVariablesCache<TypeTag, TTag::BloodFlowCCTpfa> { static constexpr bool value = true; }; | ||
336 | template<class TypeTag> struct EnableGridFluxVariablesCache<TypeTag, TTag::BloodFlowCCTpfa> { static constexpr bool value = true; }; | ||
337 | template<class TypeTag> struct SolutionDependentAdvection<TypeTag, TTag::BloodFlowCCTpfa> { static constexpr bool value = false; }; | ||
338 | template<class TypeTag> struct SolutionDependentMolecularDiffusion<TypeTag, TTag::BloodFlowCCTpfa> { static constexpr bool value = false; }; | ||
339 | template<class TypeTag> struct SolutionDependentHeatConduction<TypeTag, TTag::BloodFlowCCTpfa> { static constexpr bool value = false; }; | ||
340 | |||
341 | // Set the grid type | ||
342 | template<class TypeTag> | ||
343 | struct Grid<TypeTag, TTag::BloodFlowCCTpfa> | ||
344 | { using type = Dune::FoamGrid<1, 3>; }; | ||
345 | |||
346 | // Set the problem property | ||
347 | template<class TypeTag> | ||
348 | struct Problem<TypeTag, TTag::BloodFlowCCTpfa> | ||
349 | { using type = BloodFlowSolver::BloodFlowProblem<TypeTag>; }; | ||
350 | |||
351 | // Set the spatial parameters | ||
352 | template<class TypeTag> | ||
353 | struct SpatialParams<TypeTag, TTag::BloodFlowCCTpfa> | ||
354 | { using type = BloodFlowSolver::BloodFlowSpatialParams<GetPropType<TypeTag, Properties::GridGeometry>, double>; }; | ||
355 | |||
356 | // the fluid system | ||
357 | template<class TypeTag> | ||
358 | struct FluidSystem<TypeTag, TTag::BloodFlowCCTpfa> | ||
359 | { using type = FluidSystems::OnePLiquid<double, Components::Constant<0, double> >; }; | ||
360 | |||
361 | // Set the local residual | ||
362 | template<class TypeTag> | ||
363 | struct LocalResidual<TypeTag, TTag::BloodFlowCCTpfa> | ||
364 | { using type = OnePIncompressibleLocalResidual<TypeTag>; }; | ||
365 | |||
366 | // if we have pt scotch use the reordering dof mapper to optimally sort the dofs (cc) | ||
367 | template<class TypeTag> | ||
368 | struct GridGeometry<TypeTag, TTag::BloodFlowCCTpfa> | ||
369 | { | ||
370 | private: | ||
371 | static constexpr bool enableCache = getPropValue<TypeTag, Properties::EnableGridGeometryCache>(); | ||
372 | using GridView = typename GetPropType<TypeTag, Properties::Grid>::LeafGridView; | ||
373 | using ElementMapper = ReorderingDofMapper<GridView>; | ||
374 | using VertexMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GridView>; | ||
375 | using MapperTraits = DefaultMapperTraits<GridView, ElementMapper, VertexMapper>; | ||
376 | public: | ||
377 | using type = CCTpfaFVGridGeometry<GridView, enableCache, CCTpfaDefaultGridGeometryTraits<GridView, MapperTraits>>; | ||
378 | }; | ||
379 | |||
380 | } // end namespace Dumux::Properties | ||
381 | |||
382 | namespace Dumux { | ||
383 | |||
384 | template<class GridGeometry, class GridData> | ||
385 | 1 | std::vector<double> computeBloodVolumeFluxes(const GridGeometry& gridGeometry, const GridData& gridData) | |
386 | { | ||
387 | // Define the sub problem type tags | ||
388 | using TypeTag = Properties::TTag::BloodFlowCCTpfa; | ||
389 | |||
390 | // start the timer | ||
391 | 1 | Dune::Timer timer; | |
392 | |||
393 | //////////////////////////////////////////////////////////// | ||
394 | // Flow: prepare variables and problem | ||
395 | //////////////////////////////////////////////////////////// | ||
396 | using Problem = GetPropType<TypeTag, Properties::Problem>; | ||
397 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
1 | auto problem = std::make_shared<Problem>(gridGeometry, gridData); |
398 | |||
399 | // the solution vector | ||
400 | using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>; | ||
401 |
2/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
2 | SolutionVector sol; |
402 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | problem->applyInitialSolution(sol); |
403 | |||
404 | // the grid variables | ||
405 | using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; | ||
406 |
2/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
2 | auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry); |
407 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | gridVariables->init(sol); |
408 | |||
409 | // debug output | ||
410 | using VTKOutputModule = VtkOutputModule<GridVariables, SolutionVector>; | ||
411 |
1/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | std::unique_ptr<VTKOutputModule> vtkWriter; |
412 | |||
413 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | static const bool writeVTK = getParam<bool>("BloodFlow.WriteVTK", false); |
414 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (writeVTK) |
415 | { | ||
416 | ✗ | vtkWriter = std::make_unique<VTKOutputModule>(*gridVariables, sol, problem->name()); | |
417 | ✗ | GetPropType<TypeTag, Properties::IOFields>::initOutputModule(*vtkWriter); | |
418 | ✗ | vtkWriter->addVelocityOutput( | |
419 | std::make_shared<PorousMediumFlowVelocityOutput< | ||
420 | GridVariables, GetPropType<TypeTag, Properties::FluxVariables> | ||
421 | ✗ | >>(*gridVariables) | |
422 | ); | ||
423 | ✗ | vtkWriter->addField(problem->spatialParams().getRadii(), "radius"); | |
424 | ✗ | vtkWriter->addField(problem->spatialParams().getViscosityFactors(), "vessel tortuosity factor"); | |
425 | ✗ | vtkWriter->write(0.0, Dune::VTK::OutputType::appendedraw); | |
426 | } | ||
427 | |||
428 | using Assembler = FVAssembler<TypeTag, DiffMethod::analytic>; | ||
429 |
2/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
2 | auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables); |
430 | using LinearSolver = UMFPackIstlSolver<SeqLinearSolverTraits, LinearAlgebraTraitsFromAssembler<Assembler>>; | ||
431 |
2/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
2 | auto linearSolver = std::make_shared<LinearSolver>(); |
432 | using NewtonSolver = Dumux::NewtonSolver<Assembler, LinearSolver>; | ||
433 |
12/28✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 27 taken 1 times.
✓ Branch 29 taken 1 times.
✗ Branch 30 not taken.
✓ Branch 32 taken 1 times.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
|
5 | NewtonSolver nonLinearSolver(assembler, linearSolver); |
434 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | nonLinearSolver.solve(sol); |
435 | |||
436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (writeVTK) |
437 | ✗ | vtkWriter->write(1.0, Dune::VTK::OutputType::appendedraw); | |
438 |
2/4✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
3 | std::cout << "Flow computation took " << timer.elapsed() << " seconds." << std::endl; |
439 | |||
440 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
4 | return problem->computeVolumeFluxes(sol, *gridVariables); |
441 | } | ||
442 | |||
443 | } // end namespace Dumux | ||
444 | |||
445 | #endif | ||
446 |