OOFEM 3.0
Loading...
Searching...
No Matches
tr1bubblestokes.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 "tr1bubblestokes.h"
36#include "node.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 "masterdof.h"
49#include "fluidcrosssection.h"
50#include "classfactory.h"
51
52namespace oofem {
54
55// Set up interpolation coordinates
56FEI2dTrLin Tr1BubbleStokes :: interp(1, 2);
57// Set up ordering vectors (for assembling)
58IntArray Tr1BubbleStokes :: momentum_ordering = {1, 2, 4, 5, 7, 8, 10, 11};
59IntArray Tr1BubbleStokes :: conservation_ordering = {3, 6, 9};
60IntArray Tr1BubbleStokes :: edge_ordering [ 3 ] = {
61 {1, 2, 4, 5},
62 {4, 5, 7, 8},
63 {7, 8, 1, 2}
64};
65
66Tr1BubbleStokes :: Tr1BubbleStokes(int n, Domain *aDomain) : FMElement(n, aDomain), ZZNodalRecoveryModelInterface(this), SpatialLocalizerInterface(this)
67{
68 this->numberOfDofMans = 3;
69 this->numberOfGaussPoints = 7;
70
71 this->bubble = std::make_unique<ElementDofManager>(1, aDomain, this);
72 this->bubble->appendDof( new MasterDof(this->bubble.get(), V_u) );
73 this->bubble->appendDof( new MasterDof(this->bubble.get(), V_v) );
74}
75
76void Tr1BubbleStokes :: computeGaussPoints()
77{
78 if ( integrationRulesArray.size() == 0 ) {
79 integrationRulesArray.resize(1);
80 integrationRulesArray [ 0 ] = std::make_unique<GaussIntegrationRule>(1, this, 1, 3);
81 this->giveCrossSection()->setupIntegrationPoints(* integrationRulesArray [ 0 ], this->numberOfGaussPoints, this);
82 }
83}
84
85int Tr1BubbleStokes :: computeNumberOfDofs()
86{
87 return 11;
88}
89
90void Tr1BubbleStokes :: giveDofManDofIDMask(int inode, IntArray &answer) const
91{
92 answer = {V_u, V_v, P_f};
93}
94
95void Tr1BubbleStokes :: giveInternalDofManDofIDMask(int i, IntArray &answer) const
96{
97 answer = {V_u, V_v};
98}
99
100int Tr1BubbleStokes :: giveNumberOfInternalDofManagers() const
101{
102 return 1;
103
104}
105
106DofManager *Tr1BubbleStokes :: giveInternalDofManager(int i) const
107{
108 return this->bubble.get();
109}
110
111double Tr1BubbleStokes :: computeVolumeAround(GaussPoint *gp)
112{
113 double detJ = fabs( this->interp.giveTransformationJacobian( gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(this) ) );
114 return detJ *gp->giveWeight();
115}
116
117void Tr1BubbleStokes :: giveCharacteristicVector(FloatArray &answer, CharType mtrx, ValueModeType mode,
118 TimeStep *tStep)
119{
120 // Compute characteristic vector for this element. I.e the load vector(s)
121 if ( mtrx == ExternalForcesVector ) {
122 this->computeExternalForcesVector(answer, tStep);
123 } else if ( mtrx == InternalForcesVector ) {
124 this->computeInternalForcesVector(answer, tStep);
125 } else {
126 OOFEM_ERROR("Unknown Type of characteristic mtrx.");
127 }
128}
129
130void Tr1BubbleStokes :: giveCharacteristicMatrix(FloatMatrix &answer,
131 CharType mtrx, TimeStep *tStep)
132{
133 if ( mtrx == TangentStiffnessMatrix ) {
134 this->computeStiffnessMatrix(answer, TangentStiffness, tStep);
135 } else {
136 OOFEM_ERROR("Unknown Type of characteristic mtrx.");
137 }
138}
139
140void Tr1BubbleStokes :: computeInternalForcesVector(FloatArray &answer, TimeStep *tStep)
141{
142 FluidDynamicMaterial *mat = static_cast< FluidCrossSection * >( this->giveCrossSection() )->giveFluidMaterial();
143
144 FloatArrayF<8> a_velocity = this->computeVectorOfVelocities(VM_Total, tStep);
145 FloatArrayF<3> a_pressure = this->computeVectorOfPressures(VM_Total, tStep);
146
147 FloatArrayF<8> momentum;
148 FloatArrayF<3> conservation;
149
150 for ( auto &gp: *integrationRulesArray [ 0 ] ) {
151 const auto &lcoords = gp->giveNaturalCoordinates();
152
153 auto N = this->interp.evalN( lcoords );
154 auto val = this->interp.evaldNdx( FEIElementGeometryWrapper(this) );
155 auto detJ = val.first;
156 auto dN = val.second;
157 auto dA = std::abs(detJ) * gp->giveWeight();
158
159 FloatArrayF<8> dNv;
161 for ( int j = 0, k = 0; j < 3; j++, k += 2 ) {
162 dNv[k] = B(0, k) = B(2, k + 1) = dN(0, j);
163 dNv[k + 1] = B(1, k + 1) = B(2, k) = dN(1, j);
164 }
165
166 // Bubble contribution;
167 dNv[6] = B(0, 6) = B(2, 7) = 27. * ( dN(0, 0) * N[1] * N[2] + N[0] * dN(1, 0) * N[2] + N[0] * N[1] * dN(2, 0) );
168 dNv[7] = B(1, 7) = B(2, 6) = 27. * ( dN(0, 1) * N[1] * N[2] + N[0] * dN(1, 1) * N[2] + N[0] * N[1] * dN(2, 1) );
169
170 auto pressure = dot(N, a_pressure);
171 auto epsp = dot(B, a_velocity);
172
173 auto s_r = mat->computeDeviatoricStress2D(epsp, pressure, gp, tStep);
174 auto devStress = s_r.first;
175 auto r_vol = s_r.second;
176
177 momentum += Tdot(B, devStress * dA) + dNv * (-pressure * dA);
178 conservation += N * (r_vol * dA);
179 }
180
181 answer.resize(11);
182 answer.zero();
183 answer.assemble(momentum, this->momentum_ordering);
184 answer.assemble(conservation, this->conservation_ordering);
185}
186
187void Tr1BubbleStokes :: computeExternalForcesVector(FloatArray &answer, TimeStep *tStep)
188{
189 FloatArray vec;
190
191 int nLoads = this->boundaryLoadArray.giveSize() / 2;
192 answer.resize(11);
193 answer.zero();
194 for ( int i = 1; i <= nLoads; i++ ) { // For each Neumann boundary condition
195 int load_number = this->boundaryLoadArray.at(2 * i - 1);
196 int load_id = this->boundaryLoadArray.at(2 * i);
197 Load *load = this->domain->giveLoad(load_number);
198 bcGeomType ltype = load->giveBCGeoType();
199
200 if ( ltype == EdgeLoadBGT ) {
201 this->computeBoundarySurfaceLoadVector(vec, static_cast< BoundaryLoad * >(load), load_id, ExternalForcesVector, VM_Total, tStep);
202 answer.add(vec);
203 }
204 }
205
206 nLoads = this->giveBodyLoadArray()->giveSize();
207 for ( int i = 1; i <= nLoads; i++ ) {
208 Load *load = domain->giveLoad( bodyLoadArray.at(i) );
209 BodyLoad *bLoad;
210 if ((bLoad = dynamic_cast<BodyLoad*>(load))) {
211 bcGeomType ltype = load->giveBCGeoType();
212 if ( ltype == BodyLoadBGT && load->giveBCValType() == ForceLoadBVT ) {
213 this->computeLoadVector(vec, bLoad, ExternalForcesVector, VM_Total, tStep);
214 answer.add(vec);
215 }
216 }
217 }
218}
219
220
221void Tr1BubbleStokes :: computeLoadVector(FloatArray &answer, BodyLoad *load, CharType type, ValueModeType mode, TimeStep *tStep)
222{
223 if ( type != ExternalForcesVector ) {
224 answer.clear();
225 return;
226 }
227
228 FloatArray N, gVector, temparray(8);
229
230 load->computeComponentArrayAt(gVector, tStep, VM_Total);
231 temparray.zero();
232 if ( gVector.giveSize() ) {
233 for ( auto &gp: *integrationRulesArray [ 0 ] ) {
234 const FloatArray &lcoords = gp->giveNaturalCoordinates();
235
236 double rho = static_cast< FluidCrossSection * >( this->giveCrossSection() )->giveDensity(gp);
237 double detJ = fabs( this->interp.giveTransformationJacobian( lcoords, FEIElementGeometryWrapper(this) ) );
238 double dA = detJ * gp->giveWeight();
239
240 this->interp.evalN( N, lcoords, FEIElementGeometryWrapper(this) );
241 for ( int j = 0; j < 3; j++ ) {
242 temparray(2 * j) += N(j) * rho * gVector(0) * dA;
243 temparray(2 * j + 1) += N(j) * rho * gVector(1) * dA;
244 }
245
246 temparray(6) += N(0) * N(1) * N(2) * rho * gVector(0) * dA;
247 temparray(7) += N(0) * N(1) * N(2) * rho * gVector(1) * dA;
248 }
249 }
250
251 answer.resize(11);
252 answer.zero();
253 answer.assemble(temparray, this->momentum_ordering);
254}
255
256 void Tr1BubbleStokes :: computeBoundarySurfaceLoadVector(FloatArray &answer, BoundaryLoad *load, int iEdge, CharType type, ValueModeType mode, TimeStep *tStep, bool global)
257{
258 if ( type != ExternalForcesVector ) {
259 answer.clear();
260 return;
261 }
262
263 if ( load->giveType() == TransmissionBC ) { // Neumann boundary conditions (traction)
264
265 int numberOfEdgeIPs = ( int ) ceil( ( load->giveApproxOrder() + 2. ) / 2. );
266
267 GaussIntegrationRule iRule(1, this, 1, 1);
268 FloatArray N, t, f(4);
269
270 f.zero();
271 iRule.SetUpPointsOnLine(numberOfEdgeIPs, _Unknown);
272
273 for ( auto &gp: iRule ) {
274 const FloatArray &lcoords = gp->giveNaturalCoordinates();
275
276 this->interp.edgeEvalN( N, iEdge, lcoords, FEIElementGeometryWrapper(this) );
277 double detJ = fabs( this->interp.boundaryGiveTransformationJacobian( iEdge, lcoords, FEIElementGeometryWrapper(this) ) );
278 double dS = gp->giveWeight() * detJ;
279
280 if ( load->giveFormulationType() == Load :: FT_Entity ) { // Edge load in xi-eta system
281 load->computeValueAt(t, tStep, lcoords, VM_Total);
282 } else { // Edge load in x-y system
283 FloatArray gcoords;
284 this->interp.boundaryLocal2Global( gcoords, iEdge, lcoords, FEIElementGeometryWrapper(this) );
285 load->computeValueAt(t, tStep, gcoords, VM_Total);
286 }
287
288 // Reshape the vector
289 for ( int j = 0; j < 2; j++ ) {
290 f(2 * j) += N(j) * t(0) * dS;
291 f(2 * j + 1) += N(j) * t(1) * dS;
292 }
293 }
294
295 answer.resize(11);
296 answer.zero();
297 answer.assemble(f, this->edge_ordering [ iEdge - 1 ]);
298 } else {
299 OOFEM_ERROR("Strange boundary condition type");
300 }
301}
302
303void Tr1BubbleStokes :: computeStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, TimeStep *tStep)
304{
305 // Note: Working with the components; [K, G+Dp; G^T+Dv^T, C] . [v,p]
306 FluidDynamicMaterial *mat = static_cast< FluidCrossSection * >( this->giveCrossSection() )->giveFluidMaterial();
308 FloatMatrixF<8,3> G, Dp;
311
312 for ( auto &gp: *integrationRulesArray [ 0 ] ) {
313 // Compute Gauss point and determinant at current element
314 const auto &lcoords = gp->giveNaturalCoordinates();
315
316 auto N = this->interp.evalN( lcoords );
317 auto detj_dn = this->interp.evaldNdx( FEIElementGeometryWrapper(this) );
318 auto dN = detj_dn.second;
319 auto detJ = detj_dn.first;
320 auto dA = std::abs(detJ) * gp->giveWeight();
321
322 FloatArrayF<8> dN_V;
324 for ( int j = 0, k = 0; j < 3; j++, k += 2 ) {
325 dN_V[k] = B(0, k) = B(2, k + 1) = dN(0, j);
326 dN_V[k + 1] = B(1, k + 1) = B(2, k) = dN(1, j);
327 }
328
329 // Bubble contribution;
330 dN_V[6] = B(0, 6) = B(2, 7) = 27. * ( dN(0, 0) * N[1] * N[2] + N[0] * dN(1, 0) * N[2] + N[0] * N[1] * dN(2, 0) );
331 dN_V[7] = B(1, 7) = B(2, 6) = 27. * ( dN(0, 1) * N[1] * N[2] + N[0] * dN(1, 1) * N[2] + N[0] * N[1] * dN(2, 1) );
332
333 // Computing the internal forces should have been done first.
334 // dsigma_dev/deps_dev dsigma_dev/dp deps_vol/deps_dev deps_vol/dp
335 //auto [Ed, Ep, Cd, Cp] = mat->computeTangents2D(mode, gp, tStep);
336 auto tangents = mat->computeTangents2D(mode, gp, tStep);
337
338 K.plusProductSymmUpper(B, dot(tangents.dsdd, B), dA);
339 G.plusDyadUnsym(dN_V, N, -dA);
340 Dp.plusDyadUnsym(Tdot(B, tangents.dsdp), N, dA);
341 DvT.plusDyadUnsym(N, Tdot(B, tangents.dedd), dA);
342 C.plusDyadSymmUpper(N, tangents.dedp * dA);
343 }
344
345 K.symmetrized();
346 C.symmetrized();
347 auto GTDvT = transpose(G) + DvT;
348 auto GDp = G + Dp;
349
350 answer.resize(11, 11);
351 answer.zero();
352 answer.assemble(K, this->momentum_ordering);
353 answer.assemble(GTDvT, this->conservation_ordering, this->momentum_ordering);
354 answer.assemble(GDp, this->momentum_ordering, this->conservation_ordering);
355 answer.assemble(C, this->conservation_ordering);
356}
357
358FEInterpolation *Tr1BubbleStokes :: giveInterpolation() const
359{
360 return & interp;
361}
362
363FEInterpolation *Tr1BubbleStokes :: giveInterpolation(DofIDItem id) const
364{
365 return & interp;
366}
367
368void Tr1BubbleStokes :: updateYourself(TimeStep *tStep)
369{
370 Element :: updateYourself(tStep);
371}
372
373// Some extension Interfaces to follow:
374
375Interface *Tr1BubbleStokes :: giveInterface(InterfaceType it)
376{
377 switch ( it ) {
379 return static_cast< ZZNodalRecoveryModelInterface * >(this);
380
382 return static_cast< SpatialLocalizerInterface * >(this);
383
384 default:
385 return FMElement :: giveInterface(it);
386 }
387}
388
389void Tr1BubbleStokes :: computeField(ValueModeType mode, TimeStep *tStep, const FloatArray &lcoords, FloatArray &answer)
390{
391 FloatArray n, n_lin, pressures, velocities;
392 this->interp.evalN( n, lcoords, FEIElementGeometryWrapper(this) );
393 this->interp.evalN( n_lin, lcoords, FEIElementGeometryWrapper(this) );
394 this->computeVectorOf({P_f}, mode, tStep, pressures);
395 this->computeVectorOf({V_u, V_v}, mode, tStep, velocities);
396
397 answer.resize(3);
398 answer.zero();
399 for ( int i = 1; i <= n.giveSize(); i++ ) {
400 answer(0) += n.at(i) * velocities.at(i*2-1);
401 answer(1) += n.at(i) * velocities.at(i*2);
402 }
403 answer(0) += n.at(1) * n.at(2) * n.at(3) * velocities.at(7);
404 answer(1) += n.at(1) * n.at(2) * n.at(3) * velocities.at(8);
405
406 for ( int i = 1; i <= n_lin.giveSize(); i++ ) {
407 answer(2) += n_lin.at(i) * pressures.at(i);
408 }
409}
410
411} // 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
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
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
SpatialLocalizerInterface(Element *element)
void computeInternalForcesVector(FloatArray &answer, TimeStep *tStep)
void computeLoadVector(FloatArray &answer, BodyLoad *load, CharType type, ValueModeType mode, TimeStep *tStep) override
void computeStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, TimeStep *tStep)
static IntArray momentum_ordering
Ordering of dofs in element. Used to assemble the element stiffness.
static IntArray edge_ordering[3]
Ordering of dofs on edges. Used to assemble edge loads.
void computeExternalForcesVector(FloatArray &answer, TimeStep *tStep)
void computeBoundarySurfaceLoadVector(FloatArray &answer, BoundaryLoad *load, int boundary, CharType type, ValueModeType mode, TimeStep *tStep, bool global=true) override
static IntArray conservation_ordering
std ::unique_ptr< ElementDofManager > bubble
The extra dofs from the bubble.
static FEI2dTrLin interp
Interpolation for pressure.
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
double dot(const FloatArray &x, const FloatArray &y)
@ ForceLoadBVT
Definition bcvaltype.h:43
@ ZZNodalRecoveryModelInterfaceType
@ SpatialLocalizerInterfaceType
@ TransmissionBC
Neumann type (prescribed flux).
Definition bctype.h:43

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