OOFEM 3.0
Loading...
Searching...
No Matches
mdm.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 "mdm.h"
36#include "gausspoint.h"
37#include "floatmatrix.h"
38#include "floatarray.h"
39#include "mathfem.h"
42#include "nonlocalmaterialext.h"
43#include "contextioerr.h"
44#include "classfactory.h"
45#include "dynamicinputrecord.h"
46#include "datastream.h"
47
48namespace oofem {
50
51#ifndef MDM_MAPPING_DEBUG
52
53 #ifdef MDM_USE_MMAClosestIPTransfer
54MMAClosestIPTransfer MDM :: mapper;
55 #endif
56
57 #ifdef MDM_USE_MMAShapeFunctProjection
58MMAShapeFunctProjection MDM :: mapper;
59 #endif
60
61 #ifdef MDM_USE_MMALeastSquareProjection
62MMALeastSquareProjection MDM :: mapper;
63 #endif
64
65#else
66MMAShapeFunctProjection MDM :: mapperSFT;
67MMALeastSquareProjection MDM :: mapperLST;
68
69#endif
70
71MMAClosestIPTransfer MDM :: mapper2;
72
73std::unique_ptr<MaterialStatus>
74MDM :: CreateStatus(GaussPoint *gp) const
75{
76 return std::make_unique<MDMStatus>(gp, this->nsd, this->numberOfMicroplanes);
77}
78
79
80bool
81MDM :: hasMaterialModeCapability(MaterialMode mode) const
82{
83 return mode == _3dMat || mode == _PlaneStress || mode == _PlaneStrain;
84}
85
86void
87MDM :: giveRealStressVector(FloatArray &answer, GaussPoint *gp,
88 const FloatArray &totalStrain, TimeStep *tStep) const
89{
90 FloatArray reducedStrain, strainPDC, stressPDC, stress;
91 FloatArray tempDamageTensorEigenVals;
92 FloatMatrix tempDamageTensor, tempDamageTensorEigenVec;
93 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
94
95 this->giveStressDependentPartOfStrainVector(reducedStrain, gp, totalStrain,
96 tStep, VM_Total);
97
98 // computeDamageTensor : locaL OR nonlocal
99 this->computeDamageTensor(tempDamageTensor, totalStrain, gp, tStep);
100 // compute principal direction and corresponding eigenvalues
101 this->computePDC(tempDamageTensor, tempDamageTensorEigenVals, tempDamageTensorEigenVec);
102
103 // check the sign
104 for ( int ii = 1; ii <= nsd; ii++ ) {
105 if ( tempDamageTensorEigenVals.at(ii) < 0.0 ) {
106 OOFEM_ERROR("negative eigenvalue of damage tensor detected, element %d, ip %d",
107 gp->giveElement()->giveNumber(), gp->giveNumber() );
108 }
109 }
110
111 // Transform local strain
112 // into principal damage coordinates (PDC)
113 transformStrainToPDC(strainPDC, reducedStrain, tempDamageTensorEigenVec, gp);
114
115 // Evaluate effective strain in PDC
116 applyDamageTranformation(strainPDC, tempDamageTensorEigenVals);
117
118 // Compute effective stress in PDC
119 computeEffectiveStress(stressPDC, strainPDC, gp, tStep);
120
121 // Evaluate true stress in PDC
122 applyDamageTranformation(stressPDC, tempDamageTensorEigenVals);
123
124 // Transform stress into global coordinates
125 transformStressFromPDC(stress, stressPDC, tempDamageTensorEigenVec, gp);
126
127
128 // update status
129 status->setTempDamageTensorEigenVals(tempDamageTensorEigenVals);
130 status->setTempDamageTensorEigenVec(tempDamageTensorEigenVec);
131 status->letTempStrainVectorBe(totalStrain);
132 status->letTempStressVectorBe(stress);
133 status->setTempDamageTensor(tempDamageTensor);
134
135 /*
136 * // debug test
137 * for (int i=1; i<=stress.giveSize(); i++) {
138 * if (!finite(stress.at(i))) {
139 * char buff[1024];
140 * sprintf (buff, "giveRealStressVector: INF or NAN error detected, element %d, ip %d",
141 * gp->giveElement()->giveNumber(), gp->giveNumber());
142 * OOFEM_ERROR(buff);
143 * }
144 * }
145 * // end debug test
146 */
147
148 answer = stress;
149}
150
151
152void
153MDM :: computeDamageTensor(FloatMatrix &damageTensor, const FloatArray &totalStrain,
154 GaussPoint *gp, TimeStep *tStep) const
155{
156 // local or nonlocal
157 if ( nonlocal ) {
158 FloatMatrix nonlocalDamageTensor(nsd, nsd);
159 MDMStatus *nonlocStatus, *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
160
161 this->buildNonlocalPointTable(gp);
163
164 // compute nonlocal strain increment first
165 for ( auto &lir: *this->giveIPIntegrationList(gp) ) {
166 nonlocStatus = static_cast< MDMStatus * >( this->giveStatus(lir.nearGp) );
167 const FloatMatrix &nonlocalContribution = nonlocStatus->giveLocalDamageTensorForAverage();
168
169 if ( ndc == 3 ) {
170 nonlocalDamageTensor.at(1, 1) += nonlocalContribution.at(1, 1) * lir.weight;
171 nonlocalDamageTensor.at(2, 2) += nonlocalContribution.at(2, 2) * lir.weight;
172 nonlocalDamageTensor.at(1, 2) += nonlocalContribution.at(1, 2) * lir.weight;
173 } else {
174 nonlocalDamageTensor.at(1, 1) += nonlocalContribution.at(1, 1) * lir.weight;
175 nonlocalDamageTensor.at(2, 2) += nonlocalContribution.at(2, 2) * lir.weight;
176 nonlocalDamageTensor.at(3, 3) += nonlocalContribution.at(3, 3) * lir.weight;
177 nonlocalDamageTensor.at(1, 2) += nonlocalContribution.at(1, 2) * lir.weight;
178 nonlocalDamageTensor.at(1, 3) += nonlocalContribution.at(1, 3) * lir.weight;
179 nonlocalDamageTensor.at(2, 3) += nonlocalContribution.at(2, 3) * lir.weight;
180 }
181 }
182
183 nonlocalDamageTensor.times( 1. / status->giveIntegrationScale() );
184 nonlocalDamageTensor.symmetrized();
185 this->endIPNonlocalAverage(gp); // !
186
187 damageTensor = nonlocalDamageTensor;
188 } else {
189 computeLocalDamageTensor(damageTensor, totalStrain, gp, tStep);
190 }
191}
192
193
194
195
196
197void
198MDM :: computeLocalDamageTensor(FloatMatrix &damageTensor, const FloatArray &totalStrain,
199 GaussPoint *gp, TimeStep *tStep) const
200{
201 FloatArray damageVector(6);
202 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
203
204 // Loop over microplanes.
205 for ( int im = 0; im < numberOfMicroplanes; im++ ) {
206 int im1 = im + 1;
207
208 double Psi = computeDamageOnPlane(gp, im1, totalStrain);
209 double PsiOld = status->giveMicroplaneDamage(im1);
210 if ( PsiOld > Psi ) {
211 Psi = PsiOld;
212 }
213
214 // update damage on microplane
215 status->setMicroplaneTempDamage(im1, Psi);
216
218 //for (int i=1; i<=ndc; i++) DamageVector->at(i) += MP->N[im][i] * MP->W[im] * PsiActive;
219 for ( int i = 1; i <= 6; i++ ) {
220 damageVector.at(i) += this->N [ im ] [ i - 1 ] * this->microplaneWeights [ im ] * Psi;
221 }
222 } else if ( formulation == STIFFNESS_DAMAGE ) {
223 //for (int i=1; i<=ndc; i++) DamageVector->at(i) += MP->N[im][i] * MP->W[im] / PsiActive;
224 for ( int i = 1; i <= 6; i++ ) {
225 damageVector.at(i) += this->N [ im ] [ i - 1 ] * this->microplaneWeights [ im ] / Psi;
226 }
227 }
228 //else MicroplaneMaterial::_error("Unknown type of formulation");
229 else {
230 OOFEM_ERROR("Unknown type of formulation");
231 }
232 }
233
234 if ( ndc == 3 ) {
235 // 2d case
236 damageTensor.resize(2, 2);
237 damageVector.times(2. / M_PI);
238
239 damageTensor.at(1, 1) = damageVector.at(1);
240 damageTensor.at(2, 2) = damageVector.at(2);
241 damageTensor.at(1, 2) = damageTensor.at(2, 1) = damageVector.at(6);
242 } else if ( ndc == 6 ) {
243 // 3d case
244 damageTensor.resize(3, 3);
245 damageVector.times(6.0);
246
247 damageTensor.at(1, 1) = damageVector.at(1);
248 damageTensor.at(2, 2) = damageVector.at(2);
249 damageTensor.at(3, 3) = damageVector.at(3);
250 damageTensor.at(2, 3) = damageTensor.at(3, 2) = damageVector.at(4);
251 damageTensor.at(3, 1) = damageTensor.at(1, 3) = damageVector.at(5);
252 damageTensor.at(1, 2) = damageTensor.at(2, 1) = damageVector.at(6);
253
254 //} else MicroplaneMaterial::_error("computeDamageTensor: unknown ndc value encountered");
255 } else {
256 OOFEM_ERROR("unknown ndc value encountered");
257 }
258}
259
260#define LARGE_EXPONENT 50.0
261#define HUGE_RELATIVE_COMPLIANCE 1.e20
262
263double
264MDM :: computeDamageOnPlane(GaussPoint *gp, int mnumber, const FloatArray &strain) const
265{
266 double en, em, el, Ep, Efp, ParEpp;
267 double Enorm = 0.0, sv = 0.0, answer = 0.0;
268 double fmicroplane;
269 IntArray mask;
270 FloatArray fullStrain, prevStress = static_cast< StructuralMaterialStatus * >( this->giveStatus(gp) )->giveStressVector();
271 StructuralMaterial :: giveInvertedVoigtVectorMask( mask, gp->giveMaterialMode() );
272
273 StructuralMaterial :: giveFullSymVectorForm( fullStrain, strain, gp->giveMaterialMode() );
274 en = this->computeNormalStrainComponent(mnumber, fullStrain);
275 em = this->computeShearMStrainComponent(mnumber, fullStrain);
276 el = this->computeShearLStrainComponent(mnumber, fullStrain);
277
278
279 // request raw parameters
280 this->giveRawMDMParameters(Efp, Ep, strain, gp);
281
282 // compute trace of stressTensor
283 if ( prevStress.isNotEmpty() ) {
284 for ( int i = 1; i <= nsd; i++ ) {
285 if ( mask.at(i) ) {
286 sv += prevStress.at( mask.at(i) );
287 }
288 }
289 }
290
291 ParEpp = Ep / ( 1. - ParMd ); // 1d sv reduction
292 fmicroplane = linearElasticMaterial.give('E', gp) * ParEpp;
293 // en /= (1.-ParMd*sv);
294 en /= ( 1. - ParMd * sv / ( fmicroplane ) ); // suggested by P.Grassl (ParMd is unit dependent)
295
296 if ( type_dam == 0 ) {
297 if ( en < 0. ) {
298 en = 0.; // take the positive part of normal strain
299 }
300
301 Enorm = en;
302 } else if ( type_dam == 1 ) {
303 if ( en < 0. ) {
304 en = 0.; // take the positive part of normal strain
305 }
306
307 Enorm = sqrt(en * en + em * em + el * el);
308 //} else MicroplaneMaterial::_error("Unknown type of damage law");
309 } else {
310 OOFEM_ERROR("Unknown type of damage law");
311 }
312
313
314 // evaluate softening law
315 if ( type_soft == 0 ) {
316 if ( Enorm <= ParEpp ) {
317 answer = 1.;
318 } else {
319 double aux = ( Enorm - ParEpp ) / Efp;
320 if ( aux < LARGE_EXPONENT ) {
321 answer = sqrt( ( Enorm / ParEpp ) * exp(aux) );
322 } else {
324 }
325 }
326
327 //} else MicroplaneMaterial::_error("Unknown type of softening");
328 } else {
329 OOFEM_ERROR("Unknown type of softening");
330 }
331
332 return answer;
333}
334
335void
336MDM :: computePDC(FloatMatrix &tempDamageTensor, FloatArray &tempDamageTensorEigenVals,
337 FloatMatrix &tempDamageTensorEigenVec) const
338{
339 FloatMatrix help = tempDamageTensor;
340
341 // resize the results
342 tempDamageTensorEigenVals.resize(nsd);
343 tempDamageTensorEigenVec.resize(nsd, nsd);
344
345#if 0
346 int nrot;
347 help.Jacobi(& tempDamageTensorEigenVals, & tempDamageTensorEigenVec, & nrot);
348#else
349 help.jaco_(tempDamageTensorEigenVals, tempDamageTensorEigenVec, 10);
350#endif
351}
352
353
354#define N(p, q) t.at(q, p)
355#define E(p) fullStrain.at(p)
356
357void
358MDM :: transformStrainToPDC(FloatArray &answer, FloatArray &strain,
359 FloatMatrix &t, GaussPoint *gp) const
360{
361 FloatArray fullStrain;
362
363 if ( mdmMode == mdm_3d ) {
364 StructuralMaterial :: giveFullSymVectorForm( fullStrain, strain, gp->giveMaterialMode() );
365
366 answer.resize(6);
367 answer.at(1) = N(1, 1) * ( N(1, 1) * E(1) + N(1, 2) * E(6) + N(1, 3) * E(5) )
368 + N(1, 2) * ( N(1, 2) * E(2) + N(1, 3) * E(4) )
369 + N(1, 3) * N(1, 3) * E(3);
370 answer.at(2) = N(2, 1) * ( N(2, 1) * E(1) + N(2, 2) * E(6) + N(2, 3) * E(5) )
371 + N(2, 2) * ( N(2, 2) * E(2) + N(2, 3) * E(4) )
372 + N(2, 3) * N(2, 3) * E(3);
373 answer.at(3) = N(3, 1) * ( N(3, 1) * E(1) + N(3, 2) * E(6) + N(3, 3) * E(5) )
374 + N(3, 2) * ( N(3, 2) * E(2) + N(3, 3) * E(4) )
375 + N(3, 3) * N(3, 3) * E(3);
376 answer.at(4) = N(2, 1) * ( N(3, 1) * E(1) + N(3, 2) * E(6) / 2 + N(3, 3) * E(5) / 2 )
377 + N(2, 2) * ( N(3, 1) * E(6) / 2 + N(3, 2) * E(2) + N(3, 3) * E(4) / 2 )
378 + N(2, 3) * ( N(3, 1) * E(5) / 2 + N(3, 2) * E(4) / 2 + N(3, 3) * E(3) );
379 answer.at(4) *= 2;
380 answer.at(5) = N(1, 1) * ( N(3, 1) * E(1) + N(3, 2) * E(6) / 2 + N(3, 3) * E(5) / 2 )
381 + N(1, 2) * ( N(3, 1) * E(6) / 2 + N(3, 2) * E(2) + N(3, 3) * E(4) / 2 )
382 + N(1, 3) * ( N(3, 1) * E(5) / 2 + N(3, 2) * E(4) / 2 + N(3, 3) * E(3) );
383 answer.at(5) *= 2;
384 answer.at(6) = N(1, 1) * ( N(2, 1) * E(1) + N(2, 2) * E(6) / 2 + N(2, 3) * E(5) / 2 )
385 + N(1, 2) * ( N(2, 1) * E(6) / 2 + N(2, 2) * E(2) + N(2, 3) * E(4) / 2 )
386 + N(1, 3) * ( N(2, 1) * E(5) / 2 + N(2, 2) * E(4) / 2 + N(2, 3) * E(3) );
387 answer.at(6) *= 2;
388 } else if ( mdmMode == mdm_2d ) {
389 fullStrain = strain;
390
391 answer.resize(3);
392 answer.at(1) = N(1, 1) * ( N(1, 1) * E(1) + N(1, 2) * E(3) )
393 + N(1, 2) * N(1, 2) * E(2);
394 answer.at(2) = N(2, 1) * ( N(2, 1) * E(1) + N(2, 2) * E(3) )
395 + N(2, 2) * N(2, 2) * E(2);
396 answer.at(3) = N(1, 1) * ( N(2, 1) * E(1) + N(2, 2) * E(3) / 2 )
397 + N(1, 2) * ( N(2, 1) * E(3) / 2 + N(2, 2) * E(2) );
398 answer.at(3) *= 2;
399 }
400}
401
402void
403MDM :: applyDamageTranformation(FloatArray &strainPDC, const FloatArray &tempDamageTensorEigenVals) const
404{
405 if ( mdmMode == mdm_3d ) {
406 double psi1 = tempDamageTensorEigenVals.at(1);
407 double psi2 = tempDamageTensorEigenVals.at(2);
408 double psi3 = tempDamageTensorEigenVals.at(3);
409
411 strainPDC.at(1) /= psi1;
412 strainPDC.at(2) /= psi2;
413 strainPDC.at(3) /= psi3;
414 strainPDC.at(4) /= sqrt(psi2 * psi3);
415 strainPDC.at(5) /= sqrt(psi1 * psi3);
416 strainPDC.at(6) /= sqrt(psi1 * psi2);
417 } else if ( formulation == STIFFNESS_DAMAGE ) {
418 strainPDC.at(1) *= psi1;
419 strainPDC.at(2) *= psi2;
420 strainPDC.at(3) *= psi3;
421 strainPDC.at(4) *= sqrt(psi2 * psi3);
422 strainPDC.at(5) *= sqrt(psi1 * psi3);
423 strainPDC.at(6) *= sqrt(psi1 * psi2);
424 } else {
425 //MicroplaneMaterial::_error("Unknown type of formulation");
426 OOFEM_ERROR("Unknown type of formulation");
427 }
428 } else if ( mdmMode == mdm_2d ) {
429 double psi1 = tempDamageTensorEigenVals.at(1);
430 double psi2 = tempDamageTensorEigenVals.at(2);
432 strainPDC.at(1) /= psi1;
433 strainPDC.at(2) /= psi2;
434 strainPDC.at(3) /= sqrt(psi1 * psi2);
435 } else if ( formulation == STIFFNESS_DAMAGE ) {
436 strainPDC.at(1) *= psi1;
437 strainPDC.at(2) *= psi2;
438 strainPDC.at(3) *= sqrt(psi1 * psi2);
439 } else {
440 //MicroplaneMaterial::_error("Unknown type of formulation");
441 OOFEM_ERROR("Unknown type of formulation");
442 }
443
444 //} else MicroplaneMaterial::_error("Unknown type of mdm mode");
445 } else {
446 OOFEM_ERROR("Unknown type of mdm mode");
447 }
448}
449
450
451void
452MDM :: computeEffectiveStress(FloatArray &stressPDC, const FloatArray &strainPDC, GaussPoint *gp, TimeStep *tStep) const
453{
454 //FloatMatrixF<6,6> de;
455 FloatMatrix de;
456 if ( mdmMode == mdm_3d ) {
457 // PDC components in 3d mode are in full 3d format, even in planeStrain situation
458 de = linearElasticMaterial.give3dMaterialStiffnessMatrix(TangentStiffness, gp, tStep);
459 } else {
460 linearElasticMaterial.giveStiffnessMatrix(de, TangentStiffness, gp, tStep);
461 }
462
463 stressPDC.beProductOf(de, strainPDC);
464}
465
466
467
468#define Nt(p, q) t.at(p, q)
469#define S(p) stressPDC.at(p)
470
471void
472MDM :: transformStressFromPDC(FloatArray &answer, const FloatArray &stressPDC, const FloatMatrix &t, GaussPoint *gp) const
473{
474 if ( mdmMode == mdm_3d ) {
475 FloatArray fullAnswer(6);
476 //answer.resize (6);
477
478 fullAnswer.at(1) = Nt(1, 1) * ( Nt(1, 1) * S(1) + 2 * Nt(1, 2) * S(6) + 2 * Nt(1, 3) * S(5) )
479 + Nt(1, 2) * ( Nt(1, 2) * S(2) + 2 * Nt(1, 3) * S(4) )
480 + Nt(1, 3) * Nt(1, 3) * S(3);
481 fullAnswer.at(2) = Nt(2, 1) * ( Nt(2, 1) * S(1) + 2 * Nt(2, 2) * S(6) + 2 * Nt(2, 3) * S(5) )
482 + Nt(2, 2) * ( Nt(2, 2) * S(2) + 2 * Nt(2, 3) * S(4) )
483 + Nt(2, 3) * Nt(2, 3) * S(3);
484 fullAnswer.at(3) = Nt(3, 1) * ( Nt(3, 1) * S(1) + 2 * Nt(3, 2) * S(6) + 2 * Nt(3, 3) * S(5) )
485 + Nt(3, 2) * ( Nt(3, 2) * S(2) + 2 * Nt(3, 3) * S(4) )
486 + Nt(3, 3) * Nt(3, 3) * S(3);
487 fullAnswer.at(4) = Nt(2, 1) * ( Nt(3, 1) * S(1) + Nt(3, 2) * S(6) + Nt(3, 3) * S(5) )
488 + Nt(2, 2) * ( Nt(3, 1) * S(6) + Nt(3, 2) * S(2) + Nt(3, 3) * S(4) )
489 + Nt(2, 3) * ( Nt(3, 1) * S(5) + Nt(3, 2) * S(4) + Nt(3, 3) * S(3) );
490 fullAnswer.at(5) = Nt(1, 1) * ( Nt(3, 1) * S(1) + Nt(3, 2) * S(6) + Nt(3, 3) * S(5) )
491 + Nt(1, 2) * ( Nt(3, 1) * S(6) + Nt(3, 2) * S(2) + Nt(3, 3) * S(4) )
492 + Nt(1, 3) * ( Nt(3, 1) * S(5) + Nt(3, 2) * S(4) + Nt(3, 3) * S(3) );
493 fullAnswer.at(6) = Nt(1, 1) * ( Nt(2, 1) * S(1) + Nt(2, 2) * S(6) + Nt(2, 3) * S(5) )
494 + Nt(1, 2) * ( Nt(2, 1) * S(6) + Nt(2, 2) * S(2) + Nt(2, 3) * S(4) )
495 + Nt(1, 3) * ( Nt(2, 1) * S(5) + Nt(2, 2) * S(4) + Nt(2, 3) * S(3) );
496
497 StructuralMaterial :: giveReducedSymVectorForm( answer, fullAnswer, gp->giveMaterialMode() );
498 } else if ( mdmMode == mdm_2d ) {
499 answer.resize(3);
500
501 answer.at(1) = Nt(1, 1) * ( Nt(1, 1) * S(1) + Nt(1, 2) * 2. * S(3) )
502 + Nt(1, 2) * Nt(1, 2) * S(2);
503 answer.at(2) = Nt(2, 1) * ( Nt(2, 1) * S(1) + Nt(2, 2) * 2. * S(3) )
504 + Nt(2, 2) * Nt(2, 2) * S(2);
505 answer.at(3) = Nt(1, 1) * ( Nt(2, 1) * S(1) + Nt(2, 2) * S(3) )
506 + Nt(1, 2) * ( Nt(2, 1) * S(3) + Nt(2, 2) * S(2) );
507 }
508}
509
510
511
512void
513MDM :: giveMaterialStiffnessMatrix(FloatMatrix &answer,
514 MatResponseMode mode,
515 GaussPoint *gp,
516 TimeStep *tStep) const
517{
518 auto status = static_cast< MDMStatus * >( this->giveStatus(gp) );
519
521 const_cast<MDM*>(this)->linearElasticMaterial.giveStiffnessMatrix(answer, TangentStiffness, gp, tStep);
522 //answer = de;
523 //return;
524 // if (isVirgin()) return ;
525 if ( ( mode == TangentStiffness ) || ( mode == SecantStiffness ) ) {
526 // Apply damage in principal coordinates
527 this->applyDamageToStiffness(answer, gp);
528
529 // Transform to global coordinates (in reduced space)
530 this->transformStiffnessfromPDC( answer, status->giveTempDamageTensorEigenVec() );
531 }
532}
533
534
535#define MAX_REL_COMPL_TRESHOLD 1.e6
536
537void
538MDM :: applyDamageToStiffness(FloatMatrix &d, GaussPoint *gp) const
539{
540 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
541
542 if ( mdmMode == mdm_3d ) {
543 double psi1 = 0.0, psi2 = 0.0, psi3 = 0.0;
545 psi1 = status->giveTempDamageTensorEigenVals().at(1);
546 psi2 = status->giveTempDamageTensorEigenVals().at(2);
547 psi3 = status->giveTempDamageTensorEigenVals().at(3);
548 } else if ( formulation == STIFFNESS_DAMAGE ) {
549 psi1 = 1. / ( status->giveTempDamageTensorEigenVals().at(1) );
550 psi2 = 1. / ( status->giveTempDamageTensorEigenVals().at(2) );
551 psi3 = 1. / ( status->giveTempDamageTensorEigenVals().at(3) );
552 //} else MicroplaneMaterial::_error("Unknown type of formulation");
553 } else {
554 OOFEM_ERROR("Unknown type of formulation");
555 }
556
557 //if ((psi1 > MAX_REL_COMPL_TRESHOLD) || (psi2 > MAX_REL_COMPL_TRESHOLD) || (psi3 > MAX_REL_COMPL_TRESHOLD)) printf (":");
558
559 psi1 = min(psi1, MAX_REL_COMPL_TRESHOLD);
560 psi2 = min(psi2, MAX_REL_COMPL_TRESHOLD);
561 psi3 = min(psi3, MAX_REL_COMPL_TRESHOLD);
562
563 if ( d.giveNumberOfRows() == 6 ) {
564 d.at(1, 1) /= ( psi1 * psi1 );
565 d.at(1, 2) /= ( psi1 * psi2 );
566 d.at(1, 3) /= ( psi1 * psi3 );
567 d.at(2, 1) /= ( psi2 * psi1 );
568 d.at(2, 2) /= ( psi2 * psi2 );
569 d.at(2, 3) /= ( psi2 * psi3 );
570 d.at(3, 1) /= ( psi3 * psi1 );
571 d.at(3, 2) /= ( psi3 * psi2 );
572 d.at(3, 3) /= ( psi3 * psi3 );
573 d.at(4, 4) /= ( psi2 * psi3 );
574 d.at(5, 5) /= ( psi1 * psi3 );
575 d.at(6, 6) /= ( psi1 * psi2 );
576 } else if ( d.giveNumberOfRows() == 4 ) {
577 d.at(1, 1) /= ( psi1 * psi1 );
578 d.at(1, 2) /= ( psi1 * psi2 );
579 d.at(1, 3) /= ( psi1 * psi3 );
580 d.at(2, 1) /= ( psi2 * psi1 );
581 d.at(2, 2) /= ( psi2 * psi2 );
582 d.at(2, 3) /= ( psi2 * psi3 );
583 d.at(3, 1) /= ( psi3 * psi1 );
584 d.at(3, 2) /= ( psi3 * psi2 );
585 d.at(3, 3) /= ( psi3 * psi3 );
586 d.at(4, 4) /= ( psi1 * psi2 );
587 //} else MicroplaneMaterial::_error("Unknown type stiffness");
588 } else {
589 OOFEM_ERROR("Unknown type stiffness");
590 }
591
592 return;
593 } else if ( mdmMode == mdm_2d ) {
594 double psi1 = 0.0, psi2 = 0.0;
596 psi1 = status->giveTempDamageTensorEigenVals().at(1);
597 psi2 = status->giveTempDamageTensorEigenVals().at(2);
598 } else if ( formulation == STIFFNESS_DAMAGE ) {
599 psi1 = 1. / ( status->giveTempDamageTensorEigenVals().at(1) );
600 psi2 = 1. / ( status->giveTempDamageTensorEigenVals().at(2) );
601 //} else MicroplaneMaterial::_error("Unknown type of formulation");
602 } else {
603 OOFEM_ERROR("Unknown type of formulation");
604 }
605
606
607 //if ((psi1 > MAX_REL_COMPL_TRESHOLD) || (psi2 > MAX_REL_COMPL_TRESHOLD)) printf (":");
608 psi1 = min(psi1, MAX_REL_COMPL_TRESHOLD);
609 psi2 = min(psi2, MAX_REL_COMPL_TRESHOLD);
610
611 d.at(1, 1) /= psi1 * psi1;
612 d.at(1, 2) /= psi1 * psi2;
613 d.at(2, 1) /= psi2 * psi1;
614 d.at(2, 2) /= psi2 * psi2;
615 d.at(3, 3) /= psi1 * psi2;
616
617 return;
618 }
619}
620
621
622void
623MDM :: transformStiffnessfromPDC(FloatMatrix &de, const FloatMatrix &t) const
624{
625 this->rotateTensor4(de, t);
626}
627
628
630MDM :: give3dMaterialStiffnessMatrix(MatResponseMode mode,
631 GaussPoint *gp,
632 TimeStep *tStep) const
633{
634 FloatMatrix answer;
635 const_cast<MDM*>(this)->giveMaterialStiffnessMatrix(answer, mode, gp, tStep);
636 return answer;
637}
638
639
641MDM :: givePlaneStressStiffMtrx(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const
642{
643 FloatMatrix answer;
644 const_cast<MDM*>(this)->giveMaterialStiffnessMatrix(answer, mode, gp, tStep);
645 return answer;
646}
647
648
650MDM :: givePlaneStrainStiffMtrx(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const
651{
652 FloatMatrix answer;
653 const_cast<MDM*>(this)->giveMaterialStiffnessMatrix(answer, mode, gp, tStep);
654 return answer;
655}
656
657
658int
659MDM :: giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *tStep)
660{
661 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
662
663 if ( type == IST_DamageTensor ) {
664 // DamageTensor = I-Phi*Phi \approx I - Phi^{-1}*Phi*^{-1}
665 // d corresponds damage compliance
666 // c corresponds to damage
667 FloatMatrix d, c;
669 c.beInverseOf(status->giveDamageTensor());
670 } else {
671 c = status->giveDamageTensor();
672 }
673
674 d.beProductOf(c, c);
675 if ( ndc == 3 ) {
676 answer.resize(6);
677 answer.at(1) = 1. - d.at(1, 1);
678 answer.at(2) = 1. - d.at(2, 2);
679 answer.at(3) = d.at(1, 2);
680 answer.at(4) = 0.;
681 answer.at(5) = 0.;
682 answer.at(6) = 0.;
683 } else {
684 answer.resize(6);
685 answer.at(1) = 1. - d.at(1, 1);
686 answer.at(2) = 1. - d.at(2, 2);
687 answer.at(3) = 1. - d.at(3, 3);
688 answer.at(4) = d.at(2, 3);
689 answer.at(5) = d.at(1, 3);
690 answer.at(6) = d.at(1, 2);
691 }
692
693 return 1;
694 } else if ( type == IST_DamageTensorTemp ) {
695 FloatMatrix d, c;
698 } else {
699 c = status->giveTempDamageTensor();
700 }
701
702 d.beProductOf(c, c);
703 if ( ndc == 3 ) {
704 answer.resize(6);
705 answer.at(1) = 1. - d.at(1, 1);
706 answer.at(2) = 1. - d.at(2, 2);
707 answer.at(3) = d.at(1, 2);
708 answer.at(4) = 0.;
709 answer.at(5) = 0.;
710 answer.at(6) = 0.;
711 } else {
712 answer.resize(6);
713 answer.at(1) = 1. - d.at(1, 1);
714 answer.at(2) = 1. - d.at(2, 2);
715 answer.at(3) = 1. - d.at(3, 3);
716 answer.at(4) = d.at(2, 3);
717 answer.at(5) = d.at(1, 3);
718 answer.at(6) = d.at(1, 2);
719 }
720
721 return 1;
722 } else if ( type == IST_PrincipalDamageTensor ) {
723 const FloatArray &d = status->giveDamageTensorEigenVals();
724
725 answer.resize(3);
726 answer.zero();
728 for ( int i = 1; i <= nsd; i++ ) {
729 answer.at(i) = 1. - 1. / d.at(i) / d.at(i);
730 }
731 } else {
732 for ( int i = 1; i <= nsd; i++ ) {
733 answer.at(i) = 1. - d.at(i) * d.at(i);
734 }
735 }
736
737 return 1;
738 } else if ( type == IST_PrincipalDamageTempTensor ) {
739 const FloatArray &d = status->giveTempDamageTensorEigenVals();
740
741 answer.resize(3);
742 answer.zero();
744 for ( int i = 1; i <= nsd; i++ ) {
745 answer.at(i) = 1. - 1. / d.at(i) / d.at(i);
746 }
747 } else {
748 for ( int i = 1; i <= nsd; i++ ) {
749 answer.at(i) = 1. - d.at(i) * d.at(i);
750 }
751 }
752
753 return 1;
754 } else if ( type == IST_MicroplaneDamageValues ) {
755 answer = status->giveMicroplaneDamageValues();
756 return 1;
757 } else {
758 return StructuralMaterial :: giveIPValue(answer, gp, type, tStep);
759 }
760}
761
763MDM :: giveThermalDilatationVector(GaussPoint *gp, TimeStep *tStep) const
764{
765 return {
766 this->tempDillatCoeff,
767 this->tempDillatCoeff,
768 this->tempDillatCoeff,
769 0., 0., 0.
770 };
771}
772
773
774void
775MDM :: initializeFrom(InputRecord &ir)
776//
777// initializes according to string
778//
779{
783
784 if ( this->nonlocal ) {
786 if ( R < 0.0 ) {
787 R = 0.0;
788 }
789
790 if ( ir.hasField(_IFT_MDM_efp) && ir.hasField(_IFT_MDM_ep) ) {
791 // read raw_params if available
793 IR_GIVE_FIELD(ir, this->mdm_Ep, _IFT_MDM_ep);
794 } else if ( ir.hasField(_IFT_MDM_gf) && ir.hasField(_IFT_MDM_ft) ) {
795 IR_GIVE_FIELD(ir, this->Gf, _IFT_MDM_gf);
796 IR_GIVE_FIELD(ir, this->Ft, _IFT_MDM_ft);
797 } else {
798 throw ValueInputException(ir, _IFT_MDM_nonloc, "unknown set of parameters");
799 }
800 } else { // local case
801 if ( ir.hasField(_IFT_MDM_efp) && ir.hasField(_IFT_MDM_ep) ) {
802 // read raw_params if available
804 IR_GIVE_FIELD(ir, this->mdm_Ep, _IFT_MDM_ep);
805 } else if ( ir.hasField(_IFT_MDM_gf) && ir.hasField(_IFT_MDM_ep) ) {
806 IR_GIVE_FIELD(ir, this->Gf, _IFT_MDM_gf);
807 IR_GIVE_FIELD(ir, this->mdm_Ep, _IFT_MDM_ep);
808 } else {
809 throw ValueInputException(ir, _IFT_MDM_nonloc, "unknown set of parameters");
810 }
811 }
812
813 // read formulation
814 int _val = 0;
816 this->formulation = ( MDMFormulatrionType ) _val;
817
818 IR_GIVE_FIELD(ir, _val, _IFT_MDM_mode);
819 this->mdmMode = ( MDMModeType ) _val;
820
821 if ( this->mdmMode == mdm_3d ) {
822 this->ndc = 6;
823 this->nsd = 3;
824 } else if ( this->mdmMode == mdm_2d ) {
825 this->ndc = 3;
826 this->nsd = 2;
827 }
828
829
830#ifdef MDM_MAPPING_DEBUG
831 _val = 0;
833 this->mapperType = ( MDMMapperType ) _val;
834 OOFEM_LOG_INFO("MDM: using optional mapper %d\n", mapperType);
835#endif
836
837 MicroplaneMaterial :: initializeFrom(ir);
838
839 if ( this->nonlocal ) {
840 StructuralNonlocalMaterialExtensionInterface :: initializeFrom(ir);
841 }
842
843 linearElasticMaterial.initializeFrom(ir);
844
845#ifdef MDM_MAPPING_DEBUG
846 mapperSFT.initializeFrom(ir);
847 mapperLST.initializeFrom(ir);
848#else
849 mapper.initializeFrom(ir);
850#endif
851 mapper2.initializeFrom(ir);
852}
853
854
855void MDM :: giveInputRecord(DynamicInputRecord &input)
856{
857 linearElasticMaterial.giveInputRecord(input);
858 MicroplaneMaterial :: giveInputRecord(input);
859 StructuralNonlocalMaterialExtensionInterface :: giveInputRecord(input);
860#ifdef MDM_MAPPING_DEBUG
861 mapperSFT.giveInputRecord(input);
862 mapperLST.giveInputRecord(input);
863 input.setField(this->mapperType, _IFT_MDM_mapper);
864#else
865 mapper.giveInputRecord(input);
866#endif
867 mapper2.giveInputRecord(input);
868
870 input.setField(this->ParMd, _IFT_MDM_parmd);
871 input.setField(this->nonlocal, _IFT_MDM_nonloc);
872
873 if ( this->nonlocal ) {
874 input.setField(R, _IFT_MDM_r);
875
876 if ( this->mdm_Ep >= 0.0 && this->mdm_Efp >= 0.0 ) {
877 // read raw_params if available
878 input.setField(this->mdm_Efp, _IFT_MDM_efp);
879 input.setField(this->mdm_Ep, _IFT_MDM_ep);
880 } else {
881 input.setField(this->Gf, _IFT_MDM_gf);
882 input.setField(this->Ft, _IFT_MDM_ft);
883 }
884 } else { // local case
885 if ( this->mdm_Ep >= 0.0 && this->mdm_Efp >= 0.0 ) {
886 // read raw_params if available
887 input.setField(this->mdm_Efp, _IFT_MDM_efp);
888 input.setField(this->mdm_Ep, _IFT_MDM_ep);
889 } else {
890 input.setField(this->Gf, _IFT_MDM_gf);
891 input.setField(this->mdm_Ep, _IFT_MDM_ep);
892 }
893 }
894
896 input.setField(this->mdmMode, _IFT_MDM_mode);
897}
898
899
900void
901MDM :: rotateTensor4(FloatMatrix &Dlocal, const FloatMatrix &t) const
902//
903// Interpreting "t" as the rotation matrix containing in its
904// columns the local base vectors, transform a fourth-order tensor
905// represented by a matrix from local to global coordinates.
906{
907 FloatMatrix tt, td;
908 this->formTransformationMatrix( tt, t, Dlocal.giveNumberOfRows() );
909 td.beProductOf(tt, Dlocal);
910 Dlocal.beProductTOf(td, tt);
911}
912
913#define FORMT33(i, j, ij) answer.at(ij, 1) = t.at(i, 1) * t.at(j, 1); answer.at(ij, 2) = t.at(i, 2) * t.at(j, 2); answer.at(ij, 3) = t.at(i, 1) * t.at(j, 2) + t.at(i, 2) * t.at(j, 1)
914
915#define FORMT44(i, j, ij) answer.at(ij, 1) = t.at(i, 1) * t.at(j, 1); answer.at(ij, 2) = t.at(i, 2) * t.at(j, 2); answer.at(ij, 3) = t.at(i, 3) * t.at(j, 3); answer.at(ij, 4) = t.at(i, 1) * t.at(j, 2) + t.at(i, 2) * t.at(j, 1)
916
917#define FORMT66(i, j, ij) answer.at(ij, 1) = t.at(i, 1) * t.at(j, 1); answer.at(ij, 2) = t.at(i, 2) * t.at(j, 2); answer.at(ij, 3) = t.at(i, 3) * t.at(j, 3); answer.at(ij, 4) = t.at(i, 2) * t.at(j, 3) + t.at(i, 3) * t.at(j, 2); answer.at(ij, 5) = t.at(i, 1) * t.at(j, 3) + t.at(i, 3) * t.at(j, 1); answer.at(ij, 6) = t.at(i, 1) * t.at(j, 2) + t.at(i, 2) * t.at(j, 1)
918
919
920void
921MDM :: formTransformationMatrix(FloatMatrix &answer, const FloatMatrix &t, int n) const
922//
923// Interpreting "t" as the rotation matrix containing in its
924// columns the local base vectors, form the transformation matrix
925// for the transformation of a fourth-order tensor represented by
926// a matrix from local to global coordinates.
927{
928 switch ( n ) {
929 case 1:
930 answer.resize(1, 1);
931 answer.at(1, 1) = 1.0;
932 return;
933
934 case 3:
935 answer.resize(3, 3);
936 answer.zero();
937
938 FORMT33(1, 1, 1);
939 FORMT33(2, 2, 2);
940 FORMT33(1, 2, 3);
941 return;
942
943 case 4:
944 answer.resize(4, 4);
945 answer.zero();
946
947 FORMT44(1, 1, 1);
948 FORMT44(2, 2, 2);
949 FORMT44(3, 3, 3);
950 FORMT44(1, 2, 4);
951 return;
952
953 case 6:
954 answer.resize(6, 6);
955 answer.zero();
956
957 FORMT66(1, 1, 1);
958 FORMT66(2, 2, 2);
959 FORMT66(3, 3, 3);
960 FORMT66(2, 3, 4);
961 FORMT66(1, 3, 5);
962 FORMT66(1, 2, 6);
963 return;
964
965 default:
966 //MicroplaneMaterial::_error("Stress transformation matrix format not implemented");
967 OOFEM_ERROR("Stress transformation matrix format not implemented");
968 }
969}
970
971void
972MDM :: giveRawMDMParameters(double &Efp, double &Ep, const FloatArray &reducedStrain, GaussPoint *gp) const
973{
974 // test if raw parameters are given
975 if ( this->mdm_Efp > 0.0 ) {
976 Efp = this->mdm_Efp;
977 Ep = this->mdm_Ep;
978 return;
979 }
980
981 // determine params from macroscopic ones
982 if ( nonlocal ) {
983 // formulas derived for 3d case
984 double EModulus = linearElasticMaterial.give('E', gp);
985 double gammaf = ( EModulus * this->Gf ) / ( this->R * this->Ft * this->Ft );
986 double gamma = gammaf / ( 1.47 - 0.0014 * gammaf );
987 double f = this->Ft / ( 1.56 + 0.006 * gamma ); // microplane tensile strength
988 Efp = this->mdm_Efp = ( gamma * f ) / EModulus;
989 //double mdtilda = this->ParMd/f;
990 Ep = this->mdm_Ep = f / EModulus;
991 return;
992 } else { // local model
993 FloatArray strainVector, principalStrain;
994 FloatMatrix dirs(3, 3);
995 double h;
996
997 StructuralMaterial :: giveFullSymVectorForm( strainVector, reducedStrain, gp->giveMaterialMode() );
998 this->computePrincipalValDir(principalStrain, dirs,
999 strainVector,
1001
1002 // find EigenVector With Largest EigenValue
1003 int indx = 1;
1004 double max = principalStrain.at(1);
1005 if ( principalStrain.at(2) > max ) {
1006 indx = 2;
1007 }
1008
1009 if ( principalStrain.at(3) > max ) {
1010 indx = 3;
1011 }
1012
1013 FloatArray dir(3);
1014 dir.at(1) = dirs.at(1, indx);
1015 dir.at(2) = dirs.at(2, indx);
1016 dir.at(3) = dirs.at(3, indx);
1017
1018 h = gp->giveElement()->giveCharacteristicLength(dir);
1019 double E = linearElasticMaterial.give(Ex, gp);
1020 Ep = this->mdm_Ep;
1021 if ( nsd == 2 ) {
1022 Efp = ( Gf / ( h * E * Ep ) + 1.2 * Ep ) / 1.75 - Ep;
1023 } else {
1024 Efp = ( Gf / ( h * E * Ep ) + ( 2.13 + ParMd ) * Ep ) / ( 2.73 - ParMd ) - Ep;
1025 }
1026
1027 if ( Efp <= 0. ) {
1028 //MicroplaneMaterial::_error("Warning: negative Efp encountered");
1029 OOFEM_ERROR("negative Efp encountered");
1030 }
1031
1032 return;
1033 }
1034}
1035
1036/*
1037 * double
1038 * MDM::giveParameterEfp(const FloatArray& reducedStrain, GaussPoint* gp)
1039 * {
1040 * if (Efp > 0.)
1041 * return Efp;
1042 *
1043 *
1044 * StructuralCrossSection *crossSection = (StructuralCrossSection*) gp -> giveElement()->giveCrossSection();
1045 * FloatArray strainVector, principalStrain;
1046 * FloatMatrix dirs;
1047 * double h;
1048 *
1049 * if (nonlocal) h = 1.0;
1050 * else {
1051 * crossSection->giveFullCharacteristicVector(strainVector, gp, reducedStrain);
1052 * this->computePrincipalValDir (principalStrain, dirs,
1053 * strainVector,
1054 * principal_strain);
1055 *
1056 * // find EigenVector With Largest EigenValue
1057 * int indx = 1;
1058 * double max = principalStrain.at(1);
1059 * if (principalStrain.at(2) > max) indx = 2;
1060 * if (principalStrain.at(3) > max) indx = 3;
1061 *
1062 * FloatArray dir (3);
1063 * dir.at(1) = dirs.at(1,indx);
1064 * dir.at(2) = dirs.at(2,indx);
1065 * dir.at(3) = dirs.at(3,indx);
1066 *
1067 * h = gp->giveElement()->giveCharacteristicLength (dir);
1068 * }
1069 *
1070 * double E = this -> giveLinearElasticMaterial()->give(Ex);
1071 * if (nsd==2)
1072 * Efp = (Gf/(h*E*Ep)+1.2*Ep)/1.75 - Ep;
1073 * else
1074 * Efp = (Gf/(h*E*Ep)+(2.13+ParMd)*Ep)/(2.73-ParMd) - Ep;
1075 * if (Efp<=0.)
1076 * MicroplaneMaterial::_error("Warning: negative Efp encountered");
1077 *
1078 * return Efp;
1079 * }
1080 */
1081
1082void
1083MDM :: initializeData(int numberOfMicroplanes)
1084{
1085 if ( this->mdmMode == mdm_3d ) {
1086 MicroplaneMaterial :: initializeData(numberOfMicroplanes);
1087 } else if ( this->mdmMode == mdm_2d ) {
1089 //MicroplaneMaterial::_error("initializeData: required number of microplanes too big");
1090 OOFEM_ERROR("required number of microplanes too big");
1091 }
1092
1093 double alpha = M_PI / numberOfMicroplanes;
1094 FloatArray n(3), m(3), l(3);
1095
1096 int ij [ 6 ] [ 2 ] = { { 1, 1 }, { 2, 2 }, { 3, 3 }, { 2, 3 }, { 3, 1 }, { 1, 2 } };
1097
1100 M.resize(numberOfMicroplanes);
1101 N.resize(numberOfMicroplanes);
1102 L.resize(numberOfMicroplanes);
1103
1104 for ( int iplane = 0; iplane < numberOfMicroplanes; iplane++ ) {
1105 microplaneWeights [ iplane ] = alpha;
1106
1107 n.at(1) = microplaneNormals [ iplane ] [ 0 ] = cos(iplane * alpha);
1108 n.at(2) = microplaneNormals [ iplane ] [ 1 ] = sin(iplane * alpha);
1109 n.at(3) = microplaneNormals [ iplane ] [ 2 ] = 0.0;
1110
1111 // compute projection tensors for each microplane
1112 m.at(1) = n.at(2);
1113 m.at(2) = -n.at(1);
1114 m.at(3) = 0.0;
1115
1116 l.at(1) = 0.0;
1117 l.at(2) = 0.0;
1118 l.at(3) = 1.0;
1119
1120 for ( int i = 0; i < 6; i++ ) {
1121 int ii = ij [ i ] [ 0 ];
1122 int jj = ij [ i ] [ 1 ];
1123
1124 N [ iplane ] [ i ] = n.at(ii) * n.at(jj);
1125 M [ iplane ] [ i ] = 0.5 * ( m.at(ii) * n.at(jj) + m.at(jj) * n.at(ii) );
1126 L [ iplane ] [ i ] = 0.5 * ( l.at(ii) * n.at(jj) + l.at(jj) * n.at(ii) );
1127 }
1128 } // end loop over mplanes
1129
1130 //} else MicroplaneMaterial::_error("initializeData: Unknown MDMModeType ecountered");
1131 } else {
1132 OOFEM_ERROR("Unknown MDMModeType ecountered");
1133 }
1134}
1135
1136
1137void
1138MDM :: updateBeforeNonlocAverage(const FloatArray &strainVector, GaussPoint *gp, TimeStep *tStep) const
1139{
1140 /* Implements the service updating local variables in given integration points,
1141 * which take part in nonlocal average process.
1142 * The current implementation computes the localDamageTensor and stores it in
1143 * corresponding status variable.
1144 * This service is declared at StructuralNonlocalMaterial level.
1145 */
1146 auto status = static_cast< MDMStatus * >( this->giveStatus(gp) );
1147 FloatMatrix tempDamageTensor;
1148 this->computeLocalDamageTensor(tempDamageTensor, strainVector, gp, tStep);
1149 status->setLocalDamageTensorForAverage(tempDamageTensor);
1150}
1151
1152
1153double
1154MDM :: computeWeightFunction(const double R, const FloatArray &src, const FloatArray &coord) const
1155{
1156 // Bell shaped function decaying with the distance.
1157
1158 double dist = distance(src, coord);
1159
1160 if ( ( dist >= 0. ) && ( dist <= this->R ) ) {
1161 double help = ( 1. - dist * dist / ( R * R ) );
1162 return help * help;
1163 }
1164
1165 return 0.0;
1166}
1167
1168
1169int
1170MDM :: MMI_map(GaussPoint *gp, Domain *oldd, TimeStep *tStep)
1171{
1172 int result = 0;
1173 FloatArray intVal;
1174 IntArray toMap(1);
1175 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
1176
1177 toMap.at(1) = ( int ) IST_MicroplaneDamageValues;
1178
1179 // Set up source element set if not set up by user
1180 if ( !sourceElemSet ) {
1181 sourceElemSet = std::make_unique<Set>(0, oldd);
1182 IntArray el;
1183 // compile source list to contain all elements on old odmain with the same material id
1184 for ( int i = 1; i <= oldd->giveNumberOfElements(); i++ ) {
1185 if ( oldd->giveElement(i)->giveMaterial()->giveNumber() == this->giveNumber() ) {
1186 // add oldd domain element to source list
1187 el.followedBy(i, 10);
1188 }
1189 }
1190 sourceElemSet->setElementList(el);
1191 }
1192
1193#ifndef MDM_MAPPING_DEBUG
1194 this->mapper.init(oldd, toMap, gp, * sourceElemSet, tStep);
1195 result = mapper.mapVariable(intVal, gp, IST_MicroplaneDamageValues, tStep);
1196#else
1197 if ( mapperType == mdm_cpt ) {
1198 this->mapper2.init(oldd, toMap, gp, * sourceElemSet, tStep);
1199 result = mapper2.mapVariable(intVal, gp, IST_MicroplaneDamageValues, tStep);
1200 } else if ( mapperType == mdm_sft ) {
1201 this->mapperSFT.init(oldd, toMap, gp, * sourceElemSet, tStep);
1202 result = mapperSFT.mapVariable(intVal, gp, IST_MicroplaneDamageValues, tStep);
1203 } else if ( mapperType == mdm_lst ) {
1204 this->mapperLST.init(oldd, toMap, gp, * sourceElemSet, tStep);
1205 result = mapperLST.mapVariable(intVal, gp, IST_MicroplaneDamageValues, tStep);
1206 } else {
1207 OOFEM_ERROR("unsupported Mapper id");
1208 }
1209
1210#endif
1211
1212 if ( formulation == COMPLIANCE_DAMAGE ) {
1213 for ( int i = 1; i <= intVal.giveSize(); i++ ) {
1214 if ( intVal.at(i) < 1.0 ) {
1215 intVal.at(i) = 1.0;
1216 }
1217 }
1218 } else {
1219 for ( int i = 1; i <= intVal.giveSize(); i++ ) {
1220 if ( intVal.at(i) < 0.0 ) {
1221 intVal.at(i) = 0.0;
1222 }
1223
1224 if ( intVal.at(i) > 1.0 ) {
1225 intVal.at(i) = 1.0;
1226 }
1227 }
1228 }
1229
1230 if ( result ) {
1231 status->setMicroplaneTempDamageValues(intVal);
1232 }
1233
1234 // map stress, since it is necessary for keeping the
1235 // trace of stress (sv)
1236
1237 toMap.resize(2);
1238 toMap.at(1) = ( int ) IST_StrainTensor;
1239 toMap.at(2) = ( int ) IST_StressTensor;
1240 this->mapper2.init(oldd, toMap, gp, * sourceElemSet, tStep);
1241
1242 result = mapper2.mapVariable(intVal, gp, IST_StressTensor, tStep);
1243 if ( result ) {
1244 status->letTempStressVectorBe(intVal);
1245 }
1246
1247 result = mapper2.mapVariable(intVal, gp, IST_StrainTensor, tStep);
1248 if ( result ) {
1249 status->letTempStrainVectorBe(intVal);
1250 }
1251
1252 status->updateYourself(tStep);
1253
1254 return result;
1255}
1256
1257
1258int
1259MDM :: MMI_update(GaussPoint *gp, TimeStep *tStep, FloatArray *estrain)
1260{
1261 int result = 1;
1262 FloatArray intVal, strain;
1263 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
1264
1265 // now update all internal vars accordingly
1266 strain = status->giveStrainVector();
1267 this->giveRealStressVector(intVal, gp, strain, tStep);
1268 gp->updateYourself(tStep);
1269 return result;
1270}
1271
1272
1273int
1274MDM :: MMI_finish(TimeStep *tStep)
1275{
1276#ifndef MDM_MAPPING_DEBUG
1277 this->mapper.finish(tStep);
1278#else
1279 this->mapperSFT.finish(tStep);
1280 this->mapperLST.finish(tStep);
1281#endif
1282 this->mapper2.finish(tStep);
1283 return 1;
1284}
1285
1286
1287Interface *
1288MDM :: giveInterface(InterfaceType type)
1289{
1291 return static_cast< StructuralNonlocalMaterialExtensionInterface * >(this);
1292 } else if ( type == MaterialModelMapperInterfaceType ) {
1293 return static_cast< MaterialModelMapperInterface * >(this);
1294 } else {
1295 return NULL;
1296 }
1297}
1298
1299int
1300MDM :: packUnknowns(DataStream &buff, TimeStep *tStep, GaussPoint *ip)
1301{
1302 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(ip) );
1303
1304 this->buildNonlocalPointTable(ip);
1306
1307 return (status->giveLocalDamageTensorForAveragePtr()->storeYourself(buff) == CIO_OK);
1308}
1309
1310int
1311MDM :: unpackAndUpdateUnknowns(DataStream &buff, TimeStep *tStep, GaussPoint *ip)
1312{
1313 int result;
1314 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(ip) );
1315 FloatMatrix _LocalDamageTensorForAverage;
1316
1317 result = (_LocalDamageTensorForAverage.restoreYourself(buff) == CIO_OK);
1318 status->setLocalDamageTensorForAverage(_LocalDamageTensorForAverage);
1319 return result;
1320}
1321
1322int
1323MDM :: estimatePackSize(DataStream &buff, GaussPoint *ip)
1324{
1325 //
1326 // Note: status localStrainVectorForAverage memeber must be properly sized!
1327 //
1328 if ( nonlocal ) {
1329 FloatMatrix _help(nsd, nsd);
1330 return _help.givePackSize(buff);
1331 } else {
1332 return 0;
1333 }
1334}
1335
1336
1337double
1338MDM :: predictRelativeComputationalCost(GaussPoint *gp)
1339{
1340 //
1341 // The values returned come from mesurement
1342 // do not change them unless you know what are you doing
1343 //
1344 double cost = 1.5;
1345
1346 if ( nsd == 2 ) {
1347 cost = 1.5;
1348 } else if ( nsd == 3 ) {
1349 cost = 1.8;
1350 }
1351
1352 if ( nonlocal ) {
1353 MDMStatus *status = static_cast< MDMStatus * >( this->giveStatus(gp) );
1354 int size = status->giveIntegrationDomainList()->size();
1355 // just a guess (size/10) found optimal
1356 // cost *= (1.0 + (size/10)*0.5);
1357 cost *= ( 1.0 + size / 15.0 );
1358 }
1359
1360 return cost;
1361}
1362
1363
1364
1365
1366
1368{
1369 for ( int i = 1; i <= nsd; i++ ) {
1372 }
1373}
1374
1375
1376void
1377MDMStatus :: saveContext(DataStream &stream, ContextMode mode)
1378{
1379 StructuralMaterialStatus :: saveContext(stream, mode);
1380
1381 contextIOResultType iores;
1382 if ( ( iores = Psi.storeYourself(stream) ) != CIO_OK ) {
1383 THROW_CIOERR(iores);
1384 }
1385
1386 if ( ( iores = DamageTensor.storeYourself(stream) ) != CIO_OK ) {
1387 THROW_CIOERR(iores);
1388 }
1389
1390 if ( ( iores = damageTensorEigenValues.storeYourself(stream) ) != CIO_OK ) {
1391 THROW_CIOERR(iores);
1392 }
1393
1394 if ( ( iores = damageTensorEigenVectors.storeYourself(stream) ) != CIO_OK ) {
1395 THROW_CIOERR(iores);
1396 }
1397}
1398
1399
1400void
1401MDMStatus :: restoreContext(DataStream &stream, ContextMode mode)
1402{
1403 StructuralMaterialStatus :: restoreContext(stream, mode);
1404
1405 contextIOResultType iores;
1406 if ( ( iores = Psi.restoreYourself(stream) ) != CIO_OK ) {
1407 THROW_CIOERR(iores);
1408 }
1409
1410 if ( ( iores = DamageTensor.restoreYourself(stream) ) != CIO_OK ) {
1411 THROW_CIOERR(iores);
1412 }
1413
1414 if ( ( iores = damageTensorEigenValues.restoreYourself(stream) ) != CIO_OK ) {
1415 THROW_CIOERR(iores);
1416 }
1417
1418 if ( ( iores = damageTensorEigenVectors.restoreYourself(stream) ) != CIO_OK ) {
1419 THROW_CIOERR(iores);
1420 }
1421}
1422
1423void
1424MDMStatus :: updateYourself(TimeStep *tStep)
1425{
1426 StructuralMaterialStatus :: updateYourself(tStep);
1427
1428 Psi = PsiTemp;
1432}
1433
1434void
1435MDMStatus :: initTempStatus()
1436{
1437 StructuralMaterialStatus :: initTempStatus();
1438
1439 PsiTemp = Psi;
1443}
1444
1445void
1446MDMStatus :: printOutputAt(FILE *file, TimeStep *tStep) const
1447{
1448 StructuralMaterialStatus :: printOutputAt(file, tStep);
1449 fprintf(file, "status { ");
1450
1451 fprintf(file, " compliance on microplanes: ");
1452 for ( auto &val : Psi ) {
1453 fprintf( file, " %.4e", val );
1454 }
1455
1456 fprintf(file, ", complianceTensorEigenVectors ");
1457 for ( int i = 1; i <= damageTensorEigenVectors.giveNumberOfRows(); i++ ) {
1458 fprintf(file, "{");
1459 for ( int j = 1; j <= damageTensorEigenVectors.giveNumberOfColumns(); j++ ) {
1460 fprintf( file, " %.4e", damageTensorEigenVectors.at(j, i) );
1461 }
1462
1463 fprintf(file, "}");
1464 }
1465
1466 fprintf(file, "}");
1467
1468 fprintf(file, ", complianceTensorEigenValues ");
1469 for ( auto &val : damageTensorEigenValues ) {
1470 fprintf( file, " %.4e", val );
1471 }
1472
1473 fprintf(file, "}\n");
1474}
1475
1476Interface *
1477MDMStatus :: giveInterface(InterfaceType type)
1478{
1480 return this;
1481 } else {
1482 return nullptr;
1483 }
1484}
1485} // end namespace oofem
1486 //
#define N(a, b)
#define E(a, b)
#define REGISTER_Material(class)
int giveNumberOfElements() const
Returns number of elements in domain.
Definition domain.h:463
Element * giveElement(int n)
Definition domain.C:165
void setField(int item, InputFieldType id)
virtual double giveCharacteristicLength(const FloatArray &normalToCrackPlane)
Definition element.h:938
virtual Material * giveMaterial()
Definition element.C:523
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 zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Definition floatarray.C:689
void times(double s)
Definition floatarray.C:834
bool isNotEmpty() const
Returns true if receiver is not empty.
Definition floatarray.h:263
void times(double f)
contextIOResultType storeYourself(DataStream &stream) const
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
void beProductOf(const FloatMatrix &a, const FloatMatrix &b)
bool jaco_(FloatArray &eval, FloatMatrix &v, int nf)
contextIOResultType restoreYourself(DataStream &stream)
int givePackSize(DataStream &buff) const
bool beInverseOf(const FloatMatrix &src)
int giveNumberOfRows() const
Returns number of rows of receiver.
double at(std::size_t i, std::size_t j) const
int giveNumber()
Returns number of receiver.
Definition gausspoint.h:183
MaterialMode giveMaterialMode()
Returns corresponding material mode of receiver.
Definition gausspoint.h:190
void updateYourself(TimeStep *tStep)
Definition gausspoint.C:127
Element * giveElement()
Returns corresponding element to receiver.
Definition gausspoint.h:187
virtual bool hasField(InputFieldType id)=0
Returns true if record contains field identified by idString keyword.
void followedBy(const IntArray &b, int allocChunk=0)
Definition intarray.C:94
void resize(int n)
Definition intarray.C:73
int & at(std::size_t i)
Definition intarray.h:104
FloatArray tempDamageTensorEigenValues
Principal damage directions.
Definition mdm.h:105
const FloatMatrix * giveLocalDamageTensorForAveragePtr()
Definition mdm.h:129
void setMicroplaneTempDamage(int m, double val)
Definition mdm.h:120
FloatMatrix DamageTensorTemp
Definition mdm.h:103
const FloatMatrix & giveLocalDamageTensorForAverage()
Definition mdm.h:128
FloatArray Psi
Damage values on individual microplanes.
Definition mdm.h:101
FloatMatrix damageTensorEigenVectors
Definition mdm.h:106
void setLocalDamageTensorForAverage(FloatMatrix src)
Definition mdm.h:127
void setMicroplaneTempDamageValues(FloatArray src)
Definition mdm.h:122
FloatArray PsiTemp
Definition mdm.h:101
void setTempDamageTensorEigenVals(FloatArray src)
Definition mdm.h:111
FloatArray damageTensorEigenValues
Definition mdm.h:105
const FloatArray & giveTempDamageTensorEigenVals()
Definition mdm.h:113
void setTempDamageTensor(FloatMatrix src)
Definition mdm.h:126
void updateYourself(TimeStep *tStep) override
Definition mdm.C:1424
FloatMatrix tempDamageTensorEigenVectors
Definition mdm.h:106
const FloatMatrix & giveTempDamageTensor()
Definition mdm.h:124
double giveMicroplaneDamage(int m)
Definition mdm.h:119
const FloatArray & giveDamageTensorEigenVals()
Definition mdm.h:114
const FloatMatrix & giveDamageTensor()
Definition mdm.h:125
const FloatArray & giveMicroplaneDamageValues()
Definition mdm.h:121
void setTempDamageTensorEigenVec(FloatMatrix src)
Definition mdm.h:112
FloatMatrix DamageTensor
Macroscopic damage tensor.
Definition mdm.h:103
MDMModeType
Definition mdm.h:162
@ mdm_3d
Definition mdm.h:162
@ mdm_2d
Definition mdm.h:162
void applyDamageToStiffness(FloatMatrix &d, GaussPoint *gp) const
Definition mdm.C:538
double ParMd
THREAD UNSAFE. These are modified when evaluating the material. Why? This must be avoided at all cost...
Definition mdm.h:174
MDMFormulatrionType formulation
Definition mdm.h:182
void giveRawMDMParameters(double &Efp, double &Ep, const FloatArray &reducedStrain, GaussPoint *gp) const
Definition mdm.C:972
void rotateTensor4(FloatMatrix &Dlocal, const FloatMatrix &t) const
Definition mdm.C:901
void giveMaterialStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const
Definition mdm.C:513
double Ft
Macroscopic tensile strength (necessary to determine Ep and Efp if not given).
Definition mdm.h:180
MDM(int n, Domain *d)
Definition mdm.h:229
void transformStrainToPDC(FloatArray &answer, FloatArray &strain, FloatMatrix &t, GaussPoint *gp) const
Definition mdm.C:358
double tempDillatCoeff
Temperature dilatation coeff.
Definition mdm.h:175
static MMAShapeFunctProjection mapperSFT
Mapper used to map internal variables in adaptivity.
Definition mdm.h:198
int nonlocal
Flag indicating local or nonlocal mode.
Definition mdm.h:189
void transformStiffnessfromPDC(FloatMatrix &de, const FloatMatrix &t) const
Definition mdm.C:623
void applyDamageTranformation(FloatArray &strainPDC, const FloatArray &tempDamageTensorEigenVals) const
Definition mdm.C:403
double mdm_Ep
Parameter controlling the elastic limit.
Definition mdm.h:171
double mdm_Efp
Prescribed value of ef-ep.
Definition mdm.h:173
int type_soft
Definition mdm.h:168
IsotropicLinearElasticMaterial linearElasticMaterial
Reference to bulk (undamaged) material.
Definition mdm.h:186
static MMALeastSquareProjection mapperLST
Definition mdm.h:199
void computePDC(FloatMatrix &tempDamageTensor, FloatArray &tempDamageTensorEigenVals, FloatMatrix &tempDamageTensorEigenVec) const
Definition mdm.C:336
double R
Interaction radius, related to the nonlocal characteristic length of material.
Definition mdm.h:191
std::unique_ptr< Set > sourceElemSet
cached source element set used to map internal variables (adaptivity), created on demand
Definition mdm.h:194
void giveRealStressVector(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedStrain, TimeStep *tStep) const override
Definition mdm.C:87
void computeDamageTensor(FloatMatrix &tempDamageTensor, const FloatArray &totalStrain, GaussPoint *gp, TimeStep *tStep) const
Definition mdm.C:153
MDMFormulatrionType
Definition mdm.h:161
@ COMPLIANCE_DAMAGE
Definition mdm.h:161
@ STIFFNESS_DAMAGE
Definition mdm.h:161
double computeDamageOnPlane(GaussPoint *gp, int mnumber, const FloatArray &strain) const
Definition mdm.C:264
static MMAClosestIPTransfer mapper2
Mapper used to map stresses in adaptivity.
Definition mdm.h:221
int nsd
Number of spatial dimensions.
Definition mdm.h:166
MDMModeType mdmMode
Definition mdm.h:183
void formTransformationMatrix(FloatMatrix &answer, const FloatMatrix &t, int n) const
Definition mdm.C:921
MDMMapperType mapperType
Definition mdm.h:203
MDMMapperType
Definition mdm.h:202
@ mdm_lst
Definition mdm.h:202
@ mdm_sft
Definition mdm.h:202
@ mdm_cpt
Definition mdm.h:202
double Gf
Fracture energy (necessary to determine Ep and Efp if not given).
Definition mdm.h:178
int ndc
Number of damage components.
Definition mdm.h:165
void transformStressFromPDC(FloatArray &answer, const FloatArray &stressPDC, const FloatMatrix &t, GaussPoint *gp) const
Definition mdm.C:472
int type_dam
Definition mdm.h:167
void computeEffectiveStress(FloatArray &stressPDC, const FloatArray &strainPDC, GaussPoint *gp, TimeStep *tStep) const
Definition mdm.C:452
void computeLocalDamageTensor(FloatMatrix &tempDamageTensor, const FloatArray &totalStrain, GaussPoint *gp, TimeStep *tStep) const
Definition mdm.C:198
virtual MaterialStatus * giveStatus(GaussPoint *gp) const
Definition material.C:206
std::vector< FloatArrayF< 6 > > N
FloatArray microplaneWeights
Integration weights of microplanes.
double computeShearMStrainComponent(int mnumber, const FloatArray &macroStrain) const
double E
Young's modulus.
std::vector< FloatArrayF< 3 > > microplaneNormals
Normals of microplanes.
double computeShearLStrainComponent(int mnumber, const FloatArray &macroStrain) const
int numberOfMicroplanes
Number of microplanes.
std::vector< FloatArrayF< 6 > > M
std::vector< FloatArrayF< 6 > > L
double computeNormalStrainComponent(int mnumber, const FloatArray &macroStrain) const
void buildNonlocalPointTable(GaussPoint *gp) const
void updateDomainBeforeNonlocAverage(TimeStep *tStep) const
std ::vector< localIntegrationRecord > * giveIPIntegrationList(GaussPoint *gp) const
std ::vector< localIntegrationRecord > * giveIntegrationDomainList()
double giveIntegrationScale()
Returns associated integration scale.
const FloatArray & giveStrainVector() const
Returns the const pointer to receiver's strain vector.
StructuralMaterialStatus(GaussPoint *g)
Constructor. Creates new StructuralMaterialStatus with IntegrationPoint g.
void letTempStressVectorBe(const FloatArray &v)
Assigns tempStressVector to given vector v.
void letTempStrainVectorBe(const FloatArray &v)
Assigns tempStrainVector to given vector v.
static void computePrincipalValDir(FloatArray &answer, FloatMatrix &dir, const FloatArray &s, stressStrainPrincMode mode)
void giveStressDependentPartOfStrainVector(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedStrainVector, TimeStep *tStep, ValueModeType mode) const
#define THROW_CIOERR(e)
#define OOFEM_ERROR(...)
Definition error.h:79
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Definition inputrecord.h:75
#define IR_GIVE_FIELD(__ir, __value, __id)
Definition inputrecord.h:67
#define OOFEM_LOG_INFO(...)
Definition logger.h:143
#define Ex
Definition matconst.h:59
#define M_PI
Definition mathfem.h:52
#define Nt(p, q)
Definition mdm.C:468
#define HUGE_RELATIVE_COMPLIANCE
Definition mdm.C:261
#define FORMT33(i, j, ij)
Definition mdm.C:913
#define FORMT66(i, j, ij)
Definition mdm.C:917
#define MAX_REL_COMPL_TRESHOLD
Definition mdm.C:535
#define S(p)
Definition mdm.C:469
#define LARGE_EXPONENT
Definition mdm.C:260
#define FORMT44(i, j, ij)
Definition mdm.C:915
#define _IFT_MDM_efp
Definition mdm.h:82
#define _IFT_MDM_parmd
Definition mdm.h:79
#define _IFT_MDM_talpha
Definition mdm.h:78
#define _IFT_MDM_r
Definition mdm.h:81
#define _IFT_MDM_gf
Definition mdm.h:84
#define _IFT_MDM_ft
Definition mdm.h:85
#define _IFT_MDM_ep
Definition mdm.h:83
#define _IFT_MDM_nonloc
Definition mdm.h:80
#define _IFT_MDM_mapper
Definition mdm.h:88
#define _IFT_MDM_formulation
Definition mdm.h:86
#define _IFT_MDM_mode
Definition mdm.h:87
#define MAX_NUMBER_OF_MICROPLANES
long ContextMode
Definition contextmode.h:43
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
@ principal_strain
For computing principal strains from engineering strains.
@ MaterialModelMapperInterfaceType
@ NonlocalMaterialStatusExtensionInterfaceType
@ NonlocalMaterialExtensionInterfaceType
double distance(const FloatArray &x, const FloatArray &y)

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