OOFEM 3.0
Loading...
Searching...
No Matches
mixedgradientpressureweakperiodic.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
36#include "dofiditem.h"
37#include "dofmanager.h"
38#include "dof.h"
39#include "valuemodetype.h"
40#include "floatarray.h"
41#include "floatmatrix.h"
42#include "engngm.h"
43#include "node.h"
44#include "element.h"
45#include "integrationrule.h"
47#include "gausspoint.h"
48#include "masterdof.h"
49#include "classfactory.h" // For sparse matrix creation.
50#include "sparsemtrxtype.h"
51#include "mathfem.h"
52#include "sparsemtrx.h"
53#include "sparselinsystemnm.h"
54#include "set.h"
55#include "dynamicinputrecord.h"
56#include "feinterpol.h"
58
59#ifdef _OPENMP
60#include <omp.h>
61#endif
62
63namespace oofem {
65
66MixedGradientPressureWeakPeriodic :: MixedGradientPressureWeakPeriodic(int n, Domain *d) : MixedGradientPressureBC(n, d),
67 voldman( new Node(-1, d) ),
68 tractionsdman( new Node(-1, d) )
69{
70 int dofid = this->domain->giveNextFreeDofID();
71 v_id.followedBy(dofid);
72 this->voldman->appendDof( new MasterDof( voldman.get(), ( DofIDItem ) dofid ) );
73}
74
75
76MixedGradientPressureWeakPeriodic :: ~MixedGradientPressureWeakPeriodic()
77{
78}
79
80
81int MixedGradientPressureWeakPeriodic :: giveNumberOfInternalDofManagers()
82{
83 return 2;
84}
85
86
87DofManager *MixedGradientPressureWeakPeriodic :: giveInternalDofManager(int i)
88{
89 if ( i == 1 ) {
90 return this->tractionsdman.get();
91 } else {
92 return this->voldman.get();
93 }
94}
95
96
97void MixedGradientPressureWeakPeriodic :: initializeFrom(InputRecord &ir)
98{
99 MixedGradientPressureBC :: initializeFrom(ir);
100
102 if ( this->order < 0 ) {
103 OOFEM_ERROR("order must be at least 0");
104 }
105
106 int nsd = this->domain->giveNumberOfSpatialDimensions();
107 int total = nsd * nsd * ( int ) pow(double ( order + 1 ), nsd - 1);
108 this->tractionsdman->setNumberOfDofs(0);
109 t_id.clear();
110 for ( int i = 1; i <= total; ++i ) {
111 int dofid = this->domain->giveNextFreeDofID();
112 t_id.followedBy(dofid);
113 // Simply use t_i = S_i . n, where S_1 = [1,0,0;0,0,0;0,0,0], S_2 = [0,1,0;0,0,0;0,0,0], etc.
114 // then the linear terms, [x,0,0], [0,x,0] ... and so on
115 this->tractionsdman->appendDof( new MasterDof( tractionsdman.get(), ( DofIDItem ) dofid ) );
116 }
117}
118
119
120void MixedGradientPressureWeakPeriodic :: setPrescribedDeviatoricGradientFromVoigt(const FloatArray &t)
121{
122 this->constructFullMatrixForm(this->devGradient, t);
123 this->volGradient = 0.;
124 for ( int i = 1; i <= this->devGradient.giveNumberOfRows(); i++ ) {
125 this->volGradient += this->devGradient.at(i, i);
126 }
127}
128
129
130void MixedGradientPressureWeakPeriodic :: constructFullMatrixForm(FloatMatrix &d, const FloatArray &d_voigt) const
131{
132 int n = d_voigt.giveSize();
133 if ( n == 6 ) { // Then 3D
134 d.resize(3, 3);
135 d.at(1, 1) = d_voigt.at(1);
136 d.at(2, 2) = d_voigt.at(2);
137 d.at(3, 3) = d_voigt.at(3);
138 d.at(2, 3) = d.at(3, 2) = d_voigt.at(4) * 0.5;
139 d.at(1, 3) = d.at(3, 1) = d_voigt.at(5) * 0.5;
140 d.at(1, 2) = d.at(2, 1) = d_voigt.at(6) * 0.5;
141 } else if ( n == 3 ) { // Then 2D
142 d.resize(2, 2);
143 d.at(1, 1) = d_voigt.at(1);
144 d.at(2, 2) = d_voigt.at(2);
145 d.at(1, 2) = d.at(2, 1) = d_voigt.at(3) * 0.5;
146 } else if ( n == 1 ) { // Then 1D
147 d.resize(1, 1);
148 d.at(1, 1) = d_voigt.at(1);
149 } else {
150 OOFEM_ERROR("Tensor is in strange voigt format.");
151 }
152}
153
154
155void MixedGradientPressureWeakPeriodic :: giveLocationArrays(std :: vector< IntArray > &rows, std :: vector< IntArray > &cols, CharType type,
156 const UnknownNumberingScheme &r_s, const UnknownNumberingScheme &c_s)
157{
158 if ( type != TangentStiffnessMatrix ) {
159 return;
160 }
161
162 IntArray loc_r, loc_c, t_loc_r, t_loc_c, e_loc_r, e_loc_c;
163
164 // Fetch the columns/rows for the tractions;
165 this->tractionsdman->giveLocationArray(t_id, t_loc_r, r_s);
166 this->tractionsdman->giveLocationArray(t_id, t_loc_c, c_s);
167
168 // Fetch the columns/rows for dvol;
169 this->voldman->giveLocationArray(v_id, e_loc_r, r_s);
170 this->voldman->giveLocationArray(v_id, e_loc_c, c_s);
171
172 Set *set = this->giveDomain()->giveSet(this->set);
173 const IntArray &boundaries = set->giveBoundaryList();
174
175 rows.resize(boundaries.giveSize() + 2);
176 cols.resize(boundaries.giveSize() + 2);
177 int i = 0;
178 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
179 Element *e = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) );
180 int boundary = boundaries.at(pos * 2);
181
182 const auto &bNodes = e->giveInterpolation()->boundaryGiveNodes(boundary, e->giveGeometryType());
183 e->giveBoundaryLocationArray(loc_r, bNodes, this->dofs, r_s);
184 e->giveBoundaryLocationArray(loc_c, bNodes, this->dofs, c_s);
185 // For most uses, *loc_r == *loc_c
186 rows [ i ] = loc_r;
187 cols [ i ] = t_loc_c;
188 i++;
189 // and the symmetric part (usually the transpose of above)
190 rows [ i ] = t_loc_r;
191 cols [ i ] = loc_c;
192 i++;
193 }
194
195 // The volumetric part:
196 rows [ i ] = t_loc_r;
197 cols [ i ] = e_loc_c;
198 i++;
199
200 rows [ i ] = e_loc_r;
201 cols [ i ] = t_loc_c;
202 i++;
203}
204
205
206void MixedGradientPressureWeakPeriodic :: evaluateTractionBasisFunctions(FloatArray &answer, const FloatArray &surfCoords)
207{
208 // This evaluates the function x^a * y^b, for a, b in [0,order]
209 int total = ( int ) pow(double ( order + 1 ), surfCoords.giveSize());
210 answer.resize(total);
211 int pos = 0;
212 double tx = 1.;
213 for ( int xi = 0; xi < ( this->order + 1 ); ++xi ) {
214 double ty = 1.;
215 for ( int yi = 0; yi < ( this->order + 1 ); ++yi ) {
216 answer(pos) = tx * ty;
217 pos++;
218 ty *= surfCoords(1);
219 }
220 tx *= surfCoords(0);
221 }
222}
223
224
225void MixedGradientPressureWeakPeriodic :: constructMMatrix(FloatMatrix &mMatrix, FloatArray &coords, FloatArray &normal)
226{
227 FloatArray t, surfCoords;
228 int nsd = this->giveDomain()->giveNumberOfSpatialDimensions();
229 int total = nsd * nsd * ( int ) pow(double ( this->order + 1 ), nsd - 1);
230
231 surfCoords.resize(nsd - 1);
232 mMatrix.resize(nsd, total);
233 mMatrix.zero();
234 int pos = 0;
235 for ( int kj = 0; kj < nsd; ++kj ) {
236 // First we compute the surface coordinates. Its the global coordinates without the kj component.
237 for ( int c = 0, q = 0; c < nsd; ++c ) {
238 if ( c != kj ) {
239 surfCoords(q) = coords(c);
240 q++;
241 }
242 }
243 // Evaluate all the basis functions for a given column.
244 this->evaluateTractionBasisFunctions(t, surfCoords);
245 for ( int ti = 0; ti < t.giveSize(); ++ti ) {
246 for ( int ki = 0; ki < nsd; ++ki ) {
247 mMatrix(ki, pos) = t(ti) * normal(kj);
248 pos++;
249 }
250 }
251 }
252}
253
254
255void MixedGradientPressureWeakPeriodic :: integrateTractionVelocityTangent(FloatMatrix &answer, Element *el, int boundary)
256{
257 // Computes the integral: int dt . dv dA
258 FloatArray normal, n, coords;
259 FloatMatrix nMatrix, mMatrix;
260
261 FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least).
262
263 int maxorder = this->order + interp->giveInterpolationOrder() * 3;
264 std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary, el->giveGeometryType()) );
265 int nsd = this->giveDomain()->giveNumberOfSpatialDimensions();
266
267 answer.clear();
268 for ( GaussPoint *gp: *ir ) {
269 const FloatArray &lcoords = gp->giveNaturalCoordinates();
270 FEIElementGeometryWrapper cellgeo(el);
271
272 double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo);
273 interp->boundaryEvalN(n, boundary, lcoords, cellgeo);
274 interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo);
275
276 // Construct the basis functions for the tractions:
277 this->constructMMatrix(mMatrix, coords, normal);
278 nMatrix.beNMatrixOf(n, nsd);
279
280 answer.plusProductUnsym( mMatrix, nMatrix, detJ * gp->giveWeight() );
281 }
282}
283
284
285void MixedGradientPressureWeakPeriodic :: integrateTractionXTangent(FloatMatrix &answer, Element *el, int boundary)
286{
287 // Computes the integral: int dt . dx_m dA
288 FloatMatrix mMatrix;
289 FloatArray normal, coords, vM_vol;
290
291 FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least).
292
293 int maxorder = this->order + interp->giveInterpolationOrder() * 3;
294 std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary, el->giveGeometryType()) );
295
296 FloatArray tmpAnswer;
297 for ( GaussPoint *gp: *ir ) {
298 const FloatArray &lcoords = gp->giveNaturalCoordinates();
299 FEIElementGeometryWrapper cellgeo(el);
300
301 double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo);
302 interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo);
303
304 vM_vol.beScaled(1.0/3.0, coords);
305 this->constructMMatrix(mMatrix, coords, normal);
306
307 tmpAnswer.plusProduct(mMatrix, vM_vol, detJ * gp->giveWeight());
308 }
309 answer.resize(tmpAnswer.giveSize(), 1);
310 answer.setColumn(tmpAnswer, 1);
311}
312
313
314void MixedGradientPressureWeakPeriodic :: integrateTractionDev(FloatArray &answer, Element *el, int boundary, const FloatMatrix &ddev)
315{
316 // Computes the integral: int dt . dx dA
317 FloatMatrix mMatrix;
318 FloatArray normal, coords, vM_dev;
319
320 FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least).
321
322 int maxorder = this->order + interp->giveInterpolationOrder() * 3;
323 std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary, el->giveGeometryType()) );
324 answer.clear();
325
326 for ( GaussPoint *gp: *ir ) {
327 const FloatArray &lcoords = gp->giveNaturalCoordinates();
328 FEIElementGeometryWrapper cellgeo(el);
329
330 double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo);
331 // Compute v_m = d_dev . x
332 interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo);
333 vM_dev.beProductOf(ddev, coords);
334
335 this->constructMMatrix(mMatrix, coords, normal);
336
337 answer.plusProduct(mMatrix, vM_dev, detJ * gp->giveWeight());
338 }
339}
340
341
342void MixedGradientPressureWeakPeriodic :: assembleVector(FloatArray &answer, TimeStep *tStep,
343 CharType type, ValueModeType mode,
344 const UnknownNumberingScheme &s,
345 FloatArray *eNorms,
346 void*lock)
347{
348 Set *set = this->giveDomain()->giveSet(this->set);
349 const IntArray &boundaries = set->giveBoundaryList();
350
351 IntArray v_loc, t_loc, e_loc; // For the velocities and stress respectively
352 IntArray velocityDofIDs, bNodes;
353 this->tractionsdman->giveLocationArray(t_id, t_loc, s);
354 this->voldman->giveLocationArray(v_id, e_loc, s);
355
356 if ( type == ExternalForcesVector ) {
357 // The external forces have two contributions. on the traction and on dvol.
358 double rve_size = this->domainSize();
359
360 if ( e_loc.at(1) ) {
361#ifdef _OPENMP
362 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
363#endif
364 answer.at( e_loc.at(1) ) -= rve_size * pressure; // Note the negative sign (pressure as opposed to mean stress)
365 if ( eNorms ) {
366 eNorms->at( v_id.at(1) ) += rve_size * pressure * rve_size * pressure;
367 }
368#ifdef _OPENMP
369 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
370#endif
371 }
372
373 // The second contribution is on the momentumbalance equation; int t . [[ d_dev . x ]] dA = int t . [[ d_dev . x ]] dA
374 FloatArray fe;
375 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
376 Element *e = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) );
377 int boundary = boundaries.at(pos * 2);
378
379 this->integrateTractionDev(fe, e, boundary, this->devGradient);
380 fe.negated();
381#ifdef _OPENMP
382 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
383#endif
384 answer.assemble(fe, t_loc);
385 if ( eNorms ) {
386 eNorms->assembleSquared(fe, velocityDofIDs);
387 }
388#ifdef _OPENMP
389 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
390#endif
391 }
392 } else if ( type == InternalForcesVector ) {
393 FloatMatrix Ke_v, Ke_e;
394 FloatArray fe_v, fe_t, fe_t2, fe_e(1);
395 FloatArray t, e, v;
396
397 // Fetch the current values of internal dofs and their master dof ids;
398 this->tractionsdman->giveUnknownVector(t, t_id, mode, tStep);
399 this->voldman->giveUnknownVector(e, v_id, mode, tStep);
400
401 // Assemble: -int t . [[ delta_v ]] dA
402 // int delta_t . [[ e.x - v ]] dA
403 // int t . [[ x ]] dA delta_e
404 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
405 Element *el = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) );
406 int boundary = boundaries.at(pos * 2);
407
408 // Fetch the element information;
409 const auto &bNodes = el->giveInterpolation()->boundaryGiveNodes(boundary, el->giveGeometryType());
410 el->giveBoundaryLocationArray(v_loc, bNodes, this->dofs, s, & velocityDofIDs);
411 el->computeBoundaryVectorOf(bNodes, this->dofs, mode, tStep, v);
412
413 // Integrate the tangents;
414 this->integrateTractionVelocityTangent(Ke_v, el, boundary);
415 this->integrateTractionXTangent(Ke_e, el, boundary);
416
417 // We just use the tangent, less duplicated code
418 fe_v.beTProductOf(Ke_v, t);
419 fe_v.negated();
420 fe_t.beProductOf(Ke_v, v);
421 fe_t.negated();
422 fe_t2.beProductOf(Ke_e, e);
423 fe_t.add(fe_t2);
424 fe_e.beTProductOf(Ke_e, t);
425#ifdef _OPENMP
426 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
427#endif
428 answer.assemble(fe_v, v_loc); // Contributions to delta_v equations
429 answer.assemble(fe_t, t_loc); // Contribution to delta_t equations
430 answer.assemble(fe_e, e_loc); // Contribution to delta_e equations
431 if ( eNorms ) {
432 eNorms->assembleSquared(fe_v, velocityDofIDs);
433 eNorms->assembleSquared(fe_t, t_id);
434 eNorms->assembleSquared(fe_e, v_id);
435 }
436#ifdef _OPENMP
437 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
438#endif
439 }
440 }
441}
442
443
444void MixedGradientPressureWeakPeriodic :: assemble(SparseMtrx &answer, TimeStep *tStep,
445 CharType type, const UnknownNumberingScheme &r_s,
446 const UnknownNumberingScheme &c_s, double scale,
447 void*lock)
448{
449 if ( type == TangentStiffnessMatrix || type == SecantStiffnessMatrix || type == ElasticStiffnessMatrix ) {
450 FloatMatrix Ke_v, Ke_vT, Ke_e, Ke_eT;
451 IntArray v_loc_r, v_loc_c, t_loc_r, t_loc_c, e_loc_r, e_loc_c;
452 Set *set = this->giveDomain()->giveSet(this->set);
453 const IntArray &boundaries = set->giveBoundaryList();
454
455 // Fetch the columns/rows for the stress contributions;
456 this->tractionsdman->giveLocationArray(t_id, t_loc_r, r_s);
457 this->tractionsdman->giveLocationArray(t_id, t_loc_c, c_s);
458
459 this->voldman->giveLocationArray(v_id, e_loc_r, r_s);
460 this->voldman->giveLocationArray(v_id, e_loc_c, c_s);
461
462 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
463 Element *el = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) );
464 int boundary = boundaries.at(pos * 2);
465
466 // Fetch the element information;
467 const auto &bNodes = el->giveInterpolation()->boundaryGiveNodes(boundary, el->giveGeometryType());
468 el->giveBoundaryLocationArray(v_loc_r, bNodes, this->dofs, r_s);
469 el->giveBoundaryLocationArray(v_loc_c, bNodes, this->dofs, c_s);
470
471 this->integrateTractionVelocityTangent(Ke_v, el, boundary);
472 this->integrateTractionXTangent(Ke_e, el, boundary);
473 Ke_v.negated();
474 Ke_v.times(scale);
475 Ke_e.times(scale);
476 Ke_vT.beTranspositionOf(Ke_v);
477 Ke_eT.beTranspositionOf(Ke_e);
478
479#ifdef _OPENMP
480 if (lock) omp_set_lock(static_cast<omp_lock_t*>(lock));
481#endif
482 answer.assemble(t_loc_r, v_loc_c, Ke_v);
483 answer.assemble(v_loc_r, t_loc_c, Ke_vT);
484
485 answer.assemble(t_loc_r, e_loc_c, Ke_e);
486 answer.assemble(e_loc_r, t_loc_c, Ke_eT);
487#ifdef _OPENMP
488 if (lock) omp_unset_lock(static_cast<omp_lock_t*>(lock));
489#endif
490 }
491 }
492}
493
494
495void MixedGradientPressureWeakPeriodic :: computeFields(FloatArray &sigmaDev, double &vol, TimeStep *tStep)
496{
497 double rve_size = this->domainSize();
498 FloatArray tractions;
499 this->tractionsdman->giveUnknownVector(tractions, t_id, VM_Total, tStep);
500 this->computeStress(sigmaDev, tractions, rve_size);
501
502 // And the volumetric part is much easier.
503 vol = (*this->voldman->begin())->giveUnknown(VM_Total, tStep);
504 vol /= rve_size;
505 vol -= volGradient; // This is needed for consistency; We return the volumetric "residual" if a gradient with volumetric contribution is set.
506}
507
508
509void MixedGradientPressureWeakPeriodic :: computeStress(FloatArray &sigmaDev, FloatArray &tractions, double rve_size)
510{
511 FloatMatrix mMatrix;
512 FloatArray normal, coords, t;
513
514 int nsd = domain->giveNumberOfSpatialDimensions();
515 Set *set = this->giveDomain()->giveSet(this->set);
516 const IntArray &boundaries = set->giveBoundaryList();
517 // Reminder: sigma = int t * n dA, where t = sum( C_i * n t_i ).
518 // This loop will construct sigma in matrix form.
519
520 FloatMatrix sigma;
521
522 for ( int pos = 1; pos <= boundaries.giveSize() / 2; ++pos ) {
523 Element *el = this->giveDomain()->giveElement( boundaries.at(pos * 2 - 1) );
524 int boundary = boundaries.at(pos * 2);
525
526 FEInterpolation *interp = el->giveInterpolation(); // Geometry interpolation. The displacements or velocities must have the same interpolation scheme (on the boundary at least).
527
528 int maxorder = this->order + interp->giveInterpolationOrder() * 3;
529 std :: unique_ptr< IntegrationRule >ir( interp->giveBoundaryIntegrationRule(maxorder, boundary, el->giveGeometryType()) );
530
531 for ( GaussPoint *gp: *ir ) {
532 const FloatArray &lcoords = gp->giveNaturalCoordinates();
533 FEIElementGeometryWrapper cellgeo(el);
534
535 double detJ = interp->boundaryEvalNormal(normal, boundary, lcoords, cellgeo);
536 // Compute v_m = d_dev . x
537 interp->boundaryLocal2Global(coords, boundary, lcoords, cellgeo);
538
539 this->constructMMatrix(mMatrix, coords, normal);
540 t.beProductOf(mMatrix, tractions);
541 sigma.plusDyadUnsym(t, coords, detJ * gp->giveWeight());
542 }
543 }
544 sigma.times(1. / rve_size);
545
546 double pressure = 0.;
547 for ( int i = 1; i <= nsd; i++ ) {
548 pressure += sigma.at(i, i);
549 }
550 pressure /= 3; // Not 100% sure about this for 2D cases.
551 if ( nsd == 3 ) {
552 sigmaDev.resize(6);
553 sigmaDev.at(1) = sigma.at(1, 1) - pressure;
554 sigmaDev.at(2) = sigma.at(2, 2) - pressure;
555 sigmaDev.at(3) = sigma.at(3, 3) - pressure;
556 sigmaDev.at(4) = 0.5 * ( sigma.at(2, 3) + sigma.at(3, 2) );
557 sigmaDev.at(5) = 0.5 * ( sigma.at(1, 3) + sigma.at(3, 1) );
558 sigmaDev.at(6) = 0.5 * ( sigma.at(1, 2) + sigma.at(2, 1) );
559 } else if ( nsd == 2 ) {
560 sigmaDev.resize(3);
561 sigmaDev.at(1) = sigma.at(1, 1) - pressure;
562 sigmaDev.at(2) = sigma.at(2, 2) - pressure;
563 sigmaDev.at(3) = 0.5 * ( sigma.at(1, 2) + sigma.at(2, 1) );
564 } else {
565 sigmaDev.resize(1);
566 sigmaDev.at(1) = sigma.at(1, 1) - pressure;
567 }
568}
569
570void MixedGradientPressureWeakPeriodic :: computeTangents(FloatMatrix &Ed, FloatArray &Ep, FloatArray &Cd, double &Cp, TimeStep *tStep)
571{
572 //double size = this->domainSize();
573 // Fetch some information from the engineering model
574 EngngModel *rve = this->giveDomain()->giveEngngModel();
576 std :: unique_ptr< SparseLinearSystemNM > solver(
577 classFactory.createSparseLinSolver( ST_Petsc, this->domain, this->domain->giveEngngModel() ) ); // = rve->giveLinearSolver();
578 SparseMtrxType stype = solver->giveRecommendedMatrix(true);
580 Set *set = this->giveDomain()->giveSet(this->set);
581 const IntArray &boundaries = set->giveBoundaryList();
582 double rve_size = this->domainSize();
583
584 // Set up and assemble tangent FE-matrix which will make up the sensitivity analysis for the macroscopic material tangent.
585 std :: unique_ptr< SparseMtrx > Kff( classFactory.createSparseMtrx(stype) );
586 if ( !Kff ) {
587 OOFEM_ERROR("Couldn't create sparse matrix of type %d\n", stype);
588 }
589 Kff->buildInternalStructure(rve, this->domain->giveNumber(), fnum);
590 rve->assemble(*Kff, tStep, TangentAssembler(TangentStiffness), fnum, this->domain);
591
592 // Setup up indices and locations
593 int neq = Kff->giveNumberOfRows();
594
595 // Indices and such of internal dofs
596 int nsd = this->devGradient.giveNumberOfColumns();
597 int nd = nsd * ( 1 + nsd ) / 2;
598
599 IntArray t_loc, e_loc;
600
601 // Fetch the positions;
602 this->tractionsdman->giveLocationArray( t_id, t_loc, fnum );
603 this->voldman->giveLocationArray( v_id, e_loc, fnum );
604
605 // Matrices and arrays for sensitivities
606 FloatMatrix ddev_pert(neq, nd);
607 FloatArray p_pert(neq);
608
609 // Solutions for the pertubations:
610 FloatMatrix s_d(neq, nd);
611 FloatArray s_p(neq);
612
613 // Unit pertubations for d_dev
614 for ( int i = 1; i <= nd; ++i ) {
615 FloatMatrix ddev_tmp;
616 FloatArray tmp(neq), fe, fetot, ddevVoigt(nd);
617 ddevVoigt.at(i) = 1.0;
618 this->constructFullMatrixForm(ddev_tmp, ddevVoigt);
619 for ( int k = 1; k <= boundaries.giveSize() / 2; ++k ) {
620 Element *e = this->giveDomain()->giveElement( boundaries.at(k * 2 - 1) );
621 int boundary = boundaries.at(k * 2);
622
623 this->integrateTractionDev(fe, e, boundary, ddev_tmp);
624 fetot.subtract(fe);
625 }
626 tmp.assemble(fetot, t_loc);
627 ddev_pert.setColumn(tmp, i);
628 }
629
630 // Unit pertubation for p
631 p_pert.zero();
632 p_pert.at( e_loc.at(1) ) = - 1.0 * rve_size;
633
634 // Solve all sensitivities
635 solver->solve(*Kff, ddev_pert, s_d);
636 solver->solve(*Kff, p_pert, s_p);
637
638 // Extract the tractions from the sensitivity solutions s_d and s_p:
639 FloatArray tractions_p( t_loc.giveSize() );
640 FloatMatrix tractions_d(t_loc.giveSize(), nd);
641 tractions_p.beSubArrayOf(s_p, t_loc);
642 for ( int i = 1; i <= nd; ++i ) {
643 for ( int k = 1; k <= t_loc.giveSize(); ++k ) {
644 tractions_d.at(k, i) = s_d.at(t_loc.at(k), i);
645 }
646 }
647
648 // The de/dp tangent:
649 Cp = - s_p.at( e_loc.at(1) );
650 // The de/dd tangent:
651 Cd.resize(nd);
652 if ( nsd == 3 ) {
653 Cd.at(1) = s_d.at(e_loc.at(1), 1);
654 Cd.at(2) = s_d.at(e_loc.at(1), 2);
655 Cd.at(3) = s_d.at(e_loc.at(1), 3);
656 Cd.at(4) = s_d.at(e_loc.at(1), 4);
657 Cd.at(5) = s_d.at(e_loc.at(1), 5);
658 Cd.at(6) = s_d.at(e_loc.at(1), 6);
659 } else if ( nsd == 2 ) {
660 Cd.at(1) = s_d.at(e_loc.at(1), 1);
661 Cd.at(2) = s_d.at(e_loc.at(1), 2);
662 Cd.at(3) = s_d.at(e_loc.at(1), 3);
663 }
664 // The ds/de tangent:
665 Ep = Cd; // This is much simpler, but it's "only" correct if there is a potential (i.e. symmetric problems). This could be generalized if needed.
666 // The ds/dd tangent:
667 Ed.resize(nd, nd);
668 for ( int dpos = 1; dpos <= nd; ++dpos ) {
669 FloatArray tractions, sigmaDev;
670 tractions.beColumnOf(tractions_d, dpos);
671 this->computeStress(sigmaDev, tractions, rve_size);
672 Ed.setColumn(sigmaDev, dpos);
673 }
674}
675
676void MixedGradientPressureWeakPeriodic :: giveInputRecord(DynamicInputRecord &input)
677{
678 MixedGradientPressureBC :: giveInputRecord(input);
680 OOFEM_ERROR("Not supported yet");
681 //FloatArray devGradientVoigt;
682 //input.setField(devGradientVoigt, _IFT_MixedGradientPressure_devGradient);
683}
684
685void MixedGradientPressureWeakPeriodic :: scale(double s)
686{
687 devGradient.times(s);
688 pressure *= s;
689}
690} // end namespace oofem
#define REGISTER_BoundaryCondition(class)
void setField(int item, InputFieldType id)
virtual void giveBoundaryLocationArray(IntArray &locationArray, const IntArray &bNodes, const UnknownNumberingScheme &s, IntArray *dofIds=NULL)
Definition element.C:485
virtual FEInterpolation * giveInterpolation() const
Definition element.h:648
void computeBoundaryVectorOf(const IntArray &bNodes, const IntArray &dofIDMask, ValueModeType u, TimeStep *tStep, FloatArray &answer, bool padding=false)
Definition element.C:163
virtual Element_Geometry_Type giveGeometryType() const =0
virtual void assemble(SparseMtrx &answer, TimeStep *tStep, const MatrixAssembler &ma, const UnknownNumberingScheme &s, Domain *domain)
Definition engngm.C:889
virtual std::unique_ptr< IntegrationRule > giveBoundaryIntegrationRule(int order, int boundary, const Element_Geometry_Type) const
Definition feinterpol.C:101
virtual IntArray boundaryGiveNodes(int boundary, const Element_Geometry_Type) const =0
int giveInterpolationOrder() const
Definition feinterpol.h:199
virtual void boundaryLocal2Global(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
virtual double boundaryEvalNormal(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
virtual void boundaryEvalN(FloatArray &answer, int boundary, const FloatArray &lcoords, const FEICellGeometry &cellgeo) const =0
Domain * giveDomain() const
Definition femcmpnn.h:97
Domain * domain
Link to domain object, useful for communicating with other FEM components.
Definition femcmpnn.h:79
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
void plusProduct(const FloatMatrix &b, const FloatArray &s, double dV)
Definition floatarray.C:288
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void beColumnOf(const FloatMatrix &mat, int col)
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void assembleSquared(const FloatArray &fe, const IntArray &loc)
Definition floatarray.C:637
void beScaled(double s, const FloatArray &b)
Definition floatarray.C:208
void beTProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:721
void add(const FloatArray &src)
Definition floatarray.C:218
void subtract(const FloatArray &src)
Definition floatarray.C:320
void beSubArrayOf(const FloatArray &src, const IntArray &indx)
Definition floatarray.C:440
void times(double f)
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
*Sets size of receiver to be an empty matrix It will have zero rows and zero columns size void clear()
void plusProductUnsym(const FloatMatrix &a, const FloatMatrix &b, double dV)
void beNMatrixOf(const FloatArray &n, int nsd)
void plusDyadUnsym(const FloatArray &a, const FloatArray &b, double dV)
void setColumn(const FloatArray &src, int c)
void beTranspositionOf(const FloatMatrix &src)
void zero()
Zeroes all coefficient of receiver.
double at(std::size_t i, std::size_t j) const
int set
Set number for boundary condition to be applied to.
IntArray dofs
Dofs that b.c. is applied to (relevant for Dirichlet type b.c.s).
int & at(std::size_t i)
Definition intarray.h:104
int giveSize() const
Definition intarray.h:211
void constructMMatrix(FloatMatrix &mMatrix, FloatArray &coords, FloatArray &normal)
std ::unique_ptr< Node > tractionsdman
DOF-manager containing the unknown tractions (Lagrange mult. for micro-periodic velocity).
void computeStress(FloatArray &sigmaDev, FloatArray &tractions, double rve_size)
void constructFullMatrixForm(FloatMatrix &d, const FloatArray &d_voigt) const
void evaluateTractionBasisFunctions(FloatArray &answer, const FloatArray &coords)
std ::unique_ptr< Node > voldman
DOF-manager containing the unknown volumetric gradient (always exactly one dof).
void integrateTractionXTangent(FloatMatrix &answer, Element *el, int boundary)
void integrateTractionVelocityTangent(FloatMatrix &answer, Element *el, int boundary)
void integrateTractionDev(FloatArray &answer, Element *el, int boundary, const FloatMatrix &ddev)
virtual int assemble(const IntArray &loc, const FloatMatrix &mat)=0
#define OOFEM_ERROR(...)
Definition error.h:79
#define IR_GIVE_FIELD(__ir, __value, __id)
Definition inputrecord.h:67
#define _IFT_MixedGradientPressure_pressure
#define _IFT_MixedGradientPressureWeakPeriodic_order
Order of global polynomial in the unknown tractions. Should be at least 1.
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