tpsamodel.hpp
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 Copyright 2025 NORCE AS
5
6 This file is part of the Open Porous Media project (OPM).
7
8 OPM is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 OPM is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with OPM. If not, see <http://www.gnu.org/licenses/>.
20
21 Consult the COPYING file in the top-level source directory of this
22 module for the precise wording of the license and the list of
23 copyright holders.
24*/
25#ifndef TPSA_MODEL_HPP
26#define TPSA_MODEL_HPP
27
28#include <dune/grid/common/gridenums.hh>
29
30#include <dune/common/dynmatrix.hh>
31#include <dune/common/dynvector.hh>
32
33#include <opm/grid/utility/ElementChunks.hpp>
34
35#include <opm/material/common/MathToolbox.hpp>
36
41
42#include <array>
43#include <memory>
44#include <unordered_map>
45
46
47namespace Opm {
48
54template <class TypeTag>
56{
68
69 enum { dimWorld = GridView::dimensionworld };
70 enum { historySize = getPropValue<TypeTag, Properties::SolutionHistorySizeTPSA>() };
71 enum { numEq = getPropValue<TypeTag, Properties::NumEqTPSA>() };
72
73 enum { disp0Idx = Indices::disp0Idx };
74 enum { rot0Idx = Indices::rot0Idx };
75 enum { solidPres0Idx = Indices::solidPres0Idx };
76
77 using MaterialState = MaterialStateTPSA<Evaluation>;
78
79 using DimVector = Dune::FieldVector<Scalar, dimWorld>;
80 using SymTensor = Dune::FieldVector<Scalar, 6>;
81 using PotForceVector = Dune::BlockVector<Scalar>;
82
83public:
88 {
89 protected:
90 SolutionVector blockVector_;
91 public:
98 TpsaBlockVectorWrapper(const std::string&, const std::size_t size)
99 : blockVector_(size)
100 {}
101
106
111 {
112 TpsaBlockVectorWrapper result("dummy", 3);
113 result.blockVector_[0] = 1.0;
114 result.blockVector_[1] = 2.0;
115 result.blockVector_[2] = 3.0;
116
117 return result;
118 }
119
125 SolutionVector& blockVector()
126 { return blockVector_; }
127
133 const SolutionVector& blockVector() const
134 { return blockVector_; }
135
142 bool operator==(const TpsaBlockVectorWrapper& wrapper) const
143 {
144 return std::equal(this->blockVector_.begin(), this->blockVector_.end(),
145 wrapper.blockVector_.begin(), wrapper.blockVector_.end());
146 }
147
153 template<class Serializer>
154 void serializeOp(Serializer& serializer)
155 {
156 serializer(blockVector_);
157 }
158 };
159
160 // ///
161 // Public functions
162 // ///
168 explicit TpsaModel(Simulator& simulator)
169 : linearizer_(std::make_unique<Linearizer>())
170 , newtonMethod_(simulator)
171 , simulator_(simulator)
172 , element_chunks_(simulator.gridView(), Dune::Partitions::all, ThreadManager::maxThreads())
173 {
174 // Initialize equation weights to 1.0
175 eqWeights_.resize(numEq, 1.0);
176
177 // Initialize historic solution vectors
178 // OBS: need at least history size = 2, due to time-derivative of solid-pressure in Flow coupling term
179 const std::size_t numDof = simulator_.model().numGridDof();
180 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
181 solution_[timeIdx] = std::make_unique<TpsaBlockVectorWrapper>("solution", numDof);
182 }
183
184 // Initialize potential force vectors
185 mechPotPresForce_.resize(numDof);
186 }
187
192 {
193 // Initialize the linearizer
194 linearizer_->init(simulator_);
195
196 // Resize material state vector
198 }
199
203 static void registerParameters()
204 {
205 // Newton method parameters
207 }
208
213 {
214 // Update historic solution
215 solution(/*timeIdx=*/1) = solution(/*timeIdx=*/0);
216 }
217
224 {
225 // Syncronize the solution on the ghost and overlap elements
226 using GhostSyncHandle = GridCommHandleGhostSync<PrimaryVariables,
227 SolutionVector,
228 DofMapper,
229 /*commCodim=*/0>;
230
231 auto ghostSync = GhostSyncHandle(solution(/*timeIdx=*/0),
232 simulator_.model().dofMapper());
233
234 simulator_.gridView().communicate(ghostSync,
235 Dune::InteriorBorder_All_Interface,
236 Dune::ForwardCommunication);
237 }
238
246 void updateMaterialState(const unsigned /*timeIdx*/)
247 {
248 // Loop over all elements chuncks and update material state from current solution
249 const auto& elementMapper = simulator_.model().elementMapper();
250#ifdef _OPENMP
251#pragma omp parallel for
252#endif
253 for (const auto& chunk : element_chunks_) {
254 for (const auto& elem : chunk) {
255 const unsigned globalIdx = elementMapper.index(elem);
256 auto& currSol = solution(/*timeIdx=*/0)[globalIdx];
257 setMaterialState_(globalIdx, /*timeIdx=*/0, currSol);
258 }
259 }
260 }
261
262 // ///
263 // Public get and set functions
264 // ///
270 const Linearizer& linearizer() const
271 {
272 return *linearizer_;
273 }
274
280 Linearizer& linearizer()
281 {
282 return *linearizer_;
283 }
284
290 const NewtonMethod& newtonMethod() const
291 {
292 return newtonMethod_;
293 }
294
300 NewtonMethod& newtonMethod()
301 {
302 return newtonMethod_;
303 }
304
311 const SolutionVector& solution(unsigned timeIdx) const
312 {
313 return solution_[timeIdx]->blockVector();
314 }
315
322 SolutionVector& solution(unsigned timeIdx)
323 {
324 return solution_[timeIdx]->blockVector();
325 }
326
331 std::size_t numGridDof() const
332 {
333 return simulator_.model().numGridDof();
334 }
335
340 std::size_t numTotalDof() const
341 {
342 return numGridDof() + numAuxiliaryDof();
343 }
344
351 Scalar dofTotalVolume(unsigned globalIdx) const
352 {
353 return simulator_.model().dofTotalVolume(globalIdx);
354 }
355
363 Scalar eqWeight(unsigned /*dofIdx*/, unsigned eqIdx) const
364 {
365 return eqWeights_[eqIdx];
366 }
367
374 void setEqWeight(unsigned eqIdx, Scalar value)
375 {
376 eqWeights_[eqIdx] = value;
377 }
378
383 std::size_t numAuxiliaryModules() const
384 {
385 return 0;
386 }
387
392 std::size_t numAuxiliaryDof() const
393 {
394 return 0;
395 }
396
406 const MaterialState& materialState(const unsigned globalIdx, unsigned /*timeIdx*/) const
407 {
408 return materialState_[globalIdx];
409 }
410
420 DimVector disp(const unsigned globalIdx, const bool /*with_fracture*/) const
421 {
422 DimVector d;
423 for (std::size_t i = 0; i < 3; ++i) {
424 d[i] = decay<Scalar>(materialState_[globalIdx].displacement(i));
425 }
426 return d;
427 }
428
435 DimVector rotation(const unsigned globalIdx) const
436 {
437 DimVector rot;
438 for (std::size_t i = 0; i < 3; ++i) {
439 rot[i] = decay<Scalar>(materialState_[globalIdx].rotation(i));
440 }
441 return rot;
442 }
443
450 Scalar solidPressure(const unsigned globalIdx) const
451 {
452 return decay<Scalar>(materialState_[globalIdx].solidPressure());
453 }
454
461 SymTensor delstress(const unsigned globalIdx) const
462 {
463 return stress(globalIdx, false);
464 }
465
474 SymTensor fractureStress(const unsigned /*globalIdx*/) const
475 {
476 SymTensor val;
477 return val;
478 }
479
488 SymTensor linstress(const unsigned globalIdx) const
489 {
490 // Subtract the potential forces from pressure and temperature from the main diagonal of
491 // the total stress
492 SymTensor linStressTensor = stress(globalIdx, false);
493 const auto potForce = mechPotentialForce(globalIdx);
494 for (unsigned dirIdx = 0; dirIdx < 3; ++dirIdx) {
495 linStressTensor[dirIdx] -= potForce;
496 }
497 return -1.0 * linStressTensor;
498 }
499
510 SymTensor stress(const unsigned globalIdx, const bool /*with_fracture*/) const
511 {
512 SymTensor stressOutput;
513 const auto& stressInfo = linearizer_->getStressInfo();
514 if (!stressInfo.empty()) {
515 const auto& stressInfoGlobI = stressInfo[globalIdx];
516
517 // Setup least-squares matrix of face normals and right-hand side of traction vectors
518 // per faces. Matrix shape = 3 rows per face x 6 columns for each (symmetric) stress
519 // tensor component.
520 std::unordered_multimap<int, std::size_t> faceIdMap;
521 std::size_t mapSize = 0;
522 for (std::size_t sInfoIdx = 0; sInfoIdx < stressInfoGlobI.size(); ++sInfoIdx) {
523 const auto faceId = stressInfoGlobI[sInfoIdx].faceId;
524
525 // OBS: NNC faces are not added to least squares system, since TPSA does not handle
526 // NNC connections, like numerical aquifers, yet!
527 if (faceId < 0 || stressInfoGlobI[sInfoIdx].faceArea == 0.0) {
528 continue;
529 }
530 if (!faceIdMap.contains(faceId)) {
531 ++mapSize;
532 }
533 faceIdMap.insert({faceId, sInfoIdx});
534 }
535
536 // If no valid faces exist for cell, return zero SymTensor
537 if (mapSize == 0) {
538 return stressOutput;
539 }
540
541 Dune::DynamicMatrix<Scalar> mat(3 * mapSize, 6);
542 Dune::DynamicVector<Scalar> rhs(3 * mapSize);
543 std::size_t rowIdx = 0;
544 for (auto it = faceIdMap.begin(); it != faceIdMap.end();) {
545 auto [first, last] = faceIdMap.equal_range(it->first);
546
547 // Loop over possible multiple of the same face
548 Scalar sumFaceArea = 0.0;
549 for (auto inner = first; inner != last; ++inner) {
550 const auto sInfoIdx = inner->second;
551 const auto& faceStressInfo = stressInfoGlobI[sInfoIdx];
552
553 // One normal per face
554 if (inner == first) {
555 const auto& fNormal = faceStressInfo.faceNormal;
556 mat[3*rowIdx][0] = fNormal[0];
557 mat[3*rowIdx][3] = fNormal[1];
558 mat[3*rowIdx][4] = fNormal[2];
559
560 mat[3*rowIdx + 1][1] = fNormal[1];
561 mat[3*rowIdx + 1][3] = fNormal[0];
562 mat[3*rowIdx + 1][5] = fNormal[2];
563
564 mat[3*rowIdx + 2][2] = fNormal[2];
565 mat[3*rowIdx + 2][4] = fNormal[0];
566 mat[3*rowIdx + 2][5] = fNormal[1];
567 }
568
569 // Add traction vectors for same faces
570 const auto& fTraction = faceStressInfo.traction;
571 rhs[3*rowIdx] += fTraction[0];
572 rhs[3*rowIdx + 1] += fTraction[1];
573 rhs[3*rowIdx + 2] += fTraction[2];
574
575 // Sum face area
576 sumFaceArea += faceStressInfo.faceArea;
577 }
578 // Divide rhs for (unique) face by sum of face areas
579 rhs[3*rowIdx] /= sumFaceArea;
580 rhs[3*rowIdx + 1] /= sumFaceArea;
581 rhs[3*rowIdx + 2] /= sumFaceArea;
582
583 // Move to next unique face
584 ++rowIdx;
585 it = last;
586 }
587
588 // Use least squares solver for underdetermined system
589 LinearLeastSquares<Scalar> lsq(mat, rhs);
590 lsq.solve();
591
592 // Reconstructed stress tensor at cell center
593 const auto& stress = lsq.x();
594 stressOutput[0] = stress[0]; // XX
595 stressOutput[1] = stress[1]; // YY
596 stressOutput[2] = stress[2]; // ZZ
597 stressOutput[3] = stress[5]; // YZ
598 stressOutput[4] = stress[4]; // XZ
599 stressOutput[5] = stress[3]; // XY
600 }
601 return stressOutput;
602 }
603
611 SymTensor strain(const unsigned globalIdx, const bool /*with_fracture*/) const
612 {
613 // Deviatoric stress
614 auto stressDev = this->linstress(globalIdx);
615 Scalar traceStress = 1.0 / 3.0 * (stressDev[0] + stressDev[1] + stressDev[2]);
616 stressDev[0] -= traceStress;
617 stressDev[1] -= traceStress;
618 stressDev[2] -= traceStress;
619
620 // Deviatoric strain
621 auto& problem = simulator_.problem();
622 const auto sMod = problem.shearModulus(globalIdx);
623 SymTensor strainDev = 1.0 / (2.0 * sMod) * stressDev;
624
625 // Volumetric strain
626 const auto lameParam = problem.lame(globalIdx);
627 Scalar strainVolTerm = traceStress / (3.0 * lameParam + 2 * sMod);
628
629 SymTensor strainVol;
630 strainVol[0] = strainVolTerm;
631 strainVol[1] = strainVolTerm;
632 strainVol[2] = strainVolTerm;
633
634 // Total
635 SymTensor strainOutput = strainDev + strainVol;
636 return strainOutput;
637 }
638
645 Scalar mechPotentialForce(unsigned globalIdx) const
646 {
647 return mechPotentialPressForce(globalIdx);
648 }
649
656 Scalar mechPotentialPressForce(unsigned globalIdx) const
657 {
658 return mechPotPresForce_[globalIdx];
659 }
660
661 void setMechPotentialPressForce(unsigned globalIdx, Scalar val)
662 {
663 mechPotPresForce_[globalIdx] = val;
664 }
665
674 Scalar mechPotentialTempForce(unsigned /*globalIdx*/) const
675 {
676 return Scalar(0.0);
677 }
678
679protected:
680 // ///
681 // Protected functions
682 // ///
689 {
690 const std::size_t numDof = simulator_.model().numGridDof();
691 materialState_.resize(numDof);
692 }
693
694private:
695 // ///
696 // Private functions
697 // ///
707 void setMaterialState_(const unsigned globalIdx, const unsigned /*timeIdx*/, PrimaryVariables& values)
708 {
709 auto& dofMaterialState = materialState_[globalIdx];
710 for (unsigned dirIdx = 0; dirIdx < 3; ++dirIdx) {
711 dofMaterialState.setDisplacement(dirIdx, values.makeEvaluation(disp0Idx + dirIdx, 0));
712 dofMaterialState.setRotation(dirIdx, values.makeEvaluation(rot0Idx + dirIdx, 0));
713 }
714 dofMaterialState.setSolidPressure(values.makeEvaluation(solidPres0Idx, 0));
715 }
716
717 std::unique_ptr<Linearizer> linearizer_;
718 NewtonMethod newtonMethod_;
719 Simulator& simulator_;
720 ElementChunks<GridView, Dune::Partitions::All> element_chunks_;
721
722 std::array<std::unique_ptr<TpsaBlockVectorWrapper>, historySize> solution_;
723 std::vector<Scalar> eqWeights_;
724 std::vector<MaterialState> materialState_;
725 PotForceVector mechPotPresForce_;
726}; // class TpsaModel
727
728} // namespace Opm
729
730
731#endif
Data handle for parallel communication which can be used to set the values values of ghost and overla...
Definition: gridcommhandles.hh:109
Linear least squares calculations and properties.
Definition: linearleastsquares.hpp:45
const Vector & x() const
Read-only vector of calculated coefficient vector.
Definition: linearleastsquares.hpp:76
void solve()
Solve linear least squares system.
Definition: linearleastsquares.hpp:66
static void registerParameters()
Register all run-time parameters for the Newton method.
Definition: newtonmethod.hh:135
Simplifies multi-threaded capabilities.
Definition: threadmanager.hpp:36
Small block vector wrapper class for model solutions.
Definition: tpsamodel.hpp:88
bool operator==(const TpsaBlockVectorWrapper &wrapper) const
Check if incoming block vector is the same as current.
Definition: tpsamodel.hpp:142
static TpsaBlockVectorWrapper serializationTestObject()
Test function for serialization.
Definition: tpsamodel.hpp:110
TpsaBlockVectorWrapper()=default
Default constructor.
TpsaBlockVectorWrapper(const std::string &, const std::size_t size)
Constructor.
Definition: tpsamodel.hpp:98
void serializeOp(Serializer &serializer)
Serializing operation.
Definition: tpsamodel.hpp:154
const SolutionVector & blockVector() const
Get const reference of block vector.
Definition: tpsamodel.hpp:133
SolutionVector & blockVector()
Get reference of block vector.
Definition: tpsamodel.hpp:125
SolutionVector blockVector_
Definition: tpsamodel.hpp:90
TPSA geomechanics model.
Definition: tpsamodel.hpp:56
SymTensor delstress(const unsigned globalIdx) const
Output stress tensor without fracture contribution.
Definition: tpsamodel.hpp:461
NewtonMethod & newtonMethod()
Return the Newton method.
Definition: tpsamodel.hpp:300
std::size_t numAuxiliaryDof() const
Return number of auxillary degrees of freedom.
Definition: tpsamodel.hpp:392
SymTensor stress(const unsigned globalIdx, const bool) const
Output stress tensor.
Definition: tpsamodel.hpp:510
SymTensor strain(const unsigned globalIdx, const bool) const
Output strain tensor.
Definition: tpsamodel.hpp:611
DimVector disp(const unsigned globalIdx, const bool) const
Output displacement vector.
Definition: tpsamodel.hpp:420
void finishInit()
Initialize TPSA model.
Definition: tpsamodel.hpp:191
void setEqWeight(unsigned eqIdx, Scalar value)
Set weights for equation.
Definition: tpsamodel.hpp:374
std::size_t numGridDof() const
Return number of degrees of freedom in the grid from the Flow model.
Definition: tpsamodel.hpp:331
const Linearizer & linearizer() const
Return the linearizer.
Definition: tpsamodel.hpp:270
const NewtonMethod & newtonMethod() const
Return the Newton method.
Definition: tpsamodel.hpp:290
std::size_t numAuxiliaryModules() const
Return number of auxillary modules.
Definition: tpsamodel.hpp:383
void updateMaterialState(const unsigned)
Update material state for all cells.
Definition: tpsamodel.hpp:246
Scalar mechPotentialPressForce(unsigned globalIdx) const
Output potential pressure forces.
Definition: tpsamodel.hpp:656
Scalar mechPotentialTempForce(unsigned) const
Output potential temparature forces.
Definition: tpsamodel.hpp:674
SymTensor linstress(const unsigned globalIdx) const
Output linear stress tensor.
Definition: tpsamodel.hpp:488
const SolutionVector & solution(unsigned timeIdx) const
Get reference to history solution vector.
Definition: tpsamodel.hpp:311
const MaterialState & materialState(const unsigned globalIdx, unsigned) const
Return current material state.
Definition: tpsamodel.hpp:406
Scalar dofTotalVolume(unsigned globalIdx) const
Return the total grid volume from the Flow model.
Definition: tpsamodel.hpp:351
void resizeMaterialState_()
Resize material state vector.
Definition: tpsamodel.hpp:688
static void registerParameters()
Register runtime parameters.
Definition: tpsamodel.hpp:203
void setMechPotentialPressForce(unsigned globalIdx, Scalar val)
Definition: tpsamodel.hpp:661
Scalar eqWeight(unsigned, unsigned eqIdx) const
Return equation weights.
Definition: tpsamodel.hpp:363
TpsaModel(Simulator &simulator)
Constructor.
Definition: tpsamodel.hpp:168
SolutionVector & solution(unsigned timeIdx)
Get reference to history solution vector.
Definition: tpsamodel.hpp:322
void prepareTPSA()
Prepare TPSA model for coupled Flow-TPSA scheme.
Definition: tpsamodel.hpp:212
Scalar solidPressure(const unsigned globalIdx) const
Output solid pressure.
Definition: tpsamodel.hpp:450
SymTensor fractureStress(const unsigned) const
Output fracture stress tensor.
Definition: tpsamodel.hpp:474
std::size_t numTotalDof() const
Return the total number of degrees of freedom.
Definition: tpsamodel.hpp:340
Linearizer & linearizer()
Return the linearizer.
Definition: tpsamodel.hpp:280
void syncOverlap()
Sync primary variables in overlapping cells.
Definition: tpsamodel.hpp:223
DimVector rotation(const unsigned globalIdx) const
Output rotation vector.
Definition: tpsamodel.hpp:435
Scalar mechPotentialForce(unsigned globalIdx) const
Output potential forces.
Definition: tpsamodel.hpp:645
Definition: fvbaseprimaryvariables.hh:161
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
The Opm property system, traits with inheritance.