3.6-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
porousmediumflow/2p/griddatatransfer.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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
25#ifndef DUMUX_TWOP_GRIDDATA_TRANSFER_HH
26#define DUMUX_TWOP_GRIDDATA_TRANSFER_HH
27
28#include <memory>
29
30#include <dune/grid/common/partitionset.hh>
31#include <dune/grid/utility/persistentcontainer.hh>
32
34
41
42namespace Dumux {
43
48template<class TypeTag>
49class TwoPGridDataTransfer : public GridDataTransfer<GetPropType<TypeTag, Properties::Grid>>
50{
56 using GridView = typename GridGeometry::GridView;
57 using FVElementGeometry = typename GridGeometry::LocalView;
58 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
59 using Extrusion = Extrusion_t<GridGeometry>;
64 using Element = typename Grid::template Codim<0>::Entity;
65 using ElementSolution = std::decay_t<decltype(elementSolution(std::declval<Element>(),
66 std::declval<SolutionVector>(),
67 std::declval<GridGeometry>()))>;
70 using Indices = typename ModelTraits::Indices;
71
72 struct AdaptedValues
73 {
74 AdaptedValues() : associatedMass(0.0) {}
75 ElementSolution u;
76 int count = 0;
77 PrimaryVariables associatedMass;
78 bool wasLeaf = false;
79 };
80
81 using PersistentContainer = Dune::PersistentContainer<Grid, AdaptedValues>;
82
83 static constexpr int dim = Grid::dimension;
84 static constexpr int dimWorld = Grid::dimensionworld;
86
87 // saturation primary variable index
88 enum { saturationIdx = Indices::saturationIdx };
89
90 // phase indices
91 enum
92 {
93 phase0Idx = FluidSystem::phase0Idx,
94 phase1Idx = FluidSystem::phase1Idx,
95 };
96
97 // formulations
98 static constexpr auto p0s1 = TwoPFormulation::p0s1;
99 static constexpr auto p1s0 = TwoPFormulation::p1s0;
100
101 // the formulation that is actually used
102 static constexpr auto formulation = ModelTraits::priVarFormulation();
103
104 // This won't work (mass conservative) for compressible fluids
105 static_assert(!FluidSystem::isCompressible(phase0Idx)
106 && !FluidSystem::isCompressible(phase1Idx),
107 "This adaption helper is only mass conservative for incompressible fluids!");
108
109 // check if the used formulation is implemented here
110 static_assert(formulation == p0s1 || formulation == p1s0, "Chosen formulation not known to the TwoPGridDataTransfer");
111
112public:
121 TwoPGridDataTransfer(std::shared_ptr<const Problem> problem,
122 std::shared_ptr<GridGeometry> gridGeometry,
123 std::shared_ptr<const GridVariables> gridVariables,
124 SolutionVector& sol)
125 : ParentType()
126 , problem_(problem)
127 , gridGeometry_(gridGeometry)
128 , gridVariables_(gridVariables)
129 , sol_(sol)
130 , adaptionMap_(gridGeometry->gridView().grid(), 0)
131 {}
132
141 void store(const Grid& grid) override
142 {
143 adaptionMap_.resize();
144
145 for (auto level = grid.maxLevel(); level >= 0; level--)
146 {
147 auto fvGeometry = localView(*gridGeometry_);
148 for (const auto& element : elements(grid.levelGridView(level)))
149 {
150 // get map entry
151 auto& adaptedValues = adaptionMap_[element];
152
153 // put values in the map for leaf elements
154 if (element.isLeaf())
155 {
156 fvGeometry.bindElement(element);
157
158 // store current element solution
159 adaptedValues.u = ElementSolution(element, sol_, *gridGeometry_);
160
161 // compute mass in the scvs
162 for (const auto& scv : scvs(fvGeometry))
163 {
164 VolumeVariables volVars;
165 volVars.update(adaptedValues.u, *problem_, element, scv);
166
167 const auto poreVolume = Extrusion::volume(fvGeometry, scv)*volVars.porosity();
168 adaptedValues.associatedMass[phase1Idx] += poreVolume * volVars.density(phase1Idx) * volVars.saturation(phase1Idx);
169 adaptedValues.associatedMass[phase0Idx] += poreVolume * volVars.density(phase0Idx) * volVars.saturation(phase0Idx);
170 }
171
172 // leaf elements always start with count = 1
173 adaptedValues.count = 1;
174 adaptedValues.wasLeaf = true;
175 }
176 // Average in father elements
177 if (element.level() > 0)
178 {
179 auto& adaptedValuesFather = adaptionMap_[element.father()];
180 // For some grids the father element is identical to the son element.
181 // In that case averaging is not necessary.
182 if(&adaptedValues != &adaptedValuesFather)
183 storeAdaptionValues(adaptedValues, adaptedValuesFather);
184 }
185
186 // The vertices of the non-leaf elements exist on the leaf as well
187 // This element solution constructor uses the vertex mapper to obtain
188 // the privars at the vertices, thus, this works for non-leaf elements!
189 if(isBox && !element.isLeaf())
190 adaptedValues.u = ElementSolution(element, sol_, *gridGeometry_);
191 }
192 }
193 }
194
206 void reconstruct(const Grid& grid) override
207 {
208 gridGeometry_->update(grid.leafGridView());
209 reconstruct_();
210 }
211
212 private:
213
214 void reconstruct_()
215 {
216 // resize stuff (grid might have changed)
217 adaptionMap_.resize();
218 sol_.resize(gridGeometry_->numDofs());
219
220 // vectors storing the mass associated with each vertex, when using the box method
221 std::vector<Scalar> massCoeff;
222 std::vector<Scalar> associatedMass;
223
224 if(isBox)
225 {
226 massCoeff.resize(gridGeometry_->numDofs(), 0.0);
227 associatedMass.resize(gridGeometry_->numDofs(), 0.0);
228 }
229
230 // iterate over leaf and reconstruct the solution
231 auto fvGeometry = localView(*gridGeometry_);
232 for (const auto& element : elements(gridGeometry_->gridView().grid().leafGridView(), Dune::Partitions::interior))
233 {
234 if (!element.isNew())
235 {
236 const auto& adaptedValues = adaptionMap_[element];
237 fvGeometry.bindElement(element);
238
239 // obtain element solution from map (divide by count!)
240 auto elemSol = adaptedValues.u;
241 if (!isBox)
242 elemSol[0] /= adaptedValues.count;
243
244 const auto elementVolume = volume(element.geometry(), Extrusion{});
245 for (const auto& scv : scvs(fvGeometry))
246 {
247 VolumeVariables volVars;
248 volVars.update(elemSol, *problem_, element, scv);
249
250 // write solution at dof in current solution vector
251 sol_[scv.dofIndex()] = elemSol[scv.localDofIndex()];
252
253 const auto dofIdxGlobal = scv.dofIndex();
254 // For cc schemes, overwrite the saturation by a mass conservative one here
255 if (!isBox)
256 {
257 // only recalculate the saturations if element hasn't been leaf before adaptation
258 if (!adaptedValues.wasLeaf)
259 {
260 if (formulation == p0s1)
261 {
262 sol_[dofIdxGlobal][saturationIdx] = adaptedValues.associatedMass[phase1Idx];
263 sol_[dofIdxGlobal][saturationIdx] /= elementVolume * volVars.density(phase1Idx) * volVars.porosity();
264 }
265 else if (formulation == p1s0)
266 {
267 sol_[dofIdxGlobal][saturationIdx] = adaptedValues.associatedMass[phase0Idx];
268 sol_[dofIdxGlobal][saturationIdx] /= elementVolume * volVars.density(phase0Idx) * volVars.porosity();
269 }
270 }
271 }
272
273 // For the box scheme, add mass & mass coefficient to container (saturations are recalculated at the end)
274 else
275 {
276 const auto scvVolume = Extrusion::volume(fvGeometry, scv);
277 if (formulation == p0s1)
278 {
279 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase1Idx) * volVars.porosity();
280 associatedMass[dofIdxGlobal] += scvVolume / elementVolume * adaptedValues.associatedMass[phase1Idx];
281 }
282 else if (formulation == p1s0)
283 {
284 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase0Idx) * volVars.porosity();
285 associatedMass[dofIdxGlobal] += scvVolume / elementVolume * adaptedValues.associatedMass[phase0Idx];
286 }
287 }
288 }
289 }
290 else
291 {
292 // value is not in map, interpolate from father element
293 assert(element.hasFather() && "new element does not have a father element!");
294
295 // find the ancestor element that existed on the old grid already
296 auto fatherElement = element.father();
297 while(fatherElement.isNew() && fatherElement.level() > 0)
298 fatherElement = fatherElement.father();
299
300 if(!isBox)
301 {
302 const auto& adaptedValuesFather = adaptionMap_[fatherElement];
303
304 // obtain the mass contained in father
305 Scalar massFather = 0.0;
306 if (formulation == p0s1)
307 massFather = adaptedValuesFather.associatedMass[phase1Idx];
308 else if (formulation == p1s0)
309 massFather = adaptedValuesFather.associatedMass[phase0Idx];
310
311 // obtain the element solution through the father
312 auto elemSolSon = adaptedValuesFather.u;
313 elemSolSon[0] /= adaptedValuesFather.count;
314
315 fvGeometry.bindElement(element);
316
317 for (const auto& scv : scvs(fvGeometry))
318 {
319 VolumeVariables volVars;
320 volVars.update(elemSolSon, *problem_, element, scv);
321
322 // store constructed values of son in the current solution
323 sol_[scv.dofIndex()] = elemSolSon[0];
324
325 // overwrite the saturation by a mass conservative one here
326 Scalar massCoeffSon = 0.0;
327 if (formulation == p0s1)
328 massCoeffSon = Extrusion::volume(fvGeometry, scv) * volVars.density(phase1Idx) * volVars.porosity();
329 else if (formulation == p1s0)
330 massCoeffSon = Extrusion::volume(fvGeometry, scv) * volVars.density(phase0Idx) * volVars.porosity();
331 sol_[scv.dofIndex()][saturationIdx] =
332 ( Extrusion::volume(fvGeometry, scv)/volume(fatherElement.geometry(), Extrusion{})*massFather )/massCoeffSon;
333 }
334 }
335 else
336 {
337 auto& adaptedValuesFather = adaptionMap_[fatherElement];
338
339 fvGeometry.bindElement(element);
340
341 // interpolate solution in the father to the vertices of the new son
342 ElementSolution elemSolSon(element, sol_, *gridGeometry_);
343 const auto fatherGeometry = fatherElement.geometry();
344 for (const auto& scv : scvs(fvGeometry))
345 elemSolSon[scv.localDofIndex()] = evalSolution(fatherElement,
346 fatherGeometry,
347 adaptedValuesFather.u,
348 scv.dofPosition());
349
350 // compute mass & mass coefficients for the scvs (saturations are recalculated at the end)
351 const auto fatherElementVolume = volume(fatherGeometry, Extrusion{});
352 for (const auto& scv : scvs(fvGeometry))
353 {
354 VolumeVariables volVars;
355 volVars.update(elemSolSon, *problem_, element, scv);
356
357 const auto dofIdxGlobal = scv.dofIndex();
358 const auto scvVolume = Extrusion::volume(fvGeometry, scv);
359 if (formulation == p0s1)
360 {
361 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase1Idx) * volVars.porosity();
362 associatedMass[dofIdxGlobal] += scvVolume / fatherElementVolume * adaptedValuesFather.associatedMass[phase1Idx];
363 }
364 else if (formulation == p1s0)
365 {
366 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase0Idx) * volVars.porosity();
367 associatedMass[dofIdxGlobal] += scvVolume / fatherElementVolume * adaptedValuesFather.associatedMass[phase0Idx];
368 }
369
370 // store constructed (pressure) values of son in the current solution (saturation comes later)
371 sol_[dofIdxGlobal] = elemSolSon[scv.localDofIndex()];
372 }
373 }
374 }
375 }
376
377 if(isBox)
378 {
379 for(std::size_t dofIdxGlobal = 0; dofIdxGlobal < gridGeometry_->numDofs(); dofIdxGlobal++)
380 sol_[dofIdxGlobal][saturationIdx] = associatedMass[dofIdxGlobal] / massCoeff[dofIdxGlobal];
381 }
382
383 // reset entries in adaptation map
384 adaptionMap_.resize( typename PersistentContainer::Value() );
385 adaptionMap_.shrinkToFit();
386 adaptionMap_.fill( typename PersistentContainer::Value() );
387
389//#if HAVE_MPI
390// // communicate ghost data
391// using SolutionTypes = typename GetProp<TypeTag, SolutionTypes>;
392// using ElementMapper = typename SolutionTypes::ElementMapper;
393// using DataHandle = VectorExchange<ElementMapper, std::vector<CellData> >;
394// DataHandle dataHandle(problem.elementMapper(), this->cellDataGlobal());
395// problem.gridView().template communicate<DataHandle>(dataHandle,
396// Dune::InteriorBorder_All_Interface,
397// Dune::ForwardCommunication);
398//#endif
399 }
400
411 static void storeAdaptionValues(AdaptedValues& adaptedValues,
412 AdaptedValues& adaptedValuesFather)
413 {
414 // Add associated mass of the child to the one of the father
415 adaptedValuesFather.associatedMass += adaptedValues.associatedMass;
416
417 if(!isBox)
418 {
419 // add the child's primary variables to the ones of father
420 // we have to divide the child's ones in case it was composed
421 // of several children as well!
422 auto values = adaptedValues.u[0];
423 values /= adaptedValues.count;
424 adaptedValuesFather.u[0] += values;
425
426 // keep track of the number of children that composed this father
427 adaptedValuesFather.count += 1;
428
429 // A father element is never leaf
430 adaptedValuesFather.wasLeaf = false;
431 }
432 else
433 {
434 // For the box scheme, scaling of primary variables by count is obsolete
435 // Thus, we always want count = 1
436 adaptedValuesFather.count = 1;
437
438 // A father element is never leaf
439 adaptedValuesFather.wasLeaf = false;
440 }
441 }
442
443 std::shared_ptr<const Problem> problem_;
444 std::shared_ptr<GridGeometry> gridGeometry_;
445 std::shared_ptr<const GridVariables> gridVariables_;
446 SolutionVector& sol_;
447 PersistentContainer adaptionMap_;
448};
449
450} // end namespace Dumux
451
452#endif
Element solution classes and factory functions.
Helper classes to compute the integration elements.
The available discretization methods in Dumux.
Defines an enumeration for the formulations accepted by the two-phase model.
Compute the volume of several common geometry types.
@ p1s0
first phase saturation and second phase pressure as primary variables
@ p0s1
first phase pressure and second phase saturation as primary variables
auto volume(const Geometry &geo, unsigned int integrationOrder=4)
The volume of a given geometry.
Definition: volume.hh:171
PrimaryVariables evalSolution(const Element &element, const typename Element::Geometry &geometry, const typename FVElementGeometry::GridGeometry &gridGeometry, const BoxElementSolution< FVElementGeometry, PrimaryVariables > &elemSol, const typename Element::Geometry::GlobalCoordinate &globalPos, bool ignoreState=false)
Interpolates a given box element solution at a given global position. Uses the finite element cache o...
Definition: evalsolution.hh:165
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:38
Adaption of the non-isothermal two-phase two-component flow model to problems with CO2.
Definition: adapt.hh:29
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition: extrusion.hh:251
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:180
constexpr Box box
Definition: method.hh:136
Interface to be used by classes transferring grid data on adaptive grids.
Definition: adaptive/griddatatransfer.hh:35
Class performing the transfer of data on a grid from before to after adaptation.
Definition: porousmediumflow/2p/griddatatransfer.hh:50
void store(const Grid &grid) override
Stores primary variables and additional data.
Definition: porousmediumflow/2p/griddatatransfer.hh:141
TwoPGridDataTransfer(std::shared_ptr< const Problem > problem, std::shared_ptr< GridGeometry > gridGeometry, std::shared_ptr< const GridVariables > gridVariables, SolutionVector &sol)
Constructor.
Definition: porousmediumflow/2p/griddatatransfer.hh:121
void reconstruct(const Grid &grid) override
Reconstruct missing primary variables (where elements are created/deleted)
Definition: porousmediumflow/2p/griddatatransfer.hh:206
Interface to be used by classes transferring grid data on adaptive grids.
Declares all properties used in Dumux.