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/BCState.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 BlockAddress =
typename SparseMatrixAdapter::BlockAddress;
74 using VectorBlock = Dune::FieldVector<Scalar, numEq>;
76 using StressInfoVector = Dune::FieldVector<Scalar, 3>;
87 simulatorPtr_ =
nullptr;
98 void init(Simulator& simulator)
100 simulatorPtr_ = &simulator;
120 jacobian_->finalize();
128 template <
class SubDomainType>
132 initFirstIteration_();
134 for (
int globI : domain.cells) {
135 residual_[globI] = 0.0;
136 jacobian_->clearRow(globI, 0.0);
162 catch (
const std::exception& e) {
163 std::cout <<
"rank " << simulator_().gridView().comm().rank()
164 <<
" caught an exception while linearizing TPSA system:" << e.what()
165 <<
"\n" << std::flush;
169 std::cout <<
"rank " << simulator_().gridView().comm().rank()
170 <<
" caught an exception while linearizing TPSA system"
171 <<
"\n" << std::flush;
174 succeeded = simulator_().gridView().comm().min(succeeded);
177 throw NumericalProblem(
"A process did not succeed in linearizing the TPSA system");
189 template <
class SubDomainType>
197 initFirstIteration_();
200 if (domain.cells.size() == flowModel_().numTotalDof()) {
224 void setResAndJacobi(VectorBlock& res, MatrixBlock& bMat,
const ADVectorBlock& resid)
const
227 for (
unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
228 res[eqIdx] = resid[eqIdx].value();
233 for (
unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
234 for (
unsigned pvIdx = 0; pvIdx < numEq; ++pvIdx) {
235 bMat[eqIdx][pvIdx] = resid[eqIdx].derivative(pvIdx);
245 for (
auto& bdyInfo : boundaryInfo_) {
247 const auto& mechBC = problem_().mechBoundaryCondition(bdyInfo.cell, bdyInfo.dir);
250 std::vector<double> displacement(3, 0.0);
251 for (std::size_t ii = 0; ii < displacement.size(); ++ii) {
252 displacement[ii] = mechBC.displacement[ii].value();
256 bdyInfo.bcdata.type = mechBC.type;
257 bdyInfo.bcdata.displacement = displacement;
258 bdyInfo.bcdata.shearModulus = mechBC.shearModulus;
259 bdyInfo.bcdata.distance = mechBC.distance;
268 OPM_TIMEBLOCK(updateStressInfoTPSA);
270 if (stressInfo_.empty()) {
274 const auto& geoMechModel = geoMechModel_();
275 auto& problem = problem_();
276 const unsigned int numCells = fullDomain_.cells.size();
279#pragma omp parallel for
282 for (
unsigned ii = 0; ii < numCells; ++ii) {
283 const unsigned globI = fullDomain_.cells[ii];
284 const MaterialState& materialStateIn =
285 geoMechModel.materialState(globI, 0);
288 for (
const auto& nbInfo : neighborInfo_[globI]) {
289 const unsigned globJ = nbInfo.neighbor;
290 const MaterialState& materialStateEx =
291 geoMechModel.materialState(globJ, 0);
294 ADVectorBlock adres(0.0);
295 LocalResidual::computeFaceTerm(adres,
301 adres *= nbInfo.faceArea;
305 stressInfo_[globI][loc].faceNormal = problem.cellFaceNormal(globI, globJ);
306 stressInfo_[globI][loc].faceArea = nbInfo.faceArea;
307 for (
unsigned tractionIdx = 0; tractionIdx < 3; ++tractionIdx) {
308 stressInfo_[globI][loc].traction[tractionIdx] = adres[tractionIdx].value();
315 for (
const auto& bdyInfo : boundaryInfo_) {
316 const unsigned globI = bdyInfo.cell;
317 const MaterialState& materialStateIn = geoMechModel.materialState(globI, 0);
320 ADVectorBlock adres(0.0);
321 LocalResidual::computeBoundaryTerm(adres,
326 adres *= bdyInfo.bcdata.faceArea;
330 const short loc = neighborInfo_[globI].size() + bdyInfo.bfIndex;
331 stressInfo_[globI][loc].faceNormal =
332 problem.cellFaceNormalBoundary(globI, bdyInfo.bfIndex);
333 stressInfo_[globI][loc].faceArea = bdyInfo.bcdata.faceArea;
334 for (
unsigned tractionIdx = 0; tractionIdx < 3; ++tractionIdx) {
335 stressInfo_[globI][loc].traction[tractionIdx] = adres[tractionIdx].value();
349 {
return *jacobian_; }
357 {
return *jacobian_; }
365 {
return residual_; }
373 {
return residual_; }
384 {
return linearizationType_; }
412 { linearizationType_ = linearizationType; }
426 OPM_TIMEBLOCK(createMatrixTPSA);
429 if (!neighborInfo_.empty()) {
434 const auto& flowModel = flowModel_();
435 Stencil stencil(gridView_(), flowModel.dofMapper());
438 std::vector<std::set<unsigned>> sparsityPattern(flowModel.numTotalDof());
439 unsigned numCells = flowModel.numTotalDof();
440 neighborInfo_.reserve(numCells, 6 * numCells);
441 std::vector<NeighborInfo> loc_nbinfo;
443 stressInfo_.reserve(numCells, 6 * numCells);
444 std::vector<StressInfo> loc_stressinfo;
445 StressInfoVector nullTraction(0.0);
446 StressInfoVector nullFaceNormal(0.0);
447 for (
const auto& elem : elements(gridView_())) {
449 stencil.update(elem);
451 for (
unsigned primaryDofIdx = 0; primaryDofIdx < stencil.numPrimaryDof(); ++primaryDofIdx) {
453 const unsigned myIdx = stencil.globalSpaceIndex(primaryDofIdx);
454 loc_nbinfo.resize(stencil.numDof() - 1);
457 const int numFaces = stencil.numBoundaryFaces() + stencil.numInteriorFaces();
458 loc_stressinfo.resize(numFaces);
460 for (
unsigned dofIdx = 0; dofIdx < stencil.numDof(); ++dofIdx) {
463 const unsigned neighborIdx = stencil.globalSpaceIndex(dofIdx);
464 sparsityPattern[myIdx].insert(neighborIdx);
466 const auto scvfIdx = dofIdx - 1;
467 const auto& scvf = stencil.interiorFace(scvfIdx);
468 const Scalar area = scvf.area();
469 loc_nbinfo[dofIdx - 1] = NeighborInfo{ neighborIdx, area, BlockAddress{} };
471 int faceId = scvf.dirId();
472 loc_stressinfo[dofIdx - 1] =
473 StressInfo{faceId, nullTraction, nullFaceNormal, area};
478 neighborInfo_.appendRow(loc_nbinfo.begin(), loc_nbinfo.end());
481 unsigned bfIndex = 0;
482 for (
const auto& intersection : intersections(gridView_(), elem)) {
483 if (intersection.boundary()) {
485 const auto& bf = stencil.boundaryFace(bfIndex);
486 const int dir_id = bf.dirId();
487 const auto bfArea = bf.area();
492 loc_stressinfo[stencil.numInteriorFaces() + bfIndex] =
493 StressInfo{dir_id, nullTraction, nullFaceNormal, bfArea};
501 const auto& mechBC = problem_().mechBoundaryCondition(myIdx, dir_id);
504 std::vector<double> displacement(3, 0.0);
505 for (std::size_t ii = 0; ii < displacement.size(); ++ii) {
506 displacement[ii] = mechBC.displacement[ii].value();
510 BoundaryConditionData bcdata{mechBC.type,
516 boundaryInfo_.push_back( { myIdx, dir_id, bfIndex, bcdata } );
520 if (!intersection.neighbor()) {
525 stressInfo_.appendRow(loc_stressinfo.begin(), loc_stressinfo.end());
530 jacobian_ = std::make_unique<SparseMatrixAdapter>(simulator_());
531 diagMatAddress_.resize(numCells);
532 jacobian_->reserve(sparsityPattern);
533 for (
unsigned globI = 0; globI < numCells; globI++) {
534 const auto& nbInfos = neighborInfo_[globI];
535 diagMatAddress_[globI] = jacobian_->blockAddress(globI, globI);
536 for (
auto& nbInfo : nbInfos) {
537 nbInfo.matBlockAddress = jacobian_->blockAddress(nbInfo.neighbor, globI);
542 fullDomain_.cells.resize(numCells);
543 std::iota(fullDomain_.cells.begin(), fullDomain_.cells.end(), 0);
551 template <
class SubDomainType>
552 void linearize_(
const SubDomainType& domain)
554 OPM_TIMEBLOCK(linearizeTPSA);
557 const auto& flowModel = flowModel_();
558 const auto& geoMechModel = geoMechModel_();
559 auto& problem = problem_();
560 const unsigned int numCells = domain.cells.size();
563#pragma omp parallel for
566 for (
unsigned ii = 0; ii < numCells; ++ii) {
567 OPM_TIMEBLOCK_LOCAL(linearizationForEachCellTPSA, Subsystem::Assembly);
569 const unsigned globI = domain.cells[ii];
570 const auto& nbInfos = neighborInfo_[globI];
571 VectorBlock res(0.0);
572 MatrixBlock bMat(0.0);
573 ADVectorBlock adres(0.0);
574 const MaterialState& materialStateIn = geoMechModel.materialState(globI, 0);
580 OPM_TIMEBLOCK_LOCAL(faceCalculationForEachCellTPSA, Subsystem::Assembly);
583 for (
auto& nbInfo : nbInfos) {
584 OPM_TIMEBLOCK_LOCAL(calculationForEachFaceTPSA, Subsystem::Assembly);
592 const unsigned globJ = nbInfo.neighbor;
593 assert(globJ != globI);
594 const MaterialState& materialStateEx = geoMechModel.materialState(globJ, 0);
597 LocalResidual::computeFaceTerm(adres,
603 adres *= nbInfo.faceArea;
609 residual_[globI] += res;
613 *diagMatAddress_[globI] += bMat;
621 *nbInfo.matBlockAddress += bMat;
630 OPM_TIMEBLOCK_LOCAL(computeVolumeTerm, Subsystem::Assembly);
633 LocalResidual::computeVolumeTerm(adres,
638 const double volume = flowModel.dofTotalVolume(globI);
645 residual_[globI] += res;
649 *diagMatAddress_[globI] += bMat;
659 LocalResidual::computeSourceTerm(adres,
669 residual_[globI] += res;
673 *diagMatAddress_[globI] += bMat;
679 for (
const auto& bdyInfo : boundaryInfo_) {
680 VectorBlock res(0.0);
681 MatrixBlock bMat(0.0);
682 ADVectorBlock adres(0.0);
683 const unsigned globI = bdyInfo.cell;
684 const MaterialState& materialStateIn = geoMechModel.materialState(globI, 0);
687 LocalResidual::computeBoundaryTerm(adres,
692 adres *= bdyInfo.bcdata.faceArea;
698 residual_[globI] += res;
702 *diagMatAddress_[globI] += bMat;
709 void initFirstIteration_()
715 residual_.resize(flowModel_().numTotalDof());
739 Simulator& simulator_()
740 {
return *simulatorPtr_; }
747 const Simulator& simulator_()
const
748 {
return *simulatorPtr_; }
756 {
return simulator_().problem(); }
763 const Problem& problem_()
const
764 {
return simulator_().problem(); }
771 FlowModel& flowModel_()
772 {
return simulator_().model(); }
779 const FlowModel& flowModel_()
const
780 {
return simulator_().model(); }
787 GeomechModel& geoMechModel_()
788 {
return problem_().geoMechModel(); }
795 const GeomechModel& geoMechModel_()
const
796 {
return problem_().geoMechModel(); }
803 const GridView& gridView_()
const
804 {
return problem_().gridView(); }
806 Simulator* simulatorPtr_{};
807 LinearizationType linearizationType_{};
809 std::vector<BlockAddress> diagMatAddress_{};
810 std::unique_ptr<SparseMatrixAdapter> jacobian_{};
811 GlobalEqVector residual_;
821 unsigned int neighbor;
823 BlockAddress matBlockAddress;
825 SparseTable<NeighborInfo> neighborInfo_{};
833 StressInfoVector traction;
834 StressInfoVector faceNormal;
838 SparseTable<StressInfo> stressInfo_{};
843 struct BoundaryConditionData
846 std::vector<double> displacement;
849 unsigned boundaryFaceIndex;
860 unsigned int bfIndex;
861 BoundaryConditionData bcdata;
863 std::vector<BoundaryInfo> boundaryInfo_;
870 std::vector<int> cells;
871 std::vector<bool> interior;
873 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:372
const SparseMatrixAdapter & jacobian() const
Get Jacobian matrix.
Definition: tpsalinearizer.hpp:348
const GlobalEqVector & residual() const
Get residual vector.
Definition: tpsalinearizer.hpp:364
void eraseMatrix()
Causes the Jacobian matrix to be recreated from scratch before the next iteration.
Definition: tpsalinearizer.hpp:110
void resetSystem_(const SubDomainType &domain)
Initializing and/or reset residual and Jacobian.
Definition: tpsalinearizer.hpp:129
std::map< unsigned, Constraints > constraintsMap() const
Get constraints map.
Definition: tpsalinearizer.hpp:403
void updateBoundaryConditionData()
Update boundary condition information.
Definition: tpsalinearizer.hpp:243
void updateStressInfo()
Compute the stress (or traction) for mechanics output.
Definition: tpsalinearizer.hpp:266
SparseMatrixAdapter & jacobian()
Get Jacobian matrix.
Definition: tpsalinearizer.hpp:356
TpsaLinearizer()
Constructor.
Definition: tpsalinearizer.hpp:85
void linearizeDomain(const SubDomainType &domain)
Linearize the non-linear system for the spatial domain.
Definition: tpsalinearizer.hpp:190
void linearizeDomain()
Linearize the non-linear system for the spatial domain.
Definition: tpsalinearizer.hpp:155
void finalize()
Finalize creation of Jacobian matrix and make ready for linear solver.
Definition: tpsalinearizer.hpp:118
const auto & getStressInfo() const
Definition: tpsalinearizer.hpp:391
void setLinearizationType(LinearizationType linearizationType)
Set linearization type.
Definition: tpsalinearizer.hpp:411
const LinearizationType & getLinearizationType() const
Get linearization type.
Definition: tpsalinearizer.hpp:383
void linearizeAuxiliaryEquations()
Linearize auxillary equation.
Definition: tpsalinearizer.hpp:214
void init(Simulator &simulator)
Initialize the linearizer.
Definition: tpsalinearizer.hpp:98
void linearize()
Linearize the non-linear system.
Definition: tpsalinearizer.hpp:143
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:224
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