OOFEM 3.0
Loading...
Searching...
No Matches
tr21stokes.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "tr21stokes.h"
36#include "node.h"
37#include "dof.h"
38#include "domain.h"
40#include "gausspoint.h"
41#include "bcgeomtype.h"
42#include "load.h"
43#include "bodyload.h"
44#include "boundaryload.h"
45#include "mathfem.h"
47#include "fei2dtrlin.h"
48#include "fei2dtrquad.h"
49#include "fluidcrosssection.h"
50#include "assemblercallback.h"
51#include "classfactory.h"
52#include "engngm.h"
53
54namespace oofem {
56
57// Set up interpolation coordinates
58FEI2dTrLin Tr21Stokes :: interpolation_lin(1, 2);
59FEI2dTrQuad Tr21Stokes :: interpolation_quad(1, 2);
60// Set up ordering vectors (for assembling)
61IntArray Tr21Stokes :: momentum_ordering = {1, 2, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15};
62IntArray Tr21Stokes :: conservation_ordering = {3, 6, 9};
63IntArray Tr21Stokes :: edge_ordering [ 3 ] = {
64 {1, 2, 4, 5, 10, 11},
65 {4, 5, 7, 8, 12, 13},
66 {7, 8, 1, 2, 14, 15}
67};
68
69Tr21Stokes :: Tr21Stokes(int n, Domain *aDomain) : FMElement(n, aDomain), ZZNodalRecoveryModelInterface(this), SpatialLocalizerInterface(this)
70{
71 this->numberOfDofMans = 6;
72 if ( aDomain->giveEngngModel()->giveProblemScale() == macroScale ) { // Pick the lowest default value for multiscale computations.
73 this->numberOfGaussPoints = 3;
74 } else {
75 this->numberOfGaussPoints = 4;
76 }
77}
78
79void Tr21Stokes :: computeGaussPoints()
80{
81 if ( integrationRulesArray.size() == 0 ) {
82 integrationRulesArray.resize(1);
83 integrationRulesArray [ 0 ] = std::make_unique<GaussIntegrationRule>(1, this, 1, 3);
84 this->giveCrossSection()->setupIntegrationPoints(* integrationRulesArray [ 0 ], this->numberOfGaussPoints, this);
85 }
86}
87
88int Tr21Stokes :: computeNumberOfDofs()
89{
90 return 15;
91}
92
93void Tr21Stokes :: giveDofManDofIDMask(int inode, IntArray &answer) const
94{
95 if ( inode <= 3 ) {
96 answer = {V_u, V_v, P_f};
97 } else {
98 answer = {V_u, V_v};
99 }
100}
101
102double Tr21Stokes :: computeVolumeAround(GaussPoint *gp)
103{
104 double detJ = fabs( this->interpolation_quad.giveTransformationJacobian( gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(this) ) );
105 return detJ *gp->giveWeight();
106}
107
108void Tr21Stokes :: giveCharacteristicVector(FloatArray &answer, CharType mtrx, ValueModeType mode,
109 TimeStep *tStep)
110{
111 // Compute characteristic vector for this element. I.e the load vector(s)
112 if ( mtrx == ExternalForcesVector ) {
113 this->computeExternalForcesVector(answer, tStep);
114 } else if ( mtrx == InternalForcesVector ) {
115 this->computeInternalForcesVector(answer, tStep);
116 } else {
117 OOFEM_ERROR("Unknown Type of characteristic mtrx.");
118 }
119}
120
121void Tr21Stokes :: giveCharacteristicMatrix(FloatMatrix &answer,
122 CharType mtrx, TimeStep *tStep)
123{
124 // Compute characteristic matrix for this element. The only option is the stiffness matrix...
125 if ( mtrx == TangentStiffnessMatrix ) {
126 this->computeStiffnessMatrix(answer, TangentStiffness, tStep);
127 } else {
128 OOFEM_ERROR("Unknown Type of characteristic mtrx.");
129 }
130}
131
132void Tr21Stokes :: computeInternalForcesVector(FloatArray &answer, TimeStep *tStep)
133{
134 FluidDynamicMaterial *mat = static_cast< FluidCrossSection * >( this->giveCrossSection() )->giveFluidMaterial();
135
136 FloatArrayF<12> a_velocity = this->computeVectorOfVelocities(VM_Total, tStep);
137 FloatArrayF<3> a_pressure = this->computeVectorOfPressures(VM_Total, tStep);
138
139 FloatArrayF<12> momentum;
140 FloatArrayF<3> conservation;
141
142 for ( auto &gp: *integrationRulesArray [ 0 ] ) {
143 const auto &lcoords = gp->giveNaturalCoordinates();
144
145 auto Nh = this->interpolation_lin.evalN( lcoords );
146 auto val = this->interpolation_quad.evaldNdx( lcoords, FEIElementGeometryWrapper(this) );
147 auto detJ = val.first;
148 auto dN = val.second;
149 auto dA = std::abs(detJ) * gp->giveWeight();
150
151 auto dNv = flatten(dN);
152 auto B = Bmatrix_2d(dN);
153
154 auto pressure = dot(Nh, a_pressure);
155 auto epsp = dot(B, a_velocity);
156
157 auto s_r = mat->computeDeviatoricStress2D(epsp, pressure, gp, tStep);
158 auto devStress = s_r.first;
159 auto r_vol = s_r.second;
160
161 momentum += Tdot(B, devStress * dA) + dNv * (-pressure * dA);
162 conservation += Nh * (r_vol * dA);
163 }
164
165 answer.resize(15);
166 answer.zero();
167 answer.assemble(momentum, this->momentum_ordering);
168 answer.assemble(conservation, this->conservation_ordering);
169}
170
171void Tr21Stokes :: computeExternalForcesVector(FloatArray &answer, TimeStep *tStep)
172{
173 FloatArray vec;
174
175 answer.clear();
176
177 int nLoads = this->boundaryLoadArray.giveSize() / 2;
178 for ( int i = 1; i <= nLoads; i++ ) { // For each Neumann boundary condition
179 int load_number = this->boundaryLoadArray.at(2 * i - 1);
180 int load_id = this->boundaryLoadArray.at(2 * i);
181 Load *load = this->domain->giveLoad(load_number);
182 bcGeomType ltype = load->giveBCGeoType();
183
184 if ( ltype == EdgeLoadBGT ) {
185 this->computeBoundarySurfaceLoadVector(vec, static_cast< BoundaryLoad * >(load), load_id, ExternalForcesVector, VM_Total, tStep);
186 answer.add(vec);
187 }
188 }
189
190 nLoads = this->giveBodyLoadArray()->giveSize();
191 for ( int i = 1; i <= nLoads; i++ ) {
192 Load *load = domain->giveLoad( bodyLoadArray.at(i) );
193 BodyLoad *bload;
194 if ((bload = dynamic_cast<BodyLoad*>(load))) {
195 bcGeomType ltype = load->giveBCGeoType();
196 if ( ltype == BodyLoadBGT && load->giveBCValType() == ForceLoadBVT ) {
197 this->computeLoadVector(vec, bload, ExternalForcesVector, VM_Total, tStep);
198 answer.add(vec);
199 }
200 }
201 }
202}
203
204void Tr21Stokes :: computeLoadVector(FloatArray &answer, BodyLoad *load, CharType type, ValueModeType mode, TimeStep *tStep)
205{
206 if ( type != ExternalForcesVector ) {
207 answer.clear();
208 return;
209 }
210
211 FluidDynamicMaterial *mat = static_cast< FluidCrossSection * >( this->giveCrossSection() )->giveFluidMaterial();
212 FloatArray N, gVector, temparray(12);
213
214 load->computeComponentArrayAt(gVector, tStep, VM_Total);
215 temparray.zero();
216 if ( gVector.giveSize() ) {
217 for ( auto &gp: *integrationRulesArray [ 0 ] ) {
218 const FloatArray &lcoords = gp->giveNaturalCoordinates();
219
220 double rho = mat->give('d', gp);
221 double detJ = fabs( this->interpolation_quad.giveTransformationJacobian( lcoords, FEIElementGeometryWrapper(this) ) );
222 double dA = detJ * gp->giveWeight();
223
224 this->interpolation_quad.evalN( N, lcoords, FEIElementGeometryWrapper(this) );
225 for ( int j = 0; j < 6; j++ ) {
226 temparray(2 * j) += N(j) * rho * gVector(0) * dA;
227 temparray(2 * j + 1) += N(j) * rho * gVector(1) * dA;
228 }
229 }
230 }
231
232 answer.resize(15);
233 answer.zero();
234 answer.assemble(temparray, this->momentum_ordering);
235}
236
237 void Tr21Stokes :: computeBoundarySurfaceLoadVector(FloatArray &answer, BoundaryLoad *load, int boundary, CharType type, ValueModeType mode, TimeStep *tStep, bool global)
238{
239 if ( type != ExternalForcesVector ) {
240 answer.clear();
241 return;
242 }
243
244 if ( load->giveType() == TransmissionBC ) { // Neumann boundary conditions (traction)
245
246 int numberOfEdgeIPs = ( int ) ceil( ( load->giveApproxOrder() + 1. ) / 2. ) * 2;
247
248 GaussIntegrationRule iRule(1, this, 1, 1);
249 FloatArray N, t, f(6);
250
251 f.zero();
252 iRule.SetUpPointsOnLine(numberOfEdgeIPs, _Unknown);
253
254 for ( auto &gp: iRule ) {
255 const FloatArray &lcoords = gp->giveNaturalCoordinates();
256
257 this->interpolation_quad.edgeEvalN( N, boundary, lcoords, FEIElementGeometryWrapper(this) );
258 double detJ = fabs( this->interpolation_quad.boundaryGiveTransformationJacobian( boundary, lcoords, FEIElementGeometryWrapper(this) ) );
259 double dS = gp->giveWeight() * detJ;
260
261 if ( load->giveFormulationType() == Load :: FT_Entity ) { // Edge load in xi-eta system
262 load->computeValueAt(t, tStep, lcoords, VM_Total);
263 } else { // Edge load in x-y system
264 FloatArray gcoords;
265 this->interpolation_quad.boundaryLocal2Global( gcoords, boundary, lcoords, FEIElementGeometryWrapper(this) );
266 load->computeValueAt(t, tStep, gcoords, VM_Total);
267 }
268
269 // Reshape the vector
270 for ( int j = 0; j < 3; j++ ) {
271 f(2 * j) += N(j) * t(0) * dS;
272 f(2 * j + 1) += N(j) * t(1) * dS;
273 }
274 }
275
276 answer.resize(15);
277 answer.zero();
278 answer.assemble(f, this->edge_ordering [ boundary - 1 ]);
279 } else {
280 OOFEM_ERROR("Strange boundary condition type");
281 }
282}
283
284void Tr21Stokes :: computeStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, TimeStep *tStep)
285{
286 // Note: Working with the components; [K, G+Dp; G^T+Dv^T, C] . [v,p]
287 FluidDynamicMaterial *mat = static_cast< FluidCrossSection * >( this->giveCrossSection() )->giveFluidMaterial();
289 FloatMatrixF<12,3> G, Dp;
292
293 for ( auto &gp: *integrationRulesArray [ 0 ] ) {
294 const auto &lcoords = gp->giveNaturalCoordinates();
295
296 auto Nlin = this->interpolation_lin.evalN( lcoords );
297 auto detj_dn = this->interpolation_quad.evaldNdx( lcoords, FEIElementGeometryWrapper(this) );
298 auto dN = detj_dn.second;
299 auto detJ = detj_dn.first;
300 auto dA = std::abs(detJ) * gp->giveWeight();
301
302 auto dN_V = flatten(dN);
303 auto B = Bmatrix_2d(dN);
304
305 // Computing the internal forces should have been done first.
306 // dsigma_dev/deps_dev dsigma_dev/dp deps_vol/deps_dev deps_vol/dp
307 //auto [Ed, Ep, Cd, Cp] = mat->computeTangents2D(mode, gp, tStep);
308 auto tangents = mat->computeTangents2D(mode, gp, tStep);
309
310 K.plusProductSymmUpper(B, dot(tangents.dsdd, B), dA);
311 G.plusDyadUnsym(dN_V, Nlin, -dA);
312 Dp.plusDyadUnsym(Tdot(B, tangents.dsdp), Nlin, dA);
313 DvT.plusDyadUnsym(Nlin, Tdot(B, tangents.dedd), dA);
314 C.plusDyadSymmUpper(Nlin, tangents.dedp * dA);
315 }
316
317 K.symmetrized();
318 C.symmetrized();
319 auto GTDvT = transpose(G) + DvT;
320 auto GDp = G + Dp;
321
322 answer.resize(15, 15);
323 answer.zero();
324 answer.assemble(K, this->momentum_ordering);
325 answer.assemble(GTDvT, this->conservation_ordering, this->momentum_ordering);
326 answer.assemble(GDp, this->momentum_ordering, this->conservation_ordering);
327 answer.assemble(C, this->conservation_ordering);
328}
329
330FEInterpolation *Tr21Stokes :: giveInterpolation() const
331{
332 return & interpolation_quad;
333}
334
335FEInterpolation *Tr21Stokes :: giveInterpolation(DofIDItem id) const
336{
337 if ( id == P_f ) {
338 return & interpolation_lin;
339 } else {
340 return & interpolation_quad;
341 }
342}
343
344void Tr21Stokes :: updateYourself(TimeStep *tStep)
345{
346 Element :: updateYourself(tStep);
347}
348
349// Some extension Interfaces to follow:
350
351Interface *Tr21Stokes :: giveInterface(InterfaceType it)
352{
353 switch ( it ) {
355 return static_cast< NodalAveragingRecoveryModelInterface * >(this);
356
358 return static_cast< ZZNodalRecoveryModelInterface * >(this);
359
361 return static_cast< SpatialLocalizerInterface * >(this);
362
363 default:
364 return FMElement :: giveInterface(it);
365 }
366}
367
368void Tr21Stokes :: computeField(ValueModeType mode, TimeStep *tStep, const FloatArray &lcoords, FloatArray &answer)
369{
370 FloatArray n, n_lin, pressures, velocities;
371 this->interpolation_quad.evalN( n, lcoords, FEIElementGeometryWrapper(this) );
372 this->interpolation_lin.evalN( n_lin, lcoords, FEIElementGeometryWrapper(this) );
373 this->computeVectorOf({P_f}, mode, tStep, pressures);
374 this->computeVectorOf({V_u, V_v, V_w}, mode, tStep, velocities);
375
376 answer.resize(4);
377 answer.zero();
378 for ( int i = 1; i <= n.giveSize(); i++ ) {
379 answer(0) += n.at(i) * velocities.at(i*2-1);
380 answer(1) += n.at(i) * velocities.at(i*2);
381 }
382
383 for ( int i = 1; i <= n_lin.giveSize(); i++ ) {
384 answer(2) += n_lin.at(i) * pressures.at(i);
385 }
386}
387
388
389void Tr21Stokes :: NodalAveragingRecoveryMI_computeNodalValue(FloatArray &answer, int node, InternalStateType type, TimeStep *tStep)
390{
391 if ( type == IST_Pressure ) {
392 answer.resize(1);
393 if ( node == 1 || node == 2 || node == 3 ) {
394 answer.at(1) = this->giveNode(node)->giveDofWithID(P_f)->giveUnknown(VM_Total, tStep);
395 } else {
396 double a, b;
397 if ( node == 4 ) {
398 a = this->giveNode(1)->giveDofWithID(P_f)->giveUnknown(VM_Total, tStep);
399 b = this->giveNode(2)->giveDofWithID(P_f)->giveUnknown(VM_Total, tStep);
400 } else if ( node == 5 ) {
401 a = this->giveNode(2)->giveDofWithID(P_f)->giveUnknown(VM_Total, tStep);
402 b = this->giveNode(3)->giveDofWithID(P_f)->giveUnknown(VM_Total, tStep);
403 } else { /*if ( node == 6 )*/
404 a = this->giveNode(3)->giveDofWithID(P_f)->giveUnknown(VM_Total, tStep);
405 b = this->giveNode(1)->giveDofWithID(P_f)->giveUnknown(VM_Total, tStep);
406 }
407
408 answer.at(1) = ( a + b ) / 2;
409 }
410 } else {
411 answer.clear();
412 }
413}
414
415} // end namespace oofem
#define N(a, b)
#define REGISTER_Element(class)
bcType giveType() const override
void computeValueAt(FloatArray &answer, TimeStep *tStep, const FloatArray &coords, ValueModeType mode) override
int giveApproxOrder() override=0
EngngModel * giveEngngModel()
Definition domain.C:419
Node * giveNode(int i) const
Definition element.h:629
IntArray boundaryLoadArray
Definition element.h:147
IntArray * giveBodyLoadArray()
Returns array containing load numbers of loads acting on element.
Definition element.C:411
int numberOfDofMans
Number of dofmanagers.
Definition element.h:136
void computeVectorOf(ValueModeType u, TimeStep *tStep, FloatArray &answer)
Definition element.C:103
std::vector< std ::unique_ptr< IntegrationRule > > integrationRulesArray
Definition element.h:157
int numberOfGaussPoints
Definition element.h:175
CrossSection * giveCrossSection()
Definition element.C:534
IntArray bodyLoadArray
Definition element.h:147
problemScale giveProblemScale() const
Returns scale in multiscale simulation.
Definition engngm.h:447
Domain * domain
Link to domain object, useful for communicating with other FEM components.
Definition femcmpnn.h:79
void computeVectorOfPressures(ValueModeType mode, TimeStep *tStep, FloatArray &pressures)
Definition fmelement.C:51
void computeVectorOfVelocities(ValueModeType mode, TimeStep *tStep, FloatArray &velocities)
Definition fmelement.C:44
FMElement(int n, Domain *aDomain)
Definition fmelement.C:38
void assemble(const FloatArray &fe, const IntArray &loc)
Definition floatarray.C:616
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void add(const FloatArray &src)
Definition floatarray.C:218
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
void zero()
Zeroes all coefficient of receiver.
void assemble(const FloatMatrix &src, const IntArray &loc)
virtual std::pair< FloatArrayF< 3 >, double > computeDeviatoricStress2D(const FloatArrayF< 3 > &eps, double pressure, GaussPoint *gp, TimeStep *tStep) const
virtual Tangents< 3 > computeTangents2D(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const
int SetUpPointsOnLine(int nPoints, MaterialMode mode) override
const FloatArray & giveNaturalCoordinates() const
Returns coordinate array of receiver.
Definition gausspoint.h:138
double giveWeight()
Returns integration weight of receiver.
Definition gausspoint.h:180
virtual bcGeomType giveBCGeoType() const
virtual void computeComponentArrayAt(FloatArray &answer, TimeStep *tStep, ValueModeType mode)
Definition load.C:84
virtual FormulationType giveFormulationType()
Definition load.h:170
virtual double give(int aProperty, GaussPoint *gp) const
Definition material.C:51
SpatialLocalizerInterface(Element *element)
static IntArray momentum_ordering
Ordering of dofs in element. Used to assemble the element stiffness.
Definition tr21stokes.h:68
static IntArray conservation_ordering
Definition tr21stokes.h:68
void computeStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, TimeStep *tStep)
Definition tr21stokes.C:284
void computeBoundarySurfaceLoadVector(FloatArray &answer, BoundaryLoad *load, int boundary, CharType type, ValueModeType mode, TimeStep *tStep, bool global=true) override
Definition tr21stokes.C:237
static FEI2dTrLin interpolation_lin
Interpolation for pressure.
Definition tr21stokes.h:64
static IntArray edge_ordering[3]
Ordering of dofs on edges. Used to assemble edge loads.
Definition tr21stokes.h:70
void computeExternalForcesVector(FloatArray &answer, TimeStep *tStep)
Definition tr21stokes.C:171
void computeInternalForcesVector(FloatArray &answer, TimeStep *tStep)
Definition tr21stokes.C:132
static FEI2dTrQuad interpolation_quad
Interpolation for geometry and velocity.
Definition tr21stokes.h:66
void computeLoadVector(FloatArray &answer, BodyLoad *load, CharType type, ValueModeType mode, TimeStep *tStep) override
Definition tr21stokes.C:204
ZZNodalRecoveryModelInterface(Element *element)
Constructor.
#define OOFEM_ERROR(...)
Definition error.h:79
FloatMatrixF< M, N > transpose(const FloatMatrixF< N, M > &mat)
Constructs transposed matrix.
FloatMatrixF< N, P > Tdot(const FloatMatrixF< M, N > &a, const FloatMatrixF< M, P > &b)
Computes .
bcGeomType
Type representing the geometric character of loading.
Definition bcgeomtype.h:40
@ BodyLoadBGT
Distributed body load.
Definition bcgeomtype.h:43
@ EdgeLoadBGT
Distributed edge load.
Definition bcgeomtype.h:44
FloatMatrixF< 3, N *2 > Bmatrix_2d(const FloatMatrixF< 2, N > &dN)
Constructs the B matrix for plane stress momentum balance problems.
double dot(const FloatArray &x, const FloatArray &y)
@ ForceLoadBVT
Definition bcvaltype.h:43
@ ZZNodalRecoveryModelInterfaceType
@ SpatialLocalizerInterfaceType
@ NodalAveragingRecoveryModelInterfaceType
@ TransmissionBC
Neumann type (prescribed flux).
Definition bctype.h:43
FloatArrayF< N *M > flatten(const FloatMatrixF< N, M > &m)
@ macroScale
Definition problemmode.h:46

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011