elasticitylocalresidualtpsa.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 ELASTICITY_LOCAL_RESIDUAL_TPSA_HPP
26#define ELASTICITY_LOCAL_RESIDUAL_TPSA_HPP
27
28#include <dune/common/fvector.hh>
29
30#include <opm/input/eclipse/Schedule/BCState.hpp>
31
32#include <opm/material/common/MathToolbox.hpp>
33#include <opm/material/materialstates/MaterialStateTPSA.hpp>
34
38
40
41#include <stdexcept>
42
43
44namespace Opm {
45
46namespace detail {
47
52inline int modNeg(int i)
53{
54 return ((i % 3) + 3) % 3;
55}
56
57} // namespace detail
58
80template <class TypeTag>
82{
87
88 using MaterialState = MaterialStateTPSA<Evaluation>;
89 using Toolbox = MathToolbox<Evaluation>;
90
91 enum { conti0EqIdx = Indices::conti0EqIdx };
92 enum { contiRotEqIdx = Indices::contiRotEqIdx };
93 enum { contiSolidPresEqIdx = Indices::contiSolidPresEqIdx };
94 enum { numEq = getPropValue<TypeTag, Properties::NumEqTPSA>() };
95
96public:
108 template <class LhsEval>
109 static void computeVolumeTerm(Dune::FieldVector<LhsEval, numEq>& volTerm,
110 const MaterialState& materialState,
111 const Problem& problem,
112 const unsigned globalIndex)
113 {
114 // Reset volume terms
115 volTerm = 0.0;
116
117 // Rotation equations (one per direction)
118 const Scalar sModulus = problem.shearModulus(globalIndex);
119 for (unsigned dirIdx = 0; dirIdx < 3; ++dirIdx) {
120 volTerm[contiRotEqIdx + dirIdx] +=
121 Toolbox::template decay<LhsEval>(materialState.rotation(dirIdx))
122 / sModulus;
123 }
124
125 // Solid pressure equation
126 const Scalar lame = problem.lame(globalIndex);
127 volTerm[contiSolidPresEqIdx] +=
128 Toolbox::template decay<LhsEval>(materialState.solidPressure())
129 / lame;
130 }
131
145 static void computeFaceTerm(Dune::FieldVector<Evaluation, numEq>& faceTerm,
146 const MaterialState& materialStateIn,
147 const MaterialState& materialStateEx,
148 Problem& problem,
149 const unsigned globalIndexIn,
150 const unsigned globalIndexEx)
151 {
152 // Reset face terms
153 faceTerm = 0.0;
154
155 // Extract some face properties
156 const Scalar weightAvgIn = problem.weightAverage(globalIndexIn, globalIndexEx);
157 const Scalar weightAvgEx = problem.weightAverage(globalIndexEx, globalIndexIn);
158 const Scalar weightProd = problem.weightProduct(globalIndexIn, globalIndexEx);
159 const Scalar normDist = problem.normalDistance(globalIndexIn, globalIndexEx);
160 const auto& faceNormal = problem.cellFaceNormal(globalIndexIn, globalIndexEx);
161
162 // Effective shear modulus
163 const Scalar sModulusIn = problem.shearModulus(globalIndexIn);
164 const Scalar sModulusEx = problem.shearModulus(globalIndexEx);
165 const Scalar eff_sModulus = weightAvgIn * sModulusIn + weightAvgEx * sModulusEx;
166
167 // Distance ratio
168 const Scalar distRatio = 0.5 * weightProd / normDist;
169
170 // Solid pressures
171 const Evaluation& solidPIn = materialStateIn.solidPressure();
172 const Scalar solidPEx = decay<Scalar>(materialStateEx.solidPressure());
173
174 // ///
175 // Solid pressure equation (direction-independent equation)
176 // ///
177 faceTerm[contiSolidPresEqIdx] +=
178 distRatio * eff_sModulus * (solidPIn - solidPEx);
179
180 // ///
181 // Displacement, rotation and solid pressure (directional-dependent) equations
182 // ///
183 // Loop over x-, y- and z-dir (corresponding to dirIdx = 0, 1, 2)
184 for (int dirIdx = 0; dirIdx < 3; ++dirIdx) {
185 // Direction indices in cross-product
186 unsigned dirIdxNeg = detail::modNeg(dirIdx - 1);
187 unsigned dirIdxPos = detail::modNeg(dirIdx + 1);
188
189 // Displacement equation
190 const Scalar faceNormalDir = faceNormal[dirIdx];
191 const Scalar faceNormalNeg = faceNormal[dirIdxNeg];
192 const Scalar faceNormalPos = faceNormal[dirIdxPos];
193
194 const Evaluation& dispIn = materialStateIn.displacement(dirIdx);
195 const Scalar dispEx = decay<Scalar>(materialStateEx.displacement(dirIdx));
196
197 const Evaluation& rotInNeg = materialStateIn.rotation(dirIdxNeg);
198 const Evaluation& rotInPos = materialStateIn.rotation(dirIdxPos);
199 const Scalar rotExNeg = decay<Scalar>(materialStateEx.rotation(dirIdxNeg));
200 const Scalar rotExPos = decay<Scalar>(materialStateEx.rotation(dirIdxPos));
201
202 faceTerm[conti0EqIdx + dirIdx] +=
203 2.0 * (eff_sModulus / normDist) * (dispIn - dispEx)
204 - weightAvgIn * (faceNormalNeg * rotInPos - faceNormalPos * rotInNeg)
205 - weightAvgEx * (faceNormalNeg * rotExPos - faceNormalPos * rotExNeg)
206 - faceNormalDir * (weightAvgIn * solidPIn + weightAvgEx * solidPEx);
207
208 // Rotation equation
209 const Evaluation& dispInNeg = materialStateIn.displacement(dirIdxNeg);
210 const Evaluation& dispInPos = materialStateIn.displacement(dirIdxPos);
211 const Scalar dispExNeg = decay<Scalar>(materialStateEx.displacement(dirIdxNeg));
212 const Scalar dispExPos = decay<Scalar>(materialStateEx.displacement(dirIdxPos));
213
214 faceTerm[contiRotEqIdx + dirIdx] +=
215 - weightAvgEx * (faceNormalNeg * dispInPos - faceNormalPos * dispInNeg)
216 - weightAvgIn * (faceNormalNeg * dispExPos - faceNormalPos * dispExNeg);
217
218 // Solid pressure equation
219 faceTerm[contiSolidPresEqIdx] +=
220 - faceNormalDir * (weightAvgEx * dispIn + weightAvgIn * dispEx);
221 }
222 }
223
233 template <class BoundaryConditionData>
234 static void computeBoundaryTerm(Dune::FieldVector<Evaluation, numEq>& bndryTerm,
235 const MaterialState& materialState,
236 const BoundaryConditionData& bdyInfo,
237 Problem& problem,
238 unsigned globalIndex)
239 {
240 // Switch between possible boundary conditions
241 switch (bdyInfo.type) {
242 // OBS: NONE is interpreted as FIXED with zero displacement
243 case BCMECHType::NONE:
244 computeBoundaryTermFixed(bndryTerm,
245 materialState,
246 bdyInfo,
247 problem,
248 globalIndex);
249 break;
250 case BCMECHType::FIXED:
251 throw std::runtime_error("BCTYPE FIXED has not been implemented in TPSA");
252 case BCMECHType::FREE:
253 computeBoundaryTermFree(bndryTerm,
254 materialState,
255 bdyInfo,
256 problem,
257 globalIndex);
258 break;
259 case BCMECHType::SPRING:
261 materialState,
262 bdyInfo,
263 problem,
264 globalIndex);
265 break;
266 default:
267 throw std::logic_error("Unknown boundary condition type " +
268 std::to_string(static_cast<int>(bdyInfo.type)) +
269 " in computeBoundaryFlux()." );
270 }
271 }
272
285 template <class BoundaryConditionData>
286 static void computeBoundaryTermFixed(Dune::FieldVector<Evaluation, numEq>& bndryTerm,
287 const MaterialState& materialState,
288 const BoundaryConditionData& bdyInfo,
289 Problem& problem,
290 unsigned globalIndex)
291 {
292 // !!!!
293 // Only BCMECHType::NONE, where we have zero displacement on boundary face, have been implemented!
294 // !!!!
295
296 // Reset bondary term
297 bndryTerm = 0.0;
298
299 // Extract some face properties
300 const unsigned bfIdx = bdyInfo.boundaryFaceIndex;
301 const Scalar weightAvg = problem.weightAverageBoundary(globalIndex, bfIdx);
302 const Scalar normDist = problem.normalDistanceBoundary(globalIndex, bfIdx);
303 const auto& faceNormal = problem.cellFaceNormalBoundary(globalIndex, bfIdx);
304
305 // Effective shear modulus (= cell shear modulus)
306 const Scalar eff_sModulus = problem.shearModulus(globalIndex);
307
308 // Solid pressure
309 const Evaluation& solidP = materialState.solidPressure();
310
311 // ///
312 // Displacement equation
313 // ///
314 // Loop over x-, y- and z-dir (corresponding to dirIdx = 0, 1, 2)
315 for (int dirIdx = 0; dirIdx < 3; ++dirIdx) {
316 // Direction indices in cross-product
317 unsigned dirIdxNeg = detail::modNeg(dirIdx - 1);
318 unsigned dirIdxPos = detail::modNeg(dirIdx + 1);
319
320 // Displacement equation
321 const Scalar faceNormalDir = faceNormal[dirIdx];
322 const Scalar faceNormalNeg = faceNormal[dirIdxNeg];
323 const Scalar faceNormalPos = faceNormal[dirIdxPos];
324
325 const Evaluation& disp = materialState.displacement(dirIdx);
326
327 const Evaluation& rotNeg = materialState.rotation(dirIdxNeg);
328 const Evaluation& rotPos = materialState.rotation(dirIdxPos);
329
330 bndryTerm[conti0EqIdx + dirIdx] +=
331 2.0 * (eff_sModulus / normDist) * disp
332 - weightAvg * (faceNormalNeg * rotPos - faceNormalPos * rotNeg)
333 - faceNormalDir * weightAvg * solidP;
334 }
335 }
336
349 template <class BoundaryConditionData>
350 static void computeBoundaryTermFree(Dune::FieldVector<Evaluation, numEq>& bndryTerm,
351 const MaterialState& materialState,
352 const BoundaryConditionData& bdyInfo,
353 Problem& problem,
354 unsigned globalIndex)
355 {
356 // Reset bondary term
357 bndryTerm = 0.0;
358
359 // Face properties
360 const unsigned bfIdx = bdyInfo.boundaryFaceIndex;
361 const Scalar weightAvg = 1.0;
362 const Scalar normDist = problem.normalDistanceBoundary(globalIndex, bfIdx);
363 const auto& faceNormal = problem.cellFaceNormalBoundary(globalIndex, bfIdx);
364
365 const Scalar sModulus = problem.shearModulus(globalIndex);
366
367 // ///
368 // Solid pressure equation (direction-independent equation)
369 // ///
370 const Evaluation& solidP = materialState.solidPressure();
371 bndryTerm[contiSolidPresEqIdx] +=
372 0.5 * (normDist / sModulus) * solidP;
373
374 // ///
375 // Rotation and solid pressure (directional-dependent) equations
376 // ///
377 // Pre-compute dot product for rotation equation
378 Evaluation dotProd = 0;
379 for (int dirIdx = 0; dirIdx < 3; ++dirIdx) {
380 dotProd += faceNormal[dirIdx] * materialState.rotation(dirIdx);
381 }
382
383 // Loop over x-, y- and z-dir (corresponding to dirIdx = 0, 1, 2)
384 for (int dirIdx = 0; dirIdx < 3; ++dirIdx) {
385 // Direction indices in cross-product
386 unsigned dirIdxNeg = detail::modNeg(dirIdx - 1);
387 unsigned dirIdxPos = detail::modNeg(dirIdx + 1);
388
389 // Rotation equation
390 const Scalar faceNormalDir = faceNormal[dirIdx];
391 const Scalar faceNormalNeg = faceNormal[dirIdxNeg];
392 const Scalar faceNormalPos = faceNormal[dirIdxPos];
393
394 const Evaluation& dispNeg = materialState.displacement(dirIdxNeg);
395 const Evaluation& dispPos = materialState.displacement(dirIdxPos);
396
397 const Evaluation& rot = materialState.rotation(dirIdx);
398
399 bndryTerm[contiRotEqIdx + dirIdx] +=
400 - weightAvg * (faceNormalNeg * dispPos - faceNormalPos * dispNeg)
401 + 0.5 * (normDist / sModulus) * (dotProd * faceNormalDir - rot);
402
403 // Solid pressure (directional-dependent) equation
404 const Evaluation& disp = materialState.displacement(dirIdx);
405
406 bndryTerm[contiSolidPresEqIdx] +=
407 - faceNormalDir * weightAvg * disp;
408 }
409 }
410
423 template <class BoundaryConditionData>
424 static void computeBoundaryTermSpring(Dune::FieldVector<Evaluation, numEq>& bndryTerm,
425 const MaterialState& materialState,
426 const BoundaryConditionData& bdyInfo,
427 Problem& problem,
428 unsigned globalIndex)
429 {
430 // Reset boundary term
431 bndryTerm = 0.0;
432
433 // Extract cell and boundary information
434 const unsigned bfIdx = bdyInfo.boundaryFaceIndex;
435 const auto& faceNormal = problem.cellFaceNormalBoundary(globalIndex, bfIdx);
436 const Scalar distIn = problem.normalDistanceBoundary(globalIndex, bfIdx);
437 const Scalar distEx = bdyInfo.distance;
438 const Scalar sModulusIn = problem.shearModulus(globalIndex);
439 const Scalar sModulusEx = bdyInfo.shearModulus;
440
441 // Calculate face properties
442 const Scalar weightIn = distIn / sModulusIn;
443 const Scalar weightEx = distEx / sModulusEx;
444 const Scalar weightAvgIn = weightIn / (weightIn + weightEx);
445 const Scalar weightAvgEx = 1.0 - weightAvgIn;
446 const Scalar weightProd = weightIn * weightEx;
447 const Scalar normDist = distIn + distEx;
448
449 // Effective shear modulus
450 const Scalar eff_sModulus = weightAvgIn * sModulusIn + weightAvgEx * sModulusEx;
451
452 // Distance ratio
453 const Scalar distRatio = 0.5 * weightProd / normDist;
454
455 // Solid pressure equation (direction-independent equation)
456 const Evaluation& solidP = materialState.solidPressure();
457 bndryTerm[contiSolidPresEqIdx] +=
458 distRatio * eff_sModulus * solidP;
459
460 // Pre-compute dot product for rotation equation
461 Evaluation dotProd = 0;
462 for (int dirIdx = 0; dirIdx < 3; ++dirIdx) {
463 dotProd += faceNormal[dirIdx] * materialState.rotation(dirIdx);
464 }
465
466 // Loop over x-, y- and z-dir (corresponding to dirIdx = 0, 1, 2)
467 for (int dirIdx = 0; dirIdx < 3; ++dirIdx) {
468 // Direction indices in cross-product
469 unsigned dirIdxNeg = detail::modNeg(dirIdx - 1);
470 unsigned dirIdxPos = detail::modNeg(dirIdx + 1);
471
472 // Displacement equation
473 const Scalar faceNormalDir = faceNormal[dirIdx];
474 const Scalar faceNormalNeg = faceNormal[dirIdxNeg];
475 const Scalar faceNormalPos = faceNormal[dirIdxPos];
476
477 const Evaluation& disp = materialState.displacement(dirIdx);
478
479 const Evaluation& rotNeg = materialState.rotation(dirIdxNeg);
480 const Evaluation& rotPos = materialState.rotation(dirIdxPos);
481
482 bndryTerm[conti0EqIdx + dirIdx] +=
483 2.0 * (eff_sModulus / normDist) * disp
484 - weightAvgIn * (faceNormalNeg * rotPos - faceNormalPos * rotNeg)
485 - faceNormalDir * weightAvgIn * solidP;
486
487 // Rotation equation
488 const Evaluation& dispNeg = materialState.displacement(dirIdxNeg);
489 const Evaluation& dispPos = materialState.displacement(dirIdxPos);
490
491 const Evaluation& rot = materialState.rotation(dirIdx);
492
493 bndryTerm[contiRotEqIdx + dirIdx] +=
494 - weightAvgEx * (faceNormalNeg * dispPos - faceNormalPos * dispNeg)
495 + distRatio * eff_sModulus * (dotProd * faceNormalDir - rot);
496
497 // Solid pressure (directional-dependent) equation
498 bndryTerm[contiSolidPresEqIdx] +=
499 - faceNormalDir * weightAvgEx * disp;
500 }
501 }
502
511 static void computeSourceTerm(Dune::FieldVector<Evaluation, numEq>& sourceTerm,
512 Problem& problem,
513 unsigned globalSpaceIdex,
514 unsigned timeIdx)
515 {
516 // Reset source terms
517 sourceTerm = 0.0;
518
519 // Get source term from problem
520 // NOTE: separate source function than Flow source(...)!
521 problem.tpsaSource(sourceTerm, globalSpaceIdex, timeIdx);
522 }
523}; // class ElasticityLocalResidual
524
525} // namespace Opm
526
527#endif
Defines a type tags and some fundamental properties all models.
Calculation of (linear) elasticity model terms for the residual.
Definition: elasticitylocalresidualtpsa.hpp:82
static void computeFaceTerm(Dune::FieldVector< Evaluation, numEq > &faceTerm, const MaterialState &materialStateIn, const MaterialState &materialStateEx, Problem &problem, const unsigned globalIndexIn, const unsigned globalIndexEx)
Calculate terms across cell faces in TPSA formulation.
Definition: elasticitylocalresidualtpsa.hpp:145
static void computeBoundaryTermFixed(Dune::FieldVector< Evaluation, numEq > &bndryTerm, const MaterialState &materialState, const BoundaryConditionData &bdyInfo, Problem &problem, unsigned globalIndex)
Calculate fixed displacement boundary condition in TPSA formulation.
Definition: elasticitylocalresidualtpsa.hpp:286
static void computeBoundaryTermFree(Dune::FieldVector< Evaluation, numEq > &bndryTerm, const MaterialState &materialState, const BoundaryConditionData &bdyInfo, Problem &problem, unsigned globalIndex)
Calculate free (or zero traction) boundary condition in TPSA formulation.
Definition: elasticitylocalresidualtpsa.hpp:350
static void computeVolumeTerm(Dune::FieldVector< LhsEval, numEq > &volTerm, const MaterialState &materialState, const Problem &problem, const unsigned globalIndex)
Calculate volume terms in TPSA formulation.
Definition: elasticitylocalresidualtpsa.hpp:109
static void computeSourceTerm(Dune::FieldVector< Evaluation, numEq > &sourceTerm, Problem &problem, unsigned globalSpaceIdex, unsigned timeIdx)
Calculate source term in TPSA formulation.
Definition: elasticitylocalresidualtpsa.hpp:511
static void computeBoundaryTermSpring(Dune::FieldVector< Evaluation, numEq > &bndryTerm, const MaterialState &materialState, const BoundaryConditionData &bdyInfo, Problem &problem, unsigned globalIndex)
Calculate spring boundary condition in TPSA formulation.
Definition: elasticitylocalresidualtpsa.hpp:424
static void computeBoundaryTerm(Dune::FieldVector< Evaluation, numEq > &bndryTerm, const MaterialState &materialState, const BoundaryConditionData &bdyInfo, Problem &problem, unsigned globalIndex)
Calculate boundary conditions in TPSA formulation given by BCCON/BCMECH.
Definition: elasticitylocalresidualtpsa.hpp:234
Declare the properties used by the infrastructure code of the finite volume discretizations.
@ NONE
Definition: DeferredLogger.hpp:46
int modNeg(int i)
Computes modulo 3 of possibly negative integers to get indices in cross product.
Definition: elasticitylocalresidualtpsa.hpp:52
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
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
Definition: tpfalinearizerstructs.hh:89
BCType type
Definition: tpfalinearizerstructs.hh:90
unsigned boundaryFaceIndex
Definition: tpfalinearizerstructs.hh:93