25#ifndef TPSA_LINEARIZER_HPP
26#define TPSA_LINEARIZER_HPP
28#include <dune/common/fvector.hh>
30#include <opm/common/TimingMacros.hpp>
32#include <opm/grid/utility/SparseTable.hpp>
34#include <opm/input/eclipse/Schedule/BCProp.hpp>
36#include <opm/material/materialstates/MaterialStateTPSA.hpp>
51template<
class TypeTag>
67 using MaterialState = MaterialStateTPSA<Evaluation>;
69 enum { numEq = getPropValue<TypeTag, Properties::NumEqTPSA>() };
71 using ADVectorBlock = Dune::FieldVector<Evaluation, numEq>;
72 using MatrixBlock =
typename SparseMatrixAdapter::MatrixBlock;
73 using VectorBlock = Dune::FieldVector<Scalar, numEq>;
75 using StressInfoVector = Dune::FieldVector<Scalar, 3>;
86 simulatorPtr_ =
nullptr;
97 void init(Simulator& simulator)
99 simulatorPtr_ = &simulator;
119 jacobian_->finalize();
127 template <
class SubDomainType>
131 initFirstIteration_();
133 for (
int globI : domain.cells) {
134 residual_[globI] = 0.0;
135 jacobian_->clearRow(globI, 0.0);
161 catch (
const std::exception& e) {
162 std::cout <<
"rank " << simulator_().gridView().comm().rank()
163 <<
" caught an exception while linearizing TPSA system:" << e.what()
164 <<
"\n" << std::flush;
168 std::cout <<
"rank " << simulator_().gridView().comm().rank()
169 <<
" caught an exception while linearizing TPSA system"
170 <<
"\n" << std::flush;
173 succeeded = simulator_().gridView().comm().min(succeeded);
176 throw NumericalProblem(
"A process did not succeed in linearizing the TPSA system");
188 template <
class SubDomainType>
196 initFirstIteration_();
199 if (domain.cells.size() == flowModel_().numTotalDof()) {
223 void setResAndJacobi(VectorBlock& res, MatrixBlock& bMat,
const ADVectorBlock& resid)
const
226 for (
unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
227 res[eqIdx] = resid[eqIdx].value();
232 for (
unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
233 for (
unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
234 bMat[eqIdx][pvIdx] = resid[eqIdx].derivative(pvIdx);
244 for (
auto& bdyInfo : boundaryInfo_) {
246 const auto [type, displacementAD] = problem_().mechBoundaryCondition(bdyInfo.cell, bdyInfo.dir);
249 std::vector<double> displacement(3, 0.0);
250 for (std::size_t ii = 0; ii < displacement.size(); ++ii) {
251 displacement[ii] = displacementAD[ii].value();
255 bdyInfo.bcdata.type = type;
256 bdyInfo.bcdata.displacement = displacement;
269 {
return *jacobian_; }
277 {
return *jacobian_; }
285 {
return residual_; }
293 {
return residual_; }
304 {
return linearizationType_; }
332 { linearizationType_ = linearizationType; }
346 OPM_TIMEBLOCK(createMatrixTPSA);
349 if (!neighborInfo_.empty()) {
354 const auto& flowModel = flowModel_();
355 Stencil stencil(gridView_(), flowModel.dofMapper());
358 std::vector<std::set<unsigned>> sparsityPattern(flowModel.numTotalDof());
359 unsigned numCells = flowModel.numTotalDof();
360 neighborInfo_.reserve(numCells, 6 * numCells);
361 std::vector<NeighborInfo> loc_nbinfo;
363 stressInfo_.reserve(numCells, 6 * numCells);
364 std::vector<StressInfo> loc_stressinfo;
365 StressInfoVector nullTraction(0.0);
366 StressInfoVector nullFaceNormal(0.0);
367 for (
const auto& elem : elements(gridView_())) {
369 stencil.update(elem);
371 for (
unsigned primaryDofIdx = 0; primaryDofIdx < stencil.numPrimaryDof(); ++primaryDofIdx) {
373 const unsigned myIdx = stencil.globalSpaceIndex(primaryDofIdx);
374 loc_nbinfo.resize(stencil.numDof() - 1);
377 const int numFaces = stencil.numBoundaryFaces() + stencil.numInteriorFaces();
378 loc_stressinfo.resize(numFaces);
380 for (
unsigned dofIdx = 0; dofIdx < stencil.numDof(); ++dofIdx) {
383 const unsigned neighborIdx = stencil.globalSpaceIndex(dofIdx);
384 sparsityPattern[myIdx].insert(neighborIdx);
386 const auto scvfIdx = dofIdx - 1;
387 const auto& scvf = stencil.interiorFace(scvfIdx);
388 const Scalar area = scvf.area();
389 loc_nbinfo[dofIdx - 1] = NeighborInfo{ neighborIdx, area,
nullptr };
391 int faceId = scvf.dirId();
392 loc_stressinfo[dofIdx - 1] =
393 StressInfo{faceId, nullTraction, nullFaceNormal, area};
398 neighborInfo_.appendRow(loc_nbinfo.begin(), loc_nbinfo.end());
401 unsigned bfIndex = 0;
402 for (
const auto& intersection : intersections(gridView_(), elem)) {
403 if (intersection.boundary()) {
405 const auto& bf = stencil.boundaryFace(bfIndex);
406 const int dir_id = bf.dirId();
407 const auto bfArea = bf.area();
412 loc_stressinfo[stencil.numInteriorFaces() + bfIndex] =
413 StressInfo{dir_id, nullTraction, nullFaceNormal, bfArea};
421 const auto [type, displacementAD] = problem_().mechBoundaryCondition(myIdx, dir_id);
424 std::vector<double> displacement(3, 0.0);
425 for (std::size_t ii = 0; ii < displacement.size(); ++ii) {
426 displacement[ii] = displacementAD[ii].value();
430 BoundaryConditionData bcdata { type, displacement, bfIndex, bfArea };
431 boundaryInfo_.push_back( { myIdx, dir_id, bfIndex, bcdata } );
435 if (!intersection.neighbor()) {
440 stressInfo_.appendRow(loc_stressinfo.begin(), loc_stressinfo.end());
445 jacobian_ = std::make_unique<SparseMatrixAdapter>(simulator_());
446 diagMatAddress_.resize(numCells);
447 jacobian_->reserve(sparsityPattern);
448 for (
unsigned globI = 0; globI < numCells; globI++) {
449 const auto& nbInfos = neighborInfo_[globI];
450 diagMatAddress_[globI] = jacobian_->blockAddress(globI, globI);
451 for (
auto& nbInfo : nbInfos) {
452 nbInfo.matBlockAddress = jacobian_->blockAddress(nbInfo.neighbor, globI);
457 fullDomain_.cells.resize(numCells);
458 std::iota(fullDomain_.cells.begin(), fullDomain_.cells.end(), 0);
466 template <
class SubDomainType>
467 void linearize_(
const SubDomainType& domain)
469 OPM_TIMEBLOCK(linearizeTPSA);
472 const auto& flowModel = flowModel_();
473 const auto& geoMechModel = geoMechModel_();
474 auto& problem = problem_();
475 const unsigned int numCells = domain.cells.size();
478#pragma omp parallel for
481 for (
unsigned ii = 0; ii < numCells; ++ii) {
482 OPM_TIMEBLOCK_LOCAL(linearizationForEachCellTPSA, Subsystem::Assembly);
484 const unsigned globI = domain.cells[ii];
485 const auto& nbInfos = neighborInfo_[globI];
486 VectorBlock res(0.0);
487 MatrixBlock bMat(0.0);
488 ADVectorBlock adres(0.0);
489 const MaterialState& materialStateIn = geoMechModel.materialState(globI, 0);
495 OPM_TIMEBLOCK_LOCAL(faceCalculationForEachCellTPSA, Subsystem::Assembly);
499 for (
const auto& nbInfo : nbInfos) {
500 OPM_TIMEBLOCK_LOCAL(calculationForEachFaceTPSA, Subsystem::Assembly);
508 const unsigned globJ = nbInfo.neighbor;
509 assert(globJ != globI);
510 const MaterialState& materialStateEx = geoMechModel.materialState(globJ, 0);
513 LocalResidual::computeFaceTerm(adres,
519 adres *= nbInfo.faceArea;
525 residual_[globI] += res;
529 *diagMatAddress_[globI] += bMat;
537 *nbInfo.matBlockAddress += bMat;
541 const auto& faceNormal = problem.cellFaceNormal(globI, globJ);
542 stressInfo_[globI][loc].faceNormal = faceNormal;
543 stressInfo_[globI][loc].faceArea = nbInfo.faceArea;
544 for (
unsigned tractionIdx = 0; tractionIdx < 3; ++tractionIdx) {
545 stressInfo_[globI][loc].traction[tractionIdx] = res[tractionIdx];
556 OPM_TIMEBLOCK_LOCAL(computeVolumeTerm, Subsystem::Assembly);
559 LocalResidual::computeVolumeTerm(adres,
564 const double volume = flowModel.dofTotalVolume(globI);
571 residual_[globI] += res;
575 *diagMatAddress_[globI] += bMat;
585 LocalResidual::computeSourceTerm(adres,
595 residual_[globI] += res;
599 *diagMatAddress_[globI] += bMat;
605 for (
const auto& bdyInfo : boundaryInfo_) {
606 VectorBlock res(0.0);
607 MatrixBlock bMat(0.0);
608 ADVectorBlock adres(0.0);
609 const unsigned globI = bdyInfo.cell;
610 const MaterialState& materialStateIn = geoMechModel.materialState(globI, 0);
613 LocalResidual::computeBoundaryTerm(adres,
618 adres *= bdyInfo.bcdata.faceArea;
624 residual_[globI] += res;
628 *diagMatAddress_[globI] += bMat;
632 const auto& nbInfos = neighborInfo_[globI];
633 short loc = nbInfos.size() + bdyInfo.bfIndex;
634 const auto& bndyNormal = problem.cellFaceNormalBoundary(globI, bdyInfo.bfIndex);
635 stressInfo_[globI][loc].faceNormal = bndyNormal;
636 stressInfo_[globI][loc].faceArea = bdyInfo.bcdata.faceArea;
637 for (
unsigned tractionIdx = 0; tractionIdx < 3; ++tractionIdx) {
638 stressInfo_[globI][loc].traction[tractionIdx] = res[tractionIdx];
646 void initFirstIteration_()
652 residual_.resize(flowModel_().numTotalDof());
676 Simulator& simulator_()
677 {
return *simulatorPtr_; }
684 const Simulator& simulator_()
const
685 {
return *simulatorPtr_; }
693 {
return simulator_().problem(); }
700 const Problem& problem_()
const
701 {
return simulator_().problem(); }
708 FlowModel& flowModel_()
709 {
return simulator_().model(); }
716 const FlowModel& flowModel_()
const
717 {
return simulator_().model(); }
724 GeomechModel& geoMechModel_()
725 {
return problem_().geoMechModel(); }
732 const GeomechModel& geoMechModel_()
const
733 {
return problem_().geoMechModel(); }
740 const GridView& gridView_()
const
741 {
return problem_().gridView(); }
743 Simulator* simulatorPtr_{};
744 LinearizationType linearizationType_{};
746 std::vector<MatrixBlock*> diagMatAddress_{};
747 std::unique_ptr<SparseMatrixAdapter> jacobian_{};
748 GlobalEqVector residual_;
758 unsigned int neighbor;
760 MatrixBlock* matBlockAddress;
762 SparseTable<NeighborInfo> neighborInfo_{};
770 StressInfoVector traction;
771 StressInfoVector faceNormal;
775 SparseTable<StressInfo> stressInfo_{};
780 struct BoundaryConditionData
783 std::vector<double> displacement;
784 unsigned boundaryFaceIndex;
795 unsigned int bfIndex;
796 BoundaryConditionData bcdata;
798 std::vector<BoundaryInfo> boundaryInfo_;
805 std::vector<int> cells;
806 std::vector<bool> interior;
808 FullDomain fullDomain_;
Linearizes TPSA equations and generates system matrix and residual for linear solver.
Definition: tpsalinearizer.hpp:53
GlobalEqVector & residual()
Get residual vector.
Definition: tpsalinearizer.hpp:292
const SparseMatrixAdapter & jacobian() const
Get Jacobian matrix.
Definition: tpsalinearizer.hpp:268
const GlobalEqVector & residual() const
Get residual vector.
Definition: tpsalinearizer.hpp:284
void eraseMatrix()
Causes the Jacobian matrix to be recreated from scratch before the next iteration.
Definition: tpsalinearizer.hpp:109
void resetSystem_(const SubDomainType &domain)
Initializing and/or reset residual and Jacobian.
Definition: tpsalinearizer.hpp:128
std::map< unsigned, Constraints > constraintsMap() const
Get constraints map.
Definition: tpsalinearizer.hpp:323
void updateBoundaryConditionData()
Update boundary condition information.
Definition: tpsalinearizer.hpp:242
SparseMatrixAdapter & jacobian()
Get Jacobian matrix.
Definition: tpsalinearizer.hpp:276
TpsaLinearizer()
Constructor.
Definition: tpsalinearizer.hpp:84
void linearizeDomain(const SubDomainType &domain)
Linearize the non-linear system for the spatial domain.
Definition: tpsalinearizer.hpp:189
void linearizeDomain()
Linearize the non-linear system for the spatial domain.
Definition: tpsalinearizer.hpp:154
void finalize()
Finalize creation of Jacobian matrix and make ready for linear solver.
Definition: tpsalinearizer.hpp:117
const auto & getStressInfo() const
Definition: tpsalinearizer.hpp:311
void setLinearizationType(LinearizationType linearizationType)
Set linearization type.
Definition: tpsalinearizer.hpp:331
const LinearizationType & getLinearizationType() const
Get linearization type.
Definition: tpsalinearizer.hpp:303
void linearizeAuxiliaryEquations()
Linearize auxillary equation.
Definition: tpsalinearizer.hpp:213
void init(Simulator &simulator)
Initialize the linearizer.
Definition: tpsalinearizer.hpp:97
void linearize()
Linearize the non-linear system.
Definition: tpsalinearizer.hpp:142
void setResAndJacobi(VectorBlock &res, MatrixBlock &bMat, const ADVectorBlock &resid) const
Extract local residuals and sub-block Jacobians from locally computed AD residual.
Definition: tpsalinearizer.hpp:223
Definition: blackoilbioeffectsmodules.hh:45
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
Definition: linearizationtype.hh:34