OOFEM 3.0
Loading...
Searching...
No Matches
mixedgradientpressuredirichlet.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
37#include "dofiditem.h"
38#include "dofmanager.h"
39#include "dof.h"
40#include "valuemodetype.h"
41#include "floatarray.h"
42#include "floatmatrix.h"
43#include "engngm.h"
44#include "node.h"
45#include "activedof.h"
46#include "masterdof.h"
47#include "classfactory.h"
48#include "sparsemtrxtype.h"
49#include "sparsemtrx.h"
50#include "sparselinsystemnm.h"
51#include "dynamicinputrecord.h"
52#include "domain.h"
54#include "assemblercallback.h"
55
56#ifdef _OPENMP
57#include <omp.h>
58#endif
59
60namespace oofem {
62
63MixedGradientPressureDirichlet :: MixedGradientPressureDirichlet(int n, Domain *d) : MixedGradientPressureBC(n, d),
64 voldman( new Node(1, d) ),
65 devdman( new Node(2, d) )
66{
68 // The unknown volumetric strain
70 voldman->appendDof( new MasterDof( voldman.get(), (DofIDItem)vol_id ) );
71
72 int nsd = d->giveNumberOfSpatialDimensions();
73 int components = ( nsd + 1 ) * nsd / 2;
74 // The prescribed strains.
75 dev_id.clear();
76 for ( int i = 0; i < components; i++ ) {
77 int dofid = d->giveNextFreeDofID();
78 dev_id.followedBy(dofid);
79 // Just putting in X_i id-items since they don't matter.
80 // These don't actually need to be active, they are masterdofs with prescribed values, its
81 // easier to just have them here rather than trying to make another Dirichlet boundary condition.
82 devdman->appendDof( new ActiveDof( devdman.get(), (DofIDItem)dofid, this->giveNumber() ) );
83 }
84}
85
86
87MixedGradientPressureDirichlet :: ~MixedGradientPressureDirichlet()
88{
89}
90
91
92Dof *MixedGradientPressureDirichlet :: giveVolDof()
93{
94 return *voldman->begin();
95}
96
97
98int MixedGradientPressureDirichlet :: giveNumberOfInternalDofManagers()
99{
100 return 2;
101}
102
103
104DofManager *MixedGradientPressureDirichlet :: giveInternalDofManager(int i)
105{
106 if ( i == 1 ) {
107 return this->voldman.get();
108 } else {
109 return this->devdman.get();
110 }
111}
112
113
114int MixedGradientPressureDirichlet :: giveNumberOfMasterDofs(ActiveDof *dof)
115{
116 if ( this->isDevDof(dof) ) {
117 return 1;
118 }
119 return devdman->giveNumberOfDofs() + 1;
120}
121
122
123Dof *MixedGradientPressureDirichlet :: giveMasterDof(ActiveDof *dof, int mdof)
124{
125 if ( this->isDevDof(dof) ) {
126 return NULL;
127 }
128 if ( mdof == 1 ) {
129 return *voldman->begin();
130 } else {
131 return devdman->giveDofWithID(dev_id[mdof - 2]);
132 }
133}
134
135
136void MixedGradientPressureDirichlet :: computeDofTransformation(ActiveDof *dof, FloatArray &masterContribs)
137{
138 DofIDItem id = dof->giveDofID();
139 const auto &coords = dof->giveDofManager()->giveCoordinates();
140
141 FloatArray dx;
142 dx.beDifferenceOf(coords, this->centerCoord);
143
144 int nsd = dx.giveSize(); // Number of spatial dimensions
145
146 masterContribs.resize(devdman->giveNumberOfDofs() + 1);
147
148 if ( id == D_u || id == V_u ) {
149 masterContribs.at(1) = dx.at(1) / 3.0; // d_vol
150 if ( nsd == 2 ) {
151 masterContribs.at(2) = dx.at(1); // d_dev_11
152 masterContribs.at(3) = 0.0; // d_dev_22
153 masterContribs.at(4) = dx.at(2) / 2.0; // gamma_12
154 } else if ( nsd == 3 ) {
155 masterContribs.at(2) = dx.at(1); // d_dev_11
156 masterContribs.at(3) = 0.0; // d_dev_22
157 masterContribs.at(4) = 0.0; // d_dev_33
158 masterContribs.at(5) = 0.0; // gamma_23
159 masterContribs.at(6) = dx.at(3) / 2.0; // gamma_13
160 masterContribs.at(7) = dx.at(2) / 2.0; // gamma_12
161 }
162 } else if ( id == D_v || id == V_v ) {
163 masterContribs.at(1) = dx.at(2) / 3.0; // d_vol
164 masterContribs.at(2) = 0.0; // d_dev_11
165 masterContribs.at(3) = dx.at(2); // d_dev_22
166 masterContribs.at(4) = dx.at(1) / 2.0; // gamma_12
167 if ( nsd == 3 ) {
168 masterContribs.at(2) = 0.0; // d_dev_11
169 masterContribs.at(3) = dx.at(2); // d_dev_22
170 masterContribs.at(4) = 0.0; // d_dev_33
171 masterContribs.at(5) = dx.at(3) / 2.0; // gamma_23
172 masterContribs.at(6) = 0.0; // gamma_13
173 masterContribs.at(7) = dx.at(1) / 2.0; // gamma_12
174 }
175 } else if ( id == D_w || id == V_w ) { // 3D only:
176 masterContribs.at(1) = dx.at(3) / 3.0; // d_vol
177 masterContribs.at(2) = 0.0; // d_dev_11
178 masterContribs.at(3) = 0.0; // d_dev_22
179 masterContribs.at(4) = dx.at(3); // d_dev_33
180 masterContribs.at(5) = dx.at(2) / 2.0; // gamma_23
181 masterContribs.at(6) = dx.at(1) / 2.0; // gamma_13
182 masterContribs.at(7) = 0.0; // gamma_12
183 } else {
184 OOFEM_ERROR("Incompatible id on subjected dof");
185 }
186}
187
188
189double MixedGradientPressureDirichlet :: giveUnknown(double vol, const FloatArray &dev, ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
190{
191 DofIDItem id = dof->giveDofID();
192 const auto &coords = dof->giveDofManager()->giveCoordinates();
193
194 FloatArray dx;
195 dx.beDifferenceOf(coords, this->centerCoord);
196
197 int nsd = dx.giveSize(); // Number of spatial dimensions
198
199 double dev11, dev22, dev33 = 0., dev12, dev23 = 0., dev13 = 0.;
200 if ( nsd == 2 ) {
201 dev11 = dev.at(1);
202 dev22 = dev.at(2);
203 dev12 = dev.at(3) * 0.5;
204 } else { /*if (nsd == 3)*/
205 dev11 = dev.at(1);
206 dev22 = dev.at(2);
207 dev33 = dev.at(3);
208 dev23 = dev.at(4) * 0.5;
209 dev13 = dev.at(5) * 0.5;
210 dev12 = dev.at(6) * 0.5;
211 }
212
213 double val;
214 if ( id == D_u || id == V_u ) {
215 val = dx.at(1) / 3.0 * vol;
216 if ( nsd >= 2 ) {
217 val += dx.at(1) * dev11 + dx.at(2) * dev12;
218 }
219 if ( nsd == 3 ) {
220 val += dx.at(3) * dev13;
221 }
222 } else if ( id == D_v || id == V_v ) {
223 val = dx.at(2) / 3.0 * vol + dx.at(1) * dev12 + dx.at(2) * dev22;
224 if ( nsd == 3 ) {
225 val += dx.at(3) * dev23;
226 }
227 } else { /*if ( id == D_w || id == V_w )*/ // 3D only:
228 val = dx.at(3) / 3.0 * vol + dx.at(1) * dev13 + dx.at(2) * dev23 + dx.at(3) * dev33;
229 }
230 return val;
231}
232
233
234void MixedGradientPressureDirichlet :: computeFields(FloatArray &sigmaDev, double &vol, TimeStep *tStep)
235{
236 EngngModel *emodel = this->giveDomain()->giveEngngModel();
237 FloatArray tmp;
238 vol = this->giveVolDof()->giveUnknown(VM_Total, tStep);
240 // sigma = residual (since we use the slave dofs) = f_ext - f_int
241 sigmaDev.resize(npeq);
242 sigmaDev.zero();
243 emodel->assembleVector(sigmaDev, tStep, InternalForceAssembler(), VM_Total, EModelDefaultPrescribedEquationNumbering(), this->domain);
244 tmp.resize(npeq);
245 tmp.zero();
247 sigmaDev.subtract(tmp);
248 // Divide by the RVE-volume
249 sigmaDev.times( 1.0 / this->domainSize() );
250 // Above, full sigma = sigmaDev - p*I is assembled, so to obtain the deviatoric part we add p to the diagonal part.
251 int nsd = this->domain->giveNumberOfSpatialDimensions();
252 for ( int i = 1; i <= nsd; ++i ) {
253 sigmaDev.at(i) += this->pressure;
254 }
255}
256
257
258void MixedGradientPressureDirichlet :: computeTangents(FloatMatrix &Ed, FloatArray &Ep, FloatArray &Cd, double &Cp, TimeStep *tStep)
259{
260 double rve_size = this->domainSize();
261 // Fetch some information from the engineering model
262 EngngModel *rve = this->giveDomain()->giveEngngModel();
264 std :: unique_ptr< SparseLinearSystemNM > solver(
265 classFactory.createSparseLinSolver( ST_Petsc, this->domain, this->domain->giveEngngModel() ) ); // = rve->giveLinearSolver();
266 SparseMtrxType stype = solver->giveRecommendedMatrix(true);
269
270 // Set up and assemble tangent FE-matrix which will make up the sensitivity analysis for the macroscopic material tangent.
271 FloatMatrix ddev_pert;
272 FloatMatrix rhs_d; // RHS for d_dev [d_dev11, d_dev22, d_dev12] in 2D
273 FloatMatrix s_d; // Sensitivity fields for d_dev
274 FloatArray rhs_p; // RHS for pressure
275 FloatArray s_p; // Sensitivity fields for p
276
277 // Indices and such of internal dofs
278 int dvol_eq = this->giveVolDof()->giveEqn();
279 int ndev = this->devGradient.giveSize();
280
281 {
282 // Sets up RHS for all sensitivity problems;
283 std :: unique_ptr< SparseMtrx > Kfp( classFactory.createSparseMtrx(stype) );
284 Kfp->buildInternalStructure(rve, 1, fnum, pnum);
285 rve->assemble(*Kfp, tStep, TangentAssembler(TangentStiffness), fnum, pnum, this->domain);
286
287 // Setup up indices and locations
288 int neq = Kfp->giveNumberOfRows();
289 // Matrices and arrays for sensitivities
290 int npeq = Kfp->giveNumberOfColumns();
291
292 if ( npeq != ndev ) {
293 OOFEM_ERROR("Size mismatch, ndev != npeq");
294 }
295
296 // Unit pertubations for d_dev
297 ddev_pert.resize(ndev, ndev); // In fact, npeq should most likely equal ndev
298 ddev_pert.zero();
299 for ( int i = 1; i <= ndev; ++i ) {
300 int eqn = this->devdman->giveDofWithID(dev_id.at(i))->__givePrescribedEquationNumber();
301 ddev_pert.at(eqn, i) = -1.0; // Minus sign for moving it to the RHS
302 }
303 Kfp->times(ddev_pert, rhs_d);
304 s_d.resize(neq, ndev);
305
306 // Sensitivity analysis for p (already in rhs, just set value directly)
307 rhs_p.resize(neq);
308 rhs_p.zero();
309 rhs_p.at(dvol_eq) = -1.0 * rve_size; // dp = 1.0 (unit size)
310 s_p.resize(neq);
311 }
312
313 {
314 // Solve all sensitivities
315 std :: unique_ptr< SparseMtrx > Kff( classFactory.createSparseMtrx(stype) );
316 if ( !Kff ) {
317 OOFEM_ERROR("MixedGradientPressureDirichlet :: computeTangents - Couldn't create sparse matrix of type %d\n", stype);
318 }
319 Kff->buildInternalStructure(rve, 1, fnum);
320 rve->assemble(*Kff, tStep, TangentAssembler(TangentStiffness), fnum, this->domain);
321 solver->solve(*Kff, rhs_p, s_p);
322 solver->solve(*Kff, rhs_d, s_d);
323 }
324
325 // Sensitivities for d_vol is solved for directly;
326 Cp = - s_p.at(dvol_eq); // Note: Defined with negative sign de = - C * dp
327 Cd.resize(ndev);
328 for ( int i = 1; i <= ndev; ++i ) {
329 Cd.at(i) = s_d.at(dvol_eq, i); // Copy over relevant row from solution
330 }
331
332 {
333 // Sensitivities for d_dev is obtained as reactions forces;
334 std :: unique_ptr< SparseMtrx > Kpf( classFactory.createSparseMtrx(stype) );
335 std :: unique_ptr< SparseMtrx > Kpp( classFactory.createSparseMtrx(stype) );
336 Kpf->buildInternalStructure(rve, 1, pnum, fnum);
337 Kpp->buildInternalStructure(rve, 1, pnum);
338 rve->assemble(*Kpf, tStep, TangentAssembler(TangentStiffness), pnum, fnum, this->domain);
339 rve->assemble(*Kpp, tStep, TangentAssembler(TangentStiffness), pnum, this->domain);
340
341 FloatMatrix tmpMat;
342 Kpp->times(ddev_pert, tmpMat);
343 Kpf->times(s_d, Ed);
344 Ed.subtract(tmpMat);
345 Ed.times(1.0 / rve_size);
346 Kpf->times(s_p, Ep);
347 Ep.times(1.0 / rve_size);
348 }
349
350 // Not sure if i actually need to do this part, but the obtained tangents are to dsigma/dp, not dsigma_dev/dp, so they need to be corrected;
351 int nsd = this->domain->giveNumberOfSpatialDimensions();
352 for ( int i = 1; i <= nsd; ++i ) {
353 Ep.at(i) += 1.0;
354 Cd.at(i) += 1.0;
355 }
356
357#if 0
358 // Makes Ed 4th order deviatoric, in Voigt form (!)
359 for ( int i = 1; i <= Ed.giveNumberOfColumns(); ++i ) {
360 // Take the mean of the "diagonal" part of each column
361 double mean = 0.0;
362 for ( int j = 1; j <= nsd; ++j ) {
363 mean += Ed.at(i, j);
364 }
365 mean /= ( double ) nsd;
366 // And subtract it from that column
367 for ( int j = 1; j <= nsd; ++j ) {
368 Ed.at(i, j) -= mean;
369 }
370 }
371#endif
372}
373
374
375double MixedGradientPressureDirichlet :: giveUnknown(PrimaryField &field, ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
376{
377 if ( this->isDevDof(dof) ) {
378 return this->devGradient( dev_id.findFirstIndexOf(dof->giveDofID()) );
379 }
380 return this->giveUnknown(this->giveVolDof()->giveUnknown(field, mode, tStep), this->devGradient, mode, tStep, dof);
381}
382
383
384double MixedGradientPressureDirichlet :: giveUnknown(ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
385{
386 if ( this->isDevDof(dof) ) {
387 return this->devGradient( dev_id.findFirstIndexOf(dof->giveDofID()) );
388 }
389 return this->giveUnknown(this->giveVolDof()->giveUnknown(mode, tStep), this->devGradient, mode, tStep, dof);
390}
391
392
393void MixedGradientPressureDirichlet :: setPrescribedDeviatoricGradientFromVoigt(const FloatArray &t)
394{
395 devGradient = t;
396}
397
398
399void MixedGradientPressureDirichlet :: assembleVector(FloatArray &answer, TimeStep *tStep,
400 CharType type, ValueModeType mode,
401 const UnknownNumberingScheme &s,
402 FloatArray *eNorms,
403 void* lock)
404{
405 if ( type != ExternalForcesVector ) {
406 return;
407 }
408
409 Dof *vol = this->giveVolDof();
410 int vol_loc = vol->giveEquationNumber(s);
411 if ( vol_loc ) {
412 double rve_size = this->domainSize();
413#ifdef _OPENMP
414 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
415#endif
416 answer.at(vol_loc) -= rve_size * pressure; // Note the negative sign (pressure as opposed to mean stress)
417 if ( eNorms ) {
418 eNorms->at( vol->giveDofID() ) = rve_size * pressure * rve_size * pressure;
419 }
420#ifdef _OPENMP
421 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
422#endif
423 }
424}
425
426
427bool MixedGradientPressureDirichlet :: isPrimaryDof(ActiveDof *dof)
428{
429 return this->isDevDof(dof);
430}
431
432
433double MixedGradientPressureDirichlet :: giveBcValue(Dof *dof, ValueModeType mode, TimeStep *tStep)
434{
435 if ( this->isDevDof(dof) ) {
436 return this->devGradient( dev_id.findFirstIndexOf(dof->giveDofID()) );
437 }
438 OOFEM_ERROR("Has no prescribed value from bc.");
439 //return 0.0;
440}
441
442
443bool MixedGradientPressureDirichlet :: hasBc(Dof *dof, TimeStep *tStep)
444{
445 return this->isDevDof(dof);
446}
447
448
449bool MixedGradientPressureDirichlet :: isDevDof(Dof *dof)
450{
451 return devdman.get() == dof->giveDofManager();
452}
453
454
455void MixedGradientPressureDirichlet :: initializeFrom(InputRecord &ir)
456{
457 MixedGradientPressureBC :: initializeFrom(ir);
458
459 this->centerCoord.resize( domain->giveNumberOfSpatialDimensions() );
460 this->centerCoord.zero();
462}
463
464
465void MixedGradientPressureDirichlet :: giveInputRecord(DynamicInputRecord &input)
466{
467 MixedGradientPressureBC :: giveInputRecord(input);
471}
472} // end namespace oofem
#define REGISTER_BoundaryCondition(class)
const FloatArray & giveCoordinates() const
Definition dofmanager.h:390
DofIDItem giveDofID() const
Definition dof.h:276
int giveEquationNumber(const UnknownNumberingScheme &s)
Definition dof.C:56
DofManager * giveDofManager() const
Definition dof.h:123
int giveNextFreeDofID(int increment=1)
Definition domain.C:1519
int giveNumberOfSpatialDimensions()
Returns number of spatial dimensions.
Definition domain.C:1137
void setField(int item, InputFieldType id)
virtual int giveNumberOfDomainEquations(int di, const UnknownNumberingScheme &num)
Definition engngm.C:452
virtual void assemble(SparseMtrx &answer, TimeStep *tStep, const MatrixAssembler &ma, const UnknownNumberingScheme &s, Domain *domain)
Definition engngm.C:889
void assembleVector(FloatArray &answer, TimeStep *tStep, const VectorAssembler &va, ValueModeType mode, const UnknownNumberingScheme &s, Domain *domain, FloatArray *eNorms=NULL)
Definition engngm.C:1106
Domain * giveDomain() const
Definition femcmpnn.h:97
Domain * domain
Link to domain object, useful for communicating with other FEM components.
Definition femcmpnn.h:79
int giveNumber() const
Definition femcmpnn.h:104
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 beDifferenceOf(const FloatArray &a, const FloatArray &b)
Definition floatarray.C:403
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void subtract(const FloatArray &src)
Definition floatarray.C:320
void times(double s)
Definition floatarray.C:834
void times(double f)
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
int giveNumberOfColumns() const
Returns number of columns of receiver.
void zero()
Zeroes all coefficient of receiver.
double at(std::size_t i, std::size_t j) const
void subtract(const FloatMatrix &a)
double giveUnknown(double vol, const FloatArray &dev, ValueModeType mode, TimeStep *tStep, ActiveDof *dof)
bool isDevDof(Dof *dof)
Returns true is DOF represents one of the deviatoric parts.
std ::unique_ptr< Node > voldman
DOF-manager containing the unknown volumetric strain(rate).
std ::unique_ptr< Node > devdman
DOF-manager containing the known deviatoric strain(rate).
FloatArray devGradient
Prescribed gradient in Voigt form.
#define OOFEM_ERROR(...)
Definition error.h:79
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Definition inputrecord.h:75
#define _IFT_MixedGradientPressure_centerCoords
#define _IFT_MixedGradientPressure_pressure
#define _IFT_MixedGradientPressure_devGradient
ClassFactory & classFactory

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