fvgridgeometry.hh 33.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
 *   See the file COPYING for full copying permissions.                      *
 *                                                                           *
 *   This program is free software: you can redistribute it and/or modify    *
 *   it under the terms of the GNU General Public License as published by    *
 *   the Free Software Foundation, either version 2 of the License, or       *
 *   (at your option) any later version.                                     *
 *                                                                           *
 *   This program is distributed in the hope that it will be useful,         *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
 *****************************************************************************/
/*!
 * \file
Dennis Gläser's avatar
Dennis Gläser committed
21
22
 * \ingroup CCMpfaDiscretization
 * \brief The finite volume geometry (scvs and scvfs) for cell-centered mpfa models on a grid view
23
 *        This builds up the sub control volumes and sub control volume faces
Dennis Gläser's avatar
Dennis Gläser committed
24
 *        for each element of the grid partition.
25
 */
26
27
#ifndef DUMUX_DISCRETIZATION_CC_MPFA_FV_GRID_GEOMETRY_HH
#define DUMUX_DISCRETIZATION_CC_MPFA_FV_GRID_GEOMETRY_HH
28
29
30

#include <dune/geometry/multilineargeometry.hh>
#include <dune/geometry/referenceelements.hh>
31

Dennis Gläser's avatar
Dennis Gläser committed
32
33
34
35
36
#include <dumux/discretization/basefvgridgeometry.hh>
#include <dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh>
#include <dumux/discretization/cellcentered/mpfa/connectivitymap.hh>
#include <dumux/discretization/cellcentered/mpfa/dualgridindexset.hh>
#include <dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh>
37
38
39
40

namespace Dumux
{
/*!
Dennis Gläser's avatar
Dennis Gläser committed
41
42
 * \ingroup CCMpfaDiscretization
 * \brief The finite volume geometry (scvs and scvfs) for cell-centered mpfa models on a grid view
43
 *        This builds up the sub control volumes and sub control volume faces
Dennis Gläser's avatar
Dennis Gläser committed
44
 * \note This class is specialized for versions with and without caching the fv geometries on the grid view
45
46
 */
template<class TypeTag, bool EnableFVElementGeometryCache>
Dennis Gläser's avatar
Dennis Gläser committed
47
class CCMpfaFVGridGeometry;
48

Dennis Gläser's avatar
Dennis Gläser committed
49
50
51
52
53
54
/*!
 * \ingroup CCMpfaDiscretization
 * \brief The finite volume geometry (scvs and scvfs) for cell-centered mpfa models on a grid view
 *        This builds up the sub control volumes and sub control volume faces
 * \note For caching enabled we store the fv geometries for the whole grid view which is memory intensive but faster
 */
55
template<class TypeTag>
Dennis Gläser's avatar
Dennis Gläser committed
56
class CCMpfaFVGridGeometry<TypeTag, true> : public BaseFVGridGeometry<TypeTag>
57
{
Dennis Gläser's avatar
Dennis Gläser committed
58
59
    using ParentType = BaseFVGridGeometry<TypeTag>;
    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
60
    using ElementMapper = typename GET_PROP_TYPE(TypeTag, ElementMapper);
Dennis Gläser's avatar
Dennis Gläser committed
61

62
    using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper);
Dennis Gläser's avatar
Dennis Gläser committed
63
64
    using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);

65
66
67
68
    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);

Dennis Gläser's avatar
Dennis Gläser committed
69
70
71
    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
    static constexpr int dim = GridView::dimension;
    static constexpr int dimWorld = GridView::dimensionworld;
Dennis Gläser's avatar
Dennis Gläser committed
72

Dennis Gläser's avatar
Dennis Gläser committed
73
74
75
    using Element = typename GridView::template Codim<0>::Entity;
    using Vertex = typename GridView::template Codim<dim>::Entity;
    using Intersection = typename GridView::Intersection;
76
    using CoordScalar = typename GridView::ctype;
Dennis Gläser's avatar
Dennis Gläser committed
77
78
79
80
81
    using GridIndexType = typename GridView::IndexSet::IndexType;
    using LocalIndexType = typename PrimaryInteractionVolume::Traits::LocalIndexType;

    using GridIVIndexSets = CCMpfaGridInteractionVolumeIndexSets<TypeTag>;
    using ConnectivityMap = CCMpfaConnectivityMap<TypeTag>;
82
83
84
85

    using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>;

public:
Dennis Gläser's avatar
Dennis Gläser committed
86
    using SecondaryIvIndicatorType = std::function<bool(const Element&, const Intersection&, bool)>;
87
88
89

    //! Constructor without indicator function for secondary interaction volumes
    //! Per default, we use the secondary IVs at branching points & boundaries
Dennis Gläser's avatar
Dennis Gläser committed
90
91
92
93
94
95
96
97
98
99
100
    CCMpfaFVGridGeometry(const GridView& gridView)
    : ParentType(gridView)
    , secondaryIvIndicator_([] (const Element& e, const Intersection& is, bool isBranching)
                               { return is.boundary() || isBranching; } )
    {}

    //! Constructor with user-defined indicator function for secondary interaction volumes
    CCMpfaFVGridGeometry(const GridView& gridView, const SecondaryIvIndicatorType& indicator)
    : ParentType(gridView)
    , secondaryIvIndicator_(indicator)
    {}
101

102
103
    //! the element mapper is the dofMapper
    //! this is convenience to have better chance to have the same main files for box/tpfa/mpfa...
Dennis Gläser's avatar
Dennis Gläser committed
104
105
106
107
108
109
110
111
112
113
114
115
116
    const ElementMapper& dofMapper() const { return this->elementMapper(); }

    //! The total number of sub control volumes
    std::size_t numScv() const { return scvs_.size(); }

    //! The total number of sub control volume faces
    std::size_t numScvf() const { return scvfs_.size(); }

    //! The total number of boundary sub control volume faces
    std::size_t numBoundaryScvf() const { return numBoundaryScvf_; }

    //! The total number of degrees of freedom
    std::size_t numDofs() const { return this->gridView().size(0); }
117

Dennis Gläser's avatar
Dennis Gläser committed
118
119
120
121
122
123
124
    //! Get an element from a global element index
    Element element(GridIndexType eIdx) const { return this->elementMap()[eIdx]; }

    //! Get an element from a sub control volume contained in it
    Element element(const SubControlVolume& scv) const { return this->elementMap()[scv.elementIndex()]; }

    //! Returns true if primary interaction volumes are used around a given vertex.
Dennis Gläser's avatar
Dennis Gläser committed
125
126
    bool vertexUsesPrimaryInteractionVolume(const Vertex& v) const
    { return primaryInteractionVolumeVertices_[this->vertexMapper().index(v)]; }
127

Dennis Gläser's avatar
Dennis Gläser committed
128
129
    //!Returns true if primary interaction volumes are used around a vertex (index).
    bool vertexUsesPrimaryInteractionVolume(GridIndexType vIdxGlobal) const
Dennis Gläser's avatar
Dennis Gläser committed
130
    { return primaryInteractionVolumeVertices_[vIdxGlobal]; }
131

Dennis Gläser's avatar
Dennis Gläser committed
132
    //! Returns if primary interaction volumes are used around a given vertex.
Dennis Gläser's avatar
Dennis Gläser committed
133
134
    bool vertexUsesSecondaryInteractionVolume(const Vertex& v) const
    { return secondaryInteractionVolumeVertices_[this->vertexMapper().index(v)]; }
135

Dennis Gläser's avatar
Dennis Gläser committed
136
137
    //! Returns true if primary interaction volumes are used around a given vertex index.
    bool vertexUsesSecondaryInteractionVolume(GridIndexType vIdxGlobal) const
Dennis Gläser's avatar
Dennis Gläser committed
138
    { return secondaryInteractionVolumeVertices_[vIdxGlobal]; }
139

Dennis Gläser's avatar
Dennis Gläser committed
140
    //! update all fvElementGeometries (do this again after grid adaption)
141
    void update()
142
    {
143
144
        ParentType::update();

Dennis Gläser's avatar
Dennis Gläser committed
145
146
        // stop the time required for the update
        Dune::Timer timer;
147

148
        // clear scvfs container
Dennis Gläser's avatar
Dennis Gläser committed
149
150
151
152
        scvfs_.clear();

        // determine the number of geometric entities
        const auto numVert = this->gridView().size(dim);
153
        const auto numScvs = numDofs();
154
        std::size_t numScvf = MpfaHelper::getGlobalNumScvf(this->gridView());
155

Dennis Gläser's avatar
Dennis Gläser committed
156
        // resize containers
157
        scvs_.resize(numScvs);
Dennis Gläser's avatar
Dennis Gläser committed
158
        scvfs_.reserve(numScvf);
159
160
        scvfIndicesOfScv_.resize(numScvs);

Dennis Gläser's avatar
Dennis Gläser committed
161
162
163
164
        // Some methods require to use a second type of interaction volume, e.g.
        // around vertices on the boundary or branching points (surface grids)
        primaryInteractionVolumeVertices_.resize(numVert, true);
        secondaryInteractionVolumeVertices_.resize(numVert, false);
165
166

        // find vertices on processor boundaries
Dennis Gläser's avatar
Dennis Gläser committed
167
        const auto isGhostVertex = MpfaHelper::findGhostVertices(this->gridView(), this->vertexMapper());
168

Dennis Gläser's avatar
Dennis Gläser committed
169
        // instantiate the dual grid index set (to be used for construction of interaction volumes)
Dennis Gläser's avatar
Dennis Gläser committed
170
        CCMpfaDualGridIndexSet<GridIndexType, LocalIndexType, dim> dualIdSet(this->gridView());
171
172

        // Build the SCVs and SCV faces
Dennis Gläser's avatar
Dennis Gläser committed
173
        GridIndexType scvfIdx = 0;
Dennis Gläser's avatar
Dennis Gläser committed
174
175
        numBoundaryScvf_ = 0;
        for (const auto& element : elements(this->gridView()))
176
        {
Dennis Gläser's avatar
Dennis Gläser committed
177
            const auto eIdx = this->elementMapper().index(element);
178
179
180
181
182

            // the element geometry
            auto elementGeometry = element.geometry();

            // The local scvf index set
Dennis Gläser's avatar
Dennis Gläser committed
183
            std::vector<GridIndexType> scvfIndexSet;
184
185
            scvfIndexSet.reserve(MpfaHelper::getNumLocalScvfs(elementGeometry.type()));

Dennis Gläser's avatar
Dennis Gläser committed
186
            // for network grids there might be multiple intersections with the same geometryInInside
187
            // we indentify those by the indexInInside for now (assumes conforming grids at branching facets)
Dennis Gläser's avatar
Dennis Gläser committed
188
            std::vector<std::vector<GridIndexType>> outsideIndices;
189
190
191
            if (dim < dimWorld)
            {
                outsideIndices.resize(element.subEntities(1));
Dennis Gläser's avatar
Dennis Gläser committed
192
                for (const auto& intersection : intersections(this->gridView(), element))
193
194
195
196
                {
                    if (intersection.neighbor())
                    {
                        const auto& outside = intersection.outside();
Dennis Gläser's avatar
Dennis Gläser committed
197
                        auto nIdx = this->elementMapper().index(outside);
198
199
200
201
202
203
                        outsideIndices[intersection.indexInInside()].push_back(nIdx);
                    }
                }
            }

            // construct the sub control volume faces
Dennis Gläser's avatar
Dennis Gläser committed
204
            for (const auto& is : intersections(this->gridView(), element))
205
206
207
208
209
            {
                const auto indexInInside = is.indexInInside();
                const bool boundary = is.boundary();
                const bool neighbor = is.neighbor();

Dennis Gläser's avatar
Dennis Gläser committed
210
                // for surface grids, skip the rest if handled already
211
212
213
214
215
216
217
218
219
220
                if (dim < dimWorld && neighbor && outsideIndices[indexInInside].empty())
                    continue;

                // if outside level > inside level, use the outside element in the following
                const bool useNeighbor = neighbor && is.outside().level() > element.level();
                const auto& e = useNeighbor ? is.outside() : element;
                const auto indexInElement = useNeighbor ? is.indexInOutside() : indexInInside;
                const auto eg = e.geometry();
                const auto& refElement = ReferenceElements::general(eg.type());

Dennis Gläser's avatar
Dennis Gläser committed
221
222
223
224
225
226
227
228
229
                // Set up a container with all relevant positions for scvf corner computation
                const auto numCorners = is.geometry().corners();
                const auto isPositions = MpfaHelper::computeScvfCornersOnIntersection(eg,
                                                                                      refElement,
                                                                                      indexInElement,
                                                                                      numCorners);

                // evaluate if vertices on this intersection use primary/secondary IVs
                const bool isBranchingPoint = dim < dimWorld ? outsideIndices[indexInInside].size() > 1 : false;
230
                const bool usesSecondaryIV = secondaryIvIndicator_(element, is, isBranchingPoint);
231
232

                // make the scv faces belonging to each corner of the intersection
233
                for (std::size_t c = 0; c < numCorners; ++c)
234
235
236
                {
                    // get the global vertex index the scv face is connected to
                    const auto vIdxLocal = refElement.subEntity(indexInElement, 1, c, dim);
Dennis Gläser's avatar
Dennis Gläser committed
237
                    const auto vIdxGlobal = this->vertexMapper().subIndex(e, vIdxLocal, dim);
238
239
240
241
242

                    // do not build scvfs connected to a processor boundary
                    if (isGhostVertex[vIdxGlobal])
                        continue;

Dennis Gläser's avatar
Dennis Gläser committed
243
244
                    // if this vertex is tagged to use the secondary IVs, store info
                    if (usesSecondaryIV)
245
                    {
Dennis Gläser's avatar
Dennis Gläser committed
246
247
                        primaryInteractionVolumeVertices_[vIdxGlobal] = false;
                        secondaryInteractionVolumeVertices_[vIdxGlobal] = true;
248
249
                    }

Dennis Gläser's avatar
Dennis Gläser committed
250
                    // the quadrature point parameterizarion to be used on scvfs
251
                    static const Scalar q = getParamFromGroup<Scalar>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Mpfa.Q");
252

Dennis Gläser's avatar
Dennis Gläser committed
253
254
255
256
257
258
                    // make the scv face (for non-boundary scvfs on network grids, use precalculated outside indices)
                    const auto& outsideScvIndices = [&] ()
                                                    {
                                                        if (!boundary)
                                                        {
                                                            return dim == dimWorld ?
Dennis Gläser's avatar
Dennis Gläser committed
259
                                                                   std::vector<GridIndexType>({this->elementMapper().index(is.outside())}) :
Dennis Gläser's avatar
Dennis Gläser committed
260
261
262
263
264
                                                                   outsideIndices[indexInInside];
                                                        }
                                                        else
                                                        {
                                                            // compute boundary scv idx and increment counter
Dennis Gläser's avatar
Dennis Gläser committed
265
                                                            const GridIndexType bIdx = numScvs + numBoundaryScvf_;
Dennis Gläser's avatar
Dennis Gläser committed
266
                                                            numBoundaryScvf_++;
Dennis Gläser's avatar
Dennis Gläser committed
267
                                                            return std::vector<GridIndexType>(1, bIdx);
Dennis Gläser's avatar
Dennis Gläser committed
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
                                                        }
                                                    } ();

                    scvfIndexSet.push_back(scvfIdx);
                    scvfs_.emplace_back(MpfaHelper(),
                                        MpfaHelper::getScvfCorners(isPositions, numCorners, c),
                                        is.centerUnitOuterNormal(),
                                        vIdxGlobal,
                                        vIdxLocal,
                                        scvfIdx,
                                        eIdx,
                                        outsideScvIndices,
                                        q,
                                        boundary);

                    // insert the scvf data into the dual grid index set
                    dualIdSet[vIdxGlobal].insert(scvfs_.back());
285
286
287
288
289
290

                    // increment scvf counter
                    scvfIdx++;
                }

                // for network grids, clear outside indices to not make a second scvf on that facet
291
292
                if (dim < dimWorld)
                    outsideIndices[indexInInside].clear();
293
294
295
296
297
298
299
300
301
302
303
304
305
            }

            // create sub control volume for this element
            scvs_[eIdx] = SubControlVolume(std::move(elementGeometry), eIdx);

            // Save the scvf indices belonging to this scv to build up fv element geometries fast
            scvfIndicesOfScv_[eIdx] = scvfIndexSet;
        }

        // Make the flip index set for network and surface grids
        if (dim < dimWorld)
        {
            flipScvfIndices_.resize(scvfs_.size());
306
            for (const auto& scvf : scvfs_)
307
308
309
310
311
312
313
314
315
            {
                if (scvf.boundary())
                    continue;

                const auto numOutsideScvs = scvf.numOutsideScvs();
                const auto vIdxGlobal = scvf.vertexIndex();
                const auto insideScvIdx = scvf.insideScvIdx();

                flipScvfIndices_[scvf.index()].resize(numOutsideScvs);
316
                for (std::size_t i = 0; i < numOutsideScvs; ++i)
317
318
319
320
321
322
                {
                    const auto outsideScvIdx = scvf.outsideScvIdx(i);
                    for (auto outsideScvfIndex : scvfIndicesOfScv_[outsideScvIdx])
                    {
                        const auto& outsideScvf = this->scvf(outsideScvfIndex);
                        if (outsideScvf.vertexIndex() == vIdxGlobal &&
Dennis Gläser's avatar
Dennis Gläser committed
323
                            MpfaHelper::vectorContainsValue(outsideScvf.outsideScvIndices(), insideScvIdx))
324
325
326
327
328
329
330
331
332
333
334
                        {
                            flipScvfIndices_[scvf.index()][i] = outsideScvfIndex;
                            // there is always only one flip face in an outside element
                            break;
                        }
                    }

                }
            }
        }

335
        // building the geometries has finished
Dennis Gläser's avatar
Dennis Gläser committed
336
337
338
339
340
341
342
        std::cout << "Initializing of the grid finite volume geometry took " << timer.elapsed() << " seconds." << std::endl;

        // Initialize the grid interaction volume seeds
        timer.reset();
        ivIndexSets_.update(*this, std::move(dualIdSet));
        std::cout << "Initializing of the grid interaction volume index sets took " << timer.elapsed() << " seconds." << std::endl;

343
        // build the connectivity map for an efficient assembly
Dennis Gläser's avatar
Dennis Gläser committed
344
345
346
        timer.reset();
        connectivityMap_.update(*this);
        std::cout << "Initializing of the connectivity map took " << timer.elapsed() << " seconds." << std::endl;
347
348
    }

Dennis Gläser's avatar
Dennis Gläser committed
349
350
    //! Get a sub control volume with a global scv index
    const SubControlVolume& scv(GridIndexType scvIdx) const { return scvs_[scvIdx]; }
351

Dennis Gläser's avatar
Dennis Gläser committed
352
353
354
355
356
357
358
359
360
    //! Get a sub control volume face with a global scvf index
    const SubControlVolumeFace& scvf(GridIndexType scvfIdx) const { return scvfs_[scvfIdx]; }

    //! Returns the connectivity map of which dofs
    //! have derivatives with respect to a given dof.
    const ConnectivityMap& connectivityMap() const { return connectivityMap_; }

    //! Returns the grid interaction volume seeds class.
    const GridIVIndexSets& gridInteractionVolumeIndexSets() const { return ivIndexSets_; }
361

Dennis Gläser's avatar
Dennis Gläser committed
362
363
364
365
    //! Get the scvf on the same face but from the other side
    //! Note that e.g. the normals might be different in the case of surface grids
    const SubControlVolumeFace& flipScvf(GridIndexType scvfIdx, unsigned int outsideScvfIdx = 0) const
    { return scvfs_[flipScvfIndices_[scvfIdx][outsideScvfIdx]]; }
366

Dennis Gläser's avatar
Dennis Gläser committed
367
368
369
    //! Get the sub control volume face indices of an scv by global index
    const std::vector<GridIndexType>& scvfIndicesOfScv(GridIndexType scvIdx) const
    { return scvfIndicesOfScv_[scvIdx]; }
370

Dennis Gläser's avatar
Dennis Gläser committed
371
private:
372
    // connectivity map for efficient assembly
Dennis Gläser's avatar
Dennis Gläser committed
373
374
375
    ConnectivityMap connectivityMap_;

    // the finite volume grid geometries
376
377
378
    std::vector<SubControlVolume> scvs_;
    std::vector<SubControlVolumeFace> scvfs_;

Dennis Gläser's avatar
Dennis Gläser committed
379
    // containers storing the global data
Dennis Gläser's avatar
Dennis Gläser committed
380
    std::vector<std::vector<GridIndexType>> scvfIndicesOfScv_;
Dennis Gläser's avatar
Dennis Gläser committed
381
382
383
384
    std::vector<bool> primaryInteractionVolumeVertices_;
    std::vector<bool> secondaryInteractionVolumeVertices_;
    std::size_t numBoundaryScvf_;

385
    // needed for embedded surface and network grids (dim < dimWorld)
Dennis Gläser's avatar
Dennis Gläser committed
386
    std::vector<std::vector<GridIndexType>> flipScvfIndices_;
387

Dennis Gläser's avatar
Dennis Gläser committed
388
389
    // The grid interaction volume index set
    GridIVIndexSets ivIndexSets_;
390
391

    // Indicator function on where to use the secondary IVs
Dennis Gläser's avatar
Dennis Gläser committed
392
    SecondaryIvIndicatorType secondaryIvIndicator_;
393
394
};

Dennis Gläser's avatar
Dennis Gläser committed
395
396
397
398
399
400
401
/*!
 * \ingroup CCMpfaDiscretization
 * \brief The finite volume geometry (scvs and scvfs) for cell-centered mpfa models on a grid view
 *        This builds up the sub control volumes and sub control volume faces
 * \note For caching disabled we store only some essential index maps to build up local systems on-demand in
 *       the corresponding FVElementGeometry
 */
402
template<class TypeTag>
Dennis Gläser's avatar
Dennis Gläser committed
403
class CCMpfaFVGridGeometry<TypeTag, false> : public BaseFVGridGeometry<TypeTag>
404
{
Dennis Gläser's avatar
Dennis Gläser committed
405
406
    using ParentType = BaseFVGridGeometry<TypeTag>;
    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
Dennis Gläser's avatar
Dennis Gläser committed
407
408
    using ElementMapper = typename GET_PROP_TYPE(TypeTag, ElementMapper);

409
    using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper);
Dennis Gläser's avatar
Dennis Gläser committed
410
411
    using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume);

412
413
414
415
    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);

Dennis Gläser's avatar
Dennis Gläser committed
416
    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
417
418
    static constexpr int dim = GridView::dimension;
    static constexpr int dimWorld = GridView::dimensionworld;
Dennis Gläser's avatar
Dennis Gläser committed
419

Dennis Gläser's avatar
Dennis Gläser committed
420
421
422
423
    using Element = typename GridView::template Codim<0>::Entity;
    using Vertex = typename GridView::template Codim<dim>::Entity;
    using Intersection = typename GridView::Intersection;
    using CoordScalar = typename GridView::ctype;
Dennis Gläser's avatar
Dennis Gläser committed
424
425
426
427
428
    using GridIndexType = typename GridView::IndexSet::IndexType;
    using LocalIndexType = typename PrimaryInteractionVolume::Traits::LocalIndexType;

    using GridIVIndexSets = CCMpfaGridInteractionVolumeIndexSets<TypeTag>;
    using ConnectivityMap = CCMpfaConnectivityMap<TypeTag>;
429
430
431
432

    using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>;

public:
433
434
435
436
    using SecondaryIvIndicator = std::function<bool(const Element&, const Intersection&, bool)>;

    //! Constructor without indicator function for secondary interaction volumes
    //! Per default, we use the secondary IVs at branching points & boundaries
Dennis Gläser's avatar
Dennis Gläser committed
437
438
439
440
441
442
443
444
445
446
447
    CCMpfaFVGridGeometry(const GridView& gridView)
    : ParentType(gridView)
    , secondaryIvIndicator_([] (const Element& e, const Intersection& is, bool isBranching)
                               { return is.boundary() || isBranching; } )
    {}

    //! Constructor with user-defined indicator function for secondary interaction volumes
    CCMpfaFVGridGeometry(const GridView& gridView, const SecondaryIvIndicator& indicator)
    : ParentType(gridView)
    , secondaryIvIndicator_(indicator)
    {}
448

449
450
451
452
453
    //! the element mapper is the dofMapper
    //! this is convenience to have better chance to have the same main files for box/tpfa/mpfa...
    const ElementMapper& dofMapper() const
    { return this->elementMapper(); }

Dennis Gläser's avatar
Dennis Gläser committed
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
    //! Returns the total number of sub control volumes.
    std::size_t numScv() const { return numScvs_; }

    //! Returns the total number of sub control volume faces.
    std::size_t numScvf() const { return numScvf_; }

    //! Returns the number of scvfs on the domain boundary.
    std::size_t numBoundaryScvf() const { return numBoundaryScvf_; }

    //! Returns the total number of degrees of freedom.
    std::size_t numDofs() const { return this->gridView().size(0); }

    //! Gets an element from a global element index.
    Element element(GridIndexType eIdx) const { return this->elementMap()[eIdx]; }

    //! Gets an element from a sub control volume contained in it.
    Element element(const SubControlVolume& scv) const { return this->elementMap()[scv.elementIndex()]; }

    //! Returns true if primary interaction volumes are used around a given vertex.
Dennis Gläser's avatar
Dennis Gläser committed
473
474
    bool vertexUsesPrimaryInteractionVolume(const Vertex& v) const
    { return primaryInteractionVolumeVertices_[this->vertexMapper().index(v)]; }
475

Dennis Gläser's avatar
Dennis Gläser committed
476
477
    //! Returns true if primary interaction volumes are used around a given vertex (index).
    bool vertexUsesPrimaryInteractionVolume(GridIndexType vIdxGlobal) const
Dennis Gläser's avatar
Dennis Gläser committed
478
    { return primaryInteractionVolumeVertices_[vIdxGlobal]; }
479

Dennis Gläser's avatar
Dennis Gläser committed
480
    //! Returns if primary interaction volumes are used around a given vertex.
Dennis Gläser's avatar
Dennis Gläser committed
481
482
    bool vertexUsesSecondaryInteractionVolume(const Vertex& v) const
    { return secondaryInteractionVolumeVertices_[this->vertexMapper().index(v)]; }
483

Dennis Gläser's avatar
Dennis Gläser committed
484
485
    //! Returns true if primary interaction volumes are used around a given vertex (index).
    bool vertexUsesSecondaryInteractionVolume(GridIndexType vIdxGlobal) const
Dennis Gläser's avatar
Dennis Gläser committed
486
    { return secondaryInteractionVolumeVertices_[vIdxGlobal]; }
487

Dennis Gläser's avatar
Dennis Gläser committed
488
489
490
491
492
493
494
    //! Returns true if a given vertex lies on a processor boundary inside a ghost element.
    bool isGhostVertex(const Vertex& v) const { return isGhostVertex_[this->vertexMapper().index(v)]; }

    //! Returns true if the vertex (index) lies on a processor boundary inside a ghost element.
    bool isGhostVertex(GridIndexType vIdxGlobal) const { return isGhostVertex_[vIdxGlobal]; }

    //! Updates all finite volume geometries of the grid. Has to be called again after grid adaption.
495
    void update()
496
    {
497
498
        ParentType::update();

Dennis Gläser's avatar
Dennis Gläser committed
499
500
        // stop the time required for the update
        Dune::Timer timer;
501

Dennis Gläser's avatar
Dennis Gläser committed
502
        // resize containers
503
        numScvs_ = numDofs();
504
505
506
        scvfIndicesOfScv_.resize(numScvs_);
        neighborVolVarIndices_.resize(numScvs_);

Dennis Gläser's avatar
Dennis Gläser committed
507
508
509
510
511
        // Some methods require to use a second type of interaction volume, e.g.
        // around vertices on the boundary or branching points (surface grids)
        const auto numVert = this->gridView().size(dim);
        primaryInteractionVolumeVertices_.resize(numVert, true);
        secondaryInteractionVolumeVertices_.resize(numVert, false);
512

Dennis Gläser's avatar
Dennis Gläser committed
513
514
        // find vertices on processor boundaries HERE!!
        isGhostVertex_ = MpfaHelper::findGhostVertices(this->gridView(), this->vertexMapper());
515

Dennis Gläser's avatar
Dennis Gläser committed
516
        // instantiate the dual grid index set (to be used for construction of interaction volumes)
Dennis Gläser's avatar
Dennis Gläser committed
517
        CCMpfaDualGridIndexSet<GridIndexType, LocalIndexType, dim> dualIdSet(this->gridView());
518

Dennis Gläser's avatar
Dennis Gläser committed
519
        // Build the SCVs and SCV faces
520
        numScvf_ = 0;
Dennis Gläser's avatar
Dennis Gläser committed
521
522
        numBoundaryScvf_ = 0;
        for (const auto& element : elements(this->gridView()))
523
        {
Dennis Gläser's avatar
Dennis Gläser committed
524
525
526
527
            const auto eIdx = this->elementMapper().index(element);

            // the element geometry
            auto elementGeometry = element.geometry();
528
529

            // the element-wise index sets for finite volume geometry
Dennis Gläser's avatar
Dennis Gläser committed
530
            const auto numLocalFaces = MpfaHelper::getNumLocalScvfs(elementGeometry.type());
Dennis Gläser's avatar
Dennis Gläser committed
531
532
            std::vector<GridIndexType> scvfsIndexSet;
            std::vector< std::vector<GridIndexType> > neighborVolVarIndexSet;
533
534
535
            scvfsIndexSet.reserve(numLocalFaces);
            neighborVolVarIndexSet.reserve(numLocalFaces);

Dennis Gläser's avatar
Dennis Gläser committed
536
            // for network grids there might be multiple intersections with the same geometryInInside
537
            // we indentify those by the indexInInside for now (assumes conforming grids at branching facets)
Dennis Gläser's avatar
Dennis Gläser committed
538
            std::vector<std::vector<GridIndexType>> outsideIndices;
539
540
541
            if (dim < dimWorld)
            {
                outsideIndices.resize(element.subEntities(1));
Dennis Gläser's avatar
Dennis Gläser committed
542
                for (const auto& intersection : intersections(this->gridView(), element))
543
544
545
546
                {
                    if (intersection.neighbor())
                    {
                        const auto& outside = intersection.outside();
Dennis Gläser's avatar
Dennis Gläser committed
547
                        auto nIdx = this->elementMapper().index(outside);
548
549
550
551
552
553
                        outsideIndices[intersection.indexInInside()].push_back(nIdx);
                    }
                }
            }

            // construct the sub control volume faces
Dennis Gläser's avatar
Dennis Gläser committed
554
            for (const auto& is : intersections(this->gridView(), element))
555
556
557
558
559
            {
                const auto indexInInside = is.indexInInside();
                const bool boundary = is.boundary();
                const bool neighbor = is.neighbor();

Dennis Gläser's avatar
Dennis Gläser committed
560
                // for surface grids, skip the rest if handled already
561
562
563
564
565
566
567
568
569
570
                if (dim < dimWorld && neighbor && outsideIndices[indexInInside].empty())
                    continue;

                // if outside level > inside level, use the outside element in the following
                const bool useNeighbor = neighbor && is.outside().level() > element.level();
                const auto& e = useNeighbor ? is.outside() : element;
                const auto indexInElement = useNeighbor ? is.indexInOutside() : indexInInside;
                const auto eg = e.geometry();
                const auto& refElement = ReferenceElements::general(eg.type());

Dennis Gläser's avatar
Dennis Gläser committed
571
572
                // evaluate if vertices on this intersection use primary/secondary IVs
                const bool isBranchingPoint = dim < dimWorld ? outsideIndices[indexInInside].size() > 1 : false;
573
                const bool usesSecondaryIV = secondaryIvIndicator_(element, is, isBranchingPoint);
Dennis Gläser's avatar
Dennis Gläser committed
574
575

                // make the scv faces belonging to each corner of the intersection
576
                for (std::size_t c = 0; c < is.geometry().corners(); ++c)
577
                {
Dennis Gläser's avatar
Dennis Gläser committed
578
                    // get the global vertex index the scv face is connected to
579
                    const auto vIdxLocal = refElement.subEntity(indexInElement, 1, c, dim);
Dennis Gläser's avatar
Dennis Gläser committed
580
                    const auto vIdxGlobal = this->vertexMapper().subIndex(e, vIdxLocal, dim);
581
582

                    // do not build scvfs connected to a processor boundary
Dennis Gläser's avatar
Dennis Gläser committed
583
                    if (isGhostVertex_[vIdxGlobal])
584
585
                        continue;

Dennis Gläser's avatar
Dennis Gläser committed
586
587
                    // if this vertex is tagged to use the secondary IVs, store info
                    if (usesSecondaryIV)
588
                    {
Dennis Gläser's avatar
Dennis Gläser committed
589
590
                        primaryInteractionVolumeVertices_[vIdxGlobal] = false;
                        secondaryInteractionVolumeVertices_[vIdxGlobal] = true;
591
592
                    }

Dennis Gläser's avatar
Dennis Gläser committed
593
594
595
596
597
598
                    // make the scv face (for non-boundary scvfs on network grids, use precalculated outside indices)
                    const auto& outsideScvIndices = [&] ()
                                                    {
                                                        if (!boundary)
                                                        {
                                                            return dim == dimWorld ?
Dennis Gläser's avatar
Dennis Gläser committed
599
                                                                   std::vector<GridIndexType>({this->elementMapper().index(is.outside())}) :
Dennis Gläser's avatar
Dennis Gläser committed
600
601
602
603
604
                                                                   outsideIndices[indexInInside];
                                                        }
                                                        else
                                                        {
                                                            // compute boundary scv idx and increment counter
Dennis Gläser's avatar
Dennis Gläser committed
605
                                                            const GridIndexType bIdx = numScvs_ + numBoundaryScvf_;
Dennis Gläser's avatar
Dennis Gläser committed
606
                                                            numBoundaryScvf_++;
Dennis Gläser's avatar
Dennis Gläser committed
607
                                                            return std::vector<GridIndexType>(1, bIdx);
Dennis Gläser's avatar
Dennis Gläser committed
608
609
610
611
612
613
614
615
616
                                                        }
                                                    } ();

                    // insert the scvf data into the dual grid index set
                    dualIdSet[vIdxGlobal].insert(boundary, numScvf_, eIdx, outsideScvIndices);

                    // store information on the scv face
                    scvfsIndexSet.push_back(numScvf_++);
                    neighborVolVarIndexSet.emplace_back(std::move(outsideScvIndices));
617
618
619
                }

                // for network grids, clear outside indices to not make a second scvf on that facet
620
621
                if (dim < dimWorld)
                    outsideIndices[indexInInside].clear();
622
623
624
625
626
627
628
            }

            // store the sets of indices in the data container
            scvfIndicesOfScv_[eIdx] = scvfsIndexSet;
            neighborVolVarIndices_[eIdx] = neighborVolVarIndexSet;
        }

629
        // building the geometries has finished
Dennis Gläser's avatar
Dennis Gläser committed
630
631
632
633
634
635
636
637
638
639
640
        std::cout << "Initializing of the grid finite volume geometry took " << timer.elapsed() << " seconds." << std::endl;

        // Initialize the grid interaction volume seeds
        timer.reset();
        ivIndexSets_.update(*this, std::move(dualIdSet));
        std::cout << "Initializing of the grid interaction volume index sets took " << timer.elapsed() << " seconds." << std::endl;

        // build the connectivity map for an effecient assembly
        timer.reset();
        connectivityMap_.update(*this);
        std::cout << "Initializing of the connectivity map took " << timer.elapsed() << " seconds." << std::endl;
641
642
    }

Dennis Gläser's avatar
Dennis Gläser committed
643
644
    //! Returns the sub control volume face indices of an scv by global index.
    const std::vector<GridIndexType>& scvfIndicesOfScv(GridIndexType scvIdx) const
645
646
    { return scvfIndicesOfScv_[scvIdx]; }

Dennis Gläser's avatar
Dennis Gläser committed
647
648
    //! Returns the neighboring vol var indices for each scvf contained in an scv.
    const std::vector< std::vector<GridIndexType> >& neighborVolVarIndices(GridIndexType scvIdx) const
649
650
    { return neighborVolVarIndices_[scvIdx]; }

Dennis Gläser's avatar
Dennis Gläser committed
651
652
653
    //! Returns the connectivity map of which dofs
    //! have derivatives with respect to a given dof.
    const ConnectivityMap& connectivityMap() const { return connectivityMap_; }
654

Dennis Gläser's avatar
Dennis Gläser committed
655
656
    //! Returns the grid interaction volume seeds class.
    const GridIVIndexSets& gridInteractionVolumeIndexSets() const { return ivIndexSets_; }
657

Dennis Gläser's avatar
Dennis Gläser committed
658
private:
659
    // connectivity map for efficient assembly
Dennis Gläser's avatar
Dennis Gläser committed
660
    ConnectivityMap connectivityMap_;
661

Dennis Gläser's avatar
Dennis Gläser committed
662
    // containers storing the global data
Dennis Gläser's avatar
Dennis Gläser committed
663
664
    std::vector<std::vector<GridIndexType>> scvfIndicesOfScv_;
    std::vector< std::vector< std::vector<GridIndexType> > > neighborVolVarIndices_;
Dennis Gläser's avatar
Dennis Gläser committed
665
666
667
    std::vector<bool> primaryInteractionVolumeVertices_;
    std::vector<bool> secondaryInteractionVolumeVertices_;
    std::vector<bool> isGhostVertex_;
668
669
    std::size_t numScvs_;
    std::size_t numScvf_;
Dennis Gläser's avatar
Dennis Gläser committed
670
    std::size_t numBoundaryScvf_;
671

Dennis Gläser's avatar
Dennis Gläser committed
672
673
    // The grid interaction volume index set
    GridIVIndexSets ivIndexSets_;
674
675
676

    // Indicator function on where to use the secondary IVs
    SecondaryIvIndicator secondaryIvIndicator_;
677
678
};

Dennis Gläser's avatar
Dennis Gläser committed
679
} // end namespace Dumux
680

681
#endif