452 enum { dim = GridView::dimension };
453 enum { dimWorld = GridView::dimensionworld };
454 enum {
maxNC = dim < 3 ? 4 : 8 };
455 enum {
maxNE = dim < 3 ? 4 : 12 };
456 enum {
maxNF = dim < 3 ? 1 : 6 };
457 enum {
maxBF = dim < 3 ? 8 : 24 };
458 using CoordScalar =
typename GridView::ctype;
459 using Element =
typename GridView::Traits::template Codim<0>::Entity;
462 using Entity =
typename GridView::Traits::template Codim<dim>::Entity;
465 using Geometry =
typename Element::Geometry;
466 using DimVector = Dune::FieldVector<Scalar, dimWorld>;
467 using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
468 using LocalPosition = Dune::FieldVector<CoordScalar, dim>;
469 using IntersectionIterator =
typename GridView::IntersectionIterator;
473#if HAVE_DUNE_LOCALFUNCTIONS
476 using LocalBasisTraits =
typename LocalFiniteElement::Traits::LocalBasisType::Traits;
477 using ShapeJacobian =
typename LocalBasisTraits::JacobianType;
480 Scalar quadrilateralArea(
const GlobalPosition&
p0,
481 const GlobalPosition&
p1,
482 const GlobalPosition&
p2,
483 const GlobalPosition&
p3)
485 return 0.5 * std::abs((
p3[0] -
p1[0]) * (
p2[1] -
p0[1]) -
489 void crossProduct(DimVector&
c,
const DimVector&
a,
const DimVector&
b)
491 c[0] =
a[1] *
b[2] -
a[2] *
b[1];
492 c[1] =
a[2] *
b[0] -
a[0] *
b[2];
493 c[2] =
a[0] *
b[1] -
a[1] *
b[0];
496 Scalar pyramidVolume(
const GlobalPosition&
p0,
497 const GlobalPosition&
p1,
498 const GlobalPosition&
p2,
499 const GlobalPosition&
p3,
500 const GlobalPosition&
p4)
506 crossProduct(
n,
a,
b);
510 return 1.0 / 6.0 * (
n *
a);
513 Scalar prismVolume(
const GlobalPosition&
p0,
514 const GlobalPosition&
p1,
515 const GlobalPosition&
p2,
516 const GlobalPosition&
p3,
517 const GlobalPosition&
p4,
518 const GlobalPosition&
p5)
521 for (
unsigned k = 0;
k < dimWorld; ++
k) {
525 for (
unsigned k = 0;
k < dimWorld; ++
k) {
529 crossProduct(
m,
a,
b);
531 for (
unsigned k = 0;
k < dimWorld; ++
k) {
534 for (
unsigned k = 0;
k < dimWorld; ++
k) {
538 crossProduct(
n,
a,
b);
541 for (
unsigned k = 0;
k < dimWorld; ++
k) {
545 return std::abs(1.0 / 6.0 * (
n *
a));
548 Scalar hexahedronVolume(
const GlobalPosition&
p0,
549 const GlobalPosition&
p1,
550 const GlobalPosition&
p2,
551 const GlobalPosition&
p3,
552 const GlobalPosition&
p4,
553 const GlobalPosition&
p5,
554 const GlobalPosition&
p6,
555 const GlobalPosition&
p7)
561 void normalOfQuadrilateral3D(DimVector& normal,
562 const GlobalPosition&
p0,
563 const GlobalPosition&
p1,
564 const GlobalPosition&
p2,
565 const GlobalPosition&
p3)
568 for (
unsigned k = 0;
k < dimWorld; ++
k) {
572 for (
unsigned k = 0;
k < dimWorld; ++
k) {
576 crossProduct(normal,
a,
b);
580 Scalar quadrilateralArea3D(
const GlobalPosition&
p0,
581 const GlobalPosition&
p1,
582 const GlobalPosition&
p2,
583 const GlobalPosition&
p3)
586 normalOfQuadrilateral3D(normal,
p0,
p1,
p2,
p3);
587 return normal.two_norm();
597 {1, 2, 3, 4, 1, 3, 4, 2},
598 {0, 0, 0, 0, 3, 2, 1, 4}
601 {1, 0, 2, 0, 1, 2, 4, 4, 4},
602 {0, 2, 1, 3, 3, 3, 0, 1, 2}
605 {0, 2, 3, 1, 4, 1, 2, 4, 0, 5, 5, 3},
606 {2, 1, 0, 3, 0, 4, 4, 3, 5, 1, 2, 5}
627 throw std::logic_error(
"Not implemented: VcfvStencil::getFaceIndices for "
663 { 3, 3, -1, 0, 1, -1},
664 { 4, -1, 4, 0, -1, 2},
665 {-1, 5, 5, -1, 1, 2},
666 { 3, 3, 5, -1, -1, -1},
667 {-1, -1, -1, 6, 6, 8}
670 { 0, 1, -1, 6, 6, -1},
671 { 0, -1, 2, 7, -1, 7},
672 {-1, 1, 2, -1, 8, 8},
673 { 4, 5, 4, -1, -1, -1},
674 {-1, -1, -1, 7, 8, 7}
677 { 0, -1, 4, -1, 8, -1, 2, -1},
678 {-1, 5, -1, 3, -1, 1, -1, 9},
679 { 6, 1, -1, -1, 0, 10, -1, -1},
680 {-1, -1, 2, 7, -1, -1, 11, 3},
681 { 4, 6, 7, 5, -1, -1, -1, -1},
682 {-1, -1, -1, -1, 10, 9, 8, 11}
685 { 4, -1, 2, -1, 0, -1, 8, -1},
686 {-1, 1, -1, 5, -1, 9, -1, 3},
687 { 0, 6, -1, -1, 10, 1, -1, -1},
688 {-1, -1, 7, 3, -1, -1, 2, 11},
689 { 6, 5, 4, 7, -1, -1, -1, -1},
690 {-1, -1, -1, -1, 8, 10, 11, 9}
711 throw std::logic_error(
"Not implemented: VcfvStencil::getFaceIndices for "
719 using Mapper = Dune::MultipleCodimMultipleGeomTypeMapper<GridView>;
724 const GlobalPosition center()
const
725 {
return global(localGeometry_->
center()); }
727 const GlobalPosition corner(
unsigned cornerIdx)
const
730 const GlobalPosition global(
const LocalPosition& localPos)
const
731 {
return element_->geometry().global(localPos); }
734 {
return *localGeometry_; }
737 const Element* element_;
742 const GlobalPosition& globalPos()
const
745 const GlobalPosition center()
const
748 Scalar volume()
const
775 const DimVector& normal()
const
778 unsigned short interiorIndex()
const
781 unsigned short exteriorIndex()
const
787 const LocalPosition& localPos()
const
790 const GlobalPosition& integrationPos()
const
813 : gridView_(gridView)
815 , element_(*gridView.
template begin<0>())
818 assert(
static_cast<int>(gridView.size(dimWorld)) ==
static_cast<int>(
mapper.size()));
841 numVertices =
e.subEntities(dim);
842 numEdges =
e.subEntities(dim-1);
843 if constexpr (dim == 3) {
844 numFaces =
e.subEntities(1);
850 numBoundarySegments_ = 0;
853 const Geometry& geometry =
e.geometry();
854 geometryType_ = geometry.type();
855 const auto&
referenceElement = Dune::ReferenceElements<CoordScalar,dim>::general(geometryType_);
862 void updatePrimaryTopology(
const Element& element)
870 void update(
const Element&
e)
874 const Geometry& geometry =
e.geometry();
875 geometryType_ = geometry.type();
877 const auto&
referenceElement = Dune::ReferenceElements<CoordScalar,dim>::general(geometryType_);
879 elementVolume = geometry.volume();
881 elementGlobal = geometry.global(elementLocal);
886 subContVol[
vert].global = geometry.global(subContVol[
vert].local);
904 fillSubContVolData_();
907 for (
unsigned k = 0;
k < numEdges; ++
k) {
909 static_cast<unsigned short>(
referenceElement.subEntity(
static_cast<int>(
k), dim - 1, 0, dim));
911 static_cast<unsigned short>(
referenceElement.subEntity(
static_cast<int>(
k), dim - 1, 1, dim));
912 if (numEdges == 4 && (i == 2 || j == 2)) {
915 subContVolFace[
k].i = i;
916 subContVolFace[
k].j = j;
925 if constexpr (dim == 1) {
926 subContVolFace[
k].ipLocal_ = 0.5;
927 subContVolFace[
k].normal_ = 1.0;
928 subContVolFace[
k].area_ = 1.0;
929 ipLocal = subContVolFace[
k].ipLocal_;
931 else if constexpr (dim == 2) {
934 subContVolFace[
k].ipLocal_ =
ipLocal;
935 for (
unsigned m = 0;
m < dimWorld; ++
m) {
938 subContVolFace[
k].normal_[0] =
diffVec[1];
939 subContVolFace[
k].normal_[1] = -
diffVec[0];
941 for (
unsigned m = 0;
m < dimWorld; ++
m) {
942 diffVec[
m] = subContVol[j].global[
m] - subContVol[i].global[
m];
945 if (subContVolFace[
k].normal_ *
diffVec < 0) {
946 subContVolFace[
k].normal_ *= -1;
949 subContVolFace[
k].area_ = subContVolFace[
k].normal_.two_norm();
950 subContVolFace[
k].normal_ /= subContVolFace[
k].area_;
952 else if constexpr (dim == 3) {
961 subContVolFace[
k].ipLocal_ =
ipLocal;
962 normalOfQuadrilateral3D(subContVolFace[
k].normal_,
964 elementGlobal, faceCoord[
leftFace]);
965 subContVolFace[
k].area_ = subContVolFace[
k].normal_.two_norm();
966 subContVolFace[
k].normal_ /= subContVolFace[
k].area_;
970 subContVolFace[
k].ipGlobal_ = geometry.global(
ipLocal);
975 if (!intersection.boundary()) {
979 const unsigned face =
static_cast<unsigned>(intersection.indexInInside());
983 const unsigned bfIdx = numBoundarySegments_;
984 ++numBoundarySegments_;
986 if constexpr (dim == 1) {
988 boundaryFace_[
bfIdx].area_ = 1.0;
990 else if constexpr (dim == 2) {
991 boundaryFace_[
bfIdx].ipLocal_ =
994 boundaryFace_[
bfIdx].ipLocal_ *= 0.5;
995 boundaryFace_[
bfIdx].area_ = 0.5 * intersection.geometry().volume();
997 else if constexpr (dim == 3) {
1001 boundaryFace_[
bfIdx].ipLocal_ =
1006 boundaryFace_[
bfIdx].ipLocal_ *= 0.25;
1007 boundaryFace_[
bfIdx].area_ =
1014 throw std::logic_error(
"Not implemented:VcfvStencil for dim = " + std::to_string(dim));
1017 boundaryFace_[
bfIdx].ipGlobal_ = geometry.global(boundaryFace_[
bfIdx].ipLocal_);
1022 boundaryFace_[
bfIdx].normal_ = intersection.centerUnitOuterNormal();
1026 updateScvGeometry(
e);
1029 void updateScvGeometry(
const Element& element)
1031 auto geomType = element.geometry().type();
1036 subContVol[
vertIdx].geometry_.element_ = &element;
1037 subContVol[
vertIdx].geometry_.localGeometry_ =
1038 &VcfvScvGeometries<Scalar, dim, ElementType::simplex>::get(
vertIdx);
1043 subContVol[
vertIdx].geometry_.element_ = &element;
1044 subContVol[
vertIdx].geometry_.localGeometry_ =
1045 &VcfvScvGeometries<Scalar, dim, ElementType::cube>::get(
vertIdx);
1049 throw std::logic_error(
"Not implemented: SCV geometries for non hexahedron elements");
1053#if HAVE_DUNE_LOCALFUNCTIONS
1054 void updateCenterGradients()
1057 const auto&
geom = element_.geometry();
1059 std::vector<ShapeJacobian>
localJac;
1064 const auto& globalPos = subContVol[
scvIdx].geometry().center();
1066 const auto jacInvT =
geom.jacobianInverseTransposed(globalPos);
1074 unsigned numDof()
const
1075 {
return numVertices; }
1077 unsigned numPrimaryDof()
const
1078 {
return numDof(); }
1080 Dune::PartitionType partitionType(
unsigned scvIdx)
const
1083 const SubControlVolume& subControlVolume(
unsigned scvIdx)
const
1086 return subContVol[
scvIdx];
1089 unsigned numInteriorFaces()
const
1090 {
return numEdges; }
1092 unsigned numBoundaryFaces()
const
1093 {
return numBoundarySegments_; }
1095 const SubControlVolumeFace& interiorFace(
unsigned faceIdx)
const
1096 {
return subContVolFace[faceIdx]; }
1099 {
return boundaryFace_[
bfIdx]; }
1107 assert(dofIdx < numDof());
1109 return static_cast<unsigned>(vertexMapper_.subIndex(element_,
static_cast<int>(dofIdx), dim));
1118 assert(dofIdx < numDof());
1119 return element_.template
subEntity<dim>(
static_cast<int>(dofIdx));
1123#if __GNUC__ || __clang__
1124#pragma GCC diagnostic push
1125#pragma GCC diagnostic ignored "-Wpragmas"
1126#pragma GCC diagnostic ignored "-Warray-bounds"
1128 void fillSubContVolData_()
1130 if constexpr (dim == 1) {
1132 subContVol[0].volume_ = 0.5 * elementVolume;
1133 subContVol[1].volume_ = 0.5 * elementVolume;
1135 else if constexpr (dim == 2) {
1136 switch (numVertices) {
1138 subContVol[0].volume_ = elementVolume / 3;
1139 subContVol[1].volume_ = elementVolume / 3;
1140 subContVol[2].volume_ = elementVolume / 3;
1143 subContVol[0].volume_ =
1144 quadrilateralArea(subContVol[0].global,
1148 subContVol[1].volume_ =
1149 quadrilateralArea(subContVol[1].global,
1153 subContVol[2].volume_ =
1154 quadrilateralArea(subContVol[2].global,
1158 subContVol[3].volume_ =
1159 quadrilateralArea(subContVol[3].global,
1165 throw std::logic_error(
"Not implemented:VcfvStencil dim = " + std::to_string(dim) +
1166 ", numVertices = " + std::to_string(numVertices));
1169 else if constexpr (dim == 3) {
1170 switch (numVertices) {
1172 for (
unsigned k = 0;
k < numVertices;
k++) {
1173 subContVol[
k].volume_ = elementVolume / 4.0;
1177 subContVol[0].volume_ =
1178 hexahedronVolume(subContVol[0].global,
1186 subContVol[1].volume_ =
1187 hexahedronVolume(subContVol[1].global,
1195 subContVol[2].volume_ =
1196 hexahedronVolume(subContVol[2].global,
1204 subContVol[3].volume_ =
1205 hexahedronVolume(subContVol[3].global,
1213 subContVol[4].volume_ = elementVolume -
1214 subContVol[0].volume_ -
1215 subContVol[1].volume_ -
1216 subContVol[2].volume_ -
1217 subContVol[3].volume_;
1220 subContVol[0].volume_ =
1221 hexahedronVolume(subContVol[0].global,
1229 subContVol[1].volume_ =
1230 hexahedronVolume(subContVol[1].global,
1238 subContVol[2].volume_ =
1239 hexahedronVolume(subContVol[2].global,
1247 subContVol[3].volume_ =
1248 hexahedronVolume(edgeCoord[0],
1252 subContVol[3].global,
1256 subContVol[4].volume_ =
1257 hexahedronVolume(edgeCoord[1],
1261 subContVol[4].global,
1265 subContVol[5].volume_ =
1266 hexahedronVolume(edgeCoord[2],
1270 subContVol[5].global,
1276 subContVol[0].volume_ =
1277 hexahedronVolume(subContVol[0].global,
1285 subContVol[1].volume_ =
1286 hexahedronVolume(subContVol[1].global,
1294 subContVol[2].volume_ =
1295 hexahedronVolume(subContVol[2].global,
1303 subContVol[3].volume_ =
1304 hexahedronVolume(subContVol[3].global,
1312 subContVol[4].volume_ =
1313 hexahedronVolume(edgeCoord[0],
1317 subContVol[4].global,
1321 subContVol[5].volume_ =
1322 hexahedronVolume(edgeCoord[1],
1326 subContVol[5].global,
1330 subContVol[6].volume_ =
1331 hexahedronVolume(edgeCoord[2],
1335 subContVol[6].global,
1339 subContVol[7].volume_ =
1340 hexahedronVolume(edgeCoord[3],
1344 subContVol[7].global,
1350 throw std::logic_error(
"Not implemented:VcfvStencil for dim = " + std::to_string(dim) +
1351 ", numVertices = " + std::to_string(numVertices));
1355 throw std::logic_error(
"Not implemented:VcfvStencil for dim = " + std::to_string(dim));
1358#if __GNUC__ || __clang__
1359#pragma GCC diagnostic pop
1362 const GridView& gridView_;
1363 const Mapper& vertexMapper_;
1367#if HAVE_DUNE_LOCALFUNCTIONS
1372 LocalPosition elementLocal;
1375 GlobalPosition elementGlobal;
1378 Scalar elementVolume;
1381 std::array<SubControlVolume, maxNC> subContVol{};
1384 std::array<SubControlVolumeFace, maxNE> subContVolFace{};
1387 std::array<BoundaryFace, maxBF> boundaryFace_{};
1389 unsigned numBoundarySegments_{};
1392 std::array<GlobalPosition, maxNE> edgeCoord{};
1395 std::array<GlobalPosition, maxNF> faceCoord{};
1398 unsigned numVertices{};
1401 unsigned numEdges{};
1404 unsigned numFaces{};
1406 Dune::GeometryType geometryType_;