23#ifndef OPM_TRANSMISSIBILITY_IMPL_HPP
24#define OPM_TRANSMISSIBILITY_IMPL_HPP
26#ifndef OPM_TRANSMISSIBILITY_HPP
31#include <dune/common/version.hh>
32#include <dune/grid/common/mcmgmapper.hh>
34#include <opm/common/OpmLog/KeywordLocation.hpp>
35#include <opm/common/utility/ThreadSafeMapBuilder.hpp>
37#include <opm/grid/CpGrid.hpp>
38#include <opm/grid/utility/ElementChunks.hpp>
40#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
41#include <opm/input/eclipse/EclipseState/Grid/FaceDir.hpp>
42#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
43#include <opm/input/eclipse/EclipseState/Grid/TransMult.hpp>
44#include <opm/input/eclipse/Units/Units.hpp>
55#include <initializer_list>
62#include <fmt/format.h>
70 std::uint64_t
isId(std::uint32_t elemIdx1, std::uint32_t elemIdx2)
72 const std::uint32_t elemAIdx = std::min(elemIdx1, elemIdx2);
73 const std::uint64_t elemBIdx = std::max(elemIdx1, elemIdx2);
78 std::pair<std::uint32_t, std::uint32_t>
isIdReverse(
const std::uint64_t&
id)
83 const std::uint32_t elemAIdx =
static_cast<uint32_t
>(id);
84 const std::uint32_t elemBIdx = (
id - elemAIdx) >>
elemIdxShift;
86 return std::make_pair(elemAIdx, elemBIdx);
91 return (std::uint64_t(elemIdx1) <<
elemIdxShift) + elemIdx2;
95template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
98 const GridView& gridView,
99 const CartesianIndexMapper& cartMapper,
101 std::function<std::array<double,dimWorld>(
int)> centroids,
103 bool enableDiffusivity,
104 bool enableDispersivity)
105 : eclState_(eclState)
106 , gridView_(gridView)
107 , cartMapper_(cartMapper)
109 , centroids_(centroids)
110 , enableEnergy_(enableEnergy)
111 , enableDiffusivity_(enableDiffusivity)
112 , enableDispersivity_(enableDispersivity)
113 , lookUpData_(gridView)
114 , lookUpCartesianData_(gridView, cartMapper)
116 const UnitSystem& unitSystem =
eclState_.getDeckUnitSystem();
120template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
127template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
131 return transBoundary_.at(std::make_pair(elemIdx, boundaryFaceIdx));
134template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
141template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
145 if (!storeHalfTrans_) {
149 OPM_THROW(std::logic_error,
150 "One-sided half transmissibilities were not stored. "
151 "Call setStoreHalfTrans(true) before update() to have them "
152 "computed; they are off by default because only the adjoint "
159template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
163 return thermalHalfTransBoundary_.at(std::make_pair(insideElemIdx, boundaryFaceIdx));
166template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
170 return thermalHalfTransBoundary_;
173template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
175diffusivity(
unsigned elemIdx1,
unsigned elemIdx2)
const
177 if (diffusivity_.empty())
183template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
187 if (dispersivity_.empty())
193template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
196 const std::function<
unsigned int(
unsigned int)>& map,
const bool applyNncMultregT)
199 const bool onlyTrans = (update_quantities == TransUpdateQuantities::Trans);
200 const auto& cartDims = cartMapper_.cartesianDimensions();
201 const auto& transMult = eclState_.getTransMult();
202 const auto& comm = gridView_.comm();
203 ElementMapper elemMapper(gridView_, Dune::mcmgElementLayout());
205 unsigned numElements = elemMapper.size();
207 const std::vector<double>& ntg = this->lookUpData_.assignFieldPropsDoubleOnLeaf(eclState_.fieldProps(),
"NTG");
208 const bool updateDiffusivity = eclState_.getSimulationConfig().isDiffusive();
209 const bool updateDispersivity = eclState_.getSimulationConfig().rock_config().dispersion();
211 const bool disableNNC = eclState_.getSimulationConfig().useNONNC();
214 extractPermeability_(map);
217 extractPermeability_();
227 if (num_threads == 1) {
228 trans_.reserve(numElements*3*1.05);
231 transBoundary_.clear();
233 if (storeHalfTrans_) {
235 if (num_threads == 1) {
236 halfTrans_.reserve(numElements*6*1.05);
241 if ( enableEnergy_ && !onlyTrans) {
242 thermalHalfTrans_.clear();
243 if (num_threads == 1) {
244 thermalHalfTrans_.reserve(numElements*6*1.05);
247 thermalHalfTransBoundary_.clear();
251 if (updateDiffusivity && !onlyTrans) {
252 diffusivity_.clear();
253 if (num_threads == 1) {
254 diffusivity_.reserve(numElements*3*1.05);
260 if (updateDispersivity && !onlyTrans) {
261 dispersivity_.clear();
262 if (num_threads == 1) {
263 dispersivity_.reserve(numElements*3*1.05);
265 extractDispersion_();
271 bool useSmallestMultiplier;
272 bool pinchOption4ALL;
274 if (comm.rank() == 0) {
275 const auto& eclGrid = eclState_.getInputGrid();
276 pinchActive = eclGrid.isPinchActive();
277 auto pinchTransCalcMode = eclGrid.getPinchOption();
278 useSmallestMultiplier = eclGrid.getMultzOption() == PinchMode::ALL;
279 pinchOption4ALL = (pinchTransCalcMode == PinchMode::ALL);
280 if (pinchOption4ALL) {
281 useSmallestMultiplier =
false;
284 if (global && comm.size() > 1) {
285 comm.broadcast(&useSmallestMultiplier, 1, 0);
286 comm.broadcast(&pinchOption4ALL, 1, 0);
287 comm.broadcast(&pinchActive, 1, 0);
291 centroids_cache_.resize(gridView_.size(0));
292 for (
const auto& elem : elements(gridView_)) {
293 const unsigned elemIdx = elemMapper.index(elem);
294 centroids_cache_[elemIdx] = centroids_(elemIdx);
297 auto harmonicMean = [](
const Scalar x1,
const Scalar x2)
299 return (std::abs(x1) < 1e-30 || std::abs(x2) < 1e-30)
301 : 1.0 / (1.0 / x1 + 1.0 / x2);
304 auto faceIdToDir = [](
int insideFaceIdx)
306 switch (insideFaceIdx) {
309 return FaceDir::XPlus;
312 return FaceDir::YPlus;
316 return FaceDir::ZPlus;
318 throw std::logic_error(
"Could not determine a face direction");
322 auto halfDiff = [](
const DimVector& faceAreaNormal,
327 return computeHalfDiffusivity_(faceAreaNormal,
332 ThreadSafeMapBuilder transBoundary(transBoundary_, num_threads,
333 MapBuilderInsertionMode::Insert_Or_Assign);
334 ThreadSafeMapBuilder transMap(trans_, num_threads,
335 MapBuilderInsertionMode::Insert_Or_Assign);
336 ThreadSafeMapBuilder thermalHalfTransBoundary(thermalHalfTransBoundary_, num_threads,
337 MapBuilderInsertionMode::Insert_Or_Assign);
338 ThreadSafeMapBuilder thermalHalfTrans(thermalHalfTrans_, num_threads,
339 MapBuilderInsertionMode::Insert_Or_Assign);
340 ThreadSafeMapBuilder halfTransMap(halfTrans_, num_threads,
341 MapBuilderInsertionMode::Insert_Or_Assign);
342 ThreadSafeMapBuilder diffusivity(diffusivity_, num_threads,
343 MapBuilderInsertionMode::Insert_Or_Assign);
344 ThreadSafeMapBuilder dispersivity(dispersivity_, num_threads,
345 MapBuilderInsertionMode::Insert_Or_Assign);
347 const auto& nnc_input = eclState_.getInputNNC().input();
350#pragma omp parallel for
352 for (
const auto& chunk : ElementChunks(gridView_, Dune::Partitions::all, num_threads)) {
353 for (
const auto& elem : chunk) {
358 inside.
elemIdx = elemMapper.index(elem);
362 template getFieldPropCartesianIdx<Grid>(inside.
elemIdx);
364 auto computeHalf = [
this, &faceAreaNormal, &inside, &outside]
365 (
const auto& halfComputer,
366 const auto& prop1,
const auto& prop2) -> std::array<Scalar,2>
369 halfComputer(faceAreaNormal,
373 halfComputer(faceAreaNormal,
380 auto computeHalfMean = [&inside, &outside, &computeHalf, &ntg, &harmonicMean]
381 (
const auto& halfComputer,
const auto& prop)
383 auto onesided = computeHalf(halfComputer, prop[inside.
elemIdx], prop[outside.
elemIdx]);
384 applyNtg_(onesided[0], inside, ntg);
385 applyNtg_(onesided[1], outside, ntg);
388 return harmonicMean(onesided[0], onesided[1]);
391 unsigned boundaryIsIdx = 0;
392 for (
const auto& intersection : intersections(gridView_, elem)) {
394 if (intersection.boundary()) {
396 const auto& geometry = intersection.geometry();
399 faceAreaNormal = intersection.centerUnitOuterNormal();
400 faceAreaNormal *= geometry.volume();
402 Scalar transBoundaryIs =
403 computeHalfTrans_(faceAreaNormal,
404 intersection.indexInInside(),
406 permeability_[inside.
elemIdx]);
411 applyMultipliers_(transBoundaryIs, intersection.indexInInside(), inside.
cartElemIdx, transMult);
412 transBoundary.insert_or_assign(std::make_pair(inside.
elemIdx, boundaryIsIdx), transBoundaryIs);
416 if (enableEnergy_ && !onlyTrans) {
417 Scalar transBoundaryEnergyIs =
418 computeHalfDiffusivity_(faceAreaNormal,
421 thermalHalfTransBoundary.insert_or_assign(std::make_pair(inside.
elemIdx, boundaryIsIdx),
422 transBoundaryEnergyIs);
429 if (!intersection.neighbor()) {
436 const auto& outsideElem = intersection.outside();
437 outside.
elemIdx = elemMapper.index(outsideElem);
442 template getFieldPropCartesianIdx<Grid>(outside.
elemIdx);
456 inside.
faceIdx = intersection.indexInInside();
457 outside.
faceIdx = intersection.indexInOutside();
464 if (enableEnergy_ && !onlyTrans) {
469 if (updateDiffusivity && !onlyTrans) {
472 if (updateDispersivity && !onlyTrans) {
478 typename std::is_same<Grid, Dune::CpGrid>::type isCpGrid;
479 computeFaceProperties(intersection,
485 Scalar trans = computeHalfMean(computeHalfTrans_, permeability_);
487 if (storeHalfTrans_) {
490 auto onesided = computeHalf(computeHalfTrans_,
492 permeability_[outside.
elemIdx]);
493 applyNtg_(onesided[0], inside, ntg);
494 applyNtg_(onesided[1], outside, ntg);
495 halfTransMap.insert_or_assign(
498 halfTransMap.insert_or_assign(
507 auto find_layer = [&cartDims](std::size_t cell) {
509 auto k = cell / cartDims[1];
517 if (std::abs(kup -kdown) > 1) {
523 if (useSmallestMultiplier) {
527 applyAllZMultipliers_(trans, inside, outside, transMult, cartDims);
535 bool foundInputNNC =
false;
536 if (! nnc_input.empty()) {
538 auto it = std::lower_bound(nnc_input.begin(), nnc_input.end(),
539 NNCdata { inside.cartElemIdx, outside.cartElemIdx, 0.0 });
540 foundInputNNC = it != nnc_input.end() && it->cell1 == inside.
cartElemIdx && it->cell2 == outside.
cartElemIdx;
542 if (! foundInputNNC) {
544 trans *= transMult.getRegionMultiplier(inside.
cartElemIdx,
552 if (enableEnergy_ && !onlyTrans) {
553 const auto half = computeHalf(halfDiff, 1.0, 1.0);
562 if (updateDiffusivity && !onlyTrans) {
564 computeHalfMean(halfDiff, porosity_));
568 if (updateDispersivity && !onlyTrans) {
570 computeHalfMean(halfDiff, dispersion_));
575 centroids_cache_.clear();
578#pragma omp parallel sections
588 transBoundary.finalize();
592 thermalHalfTransBoundary.finalize();
596 thermalHalfTrans.finalize();
600 diffusivity.finalize();
604 dispersivity.finalize();
608 halfTransMap.finalize();
612 this->updateFromEclState_(global);
615 std::unordered_map<std::size_t,int> globalToLocal;
618 for (
const auto& elem : elements(grid_.leafGridView())) {
619 int elemIdx = elemMapper.index(elem);
620 int cartElemIdx = cartMapper_.cartesianIndex(elemIdx);
621 globalToLocal[cartElemIdx] = elemIdx;
630 this->applyPinchNncToGridTrans_(globalToLocal, applyNncMultregT);
631 this->applyNncToGridTrans_(globalToLocal);
632 this->applyEditNncToGridTrans_(globalToLocal);
633 this->applyEditNncrToGridTrans_(globalToLocal);
634 if (applyNncMultregT) {
635 this->applyNncMultreg_(globalToLocal);
637 warnEditNNC_ =
false;
642 this->removeNonCartesianTransmissibilities_(disableNNC);
645template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
649 unsigned numElem = gridView_.size(0);
650 permeability_.resize(numElem);
656 const auto& fp = eclState_.fieldProps();
657 if (fp.has_double(
"PERMX")) {
658 const std::vector<double>& permxData = this-> lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PERMX");
660 std::vector<double> permyData;
661 if (fp.has_double(
"PERMY"))
662 permyData = this-> lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PERMY");
664 permyData = permxData;
666 std::vector<double> permzData;
667 if (fp.has_double(
"PERMZ"))
668 permzData = this-> lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PERMZ");
670 permzData = permxData;
672 for (std::size_t dofIdx = 0; dofIdx < numElem; ++ dofIdx) {
673 permeability_[dofIdx] = 0.0;
674 permeability_[dofIdx][0][0] = permxData[dofIdx];
675 permeability_[dofIdx][1][1] = permyData[dofIdx];
676 permeability_[dofIdx][2][2] = permzData[dofIdx];
683 throw std::logic_error(
"Can't read the intrinsic permeability from the ecl state. "
684 "(The PERM{X,Y,Z} keywords are missing)");
687template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
691 unsigned numElem = gridView_.size(0);
692 permeability_.resize(numElem);
698 const auto& fp = eclState_.fieldProps();
699 if (fp.has_double(
"PERMX")) {
700 const std::vector<double>& permxData =
701 this->lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PERMX");
703 std::vector<double> permyData;
704 if (fp.has_double(
"PERMY")){
705 permyData = this->lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PERMY");
708 permyData = permxData;
711 std::vector<double> permzData;
712 if (fp.has_double(
"PERMZ")) {
713 permzData = this->lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PERMZ");
716 permzData = permxData;
719 for (std::size_t dofIdx = 0; dofIdx < numElem; ++ dofIdx) {
720 permeability_[dofIdx] = 0.0;
721 std::size_t inputDofIdx = map(dofIdx);
722 permeability_[dofIdx][0][0] = permxData[inputDofIdx];
723 permeability_[dofIdx][1][1] = permyData[inputDofIdx];
724 permeability_[dofIdx][2][2] = permzData[inputDofIdx];
730 throw std::logic_error(
"Can't read the intrinsic permeability from the ecl state. "
731 "(The PERM{X,Y,Z} keywords are missing)");
735template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
743 const auto& fp = eclState_.fieldProps();
744 if (fp.has_double(
"PORO")) {
745 if constexpr (std::is_same_v<Scalar,double>) {
746 porosity_ = this->lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PORO");
749 const auto por = this->lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"PORO");
750 porosity_.resize(por.size());
751 std::ranges::copy(por, porosity_.begin());
755 throw std::logic_error(
"Can't read the porosity from the ecl state. "
756 "(The PORO keywords are missing)");
760template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
764 if (!enableDispersivity_) {
765 throw std::runtime_error(
"Dispersion disabled at compile time, but the deck "
766 "contains the DISPERC keyword.");
768 const auto& fp = eclState_.fieldProps();
769 if constexpr (std::is_same_v<Scalar,double>) {
770 dispersion_ = this->lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"DISPERC");
773 const auto disp = this->lookUpData_.assignFieldPropsDoubleOnLeaf(fp,
"DISPERC");
774 dispersion_.resize(disp.size());
775 std::ranges::copy(disp, dispersion_.begin());
779template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
783 const auto& cartDims = cartMapper_.cartesianDimensions();
784 for (
auto&& trans: trans_) {
786 if (removeAll || trans.second < transmissibilityThreshold_) {
787 const auto&
id = trans.first;
789 int gc1 = std::min(cartMapper_.cartesianIndex(elements.first), cartMapper_.cartesianIndex(elements.second));
790 int gc2 = std::max(cartMapper_.cartesianIndex(elements.first), cartMapper_.cartesianIndex(elements.second));
795 if (gc2 - gc1 == 1 || gc2 - gc1 == cartDims[0] || gc2 - gc1 == cartDims[0]*cartDims[1] || gc2 - gc1 == 0) {
804template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
809 const TransMult& transMult,
810 const std::array<int, dimWorld>& cartDims)
812 if (grid_.maxLevel() > 0) {
813 OPM_THROW(std::invalid_argument,
"MULTZ not support with LGRS, yet.");
819 unsigned lastCartElemIdx;
824 lastCartElemIdx = outside.
cartElemIdx - cartDims[0]*cartDims[1];
827 Scalar mult = transMult.getMultiplier(lastCartElemIdx , FaceDir::ZPlus) *
828 transMult.getMultiplier(outside.
cartElemIdx , FaceDir::ZMinus);
832 for (
auto cartElemIdx = inside.
cartElemIdx; cartElemIdx < lastCartElemIdx;) {
833 auto multiplier = transMult.getMultiplier(cartElemIdx, FaceDir::ZPlus);
834 cartElemIdx += cartDims[0]*cartDims[1];
835 multiplier *= transMult.getMultiplier(cartElemIdx, FaceDir::ZMinus);
836 mult = std::min(mult,
static_cast<Scalar
>(multiplier));
847template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
851 const FieldPropsManager* fp =
852 (global) ? &(eclState_.fieldProps()) :
853 &(eclState_.globalFieldProps());
855 std::array<bool,3> is_tran {fp->tran_active(
"TRANX"),
856 fp->tran_active(
"TRANY"),
857 fp->tran_active(
"TRANZ")};
859 if (!(is_tran[0] || is_tran[1] || is_tran[2])) {
864 std::array<std::string, 3> keywords {
"TRANX",
"TRANY",
"TRANZ"};
865 std::array<std::vector<double>,3> trans = createTransmissibilityArrays_(is_tran);
866 auto key = keywords.begin();
867 auto perform = is_tran.begin();
869 for (
auto it = trans.begin(); it != trans.end(); ++it, ++key, ++perform) {
871 if (grid_.maxLevel() > 0) {
872 OPM_THROW(std::invalid_argument,
"Calculations on TRANX/TRANY/TRANZ arrays are not support with LGRS, yet.");
874 fp->apply_tran(*key, *it);
878 resetTransmissibilityFromArrays_(is_tran, trans);
881template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
882std::array<std::vector<double>,3>
886 const auto& cartDims = cartMapper_.cartesianDimensions();
887 ElementMapper elemMapper(gridView_, Dune::mcmgElementLayout());
889 auto numElem = gridView_.size(0);
890 std::array<std::vector<double>,3> trans = {
891 std::vector<double>(is_tran[0] ? numElem : 0, 0),
892 std::vector<double>(is_tran[1] ? numElem : 0, 0),
893 std::vector<double>(is_tran[2] ? numElem : 0, 0)
897 for (
const auto& elem : elements(gridView_)) {
898 for (
const auto& intersection : intersections(gridView_, elem)) {
900 if (!intersection.neighbor()) {
915 unsigned c1 = elemMapper.index(intersection.inside());
916 unsigned c2 = elemMapper.index(intersection.outside());
917 int gc1 = cartMapper_.cartesianIndex(c1);
918 int gc2 = cartMapper_.cartesianIndex(c2);
919 if (std::tie(gc1, c1) > std::tie(gc2, c2)) {
933 if ((gc2 - gc1 == 1 || (gc2 == gc1 && (intersection.indexInInside() == 0 || intersection.indexInInside() == 1)))
938 trans[0][c1] = trans_[isID];
941 else if ((gc2 - gc1 == cartDims[0] || (gc2 == gc1 && (intersection.indexInInside() == 2 || intersection.indexInInside() == 3)))
946 trans[1][c1] = trans_[isID];
949 else if (gc2 - gc1 == cartDims[0]*cartDims[1] ||
950 (gc2 == gc1 && (intersection.indexInInside() == 4 || intersection.indexInInside() == 5)))
954 trans[2][c1] = trans_[isID];
964template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
967 const std::array<std::vector<double>,3>& trans)
969 const auto& cartDims = cartMapper_.cartesianDimensions();
970 ElementMapper elemMapper(gridView_, Dune::mcmgElementLayout());
973 for (
const auto& elem : elements(gridView_)) {
974 for (
const auto& intersection : intersections(gridView_, elem)) {
975 if (!intersection.neighbor()) {
990 unsigned c1 = elemMapper.index(intersection.inside());
991 unsigned c2 = elemMapper.index(intersection.outside());
992 int gc1 = cartMapper_.cartesianIndex(c1);
993 int gc2 = cartMapper_.cartesianIndex(c2);
994 if (std::tie(gc1, c1) > std::tie(gc2, c2)) {
1008 if ((gc2 - gc1 == 1 || (gc2 == gc1 && (intersection.indexInInside() == 0 || intersection.indexInInside() == 1)))
1013 trans_[isID] = trans[0][c1];
1016 else if ((gc2 - gc1 == cartDims[0] || (gc2 == gc1 && (intersection.indexInInside() == 2|| intersection.indexInInside() == 3)))
1021 trans_[isID] = trans[1][c1];
1024 else if (gc2 - gc1 == cartDims[0]*cartDims[1] ||
1025 (gc2 == gc1 && (intersection.indexInInside() == 4 || intersection.indexInInside() == 5)))
1029 trans_[isID] = trans[2][c1];
1038template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1039template<
class Intersection>
1045 std::false_type)
const
1048 const auto& geometry = intersection.geometry();
1051 faceAreaNormal = intersection.centerUnitOuterNormal();
1052 faceAreaNormal *= geometry.volume();
1055template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1056template<
class Intersection>
1062 std::true_type)
const
1064 int faceIdx = intersection.id();
1066 if (grid_.maxLevel() == 0) {
1069 faceAreaNormal = grid_.faceAreaNormalEcl(faceIdx);
1072 if ((intersection.inside().level() != intersection.outside().level())) {
1079 const auto& parentIntersection =
1080 grid_.getParentIntersectionFromLgrBoundaryFace(intersection);
1081 const auto& parentIntersectionGeometry = parentIntersection.geometry();
1085 inside.
faceCenter = (intersection.inside().level() == 0)
1086 ? parentIntersectionGeometry.center()
1087 : grid_.faceCenterEcl(inside.
elemIdx, inside.
faceIdx, intersection);
1088 outside.
faceCenter = (intersection.outside().level() == 0)
1089 ? parentIntersectionGeometry.center()
1090 : grid_.faceCenterEcl(outside.
elemIdx, outside.
faceIdx, intersection);
1098 faceAreaNormal = intersection.centerUnitOuterNormal();
1099 faceAreaNormal *= intersection.geometry().volume();
1102 assert(intersection.inside().level() == intersection.outside().level());
1108 if (intersection.inside().level() > 0) {
1109 faceAreaNormal = intersection.centerUnitOuterNormal();
1110 faceAreaNormal *= intersection.geometry().volume();
1113 faceAreaNormal = grid_.faceAreaNormalEcl(faceIdx);
1119template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1123 const bool applyNncMultregT)
1125 const auto& pinchNnc = eclState_.getPinchNNC();
1126 const auto& transMult = this->eclState_.getTransMult();
1128 for (
const auto& nncEntry : pinchNnc) {
1129 auto c1 = nncEntry.cell1;
1130 auto c2 = nncEntry.cell2;
1131 auto lowIt = cartesianToCompressed.find(c1);
1132 auto highIt = cartesianToCompressed.find(c2);
1133 int low = (lowIt == cartesianToCompressed.end())? -1 : lowIt->second;
1134 int high = (highIt == cartesianToCompressed.end())? -1 : highIt->second;
1137 std::swap(low, high);
1140 if (low == -1 && high == -1) {
1145 if (low == -1 || high == -1) {
1154 if (candidate != trans_.end()) {
1158 candidate->second = nncEntry.trans;
1159 if (applyNncMultregT) {
1160 const auto mult = transMult.getRegionMultiplierNNC(c1, c2);
1161 candidate->second *= mult;
1168template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1174 const auto& nnc_input = eclState_.getInputNNC().input();
1176 for (
const auto& nncEntry : nnc_input) {
1177 auto c1 = nncEntry.cell1;
1178 auto c2 = nncEntry.cell2;
1179 auto lowIt = cartesianToCompressed.find(c1);
1180 auto highIt = cartesianToCompressed.find(c2);
1181 int low = (lowIt == cartesianToCompressed.end())? -1 : lowIt->second;
1182 int high = (highIt == cartesianToCompressed.end())? -1 : highIt->second;
1185 std::swap(low, high);
1188 if (low == -1 && high == -1) {
1193 if (low == -1 || high == -1) {
1195 std::ostringstream sstr;
1196 sstr <<
"NNC between active and inactive cells ("
1197 << low <<
" -> " << high <<
") with globalcell is (" << c1 <<
"->" << c2 <<
")";
1198 OpmLog::warning(sstr.str());
1202 if (
auto candidate = trans_.find(
details::isId(low, high)); candidate != trans_.end()) {
1206 candidate->second += nncEntry.trans;
1236template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1240 const auto& input = eclState_.getInputNNC();
1241 applyEditNncToGridTransHelper_(globalToLocal,
"EDITNNC",
1243 [&input](
const NNCdata& nnc){
1244 return input.edit_location(nnc);},
1246 [](Scalar& trans,
const Scalar& rhs){ trans *= rhs;});
1249template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1253 const auto& input = eclState_.getInputNNC();
1254 applyEditNncToGridTransHelper_(globalToLocal,
"EDITNNCR",
1256 [&input](
const NNCdata& nnc){
1257 return input.editr_location(nnc);},
1259 [](Scalar& trans,
const Scalar& rhs){ trans = rhs;});
1262template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1265 const std::string& keyword,
1266 const std::vector<NNCdata>& nncs,
1267 const std::function<KeywordLocation(
const NNCdata&)>& getLocation,
1268 const std::function<
void(Scalar&,
const Scalar&)>& apply)
1273 const auto& cartDims = cartMapper_.cartesianDimensions();
1275 auto format_ijk = [&cartDims](std::size_t cell) -> std::string
1277 auto i = cell % cartDims[0]; cell /= cartDims[0];
1278 auto j = cell % cartDims[1];
1279 auto k = cell / cartDims[1];
1281 return fmt::format(
"({},{},{})", i + 1,j + 1,k + 1);
1284 auto print_warning = [&format_ijk, &getLocation, &keyword] (
const NNCdata& nnc)
1286 const auto& location = getLocation( nnc );
1287 auto warning = fmt::format(
"Problem with {} keyword\n"
1289 "No NNC defined for connection {} -> {}", keyword, location.filename,
1290 location.lineno, format_ijk(nnc.cell1), format_ijk(nnc.cell2));
1291 OpmLog::warning(keyword, warning);
1297 auto nnc = nncs.begin();
1298 auto end = nncs.end();
1299 std::size_t warning_count = 0;
1300 while (nnc != end) {
1301 auto c1 = nnc->cell1;
1302 auto c2 = nnc->cell2;
1303 auto lowIt = globalToLocal.find(c1);
1304 auto highIt = globalToLocal.find(c2);
1306 if (lowIt == globalToLocal.end() || highIt == globalToLocal.end()) {
1308 if (lowIt != highIt && warnEditNNC_) {
1309 print_warning(*nnc);
1316 auto low = lowIt->second, high = highIt->second;
1319 std::swap(low, high);
1323 if (candidate == trans_.end() && warnEditNNC_) {
1324 print_warning(*nnc);
1330 while (nnc != end && c1 == nnc->cell1 && c2 == nnc->cell2) {
1331 apply(candidate->second, nnc->trans);
1337 if (warning_count > 0) {
1338 auto warning = fmt::format(
"Problems with {} keyword\n"
1339 "A total of {} connections not defined in grid", keyword, warning_count);
1340 OpmLog::warning(warning);
1344template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1347applyNncMultreg_(
const std::unordered_map<std::size_t,int>& cartesianToCompressed)
1349 const auto& inputNNC = this->eclState_.getInputNNC();
1350 const auto& transMult = this->eclState_.getTransMult();
1352 auto compressedIdx = [&cartesianToCompressed](
const std::size_t globIdx)
1354 auto ixPos = cartesianToCompressed.find(globIdx);
1355 return (ixPos == cartesianToCompressed.end()) ? -1 : ixPos->second;
1369 for (
const auto& nncList : {&NNC::input, &NNC::editr}) {
1370 for (
const auto& nncEntry : (inputNNC.*nncList)()) {
1371 const auto c1 = nncEntry.cell1;
1372 const auto c2 = nncEntry.cell2;
1374 auto low = compressedIdx(c1);
1375 auto high = compressedIdx(c2);
1377 if ((low == -1) || (high == -1)) {
1382 std::swap(low, high);
1385 auto candidate = this->trans_.find(
details::isId(low, high));
1386 if (candidate != this->trans_.end()) {
1387 candidate->second *= transMult.getRegionMultiplierNNC(c1, c2);
1393template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1401 assert(faceIdx >= 0);
1402 unsigned dimIdx = faceIdx / 2;
1403 assert(dimIdx < dimWorld);
1404 Scalar halfTrans = perm[dimIdx][dimIdx];
1405 halfTrans *= std::abs(Dune::dot(areaNormal, distance));
1406 halfTrans /= distance.two_norm2();
1411template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1418 Scalar halfDiff = poro;
1419 halfDiff *= std::abs(Dune::dot(areaNormal, distance));
1420 halfDiff /= distance.two_norm2();
1425template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1429 const unsigned& cellIdx)
const
1431 const auto& cellCenter = centroids_cache_.empty() ? centroids_(cellIdx)
1432 : centroids_cache_[cellIdx];
1434 for (
unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
1435 x[dimIdx] -= cellCenter[dimIdx];
1441template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1445 unsigned cartElemIdx,
1446 const TransMult& transMult)
const
1451 trans *= transMult.getMultiplier(cartElemIdx,
1452 FaceDir::FromIntersectionIndex(faceIdx));
1455template<
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper,
class Scalar>
1459 const std::vector<double>& ntg)
static unsigned maxThreads()
Return the maximum number of threads of the current process.
Definition: threadmanager.hpp:66
void applyMultipliers_(Scalar &trans, unsigned faceIdx, unsigned cartElemIdx, const TransMult &transMult) const
Definition: Transmissibility_impl.hpp:1443
Scalar diffusivity(unsigned elemIdx1, unsigned elemIdx2) const
Return the diffusivity for the intersection between two elements.
Definition: Transmissibility_impl.hpp:175
void applyEditNncToGridTrans_(const std::unordered_map< std::size_t, int > &globalToLocal)
Multiplies the grid transmissibilities according to EDITNNC.
Definition: Transmissibility_impl.hpp:1238
void computeFaceProperties(const Intersection &intersection, FaceInfo &inside, FaceInfo &outside, DimVector &faceAreaNormal, std::false_type) const
Definition: Transmissibility_impl.hpp:1041
Dune::FieldMatrix< Scalar, dimWorld, dimWorld > DimMatrix
Definition: Transmissibility.hpp:59
void update(bool global, TransUpdateQuantities update_quantities=TransUpdateQuantities::All, const std::function< unsigned int(unsigned int)> &map={}, bool applyNncMultRegT=false)
Definition: Transmissibility_impl.hpp:195
DimVector distanceVector_(const DimVector &faceCenter, const unsigned &cellIdx) const
Definition: Transmissibility_impl.hpp:1428
void applyNncMultreg_(const std::unordered_map< std::size_t, int > &globalToLocal)
Definition: Transmissibility_impl.hpp:1347
void applyEditNncrToGridTrans_(const std::unordered_map< std::size_t, int > &globalToLocal)
Resets the grid transmissibilities according to EDITNNCR.
Definition: Transmissibility_impl.hpp:1251
void extractDispersion_()
Definition: Transmissibility_impl.hpp:762
const std::map< std::pair< unsigned, unsigned >, Scalar > & getThermalHalfTransBoundary() const
Definition: Transmissibility_impl.hpp:168
Scalar thermalHalfTrans(unsigned insideElemIdx, unsigned outsideElemIdx) const
Return the thermal "half transmissibility" for the intersection between two elements.
Definition: Transmissibility_impl.hpp:136
Scalar transmissibilityBoundary(unsigned elemIdx, unsigned boundaryFaceIdx) const
Return the transmissibility for a given boundary segment.
Definition: Transmissibility_impl.hpp:129
std::array< std::vector< double >, 3 > createTransmissibilityArrays_(const std::array< bool, 3 > &is_tran)
Creates TRANS{XYZ} arrays for modification by FieldProps data.
Definition: Transmissibility_impl.hpp:884
void applyEditNncToGridTransHelper_(const std::unordered_map< std::size_t, int > &globalToLocal, const std::string &keyword, const std::vector< NNCdata > &nncs, const std::function< KeywordLocation(const NNCdata &)> &getLocation, const std::function< void(Scalar &, const Scalar &)> &apply)
Definition: Transmissibility_impl.hpp:1264
void updateFromEclState_(bool global)
Definition: Transmissibility_impl.hpp:849
void extractPermeability_()
Definition: Transmissibility_impl.hpp:647
void applyAllZMultipliers_(Scalar &trans, const FaceInfo &inside, const FaceInfo &outside, const TransMult &transMult, const std::array< int, dimWorld > &cartDims)
Apply the Multipliers for the case PINCH(4)==TOPBOT.
Definition: Transmissibility_impl.hpp:806
TransUpdateQuantities
Compute all transmissibilities.
Definition: Transmissibility.hpp:177
void resetTransmissibilityFromArrays_(const std::array< bool, 3 > &is_tran, const std::array< std::vector< double >, 3 > &trans)
overwrites calculated transmissibilities
Definition: Transmissibility_impl.hpp:966
Dune::FieldVector< Scalar, dimWorld > DimVector
Definition: Transmissibility.hpp:60
static Scalar computeHalfDiffusivity_(const DimVector &areaNormal, const DimVector &distance, const Scalar poro)
Definition: Transmissibility_impl.hpp:1414
Scalar transmissibilityThreshold_
Definition: Transmissibility.hpp:309
Scalar transmissibility(unsigned elemIdx1, unsigned elemIdx2) const
Return the transmissibility for the intersection between two elements.
Definition: Transmissibility_impl.hpp:122
static void applyNtg_(Scalar &trans, const FaceInfo &face, const std::vector< double > &ntg)
Definition: Transmissibility_impl.hpp:1457
const EclipseState & eclState_
Definition: Transmissibility.hpp:303
Scalar dispersivity(unsigned elemIdx1, unsigned elemIdx2) const
Return the dispersivity for the intersection between two elements.
Definition: Transmissibility_impl.hpp:185
Transmissibility(const EclipseState &eclState, const GridView &gridView, const CartesianIndexMapper &cartMapper, const Grid &grid, std::function< std::array< double, dimWorld >(int)> centroids, bool enableEnergy, bool enableDiffusivity, bool enableDispersivity)
Definition: Transmissibility_impl.hpp:97
void applyNncToGridTrans_(const std::unordered_map< std::size_t, int > &cartesianToCompressed)
Definition: Transmissibility_impl.hpp:1171
Scalar halfTransmissibility(unsigned insideElemIdx, unsigned outsideElemIdx) const
One-sided (half) transmissibility of the face between two cells, seen from the inside cell (NTG appli...
Definition: Transmissibility_impl.hpp:143
void applyPinchNncToGridTrans_(const std::unordered_map< std::size_t, int > &cartesianToCompressed, bool applyNncMultregT)
Applies the previous calculate transmissibilities to the NNCs created via PINCH.
Definition: Transmissibility_impl.hpp:1122
void extractPorosity_()
Definition: Transmissibility_impl.hpp:737
void removeNonCartesianTransmissibilities_(bool removeAll)
Definition: Transmissibility_impl.hpp:781
static Scalar computeHalfTrans_(const DimVector &areaNormal, int faceIdx, const DimVector &distance, const DimMatrix &perm)
Definition: Transmissibility_impl.hpp:1396
Scalar thermalHalfTransBoundary(unsigned insideElemIdx, unsigned boundaryFaceIdx) const
Definition: Transmissibility_impl.hpp:161
if(!linsolver_)
Definition: FlexibleSolver_impl.hpp:326
constexpr unsigned elemIdxShift
Definition: FacePropertiesTPSA_impl.hpp:52
std::pair< std::uint32_t, std::uint32_t > isIdReverse(const std::uint64_t &id)
Definition: Transmissibility_impl.hpp:78
std::uint64_t directionalIsId(std::uint32_t elemIdx1, std::uint32_t elemIdx2)
Definition: Transmissibility_impl.hpp:89
std::uint64_t isId(std::uint32_t elemIdx1, std::uint32_t elemIdx2)
Definition: Transmissibility_impl.hpp:70
Definition: blackoilbioeffectsmodules.hh:45
Definition: Transmissibility.hpp:187
unsigned cartElemIdx
Definition: Transmissibility.hpp:191
DimVector faceCenter
Definition: Transmissibility.hpp:188
unsigned elemIdx
Definition: Transmissibility.hpp:190
int faceIdx
Definition: Transmissibility.hpp:189