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
82public:
87 {
88 protected:
89 SolutionVector blockVector_;
90 public:
97 TpsaBlockVectorWrapper(const std::string&, const std::size_t size)
98 : blockVector_(size)
99 {}
100
105
110 {
111 TpsaBlockVectorWrapper result("dummy", 3);
112 result.blockVector_[0] = 1.0;
113 result.blockVector_[1] = 2.0;
114 result.blockVector_[2] = 3.0;
115
116 return result;
117 }
118
124 SolutionVector& blockVector()
125 { return blockVector_; }
126
132 const SolutionVector& blockVector() const
133 { return blockVector_; }
134
141 bool operator==(const TpsaBlockVectorWrapper& wrapper) const
142 {
143 return std::equal(this->blockVector_.begin(), this->blockVector_.end(),
144 wrapper.blockVector_.begin(), wrapper.blockVector_.end());
145 }
146
152 template<class Serializer>
153 void serializeOp(Serializer& serializer)
154 {
155 serializer(blockVector_);
156 }
157 };
158
159 // ///
160 // Public functions
161 // ///
167 explicit TpsaModel(Simulator& simulator)
168 : linearizer_(std::make_unique<Linearizer>())
169 , newtonMethod_(simulator)
170 , simulator_(simulator)
171 , element_chunks_(simulator.gridView(), Dune::Partitions::all, ThreadManager::maxThreads())
172 {
173 // Initialize equation weights to 1.0
174 eqWeights_.resize(numEq, 1.0);
175
176 // Initialize historic solution vectors
177 // OBS: need at least history size = 2, due to time-derivative of solid-pressure in Flow coupling term
178 const std::size_t numDof = simulator_.model().numGridDof();
179 for (unsigned timeIdx = 0; timeIdx < historySize; ++timeIdx) {
180 solution_[timeIdx] = std::make_unique<TpsaBlockVectorWrapper>("solution", numDof);
181 }
182 }
183
188 {
189 // Initialize the linearizer
190 linearizer_->init(simulator_);
191
192 // Resize material state vector
194 }
195
199 static void registerParameters()
200 {
201 // Newton method parameters
203 }
204
209 {
210 // Update historic solution
211 solution(/*timeIdx=*/1) = solution(/*timeIdx=*/0);
212 }
213
220 {
221 // Syncronize the solution on the ghost and overlap elements
222 using GhostSyncHandle = GridCommHandleGhostSync<PrimaryVariables,
223 SolutionVector,
224 DofMapper,
225 /*commCodim=*/0>;
226
227 auto ghostSync = GhostSyncHandle(solution(/*timeIdx=*/0),
228 simulator_.model().dofMapper());
229
230 simulator_.gridView().communicate(ghostSync,
231 Dune::InteriorBorder_All_Interface,
232 Dune::ForwardCommunication);
233 }
234
242 void updateMaterialState(const unsigned /*timeIdx*/)
243 {
244 // Loop over all elements chuncks and update material state from current solution
245 const auto& elementMapper = simulator_.model().elementMapper();
246#ifdef _OPENMP
247#pragma omp parallel for
248#endif
249 for (const auto& chunk : element_chunks_) {
250 for (const auto& elem : chunk) {
251 const unsigned globalIdx = elementMapper.index(elem);
252 auto& currSol = solution(/*timeIdx=*/0)[globalIdx];
253 setMaterialState_(globalIdx, /*timeIdx=*/0, currSol);
254 }
255 }
256 }
257
258 // ///
259 // Public get and set functions
260 // ///
266 const Linearizer& linearizer() const
267 {
268 return *linearizer_;
269 }
270
276 Linearizer& linearizer()
277 {
278 return *linearizer_;
279 }
280
286 const NewtonMethod& newtonMethod() const
287 {
288 return newtonMethod_;
289 }
290
296 NewtonMethod& newtonMethod()
297 {
298 return newtonMethod_;
299 }
300
307 const SolutionVector& solution(unsigned timeIdx) const
308 {
309 return solution_[timeIdx]->blockVector();
310 }
311
318 SolutionVector& solution(unsigned timeIdx)
319 {
320 return solution_[timeIdx]->blockVector();
321 }
322
327 std::size_t numGridDof() const
328 {
329 return simulator_.model().numGridDof();
330 }
331
336 std::size_t numTotalDof() const
337 {
338 return numGridDof() + numAuxiliaryDof();
339 }
340
347 Scalar dofTotalVolume(unsigned globalIdx) const
348 {
349 return simulator_.model().dofTotalVolume(globalIdx);
350 }
351
359 Scalar eqWeight(unsigned /*dofIdx*/, unsigned eqIdx) const
360 {
361 return eqWeights_[eqIdx];
362 }
363
370 void setEqWeight(unsigned eqIdx, Scalar value)
371 {
372 eqWeights_[eqIdx] = value;
373 }
374
379 std::size_t numAuxiliaryModules() const
380 {
381 return 0;
382 }
383
388 std::size_t numAuxiliaryDof() const
389 {
390 return 0;
391 }
392
402 const MaterialState& materialState(const unsigned globalIdx, unsigned /*timeIdx*/) const
403 {
404 return materialState_[globalIdx];
405 }
406
416 DimVector disp(const unsigned globalIdx, const bool /*with_fracture*/) const
417 {
418 DimVector d;
419 for (std::size_t i = 0; i < 3; ++i) {
420 d[i] = decay<Scalar>(materialState_[globalIdx].displacement(i));
421 }
422 return d;
423 }
424
433 SymTensor delstress(const unsigned /*globalIdx*/) const
434 {
435 SymTensor val;
436 return val;
437 }
438
447 SymTensor fractureStress(const unsigned /*globalIdx*/) const
448 {
449 SymTensor val;
450 return val;
451 }
452
461 SymTensor linstress(const unsigned /*globalIdx*/) const
462 {
463 SymTensor val;
464 return val;
465 }
466
477 SymTensor stress(const unsigned globalIdx, const bool /*with_fracture*/) const
478 {
479 SymTensor stressOutput;
480 const auto& stressInfo = linearizer_->getStressInfo();
481 if (!stressInfo.empty()) {
482 const auto& stressInfoGlobI = stressInfo[globalIdx];
483
484 // Setup least-squares matrix of face normals and right-hand side of traction vectors
485 // per faces. Matrix shape = 3 rows per face x 6 columns for each (symmetric) stress
486 // tensor component.
487 std::unordered_multimap<int, std::size_t> faceIdMap;
488 std::size_t mapSize = 0;
489 for (std::size_t sInfoIdx = 0; sInfoIdx < stressInfoGlobI.size(); ++sInfoIdx) {
490 const auto faceId = stressInfoGlobI[sInfoIdx].faceId;
491
492 // OBS: NNC faces are not added to least squares system, since TPSA does not handle
493 // NNC connections, like numerical aquifers, yet!
494 if (faceId < 0 || stressInfoGlobI[sInfoIdx].faceArea == 0.0) {
495 continue;
496 }
497 if (!faceIdMap.contains(faceId)) {
498 ++mapSize;
499 }
500 faceIdMap.insert({faceId, sInfoIdx});
501 }
502
503 // If no valid faces exist for cell, return zero SymTensor
504 if (mapSize == 0) {
505 return stressOutput;
506 }
507
508 Dune::DynamicMatrix<Scalar> mat(3 * mapSize, 6);
509 Dune::DynamicVector<Scalar> rhs(3 * mapSize);
510 std::size_t rowIdx = 0;
511 for (auto it = faceIdMap.begin(); it != faceIdMap.end();) {
512 auto [first, last] = faceIdMap.equal_range(it->first);
513
514 // Loop over possible multiple of the same face
515 Scalar sumFaceArea = 0.0;
516 for (auto inner = first; inner != last; ++inner) {
517 const auto sInfoIdx = inner->second;
518 const auto& faceStressInfo = stressInfoGlobI[sInfoIdx];
519
520 // One normal per face
521 if (inner == first) {
522 const auto& fNormal = faceStressInfo.faceNormal;
523 mat[3*rowIdx][0] = fNormal[0];
524 mat[3*rowIdx][3] = fNormal[1];
525 mat[3*rowIdx][4] = fNormal[2];
526
527 mat[3*rowIdx + 1][1] = fNormal[1];
528 mat[3*rowIdx + 1][3] = fNormal[0];
529 mat[3*rowIdx + 1][5] = fNormal[2];
530
531 mat[3*rowIdx + 2][2] = fNormal[2];
532 mat[3*rowIdx + 2][4] = fNormal[0];
533 mat[3*rowIdx + 2][5] = fNormal[1];
534 }
535
536 // Add traction vectors for same faces
537 const auto& fTraction = faceStressInfo.traction;
538 rhs[3*rowIdx] += fTraction[0];
539 rhs[3*rowIdx + 1] += fTraction[1];
540 rhs[3*rowIdx + 2] += fTraction[2];
541
542 // Sum face area
543 sumFaceArea += faceStressInfo.faceArea;
544 }
545 // Divide rhs for (unique) face by sum of face areas
546 rhs[3*rowIdx] /= sumFaceArea;
547 rhs[3*rowIdx + 1] /= sumFaceArea;
548 rhs[3*rowIdx + 2] /= sumFaceArea;
549
550 // Move to next unique face
551 ++rowIdx;
552 it = last;
553 }
554
555 // Use least squares solver for underdetermined system
556 LinearLeastSquares<Scalar> lsq(mat, rhs);
557 lsq.solve();
558
559 // Reconstructed stress tensor at cell center
560 const auto& stress = lsq.x();
561 stressOutput[0] = stress[0]; // XX
562 stressOutput[1] = stress[1]; // YY
563 stressOutput[2] = stress[2]; // ZZ
564 stressOutput[3] = stress[5]; // YZ
565 stressOutput[4] = stress[4]; // XZ
566 stressOutput[5] = stress[3]; // XY
567 }
568 return stressOutput;
569 }
570
580 SymTensor strain(const unsigned /*globalIdx*/, const bool /*with_fracture*/) const
581 {
582 SymTensor val;
583 return val;
584 }
585
594 Scalar mechPotentialForce(unsigned /*globalIdx*/) const
595 {
596 return Scalar(0.0);
597 }
598
607 Scalar mechPotentialPressForce(unsigned /*globalIdx*/) const
608 {
609 return Scalar(0.0);
610 }
611
620 Scalar mechPotentialTempForce(unsigned /*globalIdx*/) const
621 {
622 return Scalar(0.0);
623 }
624
625protected:
626 // ///
627 // Protected functions
628 // ///
635 {
636 const std::size_t numDof = simulator_.model().numGridDof();
637 materialState_.resize(numDof);
638 }
639
640private:
641 // ///
642 // Private functions
643 // ///
653 void setMaterialState_(const unsigned globalIdx, const unsigned /*timeIdx*/, PrimaryVariables& values)
654 {
655 auto& dofMaterialState = materialState_[globalIdx];
656 for (unsigned dirIdx = 0; dirIdx < 3; ++dirIdx) {
657 dofMaterialState.setDisplacement(dirIdx, values.makeEvaluation(disp0Idx + dirIdx, 0));
658 dofMaterialState.setRotation(dirIdx, values.makeEvaluation(rot0Idx + dirIdx, 0));
659 }
660 dofMaterialState.setSolidPressure(values.makeEvaluation(solidPres0Idx, 0));
661 }
662
663 std::unique_ptr<Linearizer> linearizer_;
664 NewtonMethod newtonMethod_;
665 Simulator& simulator_;
666 ElementChunks<GridView, Dune::Partitions::All> element_chunks_;
667
668 std::array<std::unique_ptr<TpsaBlockVectorWrapper>, historySize> solution_;
669 std::vector<Scalar> eqWeights_;
670 std::vector<MaterialState> materialState_;
671}; // class TpsaModel
672
673} // namespace Opm
674
675
676#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:87
bool operator==(const TpsaBlockVectorWrapper &wrapper) const
Check if incoming block vector is the same as current.
Definition: tpsamodel.hpp:141
static TpsaBlockVectorWrapper serializationTestObject()
Test function for serialization.
Definition: tpsamodel.hpp:109
TpsaBlockVectorWrapper()=default
Default constructor.
TpsaBlockVectorWrapper(const std::string &, const std::size_t size)
Constructor.
Definition: tpsamodel.hpp:97
void serializeOp(Serializer &serializer)
Serializing operation.
Definition: tpsamodel.hpp:153
const SolutionVector & blockVector() const
Get const reference of block vector.
Definition: tpsamodel.hpp:132
SolutionVector & blockVector()
Get reference of block vector.
Definition: tpsamodel.hpp:124
SolutionVector blockVector_
Definition: tpsamodel.hpp:89
TPSA geomechanics model.
Definition: tpsamodel.hpp:56
NewtonMethod & newtonMethod()
Return the Newton method.
Definition: tpsamodel.hpp:296
std::size_t numAuxiliaryDof() const
Return number of auxillary degrees of freedom.
Definition: tpsamodel.hpp:388
SymTensor stress(const unsigned globalIdx, const bool) const
Output stress tensor.
Definition: tpsamodel.hpp:477
Scalar mechPotentialPressForce(unsigned) const
Output potential pressure forces.
Definition: tpsamodel.hpp:607
Scalar mechPotentialForce(unsigned) const
Output potential forces.
Definition: tpsamodel.hpp:594
DimVector disp(const unsigned globalIdx, const bool) const
Output displacement vector.
Definition: tpsamodel.hpp:416
void finishInit()
Initialize TPSA model.
Definition: tpsamodel.hpp:187
void setEqWeight(unsigned eqIdx, Scalar value)
Set weights for equation.
Definition: tpsamodel.hpp:370
SymTensor linstress(const unsigned) const
Output linear stress tensor.
Definition: tpsamodel.hpp:461
std::size_t numGridDof() const
Return number of degrees of freedom in the grid from the Flow model.
Definition: tpsamodel.hpp:327
const Linearizer & linearizer() const
Return the linearizer.
Definition: tpsamodel.hpp:266
const NewtonMethod & newtonMethod() const
Return the Newton method.
Definition: tpsamodel.hpp:286
std::size_t numAuxiliaryModules() const
Return number of auxillary modules.
Definition: tpsamodel.hpp:379
void updateMaterialState(const unsigned)
Update material state for all cells.
Definition: tpsamodel.hpp:242
Scalar mechPotentialTempForce(unsigned) const
Output potential temparature forces.
Definition: tpsamodel.hpp:620
const SolutionVector & solution(unsigned timeIdx) const
Get reference to history solution vector.
Definition: tpsamodel.hpp:307
const MaterialState & materialState(const unsigned globalIdx, unsigned) const
Return current material state.
Definition: tpsamodel.hpp:402
Scalar dofTotalVolume(unsigned globalIdx) const
Return the total grid volume from the Flow model.
Definition: tpsamodel.hpp:347
void resizeMaterialState_()
Resize material state vector.
Definition: tpsamodel.hpp:634
static void registerParameters()
Register runtime parameters.
Definition: tpsamodel.hpp:199
SymTensor delstress(const unsigned) const
Output (del?)stress tensor.
Definition: tpsamodel.hpp:433
Scalar eqWeight(unsigned, unsigned eqIdx) const
Return equation weights.
Definition: tpsamodel.hpp:359
TpsaModel(Simulator &simulator)
Constructor.
Definition: tpsamodel.hpp:167
SymTensor strain(const unsigned, const bool) const
Output strain tensor.
Definition: tpsamodel.hpp:580
SolutionVector & solution(unsigned timeIdx)
Get reference to history solution vector.
Definition: tpsamodel.hpp:318
void prepareTPSA()
Prepare TPSA model for coupled Flow-TPSA scheme.
Definition: tpsamodel.hpp:208
SymTensor fractureStress(const unsigned) const
Output fracture stress tensor.
Definition: tpsamodel.hpp:447
std::size_t numTotalDof() const
Return the total number of degrees of freedom.
Definition: tpsamodel.hpp:336
Linearizer & linearizer()
Return the linearizer.
Definition: tpsamodel.hpp:276
void syncOverlap()
Sync primary variables in overlapping cells.
Definition: tpsamodel.hpp:219
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.