3.5-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
40
41namespace Dumux {
42
47template<class TypeTag>
48class TwoPGridDataTransfer : public GridDataTransfer<GetPropType<TypeTag, Properties::Grid>>
49{
55 using GridView = typename GridGeometry::GridView;
56 using FVElementGeometry = typename GridGeometry::LocalView;
57 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
58 using Extrusion = Extrusion_t<GridGeometry>;
63 using Element = typename Grid::template Codim<0>::Entity;
64 using ElementSolution = std::decay_t<decltype(elementSolution(std::declval<Element>(),
65 std::declval<SolutionVector>(),
66 std::declval<GridGeometry>()))>;
69 using Indices = typename ModelTraits::Indices;
70
71 struct AdaptedValues
72 {
73 AdaptedValues() : associatedMass(0.0) {}
74 ElementSolution u;
75 int count = 0;
76 PrimaryVariables associatedMass;
77 bool wasLeaf = false;
78 };
79
80 using PersistentContainer = Dune::PersistentContainer<Grid, AdaptedValues>;
81
82 static constexpr int dim = Grid::dimension;
83 static constexpr int dimWorld = Grid::dimensionworld;
85
86 // saturation primary variable index
87 enum { saturationIdx = Indices::saturationIdx };
88
89 // phase indices
90 enum
91 {
92 phase0Idx = FluidSystem::phase0Idx,
93 phase1Idx = FluidSystem::phase1Idx,
94 };
95
96 // formulations
97 static constexpr auto p0s1 = TwoPFormulation::p0s1;
98 static constexpr auto p1s0 = TwoPFormulation::p1s0;
99
100 // the formulation that is actually used
101 static constexpr auto formulation = ModelTraits::priVarFormulation();
102
103 // This won't work (mass conservative) for compressible fluids
104 static_assert(!FluidSystem::isCompressible(phase0Idx)
105 && !FluidSystem::isCompressible(phase1Idx),
106 "This adaption helper is only mass conservative for incompressible fluids!");
107
108 // check if the used formulation is implemented here
109 static_assert(formulation == p0s1 || formulation == p1s0, "Chosen formulation not known to the TwoPGridDataTransfer");
110
111public:
120 TwoPGridDataTransfer(std::shared_ptr<const Problem> problem,
121 std::shared_ptr<GridGeometry> gridGeometry,
122 std::shared_ptr<const GridVariables> gridVariables,
123 SolutionVector& sol)
124 : ParentType()
125 , problem_(problem)
126 , gridGeometry_(gridGeometry)
127 , gridVariables_(gridVariables)
128 , sol_(sol)
129 , adaptionMap_(gridGeometry->gridView().grid(), 0)
130 {}
131
140 void store(const Grid& grid) override
141 {
142 adaptionMap_.resize();
143
144 for (auto level = grid.maxLevel(); level >= 0; level--)
145 {
146 auto fvGeometry = localView(*gridGeometry_);
147 for (const auto& element : elements(grid.levelGridView(level)))
148 {
149 // get map entry
150 auto& adaptedValues = adaptionMap_[element];
151
152 // put values in the map for leaf elements
153 if (element.isLeaf())
154 {
155 fvGeometry.bindElement(element);
156
157 // store current element solution
158 adaptedValues.u = ElementSolution(element, sol_, *gridGeometry_);
159
160 // compute mass in the scvs
161 for (const auto& scv : scvs(fvGeometry))
162 {
163 VolumeVariables volVars;
164 volVars.update(adaptedValues.u, *problem_, element, scv);
165
166 const auto poreVolume = Extrusion::volume(scv)*volVars.porosity();
167 adaptedValues.associatedMass[phase1Idx] += poreVolume * volVars.density(phase1Idx) * volVars.saturation(phase1Idx);
168 adaptedValues.associatedMass[phase0Idx] += poreVolume * volVars.density(phase0Idx) * volVars.saturation(phase0Idx);
169 }
170
171 // leaf elements always start with count = 1
172 adaptedValues.count = 1;
173 adaptedValues.wasLeaf = true;
174 }
175 // Average in father elements
176 if (element.level() > 0)
177 {
178 auto& adaptedValuesFather = adaptionMap_[element.father()];
179 // For some grids the father element is identical to the son element.
180 // In that case averaging is not necessary.
181 if(&adaptedValues != &adaptedValuesFather)
182 storeAdaptionValues(adaptedValues, adaptedValuesFather);
183 }
184
185 // The vertices of the non-leaf elements exist on the leaf as well
186 // This element solution constructor uses the vertex mapper to obtain
187 // the privars at the vertices, thus, this works for non-leaf elements!
188 if(isBox && !element.isLeaf())
189 adaptedValues.u = ElementSolution(element, sol_, *gridGeometry_);
190 }
191 }
192 }
193
205 void reconstruct(const Grid& grid) override
206 {
207 gridGeometry_->update(grid.leafGridView());
208 reconstruct_();
209 }
210
211 private:
212
213 void reconstruct_()
214 {
215 // resize stuff (grid might have changed)
216 adaptionMap_.resize();
217 sol_.resize(gridGeometry_->numDofs());
218
219 // vectors storing the mass associated with each vertex, when using the box method
220 std::vector<Scalar> massCoeff;
221 std::vector<Scalar> associatedMass;
222
223 if(isBox)
224 {
225 massCoeff.resize(gridGeometry_->numDofs(), 0.0);
226 associatedMass.resize(gridGeometry_->numDofs(), 0.0);
227 }
228
229 // iterate over leaf and reconstruct the solution
230 auto fvGeometry = localView(*gridGeometry_);
231 for (const auto& element : elements(gridGeometry_->gridView().grid().leafGridView(), Dune::Partitions::interior))
232 {
233 if (!element.isNew())
234 {
235 const auto& adaptedValues = adaptionMap_[element];
236 fvGeometry.bindElement(element);
237
238 // obtain element solution from map (divide by count!)
239 auto elemSol = adaptedValues.u;
240 if (!isBox)
241 elemSol[0] /= adaptedValues.count;
242
243 const auto elementVolume = Extrusion::volume(element.geometry());
244 for (const auto& scv : scvs(fvGeometry))
245 {
246 VolumeVariables volVars;
247 volVars.update(elemSol, *problem_, element, scv);
248
249 // write solution at dof in current solution vector
250 sol_[scv.dofIndex()] = elemSol[scv.localDofIndex()];
251
252 const auto dofIdxGlobal = scv.dofIndex();
253 // For cc schemes, overwrite the saturation by a mass conservative one here
254 if (!isBox)
255 {
256 // only recalculate the saturations if element hasn't been leaf before adaptation
257 if (!adaptedValues.wasLeaf)
258 {
259 if (formulation == p0s1)
260 {
261 sol_[dofIdxGlobal][saturationIdx] = adaptedValues.associatedMass[phase1Idx];
262 sol_[dofIdxGlobal][saturationIdx] /= elementVolume * volVars.density(phase1Idx) * volVars.porosity();
263 }
264 else if (formulation == p1s0)
265 {
266 sol_[dofIdxGlobal][saturationIdx] = adaptedValues.associatedMass[phase0Idx];
267 sol_[dofIdxGlobal][saturationIdx] /= elementVolume * volVars.density(phase0Idx) * volVars.porosity();
268 }
269 }
270 }
271
272 // For the box scheme, add mass & mass coefficient to container (saturations are recalculated at the end)
273 else
274 {
275 const auto scvVolume = Extrusion::volume(scv);
276 if (formulation == p0s1)
277 {
278 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase1Idx) * volVars.porosity();
279 associatedMass[dofIdxGlobal] += scvVolume / elementVolume * adaptedValues.associatedMass[phase1Idx];
280 }
281 else if (formulation == p1s0)
282 {
283 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase0Idx) * volVars.porosity();
284 associatedMass[dofIdxGlobal] += scvVolume / elementVolume * adaptedValues.associatedMass[phase0Idx];
285 }
286 }
287 }
288 }
289 else
290 {
291 // value is not in map, interpolate from father element
292 assert(element.hasFather() && "new element does not have a father element!");
293
294 // find the ancestor element that existed on the old grid already
295 auto fatherElement = element.father();
296 while(fatherElement.isNew() && fatherElement.level() > 0)
297 fatherElement = fatherElement.father();
298
299 if(!isBox)
300 {
301 const auto& adaptedValuesFather = adaptionMap_[fatherElement];
302
303 // obtain the mass contained in father
304 Scalar massFather = 0.0;
305 if (formulation == p0s1)
306 massFather = adaptedValuesFather.associatedMass[phase1Idx];
307 else if (formulation == p1s0)
308 massFather = adaptedValuesFather.associatedMass[phase0Idx];
309
310 // obtain the element solution through the father
311 auto elemSolSon = adaptedValuesFather.u;
312 elemSolSon[0] /= adaptedValuesFather.count;
313
314 fvGeometry.bindElement(element);
315
316 for (const auto& scv : scvs(fvGeometry))
317 {
318 VolumeVariables volVars;
319 volVars.update(elemSolSon, *problem_, element, scv);
320
321 // store constructed values of son in the current solution
322 sol_[scv.dofIndex()] = elemSolSon[0];
323
324 // overwrite the saturation by a mass conservative one here
325 Scalar massCoeffSon = 0.0;
326 if (formulation == p0s1)
327 massCoeffSon = Extrusion::volume(scv) * volVars.density(phase1Idx) * volVars.porosity();
328 else if (formulation == p1s0)
329 massCoeffSon = Extrusion::volume(scv) * volVars.density(phase0Idx) * volVars.porosity();
330 sol_[scv.dofIndex()][saturationIdx] =
331 ( Extrusion::volume(scv)/Extrusion::volume(fatherElement.geometry())*massFather )/massCoeffSon;
332 }
333 }
334 else
335 {
336 auto& adaptedValuesFather = adaptionMap_[fatherElement];
337
338 fvGeometry.bindElement(element);
339
340 // interpolate solution in the father to the vertices of the new son
341 ElementSolution elemSolSon(element, sol_, *gridGeometry_);
342 const auto fatherGeometry = fatherElement.geometry();
343 for (const auto& scv : scvs(fvGeometry))
344 elemSolSon[scv.localDofIndex()] = evalSolution(fatherElement,
345 fatherGeometry,
346 adaptedValuesFather.u,
347 scv.dofPosition());
348
349 // compute mass & mass coeffients for the scvs (saturations are recalculated at the end)
350 const auto fatherElementVolume = Extrusion::volume(fatherGeometry);
351 for (const auto& scv : scvs(fvGeometry))
352 {
353 VolumeVariables volVars;
354 volVars.update(elemSolSon, *problem_, element, scv);
355
356 const auto dofIdxGlobal = scv.dofIndex();
357 const auto scvVolume = Extrusion::volume(scv);
358 if (formulation == p0s1)
359 {
360 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase1Idx) * volVars.porosity();
361 associatedMass[dofIdxGlobal] += scvVolume / fatherElementVolume * adaptedValuesFather.associatedMass[phase1Idx];
362 }
363 else if (formulation == p1s0)
364 {
365 massCoeff[dofIdxGlobal] += scvVolume * volVars.density(phase0Idx) * volVars.porosity();
366 associatedMass[dofIdxGlobal] += scvVolume / fatherElementVolume * adaptedValuesFather.associatedMass[phase0Idx];
367 }
368
369 // store constructed (pressure) values of son in the current solution (saturation comes later)
370 sol_[dofIdxGlobal] = elemSolSon[scv.localDofIndex()];
371 }
372 }
373 }
374 }
375
376 if(isBox)
377 {
378 for(std::size_t dofIdxGlobal = 0; dofIdxGlobal < gridGeometry_->numDofs(); dofIdxGlobal++)
379 sol_[dofIdxGlobal][saturationIdx] = associatedMass[dofIdxGlobal] / massCoeff[dofIdxGlobal];
380 }
381
382 // reset entries in adaptation map
383 adaptionMap_.resize( typename PersistentContainer::Value() );
384 adaptionMap_.shrinkToFit();
385 adaptionMap_.fill( typename PersistentContainer::Value() );
386
388//#if HAVE_MPI
389// // communicate ghost data
390// using SolutionTypes = typename GetProp<TypeTag, SolutionTypes>;
391// using ElementMapper = typename SolutionTypes::ElementMapper;
392// using DataHandle = VectorExchange<ElementMapper, std::vector<CellData> >;
393// DataHandle dataHandle(problem.elementMapper(), this->cellDataGlobal());
394// problem.gridView().template communicate<DataHandle>(dataHandle,
395// Dune::InteriorBorder_All_Interface,
396// Dune::ForwardCommunication);
397//#endif
398 }
399
410 static void storeAdaptionValues(AdaptedValues& adaptedValues,
411 AdaptedValues& adaptedValuesFather)
412 {
413 // Add associated mass of the child to the one of the father
414 adaptedValuesFather.associatedMass += adaptedValues.associatedMass;
415
416 if(!isBox)
417 {
418 // add the child's primary variables to the ones of father
419 // we have to divide the child's ones in case it was composed
420 // of several children as well!
421 auto values = adaptedValues.u[0];
422 values /= adaptedValues.count;
423 adaptedValuesFather.u[0] += values;
424
425 // keep track of the number of children that composed this father
426 adaptedValuesFather.count += 1;
427
428 // A father element is never leaf
429 adaptedValuesFather.wasLeaf = false;
430 }
431 else
432 {
433 // For the box scheme, scaling of primary variables by count is obsolete
434 // Thus, we always want count = 1
435 adaptedValuesFather.count = 1;
436
437 // A father element is never leaf
438 adaptedValuesFather.wasLeaf = false;
439 }
440 }
441
442 std::shared_ptr<const Problem> problem_;
443 std::shared_ptr<GridGeometry> gridGeometry_;
444 std::shared_ptr<const GridVariables> gridVariables_;
445 SolutionVector& sol_;
446 PersistentContainer adaptionMap_;
447};
448
449} // end namespace Dumux
450
451#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.
@ p1s0
first phase saturation and second phase pressure as primary variables
@ p0s1
first phase pressure and second phase saturation as primary variables
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:95
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:38
Definition: adapt.hh:29
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition: extrusion.hh:177
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
constexpr Box box
Definition: method.hh:139
Scalar volume(Shape shape, Scalar inscribedRadius)
Returns the volume of a given geometry based on the inscribed radius.
Definition: poreproperties.hh:73
Interface to be used by classes transferring grid data on adpative 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:49
void store(const Grid &grid) override
Stores primary variables and additional data.
Definition: porousmediumflow/2p/griddatatransfer.hh:140
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:120
void reconstruct(const Grid &grid) override
Reconstruct missing primary variables (where elements are created/deleted)
Definition: porousmediumflow/2p/griddatatransfer.hh:205
Interface to be used by classes transferring grid data on adpative grids.
Declares all properties used in Dumux.