OOFEM  2.4
OOFEM.org - Object Oriented Finite Element Solver
anisodamagemodel.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 - 2013 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 program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 2 of the License, or
23  * (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
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License
31  * along with this program; if not, write to the Free Software
32  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33  */
34 
35 // This code is based on the anisotropic damage model proposed by Desmorat, Gatuingt and Ragueneau in
36 // their paper "Nonlocal anisotropic damage model and related computational aspects for quasi-brittle material"
37 // published in Engineering Fracture Mechanics 74 (2007) 1539-1560.
38 
39 #include "anisodamagemodel.h"
40 #include "../sm/Materials/structuralmaterial.h"
41 #include "floatmatrix.h"
42 #include "floatarray.h"
43 #include "mathfem.h"
44 #include "datastream.h"
45 #include "contextioerr.h"
46 #include "dynamicinputrecord.h"
47 #include "gausspoint.h"
48 #include "classfactory.h"
49 
50 namespace oofem {
51 REGISTER_Material(AnisotropicDamageMaterial);
52 
54  //
55  // constructor
56  //
57 {
59  E = 0.;
60  nu = 0.;
63  kappa0 = 0.;
64  kappaf = 0.;
65  aA = 0.;
66 }
67 
69 //
70 // destructor
71 //
72 {
73  delete linearElasticMaterial;
74 }
75 
76 int
78 //
79 // returns whether receiver supports the given mode
80 //
81 {
82  return mode == _3dMat || mode == _PlaneStress;
83  //return mode == _3dMat || mode == _PlaneStress || mode == _PlaneStrain || mode == _1dMat;
84 }
85 
86 
87 //********************************************************
88 // plane stress implementation by Milan Jirasek
89 //********************************************************
90 
91 void
93  const FloatArray &totalStrain, TimeStep *atTime)
94 //
95 // special version of the stress-evaluation algorithm applicable under plane stress
96 // based on the report by Jirasek & Suarez, 25 April 2014
97 //
98 // uses the following special methods:
99 // computePrincValDir2D ... evaluation of eigenvalues and eigenvector of a symmetric 2x2 matrix
100 // computeDamage ... application of the damage law
101 // computeTraceD(double) ... function "g" evaluating trace(D) from kappa
102 // checkPrincVal2D ... checking whether principal values are <= 1
103 // computeOutOfPlaneStrain ... evaluation of epsZ for given in-plane strain and damage
104 // computeDimensionlessOutOfPlaneStress ... evaluation of scaled sigZ for given strain and damage
105 // computeInplaneStress ... evaluation of in-plane stress for given strain and damage
106 //
107 // Note: Only Mazars' equivalent strain is implemented for this case,
108 // but the damage law can be varied and there are 4 cases implemented in computeTraceD(double).
109 // There is another method computeTraceD(...), which is used by the 3D algorithm.
110 {
111 #define AD_TOLERANCE 1.e-10 // convergence tolerance for the internal iteration used under plane stress
112 #define AD_MAXITER 20 // maximum number of internal iterations used under plane stress
113  //this->initGpForNewStep(gp);
114  this->initTempStatus(gp);
115  // subtract the stress-independent part of strains (e.g. due to temperature)
116  FloatArray eps;
117  this->giveStressDependentPartOfStrainVector(eps, gp, totalStrain, atTime, VM_Total);
118 
119  // compute in-plane principal strains: epsilon1 and epsilon2
120  // and the components of the first principal strain direction: ceps and seps
121  double epsilon1, epsilon2, ceps, seps;
122  this->computePrincValDir2D(epsilon1, epsilon2, ceps, seps, eps.at(1), eps.at(2), eps.at(3) / 2.);
123 
124  // compute the equivalent strain resulting from the in-plane strains only: equivStrainInPlane
125  // only Mazars' strain implemented so far
126  double equivStrainInPlane = 0.;
127  if ( epsilon1 > 0. ) {
128  equivStrainInPlane += epsilon1 * epsilon1;
129  if ( epsilon2 > 0. ) { // note that we always have epsilon2<=epsilon1
130  equivStrainInPlane += epsilon2 * epsilon2;
131  }
132  }
133  equivStrainInPlane = sqrt(equivStrainInPlane);
134 
135  // compute ez0 = maximum value of the out-of-plane strain that still has no influence on damage
136  // formula (85)
137  double ez0 = 0.;
138  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
139  double kappa = status->giveKappa();
140  if ( equivStrainInPlane < kappa ) {
141  ez0 = sqrt(kappa * kappa - equivStrainInPlane * equivStrainInPlane);
142  }
143 
144  // compute the trial out-of-plane strain, assuming that the equivalent strain is equal to equivStrainInPlane
145  FloatMatrix Dn = status->giveDamage();
146  FloatMatrix tempDamage = Dn;
147  // update damage, if needed
148  if ( equivStrainInPlane > kappa ) {
149  // formula (76)
150  this->computeDamage(tempDamage, Dn, kappa, epsilon1, epsilon2, ceps, seps, 0.);
151  }
152  // compute the first trial value (with volumetric compression assumed, i.e., bulk damage deactivated)
153  // formula (79)
154  double ez1 = this->computeOutOfPlaneStrain(eps, tempDamage, false);
155 
156  double strainTraceInPlane = eps.at(1) + eps.at(2);
157  if ( ( ez1 + strainTraceInPlane > 0. ) || ( ez1 > ez0 ) ) { // first trial value is not admissible
158  bool iteration_needed = true;
159  if ( ez0 + strainTraceInPlane > 0. ) {
160  // compute the second trial value (with volumetric tension assumed, i.e., bulk damage activated)
161  ez1 = this->computeOutOfPlaneStrain(eps, tempDamage, true);
162  iteration_needed = ( ( ez1 > ez0 ) || ( ez1 + strainTraceInPlane < 0. ) );
163  }
164  if ( iteration_needed ) { // the second trial value is not admissible
165  // iterative procedure - out-of-plane strain does have an effect on damage
166  // scaled formula (78)
167  double s0 = this->computeDimensionlessOutOfPlaneStress(eps, ez0, tempDamage);
168  this->computeDamage(tempDamage, Dn, kappa, epsilon1, epsilon2, ceps, seps, ez1);
169  double s1 = this->computeDimensionlessOutOfPlaneStress(eps, ez1, tempDamage);
170  int count = 0;
171  while ( fabs(s1) > AD_TOLERANCE * this->kappa0 ) {
172  if ( ++count > AD_MAXITER ) {
173  OOFEM_ERROR("No convergence in AnisotropicDamageMaterial :: giveRealStressVector for the plane stress case\n");
174  }
175  double ez2 = ( ez1 * s0 - ez0 * s1 ) / ( s0 - s1 );
176  this->computeDamage(tempDamage, Dn, kappa, epsilon1, epsilon2, ceps, seps, ez2);
177  double s2 = this->computeDimensionlessOutOfPlaneStress(eps, ez2, tempDamage);
178  ez0 = ez1;
179  s0 = s1;
180  ez1 = ez2;
181  s1 = s2;
182  }
183  }
184  }
185  status->setTempStrainZ(ez1);
186  status->setTempDamage(tempDamage);
187  double equivStrain = sqrt( equivStrainInPlane * equivStrainInPlane + macbra(ez1) * macbra(ez1) );
188  if ( equivStrain > kappa ) {
189  status->setTempKappa(equivStrain);
190  } else {
191  status->setTempKappa(kappa);
192  }
193  // formulae (93)-(100)
194  computeInplaneStress(answer, eps, ez1, tempDamage);
195  //this->correctBigValues(stressTensor); // ???
196  status->setTempDamage(tempDamage);
197  status->letTempStrainVectorBe(totalStrain);
198  status->letTempStressVectorBe(answer);
199 #ifdef keep_track_of_dissipated_energy
200  status->computeWork(gp);
201 #endif
202 }
203 
204 void
205 AnisotropicDamageMaterial :: computePrincValDir2D(double &D1, double &D2, double &c, double &s, double Dx, double Dy, double Dxy)
206 //
207 // computes the principal values and directions of a symmetric second-order tensor in 2D
208 // input: Dx, Dy, Dxy ... components of the tensor wrt global coordinates
209 // output: D1, D2 ... ordered principal values, D1>=D2
210 // output: c, s ... components of the unit principal vector associated with D1
211 // (cosine and sine of the angle between the major principal direction and the global x-axis)
212 {
213  // based on formulae (88)-(89) from the report by Jirasek & Suarez, 25 April 2014
214  double aux1 = ( Dx + Dy ) / 2.;
215  double aux2 = ( Dx - Dy ) / 2.;
216  double aux3 = sqrt(aux2 * aux2 + Dxy * Dxy);
217  D1 = aux1 + aux3;
218  D2 = aux1 - aux3;
219  // formulae (90)-(92) and the two cases preceding them
220  c = 1.;
221  s = 0.; // cases 1 and 2a
222  if ( Dxy != 0. ) { // case 3
223  double t = ( D1 - Dx ) / Dxy;
224  c = 1. / sqrt(1. + t * t);
225  s = c * t;
226  } else if ( Dx < Dy ) { // case 2b
227  c = 0.;
228  s = 1.;
229  }
230  return;
231 }
232 
233 bool
234 AnisotropicDamageMaterial :: checkPrincVal2D(double Dx, double Dy, double Dxy)
235 //
236 // checks whether both eigenvalues of a symmetric second-order tensor in 2D are <= 1
237 //
238 {
239  if ( Dx + Dy > 2. ) {
240  return false;
241  }
242  if ( Dx + Dy > 1. + Dx * Dy - Dxy * Dxy ) {
243  return false;
244  }
245  return true;
246 }
247 
248 void
249 AnisotropicDamageMaterial :: computeDamage(FloatMatrix &tempDamage, const FloatMatrix &damage, double kappa, double eps1, double eps2, double ceps, double seps, double epsZ)
250 //
251 // evaluates the final damage "tempDamage" from the initial damage "damage", initial history variable "kappa"
252 // and the final in-plane strain
253 // (given by principal values eps1>=eps2, components of first principal direction ceps and seps)
254 // and out-of-plane strain
255 //
256 {
257  // set final damage to initial damage
258  tempDamage = damage;
259 
260  // evaluate final equivalent strain using Mazars' definition
261  double tempEpsEq = 0.;
262  if ( eps1 > 0. ) {
263  tempEpsEq += eps1 * eps1;
264  if ( eps2 > 0. ) {
265  tempEpsEq += eps2 * eps2;
266  }
267  }
268  if ( epsZ > 0. ) {
269  tempEpsEq += epsZ * epsZ;
270  }
271  tempEpsEq = sqrt(tempEpsEq);
272 
273  // check for damage growth
274  if ( tempEpsEq <= kappa ) { // no damage growth
275  return;
276  }
277 
278  // apply incremental damage evolution law
279  // formula (75)
280  double deltaLambda = ( computeTraceD(tempEpsEq) - computeTraceD(kappa) ) / tempEpsEq / tempEpsEq;
281  double eps1p = macbra(eps1);
282  double eps2p = macbra(eps2);
283  double epsZp = macbra(epsZ);
284  double aux1 = deltaLambda * eps1p * eps1p;
285  double aux2 = deltaLambda * eps2p * eps2p;
286  // formula (76), with the square of positive strain expressed using the spectral decomposition
287  tempDamage.at(1, 1) += aux1 * ceps * ceps + aux2 * seps * seps;
288  tempDamage.at(1, 2) += ( aux1 - aux2 ) * ceps * seps;
289  tempDamage.at(2, 1) = tempDamage.at(1, 2);
290  tempDamage.at(2, 2) += aux1 * seps * seps + aux2 * ceps * ceps;
291  tempDamage.at(3, 3) += deltaLambda * epsZp * epsZp;
292 
293  // treat the case when the out-of-plane damage exceeds 1
294  if ( tempDamage.at(3, 3) > 1. ) {
295  tempDamage.at(3, 3) = 1.;
296  }
297  // check whether in-plane principal damages do not exceed 1
298  if ( this->checkPrincVal2D( tempDamage.at(1, 1), tempDamage.at(2, 2), tempDamage.at(1, 2) ) ) {
299  return;
300  }
301  // treat the case when the in-plane damage exceeds 1
302  double D1, D2, cdam, sdam;
303  // compute principal values and direction of the initial damage
304  this->computePrincValDir2D( D1, D2, cdam, sdam, damage.at(1, 1), damage.at(2, 2), damage.at(1, 2) );
305  // compute damage increment components 11 and 22 in the principal damage coordinates
306  double dDx = tempDamage.at(1, 1) - damage.at(1, 1);
307  double dDy = tempDamage.at(2, 2) - damage.at(2, 2);
308  double dDxy = tempDamage.at(1, 2) - damage.at(1, 2);
309  double dD11 = cdam * cdam * dDx + sdam * sdam * dDy + 2. * cdam * sdam * dDxy;
310  double dD22 = sdam * sdam * dDx + cdam * cdam * dDy - 2. * cdam * sdam * dDxy;
311  // compute new principal damages, truncated to 1
312  D1 += dD11;
313  D2 += dD22;
314  if ( D1 > 1. ) {
315  D1 = 1.;
316  }
317  if ( D2 > 1. ) {
318  D2 = 1.;
319  }
320  // evaluate global components of the new damage tensor
321  tempDamage.at(1, 1) = cdam * cdam * D1 + sdam * sdam * D2;
322  tempDamage.at(2, 2) = sdam * sdam * D1 + cdam * cdam * D2;
323  tempDamage.at(1, 2) = cdam * sdam * ( D1 - D2 );
324  tempDamage.at(2, 1) = tempDamage.at(1, 2);
325 }
326 
327 double
329 {
330  double knu, aux;
331  double answer = 0.;
332  if ( equivStrain > this->kappa0 ) {
333  switch ( this->damageLawType ) {
334  case DLT_Desmorat1:
335  answer = ( equivStrain - this->kappa0 ) / ( this->kappaf - this->kappa0 );
336  break;
337  case DLT_Desmorat2:
338  answer = this->aA * ( atan(equivStrain / this->kappaf) - atan(this->kappa0 / this->kappaf) );
339  break;
340  case DLT_Linear:
341  knu = 2. * ( 1. + this->nu ) / 9.;
342  answer = this->kappaf * ( equivStrain - this->kappa0 ) / ( equivStrain * ( this->kappaf - this->kappa0 ) - knu * this->kappa0 * ( this->kappaf - equivStrain ) );
343  break;
344  case DLT_Exponential:
345  knu = 2. * ( 1. + this->nu ) / 9.;
346  aux = exp( -( equivStrain - this->kappa0 ) / ( this->kappaf - this->kappa0 ) );
347  answer = ( equivStrain - aux * this->kappa0 ) / ( equivStrain - aux * knu * this->kappa0 );
348  break;
349  default:
350  OOFEM_ERROR("Unknown type of damage law.\n");
351  }
352  }
353  return answer;
354 }
355 
356 double
357 AnisotropicDamageMaterial :: computeOutOfPlaneStrain(const FloatArray &inplaneStrain, const FloatMatrix &dam, bool tens_flag)
358 //
359 // evaluate the out-of-plane strain from the condition of zero out-of-plane stress for the given damage
360 // based on formula (79) from the report by Jirasek & Suarez, 25 April 2014
361 //
362 {
363  // evaluate principal damage values and directions (in-plane)
364  double D1, D2, cdam, sdam;
365  this->computePrincValDir2D( D1, D2, cdam, sdam, dam.at(1, 1), dam.at(2, 2), dam.at(1, 2) );
366 
367  // evaluate normal strain components in directions of principal damage (in-plane)
368  // formulae (93)-(94)
369  double eps11 = cdam * cdam * inplaneStrain.at(1) + cdam *sdam *inplaneStrain.at(3) + sdam *sdam *inplaneStrain.at(2);
370  double eps22 = sdam * sdam * inplaneStrain.at(1) - cdam *sdam *inplaneStrain.at(3) + cdam *cdam *inplaneStrain.at(2);
371 
372  // out-of-plane damage
373  double Dz = dam.at(3, 3);
374  // formula (4)
375  double Bv = 1.;
376  if ( tens_flag ) {
377  Bv = macbra(1. - D1 - D2 - Dz);
378  }
379  // evaluate auxiliary constants
380  // Q corresponds to K*B*Bv, Q1 corresponds to 2*G*Bz*B1 and Q2 corresponds to 2*G*Bz*B2
381  // but all of them divided by E and multiplied by 3*(1+nu)*(1-2*nu)
382  double Q = ( 3. - D1 - D2 - Dz ) * Bv * ( 1. + nu );
383  double Q1 = 3. * ( 1. - D1 ) * ( 1. - Dz ) * ( 1. - 2. * nu );
384  double Q2 = 3. * ( 1. - D2 ) * ( 1. - Dz ) * ( 1. - 2. * nu );
385 
386  // evaluate out-of-plane strain which would give zero out-of-plane stress (at the given damage)
387  // formula (79)
388  double answer = ( ( Q1 - Q ) * eps11 + ( Q2 - Q ) * eps22 ) / ( Q + Q1 + Q2 );
389  return answer;
390 }
391 
392 double
394 //
395 // evaluate the dimensionless out-of-plane stress (i.e., stress divided by E and multiplied by 3*B*(1+nu)*(1-2*nu))
396 // for the given final in-plane strain, out-of-plane strain and damage (which is already updated for this strain)
397 // based on formula (78) from the report by Jirasek & Suarez, 25 April 2014
398 //
399 {
400  // evaluate principal damage values and directions (in-plane)
401  double D1, D2, cdam, sdam;
402  this->computePrincValDir2D( D1, D2, cdam, sdam, dam.at(1, 1), dam.at(2, 2), dam.at(1, 2) );
403 
404  // evaluate normal strain components in directions of principal damage (in-plane)
405  // formulae (93)-(94)
406  double eps11 = cdam * cdam * inplaneStrain.at(1) + cdam *sdam *inplaneStrain.at(3) + sdam *sdam *inplaneStrain.at(2);
407  double eps22 = sdam * sdam * inplaneStrain.at(1) - cdam *sdam *inplaneStrain.at(3) + cdam *cdam *inplaneStrain.at(2);
408 
409  // out-of-plane damage
410  double Dz = dam.at(3, 3);
411  // formula (4)
412  double Bv = 1.;
413  double strainTrace = inplaneStrain.at(1) + inplaneStrain.at(2) + epsZ;
414  if ( strainTrace > 0. ) {
415  Bv = macbra(1. - D1 - D2 - Dz);
416  }
417  // evaluate auxiliary constants
418  // Q corresponds to K*B*Bv, Q1 corresponds to 2*G*Bz*B1 and Q2 corresponds to 2*G*Bz*B2
419  // but all of them divided by E and multiplied by 3*(1+nu)*(1-2*nu)
420  double Q = ( 3. - D1 - D2 - Dz ) * Bv * ( 1. + nu );
421  double Q1 = 3. * ( 1. - D1 ) * ( 1. - Dz ) * ( 1. - 2. * nu );
422  double Q2 = 3. * ( 1. - D2 ) * ( 1. - Dz ) * ( 1. - 2. * nu );
423  // formula (78) divided by E and multiplied by 3*B*(1+nu)*(1-2*nu)
424  double answer = ( Q - Q1 ) * eps11 + ( Q - Q2 ) * eps22 + ( Q + Q1 + Q2 ) * epsZ;
425  //printf("%g %g %g %g %g %g %g\n",epsZ,eps11,eps22,Q,Q1,Q2,answer);
426  return answer;
427 }
428 
429 void
430 AnisotropicDamageMaterial :: computeInplaneStress(FloatArray &inplaneStress, const FloatArray &inplaneStrain, double epsZ, const FloatMatrix &dam)
431 //
432 // evaluate the in-plane stress components
433 // for the given final in-plane strain, out-of-plane strain and damage (which is already updated for this strain)
434 //
435 {
436  // evaluate principal damage values and directions (in-plane)
437  double D1, D2, cdam, sdam;
438  this->computePrincValDir2D( D1, D2, cdam, sdam, dam.at(1, 1), dam.at(2, 2), dam.at(1, 2) );
439 
440  // evaluate strain components with respect to the principal damage coordinates (in-plane)
441  // formulae (93)-(95), with both sides of (95) multiplied by factor 2
442  double eps11 = cdam * cdam * inplaneStrain.at(1) + cdam *sdam *inplaneStrain.at(3) + sdam *sdam *inplaneStrain.at(2);
443  double eps22 = sdam * sdam * inplaneStrain.at(1) - cdam *sdam *inplaneStrain.at(3) + cdam *cdam *inplaneStrain.at(2);
444  double gam12 = 2. * cdam * sdam * ( inplaneStrain.at(2) - inplaneStrain.at(1) ) + ( cdam * cdam - sdam * sdam ) * inplaneStrain.at(3);
445 
446  /* OLD STYLE
447  * // evaluate in-plane effective stress
448  * double Eaux = E / ( ( 1 + nu ) * ( 1 - 2 * nu ) );
449  * double sig11eff = Eaux * ( ( 1. - nu ) * eps11 + nu * ( eps22 + epsZ ) );
450  * double sig22eff = Eaux * ( ( 1. - nu ) * eps22 + nu * ( eps11 + epsZ ) );
451  * double sigZeff = Eaux * ( ( 1. - nu ) * epsZ + nu * ( eps11 + eps22 ) );
452  * double G = E / ( 2. * ( 1 + nu ) );
453  * double sig12eff = G * gam12;
454  *
455  * // evaluate auxiliary constants
456  * double Dz = dam.at(3, 3);
457  * double Bv = 1.;
458  * double strainTrace = eps11 + eps22 + epsZ;
459  * double damTrace = D1 + D2 + Dz;
460  * if ( strainTrace > 0. ) {
461  * Bv = macbra(1. - damTrace);
462  * }
463  * double K = E / ( 3. * ( 1 - 2 * nu ) );
464  * double sigm = Bv * K * strainTrace;
465  * double Bsig = ( 1. - D1 ) * sig11eff + ( 1. - D2 ) * sig22eff + ( 1. - Dz ) * sigZeff;
466  * Bsig /= ( 3. - damTrace );
467  *
468  * // evaluate nominal stress from effective stress (in principal damage coordinate system)
469  * double sig11 = ( 1. - D1 ) * ( sig11eff - Bsig ) + sigm;
470  * double sig22 = ( 1. - D2 ) * ( sig22eff - Bsig ) + sigm;
471  * double sig12 = sqrt( ( 1. - D1 ) * ( 1. - D2 ) ) * sig12eff;
472  */
473 
474  // evaluate auxiliary constants
475  double K = E / ( 3. * ( 1 - 2 * nu ) );
476  double G = E / ( 2. * ( 1 + nu ) );
477  double Bv = 1.;
478  double strainTrace = eps11 + eps22 + epsZ;
479  double damTrace = D1 + D2 + dam.at(3, 3);
480  if ( strainTrace > 0. ) {
481  Bv = macbra(1. - damTrace);
482  }
483  double B = 3. - damTrace;
484  double B1 = 1. - D1;
485  double B2 = 1. - D2;
486  double Bz = 1. - dam.at(3, 3);
487 
488  // evaluate components of nominal in-plane stress wrt principal damage coordinates
489  // formulae (96)-(97)
490  double sigm = Bv * K * strainTrace;
491  double sig11 = 2. * G * B1 * ( B2 * ( eps11 - eps22 ) + Bz * ( eps11 - epsZ ) ) / B + sigm;
492  double sig22 = 2. * G * B2 * ( B1 * ( eps22 - eps11 ) + Bz * ( eps22 - epsZ ) ) / B + sigm;
493  double sig12 = G * sqrt(B1 * B2) * gam12;
494 
495  // evaluate global components of nominal in-plane stress
496  // formulae (98)-(100)
497  inplaneStress.resize(3);
498  inplaneStress.at(1) = cdam * cdam * sig11 - 2. * cdam * sdam * sig12 + sdam * sdam * sig22;
499  inplaneStress.at(2) = sdam * sdam * sig11 + 2. * cdam * sdam * sig12 + cdam * cdam * sig22;
500  inplaneStress.at(3) = cdam * sdam * ( sig11 - sig22 ) + ( cdam * cdam - sdam * sdam ) * sig12;
501 }
502 
503 //********************************************************
504 // end of the plane stress implementation by Milan Jirasek
505 //********************************************************
506 
507 void
509  const FloatArray &totalStrain,
510  TimeStep *atTime)
511 //
512 // returns real stress vector in 3d stress space of receiver
513 // computed from the state at the beginning of the step and strain at the end of the step
514 //
515 {
516  //this->initGpForNewStep(gp);
517  this->initTempStatus(gp);
518  MaterialMode mode = gp->giveMaterialMode();
519  // subtract the stress-independent part of strains (e.g. due to temperature)
520  FloatArray reducedTotalStrainVector;
521  this->giveStressDependentPartOfStrainVector(reducedTotalStrainVector, gp, totalStrain, atTime, VM_Total);
522 
523  // evaluate stress under general triaxial stress conditions
524  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
526  FloatMatrix de, tempDamage;
527  double equivStrain, kappa = 0.0, tempKappa = 0.0, traceTempD;
528  FloatArray eVals, effectiveStressVector, fullEffectiveStressVector, stressVector;
529  FloatMatrix eVecs, effectiveStressTensor, stressTensor, strainTensor;
530  FloatMatrix Dn = status->giveDamage();
531 
532  this->computeEquivalentStrain(equivStrain, reducedTotalStrainVector, gp, atTime);
533  kappa = this->computeKappa(Dn);
534  if ( equivStrain <= kappa ) { // damage does not grow
535  tempDamage = Dn;
536  tempKappa = kappa;
537  } else {
538  this->computeDamageTensor(tempDamage, gp, reducedTotalStrainVector, equivStrain, atTime);
539  tempKappa = computeKappa(tempDamage);
540  }
541 
542  if ( ( equivStrain <= kappa ) && ( kappa <= this->kappa0 ) ) { // elastic behavior
543  lmat->giveStiffnessMatrix(de, ElasticStiffness, gp, atTime);
544  effectiveStressVector.beProductOf(de, reducedTotalStrainVector);
545  answer = effectiveStressVector;
546  } else {
547  // StructuralMaterial :: giveFullSymVectorForm(fullEffectiveStressVector, effectiveStressVector, mode);
548  // effectiveStressTensor.beMatrixForm(fullEffectiveStressVector);
549  strainTensor.resize(3, 3);
550  strainTensor.zero();
551  if ( mode == _PlaneStress ) {
552  /*
553  * this->computePlaneStressStrain(strainTensor, tempDamage, reducedTotalStrainVector, gp, atTime);
554  * effectiveStressTensor.resize(3, 3);
555  * effectiveStressTensor.zero();
556  * double aux;
557  * aux = E / ( ( 1 + nu ) * ( 1 - 2 * nu ) );
558  * effectiveStressTensor.at(1, 1) = aux * ( ( 1 - nu ) * strainTensor.at(1, 1) + nu * ( strainTensor.at(2, 2) + strainTensor.at(3, 3) ) );
559  * effectiveStressTensor.at(2, 2) = aux * ( ( 1 - nu ) * strainTensor.at(2, 2) + nu * ( strainTensor.at(1, 1) + strainTensor.at(3, 3) ) );
560  * effectiveStressTensor.at(3, 3) = aux * ( ( 1 - nu ) * strainTensor.at(3, 3) + nu * ( strainTensor.at(1, 1) + strainTensor.at(2, 2) ) );
561  * effectiveStressTensor.at(1, 2) = ( E / ( 1 + nu ) ) * strainTensor.at(1, 2);
562  * effectiveStressTensor.at(2, 1) = effectiveStressTensor.at(1, 2);
563  */
564  } else {
565  strainTensor.at(1, 1) = reducedTotalStrainVector.at(1);
566  strainTensor.at(2, 2) = reducedTotalStrainVector.at(2);
567  strainTensor.at(3, 3) = reducedTotalStrainVector.at(3);
568  strainTensor.at(2, 3) = strainTensor.at(3, 2) = reducedTotalStrainVector.at(4) / 2.0;
569  strainTensor.at(1, 3) = strainTensor.at(3, 1) = reducedTotalStrainVector.at(5) / 2.0;
570  strainTensor.at(1, 2) = strainTensor.at(2, 1) = reducedTotalStrainVector.at(6) / 2.0;
571  lmat->giveStiffnessMatrix(de, ElasticStiffness, gp, atTime);
572  effectiveStressVector.beProductOf(de, reducedTotalStrainVector);
573  StructuralMaterial :: giveFullSymVectorForm(fullEffectiveStressVector, effectiveStressVector, mode);
574  effectiveStressTensor.beMatrixForm(fullEffectiveStressVector);
575  }
576  /* lmat->giveStiffnessMatrix(de, ElasticStiffness, gp, atTime);
577  * effectiveStressVector.beProductOf(de, reducedTotalStrainVector);
578  * StructuralMaterial :: giveFullSymVectorForm(fullEffectiveStressVector, effectiveStressVector, mode);
579  * effectiveStressTensor.beMatrixForm(fullEffectiveStressVector);*/
580  //traceTempD=tempDamage.at(1,1)+tempDamage.at(2,2)+tempDamage.at(3,3);
581  double effectiveStressTrace = effectiveStressTensor.at(1, 1) + effectiveStressTensor.at(2, 2) + effectiveStressTensor.at(3, 3);
582  FloatMatrix Part1, Part2, Part3;
583  // First term of the equation 53 of the reference paper****************************************************************************************
584  FloatMatrix AuxMatrix;
585  // Compute (1-D) (called ImD here)
586  FloatMatrix ImD, sqrtImD;
587  ImD.resize(3, 3);
588  ImD.zero();
589  ImD.at(1, 1) = ImD.at(2, 2) = ImD.at(3, 3) = 1;
590  ImD.subtract(tempDamage);
591  // Compute the square root of (1-D), needed in the equation 53 of the reference paper
592  //int checker1 = this->checkSymmetry(ImD);
593  ImD.jaco_(eVals, eVecs, 40);
594  sqrtImD.resize(3, 3);
595  sqrtImD.zero();
596  for ( int i = 1; i <= 3; i++ ) {
597  for ( int j = 1; j <= 3; j++ ) {
598  for ( int k = 1; k <= 3; k++ ) {
599  if ( eVals.at(k) < 0.0 ) {
600  eVals.at(k) = 0.0;
601  }
602  }
603  sqrtImD.at(i, j) = sqrt( eVals.at(1) ) * eVecs.at(i, 1) * eVecs.at(j, 1) + sqrt( eVals.at(2) ) * eVecs.at(i, 2) * eVecs.at(j, 2) + sqrt( eVals.at(3) ) * eVecs.at(i, 3) * eVecs.at(j, 3);
604  }
605  }
606 
607  AuxMatrix.beProductOf(effectiveStressTensor, sqrtImD);
608  //stressTensor.beProductOf(sqrtImD,AuxMatrix);
609  Part1.beProductOf(sqrtImD, AuxMatrix);
610 
611  // Second term of the equation 53 of the reference paper*****************************************************************************************
613  // Correct the trace of the damage tensor if necessary (see section 8.1 of the reference paper)
614  traceTempD = computeTraceD(tempDamage, strainTensor, gp);
615  double scalar = 0;
616  AuxMatrix.zero();
617  for ( int i = 1; i <= 3; i++ ) {
618  for ( int j = 1; j <= 3; j++ ) {
619  scalar += ImD.at(i, j) * effectiveStressTensor.at(i, j);
620  }
621  }
622  if ( ( 3. - traceTempD ) < 0.0001 ) {
623  scalar = 0.0;
624  } else {
625  scalar = scalar / ( 3. - traceTempD );
626  }
627  //scalar /= 3.-traceTempD;
628  AuxMatrix = ImD;
629  AuxMatrix.times(scalar);
630  Part2 = ImD;
631  Part2.times(scalar);
632 
633 
634  //stressTensor.subtract(AuxMatrix);
635  // Third term of the equation 53 of the reference paper********************************************************************************************
636  AuxMatrix.zero();
637  AuxMatrix.at(1, 1) = AuxMatrix.at(2, 2) = AuxMatrix.at(3, 3) = 1. / 3.;
638  if ( effectiveStressTrace > 0 ) {
639  AuxMatrix.times( ( 1 - traceTempD ) * effectiveStressTrace );
640  } else {
641  AuxMatrix.times(effectiveStressTrace);
642  }
643  Part3 = AuxMatrix;
644  //stressTensor.add(AuxMatrix);
645  stressTensor = Part1;
646  stressTensor.subtract(Part2);
647  stressTensor.add(Part3);
648  double factor;
649  factor = computeCorrectionFactor(tempDamage, strainTensor, gp);
650  stressTensor.times(factor);
651  stressVector.beSymVectorForm(stressTensor);
652  StructuralMaterial :: giveReducedSymVectorForm(answer, stressVector, mode);
653  }
654 
655  // update gp
656  this->correctBigValues(stressTensor);
657  // int checker20 = this->checkSymmetry(tempDamage);
658  // int checker21 = this->checkSymmetry(stressTensor);
659  // int checker22 = this->checkSymmetry(strainTensor);
660  status->letTempStrainVectorBe(totalStrain);
661  status->letTempStressVectorBe(answer);
662  status->setTempDamage(tempDamage);
663  status->setTempKappa(tempKappa);
664 #ifdef keep_track_of_dissipated_energy
665  status->computeWork(gp);
666 #endif
667 }
668 
669 void
671 {
672  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
673 
674  if ( strain.isEmpty() ) {
675  kappa = 0.;
676  return;
677  }
678 
679 
680  if ( this->equivStrainType == EST_Mazars ) {
681  double posNorm = 0.0;
682  FloatArray principalStrains, fullstrain;
683 
685 
686  // if plane stress mode -> compute strain in z-direction from condition of zero stress in corresponding direction
687  if ( gp->giveMaterialMode() == _PlaneStress ) {
688  // fullstrain.at(3) = -nu * ( fullstrain.at(1) + fullstrain.at(2) ) / ( 1. - nu );
689  fullstrain.at(3) = status->giveTempStrainZ();
690  } else if ( gp->giveMaterialMode() == _1dMat ) {
691  fullstrain.at(2) = -nu *fullstrain.at(1);
692  fullstrain.at(3) = -nu *fullstrain.at(1);
693  }
694 
695  this->computePrincipalValues(principalStrains, fullstrain, principal_strain);
696 
697  for ( int i = 1; i <= 3; i++ ) {
698  if ( principalStrains.at(i) > 0.0 ) {
699  posNorm += principalStrains.at(i) * principalStrains.at(i);
700  }
701  }
702 
703  kappa = sqrt(posNorm);
704  } else {
705  OOFEM_ERROR("computeEquivalentStrain: unknown EquivStrainType");
706  }
707  /*
708  * if ( this->equivStrainType == EST_Mazars ) {
709  * double posNorm = 0.0;
710  * FloatArray principalStrains, fullstrain;
711  *
712  * StructuralMaterial :: giveFullSymVectorForm( fullstrain, strain, gp->giveMaterialMode() );
713  *
714  * // if plane stress mode -> compute strain in z-direction from condition of zero stress in corresponding direction
715  * if ( gp->giveMaterialMode() == _PlaneStress ) {
716  * fullstrain.at(3) = -nu * ( fullstrain.at(1) + fullstrain.at(2) ) / ( 1. - nu );
717  * } else if ( gp->giveMaterialMode() == _1dMat ) {
718  * fullstrain.at(2) = -nu *fullstrain.at(1);
719  * fullstrain.at(3) = -nu *fullstrain.at(1);
720  * }
721  *
722  * this->computePrincipalValues(principalStrains, fullstrain, principal_strain);
723  *
724  * for ( int i = 1; i <= 3; i++ ) {
725  * if ( principalStrains.at(i) > 0.0 ) {
726  * posNorm += principalStrains.at(i) * principalStrains.at(i);
727  * }
728  * }
729  *
730  * kappa = sqrt(posNorm);
731  * } else if ( ( this->equivStrainType == EST_Rankine_Smooth ) || ( this->equivStrainType == EST_Rankine_Standard ) ) {
732  * // EST_Rankine equiv strain measure
733  * double sum = 0.;
734  * FloatArray stress, fullStress, principalStress;
735  * FloatMatrix de;
736  *
737  * lmat->giveStiffnessMatrix(de, SecantStiffness, gp, atTime);
738  * stress.beProductOf(de, strain);
739  * StructuralMaterial :: giveFullSymVectorForm( fullStress, stress, gp->giveMaterialMode() );
740  * this->computePrincipalValues(principalStress, fullStress, principal_stress);
741  * for ( int i = 1; i <= 3; i++ ) {
742  * if ( principalStress.at(i) > 0.0 ) {
743  * if ( this->equivStrainType == EST_Rankine_Smooth ) {
744  * sum += principalStress.at(i) * principalStress.at(i);
745  * } else if ( sum < principalStress.at(i) ) {
746  * sum = principalStress.at(i);
747  * }
748  * } else if ( sum < principalStress.at(i) ) {
749  * sum = principalStress.at(i);
750  * }
751  * }
752  *
753  * if ( this->equivStrainType == EST_Rankine_Smooth ) {
754  * sum = sqrt(sum);
755  * }
756  *
757  * kappa = sum / lmat->give('E', gp);
758  * } else if ( ( this->equivStrainType == EST_ElasticEnergy ) || ( this->equivStrainType == EST_ElasticEnergyPositiveStress ) || ( this->equivStrainType == EST_ElasticEnergyPositiveStrain ) ) {
759  * // equivalent strain expressions based on elastic energy
760  * FloatMatrix de;
761  * FloatArray stress;
762  * double sum;
763  *
764  * lmat->giveStiffnessMatrix(de, SecantStiffness, gp, atTime);
765  * if ( this->equivStrainType == EST_ElasticEnergy ) {
766  * // standard elastic energy
767  * stress.beProductOf(de, strain);
768  * sum = strain.dotProduct(stress);
769  * } else if ( this->equivStrainType == EST_ElasticEnergyPositiveStress ) {
770  * // elastic energy corresponding to positive part of stress
771  * FloatArray fullStress, principalStress;
772  * StructuralMaterial :: giveFullSymVectorForm( fullStress, stress, gp->giveMaterialMode() );
773  * this->computePrincipalValues(principalStress, fullStress, principal_stress);
774  * // TO BE FINISHED
775  * sum = 0.;
776  * OOFEM_ERROR("Elastic energy corresponding to positive part of stress not finished");
777  * } else {
778  * // elastic energy corresponding to positive part of strain
779  * // TO BE DONE
780  * sum = 0.;
781  * OOFEM_ERROR("Elastic energy corresponding to positive part of strain not finished");
782  * }
783  *
784  * kappa = sqrt( sum / lmat->give('E', gp) );
785  * } else if ( this->equivStrainType == EST_Griffith ) {
786  * double sum = 0.;
787  * FloatArray stress, fullStress, principalStress;
788  * FloatMatrix de;
789  *
790  * lmat->giveStiffnessMatrix(de, SecantStiffness, gp, atTime);
791  * stress.beProductOf(de, strain);
792  * StructuralMaterial :: giveFullSymVectorForm( fullStress, stress, gp->giveMaterialMode() );
793  * this->computePrincipalValues(principalStress, fullStress, principal_stress);
794  * for ( int i = 1; i <= 3; i++ ) {
795  * if ( principalStress.at(i) > 0.0 && sum < principalStress.at(i) ) {
796  * sum = principalStress.at(i);
797  * }
798  * }
799  *
800  * //Use Griffith criterion if Rankine not applied
801  * if (sum == 0.){
802  * sum = -pow(principalStress.at(1)-principalStress.at(3),2.)/8./(principalStress.at(1)+principalStress.at(3));
803  * }
804  * sum = max(sum,0.);
805  * kappa = sum / lmat->give('E', gp);
806  * } else {
807  * OOFEM_ERROR("computeEquivalentStrain: unknown EquivStrainType");
808  * }
809  */
810 }
811 
812 // Computes Kappa according to the first damage law proposed in reference paper.
813 double
815 {
816  double trace = damageTensor.giveTrace();
817  double answer = ( this->kappaf - this->kappa0 ) * trace + this->kappa0;
818  return answer;
819 }
820 
821 
822 // Computes the percentage of deltaD that needs to be added so the first eigenvalue of (tempDamageTensor + alpha*deltaD) reaches Dc
823 // To do this, the middle point algorithm is used.
824 // @TODO: this algorithm is not particularly efficient and another algorithm could be implemented.
825 double
826 AnisotropicDamageMaterial :: obtainAlpha1(FloatMatrix tempDamageTensor, double deltaLambda, FloatMatrix positiveStrainTensor, double damageThreshold)
827 {
828  double alpha_a, alpha_b, newAlpha, eps, maxDamage, size;
829  FloatMatrix deltaD, positiveStrainTensorSquared, resultingDamageTensor, eVecs;
830  FloatArray eVals;
831  int cont;
832  cont = 1;
833  alpha_a = 0;
834  alpha_b = 1;
835  newAlpha = ( alpha_a + alpha_b ) / 2;
836  positiveStrainTensorSquared.beProductOf(positiveStrainTensor, positiveStrainTensor);
837  deltaD = positiveStrainTensorSquared;
838  deltaD.times(newAlpha * deltaLambda);
839  this->correctBigValues(deltaD);
840  resultingDamageTensor = tempDamageTensor;
841  resultingDamageTensor.add(deltaD);
842  //int checker2 = this->checkSymmetry(resultingDamageTensor);
843  resultingDamageTensor.jaco_(eVals, eVecs, 20);
844  size = eVals.giveSize();
845  maxDamage = eVals.at(1);
846  for ( int i = 2; i <= size; i++ ) {
847  if ( eVals.at(i) > maxDamage ) {
848  maxDamage = eVals.at(i);
849  }
850  }
851  eps = maxDamage - damageThreshold;
852  do {
853  if ( eps > 0.0 ) {
854  alpha_b = newAlpha;
855  newAlpha = ( alpha_a + alpha_b ) / 2;
856  deltaD = positiveStrainTensorSquared;
857  deltaD.times(newAlpha * deltaLambda);
858  this->correctBigValues(deltaD);
859  resultingDamageTensor = tempDamageTensor;
860  resultingDamageTensor.add(deltaD);
861  //int checker3 = this->checkSymmetry(resultingDamageTensor);
862  resultingDamageTensor.jaco_(eVals, eVecs, 20);
863  size = eVals.giveSize();
864  maxDamage = eVals.at(1);
865  for ( int i = 2; i <= size; i++ ) {
866  if ( eVals.at(i) > maxDamage ) {
867  maxDamage = eVals.at(i);
868  }
869  }
870  eps = maxDamage - damageThreshold;
871  cont = cont + 1;
872  if ( cont == 100 ) {
873  return newAlpha;
874  }
875  } else {
876  alpha_a = newAlpha;
877  newAlpha = ( alpha_a + alpha_b ) / 2;
878  deltaD = positiveStrainTensorSquared;
879  deltaD.times(newAlpha * deltaLambda);
880  this->correctBigValues(deltaD);
881  resultingDamageTensor = tempDamageTensor;
882  resultingDamageTensor.add(deltaD);
883  //int checker4 = this->checkSymmetry(resultingDamageTensor);
884  resultingDamageTensor.jaco_(eVals, eVecs, 20);
885  size = eVals.giveSize();
886  maxDamage = eVals.at(1);
887  for ( int i = 2; i <= size; i++ ) {
888  if ( eVals.at(i) > maxDamage ) {
889  maxDamage = eVals.at(i);
890  }
891  }
892  eps = maxDamage - damageThreshold;
893  cont = cont + 1;
894  if ( cont == 100 ) {
895  return newAlpha;
896  }
897  }
898  } while ( fabs(eps) > 1.0e-15 );
899  return newAlpha;
900 }
901 
902 // Computes the percentage of deltaD that needs to be added so the second eigenvalue of (tempDamageTensor + alpha*deltaD) reaches Dc
903 // To do this, the middle point algorithm is used.
904 // @TODO: this algorithm is not particularly efficient and another algorithm could be implemented.
905 double
906 AnisotropicDamageMaterial :: obtainAlpha2(FloatMatrix tempDamageTensor, double deltaLambda, FloatMatrix positiveStrainTensor, FloatMatrix projPosStrainTensor, double damageThreshold)
907 {
908  double alpha_a, alpha_b, newAlpha, eps, maxDamage, size, minVal;
909  FloatMatrix deltaD, resultingDamageTensor, eVecs;
910  FloatArray eVals;
911  int cont;
912  maxDamage = 0.0;
913  cont = 1;
914  alpha_a = 0;
915  alpha_b = 1;
916  newAlpha = ( alpha_a + alpha_b ) / 2;
917  deltaD = projPosStrainTensor;
918  deltaD.times(newAlpha * deltaLambda);
919  this->correctBigValues(deltaD);
920  resultingDamageTensor = tempDamageTensor;
921  resultingDamageTensor.add(deltaD);
922  //int checker5 = this->checkSymmetry(resultingDamageTensor);
923  resultingDamageTensor.jaco_(eVals, eVecs, 40);
924  size = eVals.giveSize();
925  minVal = eVals.at(1);
926  for ( int i = 2; i <= size; i++ ) {
927  if ( eVals.at(i) < minVal ) {
928  minVal = eVals.at(i);
929  maxDamage = ( ( eVals.at(1) + eVals.at(2) + eVals.at(3) ) - eVals.at(i) ) / 2;
930  }
931  }
932  eps = maxDamage - damageThreshold;
933  do {
934  if ( eps > 0.0 ) {
935  alpha_b = newAlpha;
936  newAlpha = ( alpha_a + alpha_b ) / 2;
937  deltaD = projPosStrainTensor;
938  deltaD.times(newAlpha * deltaLambda);
939  this->correctBigValues(deltaD);
940  resultingDamageTensor = tempDamageTensor;
941  resultingDamageTensor.add(deltaD);
942  //int checker6 = this->checkSymmetry(resultingDamageTensor);
943  resultingDamageTensor.jaco_(eVals, eVecs, 40);
944  size = eVals.giveSize();
945  minVal = eVals.at(1);
946  for ( int i = 2; i <= size; i++ ) {
947  if ( eVals.at(i) < minVal ) {
948  minVal = eVals.at(i);
949  maxDamage = ( ( eVals.at(1) + eVals.at(2) + eVals.at(3) ) - eVals.at(i) ) / 2;
950  }
951  }
952  eps = maxDamage - damageThreshold;
953  cont = cont + 1;
954  if ( cont == 100 ) {
955  return newAlpha;
956  }
957  } else {
958  alpha_a = newAlpha;
959  newAlpha = ( alpha_a + alpha_b ) / 2;
960  deltaD = projPosStrainTensor;
961  deltaD.times(newAlpha * deltaLambda);
962  this->correctBigValues(deltaD);
963  resultingDamageTensor = tempDamageTensor;
964  resultingDamageTensor.add(deltaD);
965  //int checker7 = this->checkSymmetry(resultingDamageTensor);
966  resultingDamageTensor.jaco_(eVals, eVecs, 40);
967  size = eVals.giveSize();
968  minVal = eVals.at(1);
969  for ( int i = 2; i <= size; i++ ) {
970  if ( eVals.at(i) < minVal ) {
971  minVal = eVals.at(i);
972  maxDamage = ( ( eVals.at(1) + eVals.at(2) + eVals.at(3) ) - eVals.at(i) ) / 2;
973  }
974  }
975  eps = maxDamage - damageThreshold;
976  cont = cont + 1;
977  if ( cont == 100 ) {
978  return newAlpha;
979  }
980  }
981  } while ( fabs(eps) > 1.0e-15 );
982  return newAlpha;
983 }
984 
985 // Computes the percentage of deltaD that needs to be added so the third eigenvalue of (tempDamageTensor + alpha*deltaD) reaches Dc
986 // To do this, the middle point algorithm is used.
987 // @TODO: this algorithm is not particularly efficient and another algorithm could be implemented.
988 double
989 AnisotropicDamageMaterial :: obtainAlpha3(FloatMatrix tempDamageTensor, double deltaLambda, FloatMatrix positiveStrainTensor, FloatArray vec3, double damageThreshold)
990 {
991  double alpha_a, alpha_b, newAlpha, eps, aux = 0;
992  FloatMatrix deltaD, positiveStrainTensorSquared, resultingDamageTensor, eVecs;
993  FloatArray eVals;
994  int cont;
995  cont = 1;
996  alpha_a = 0;
997  alpha_b = 1;
998  newAlpha = ( alpha_a + alpha_b ) / 2;
999  positiveStrainTensorSquared.beProductOf(positiveStrainTensor, positiveStrainTensor);
1000  for ( int i = 1; i <= 3; i++ ) {
1001  aux = aux + vec3.at(i) * ( positiveStrainTensorSquared.at(i, 1) * vec3.at(1) + positiveStrainTensorSquared.at(i, 2) * vec3.at(2) + positiveStrainTensorSquared.at(i, 3) * vec3.at(3) );
1002  }
1003  deltaD.beDyadicProductOf(vec3, vec3);
1004  deltaD.times(newAlpha * deltaLambda * aux);
1005  this->correctBigValues(deltaD);
1006  resultingDamageTensor = tempDamageTensor;
1007  resultingDamageTensor.add(deltaD);
1008  //int checker8 = this->checkSymmetry(resultingDamageTensor);
1009  resultingDamageTensor.jaco_(eVals, eVecs, 20);
1010  eps = eVals.at(1) + eVals.at(2) + eVals.at(3) - 3 * damageThreshold;
1011  do {
1012  if ( eps > 0.0 ) {
1013  alpha_b = newAlpha;
1014  newAlpha = ( alpha_a + alpha_b ) / 2;
1015  deltaD.beDyadicProductOf(vec3, vec3);
1016  deltaD.times(newAlpha * deltaLambda * aux);
1017  this->correctBigValues(deltaD);
1018  resultingDamageTensor = tempDamageTensor;
1019  resultingDamageTensor.add(deltaD);
1020  //int checker9 = this->checkSymmetry(resultingDamageTensor);
1021  resultingDamageTensor.jaco_(eVals, eVecs, 20);
1022  eps = eVals.at(1) + eVals.at(2) + eVals.at(3) - 3 * damageThreshold;
1023  cont = cont + 1;
1024  if ( cont == 100 ) {
1025  return newAlpha;
1026  }
1027  } else {
1028  alpha_a = newAlpha;
1029  newAlpha = ( alpha_a + alpha_b ) / 2;
1030  deltaD.beDyadicProductOf(vec3, vec3);
1031  deltaD.times(newAlpha * deltaLambda * aux);
1032  this->correctBigValues(deltaD);
1033  resultingDamageTensor = tempDamageTensor;
1034  resultingDamageTensor.add(deltaD);
1035  //int checker10 = this->checkSymmetry(resultingDamageTensor);
1036  resultingDamageTensor.jaco_(eVals, eVecs, 20);
1037  eps = eVals.at(1) + eVals.at(2) + eVals.at(3) - 3 * damageThreshold;
1038  cont = cont + 1;
1039  if ( cont == 100 ) {
1040  return newAlpha;
1041  }
1042  }
1043  } while ( fabs(eps) > 1.0e-15 );
1044  return newAlpha;
1045 }
1046 //To check symmetry: delete this function when everything works fine
1047 double
1049 {
1050  int a = 0;
1051  int nRows = matrix.giveNumberOfRows();
1052  for ( int i = 1; i <= nRows; i++ ) {
1053  for ( int j = 1; j <= nRows; j++ ) {
1054  if ( fabs( matrix.at(i, j) - matrix.at(j, i) ) < 1.e-6 ) {
1055  ;
1056  } else {
1057  a = 1;
1058  }
1059  }
1060  }
1061  if ( a == 1 ) {
1062  a = 1;
1063  }
1064  return a;
1065 }
1066 
1067 void
1069 {
1070  int nRows = matrix.giveNumberOfRows();
1071  for ( int i = 1; i <= nRows; i++ ) {
1072  for ( int j = 1; j <= nRows; j++ ) {
1073  if ( matrix.at(i, j) != matrix.at(j, i) ) {
1074  double Aux = ( matrix.at(i, j) + matrix.at(j, i) ) / 2.0;
1075  matrix.at(i, j) = Aux;
1076  matrix.at(j, i) = Aux;
1077  }
1078  }
1079  }
1080 }
1081 
1082 double
1084 {
1085  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1086  int flag = status->giveFlag();
1087  //int tempFlag=status->giveTempFlag();
1088  double Dc = 1.00, trD = 0;
1089  // If flag = 0, the trace of the damage tensor has never been greater than 1 before
1090  if ( flag == 0 ) {
1091  if ( ( strainTensor.at(1, 1) + strainTensor.at(2, 2) + strainTensor.at(3, 3) ) < 0 ) { // Compression
1092  trD = tempDamageTensor.at(1, 1) + tempDamageTensor.at(2, 2) + tempDamageTensor.at(3, 3);
1093  if ( trD >= 1 ) {
1094  status->setTempFlag(1);
1095  } // The trace of the damage tensor is greater than 1 for the first time, then, flag turns into 1
1096  } else { // Tension
1097  if ( ( tempDamageTensor.at(1, 1) + tempDamageTensor.at(2, 2) + tempDamageTensor.at(3, 3) ) >= 1 ) {
1098  trD = Dc;
1099  } else {
1100  trD = tempDamageTensor.at(1, 1) + tempDamageTensor.at(2, 2) + tempDamageTensor.at(3, 3);
1101  }
1102  }
1103  }
1104  // If flag = 1, the trace of the damage tensor has become greater than 1 before
1105  if ( flag == 1 ) {
1106  if ( ( strainTensor.at(1, 1) + strainTensor.at(2, 2) + strainTensor.at(3, 3) ) < 0 ) { // Compression
1107  trD = tempDamageTensor.at(1, 1) + tempDamageTensor.at(2, 2) + tempDamageTensor.at(3, 3);
1108  } else {
1109  trD = Dc;
1110  } // Tension
1111  }
1112  return trD;
1113 }
1114 
1115 double
1117 {
1118  // In the case that the material has experimented some damaged under compression, this must affect the material behaviour when it is
1119  // under tension in the future
1120  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1121  int tempFlag = status->giveFlag();
1122  double tempStoredFactor = status->giveStoredFactor();
1123  double Dc = 1.00, trD = 0;
1124  double factor = 0.0;
1125  trD = tempDamageTensor.at(1, 1) + tempDamageTensor.at(2, 2) + tempDamageTensor.at(3, 3);
1126  // If flag = 0, the trace of the damage tensor has never been greater than Dc under compression before
1127  if ( tempFlag == 0 ) {
1128  if ( ( strainTensor.at(1, 1) + strainTensor.at(2, 2) + strainTensor.at(3, 3) ) < 0 ) { // Compression
1129  factor = 1.0;
1130  if ( ( 1.0 - trD ) < tempStoredFactor ) {
1131  status->setTempStoredFactor(1.0 - trD);
1132  }
1133  if ( ( 1.0 - trD ) <= ( 1.0 - Dc ) ) {
1134  tempFlag = 1;
1135  status->setTempFlag(1); // The trace of the damage tensor is greater than Dc for the first time, then, flag turns into 1
1136  status->setTempStoredFactor(1. - Dc);
1137  }
1138  } else { // Tension
1139  factor = tempStoredFactor;
1140  }
1141  }
1142 
1143  // If flag = 1, the trace of the damage tensor has become greater than 1 before
1144  if ( tempFlag == 1 ) {
1145  if ( ( strainTensor.at(1, 1) + strainTensor.at(2, 2) + strainTensor.at(3, 3) ) < 0 ) { // Compression
1146  factor = 1.0;
1147  } else {
1148  //{factor=status->giveStoredFactor();} // Tension
1149  factor = 1. - Dc;
1150  }
1151  }
1152  return factor;
1153 }
1154 
1155 void
1157  MatResponseMode mode,
1158  GaussPoint *gp,
1159  TimeStep *atTime)
1160 //
1161 // Implementation of the 3D stiffness matrix, according to the equations 56 and 57 of the reference paper.
1162 {
1163  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1164  if ( mode == ElasticStiffness ) {
1165  this->giveLinearElasticMaterial()->giveStiffnessMatrix(answer, mode, gp, atTime);
1166  } else {
1167  const FloatArray &totalStrain = status->giveTempStrainVector();
1168  FloatArray reducedTotalStrainVector;
1169  this->giveStressDependentPartOfStrainVector(reducedTotalStrainVector, gp, totalStrain, atTime, VM_Total);
1170  //FloatArray totalStrain;
1171  FloatMatrix damageTensor, strainTensor;
1172  // The strain vector is turned into a tensor; for that, the elements that are out of the diagonal
1173  // must be divided by 2
1174  strainTensor.resize(3, 3);
1175  strainTensor.zero();
1176  strainTensor.at(1, 1) = reducedTotalStrainVector.at(1);
1177  strainTensor.at(2, 2) = reducedTotalStrainVector.at(2);
1178  strainTensor.at(3, 3) = reducedTotalStrainVector.at(3);
1179  strainTensor.at(2, 3) = reducedTotalStrainVector.at(4) / 2.0;
1180  strainTensor.at(3, 2) = reducedTotalStrainVector.at(4) / 2.0;
1181  strainTensor.at(1, 3) = reducedTotalStrainVector.at(5) / 2.0;
1182  strainTensor.at(3, 1) = reducedTotalStrainVector.at(5) / 2.0;
1183  strainTensor.at(1, 2) = reducedTotalStrainVector.at(6) / 2.0;
1184  strainTensor.at(2, 1) = reducedTotalStrainVector.at(6) / 2.0;
1185  // The damage tensor is read
1186  damageTensor = status->giveTempDamage();
1187  AnisotropicDamageMaterial :: computeSecantOperator(answer, strainTensor, damageTensor, gp);
1188  for ( int j = 4; j <= 6; j++ ) {
1189  for ( int i = 1; i <= 6; i++ ) {
1190  answer.at(i, j) = answer.at(i, j) / 2.0;
1191  }
1192  }
1193  }
1194 }
1195 
1196 
1198  GaussPoint *gp, TimeStep *atTime)
1199 {
1200  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1201  if ( mode == ElasticStiffness ) {
1202  this->giveLinearElasticMaterial()->giveStiffnessMatrix(answer, mode, gp, atTime);
1203  } else {
1204  FloatArray totalStrain = status->giveTempStrainVector();
1205  FloatArray reducedTotalStrainVector;
1206  this->giveStressDependentPartOfStrainVector(reducedTotalStrainVector, gp, totalStrain, atTime, VM_Total);
1207  FloatMatrix damageTensor, strainTensor;
1208  // The damage tensor is read
1209  damageTensor.resize(3, 3);
1210  damageTensor.zero();
1211  damageTensor = status->giveTempDamage();
1212  this->computePlaneStressStrain(strainTensor, damageTensor, reducedTotalStrainVector, gp, atTime);
1213  // The strain vector is turned into a tensor; for that, the elements that are out of the diagonal
1214  // must be divided by 2
1215  FloatMatrix secantOperator;
1216  secantOperator.resize(6, 6);
1217  AnisotropicDamageMaterial :: computeSecantOperator(secantOperator, strainTensor, damageTensor, gp);
1218  double C11, C12, C13, C16, C21, C22, C23, C26, C61, C62, C63, C66, q, r, s;
1219  C11 = secantOperator.at(1, 1);
1220  C12 = secantOperator.at(1, 2);
1221  C13 = secantOperator.at(1, 3);
1222  C16 = secantOperator.at(1, 6);
1223  C21 = secantOperator.at(2, 1);
1224  C22 = secantOperator.at(2, 2);
1225  C23 = secantOperator.at(2, 3);
1226  C26 = secantOperator.at(2, 6);
1227  C61 = secantOperator.at(6, 1);
1228  C62 = secantOperator.at(6, 2);
1229  C63 = secantOperator.at(6, 3);
1230  C66 = secantOperator.at(6, 6);
1231  //Change 14-march-2014
1232  FloatArray stressVector;
1233  FloatMatrix Dn;
1234  stressVector = status->giveTempStressVector();
1235  Dn = status->giveTempDamage();
1236  this->computePlaneStressStrain(strainTensor, Dn, reducedTotalStrainVector, gp, atTime);
1237  if ( ( stressVector.at(1) + stressVector.at(2) ) < 1.0e-5 ) {
1238  q = -nu / E;
1239  } else {
1240  q = strainTensor.at(3, 3) / ( stressVector.at(1) + stressVector.at(2) );
1241  }
1242  //q = strainTensor.at(3,3)/(stressVector.at(1)+stressVector.at(2));
1243  //q = -nu/E;
1244  r = 1. / ( 1. - C13 * q );
1245  s = 1. / ( 1. - q * C23 - C23 * q * q * r * C13 );
1246  answer.resize(3, 3);
1247  answer.at(2, 1) = s * ( C21 + C11 * C23 * q * r );
1248  answer.at(2, 2) = s * ( C22 + C12 * C23 * q * r );
1249  answer.at(2, 3) = s * ( C26 + C16 * C23 * q * r ) * 1. / 2.;
1250  answer.at(1, 1) = r * ( C11 + C13 * q * answer.at(2, 1) );
1251  answer.at(1, 2) = r * ( C12 + C13 * q * answer.at(2, 2) );
1252  answer.at(1, 3) = r * ( C16 + C13 * q * answer.at(2, 3) ) * 1 / 2;
1253  answer.at(3, 1) = C61 + C63 * q * ( answer.at(1, 1) + answer.at(2, 1) );
1254  answer.at(3, 2) = C62 + C63 * q * ( answer.at(1, 2) + answer.at(2, 2) );
1255  answer.at(3, 3) = ( C66 + C63 * q * ( answer.at(1, 3) + answer.at(2, 3) ) ) * 1. / 2.;
1256  }
1257 }
1258 
1260  GaussPoint *gp, TimeStep *atTime)
1261 {}
1262 
1264  GaussPoint *gp, TimeStep *atTime)
1265 {
1266  // Implementation of the 3D stiffness matrix
1267  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1268  if ( mode == ElasticStiffness ) {
1269  this->giveLinearElasticMaterial()->give3dMaterialStiffnessMatrix(answer, mode, gp, atTime);
1270  } else {
1271  FloatArray strain = status->giveTempStrainVector();
1272  if ( ( strain.at(1) + strain.at(2) + strain.at(3) ) > 0 ) {
1273  //@todo eq 56
1274  } else {
1275  //@todo eq 57
1276  }
1277  }
1278 }
1279 
1280 void
1282  TimeStep *atTime)
1283 //
1284 {
1285  FloatMatrix inPlaneStrain, B, eVecs;
1286  FloatArray eVals;
1287  double outOfPlaneStrain;
1288  B.resize(2, 2);
1289  B.at(1, 1) = 1. - damageTensor.at(1, 1);
1290  B.at(1, 2) = 0. - damageTensor.at(1, 2);
1291  B.at(2, 1) = 0. - damageTensor.at(2, 1);
1292  B.at(2, 2) = 1. - damageTensor.at(2, 2);
1293  //The eigenVectors for the change of base must be computed using the damageTensor, NOT the B matrix!!!
1294  //B.jaco_(eVals, eVecs, 40);
1295  FloatMatrix Auxiliar;
1296  Auxiliar.resize(2, 2);
1297  Auxiliar.at(1, 1) = damageTensor.at(1, 1);
1298  Auxiliar.at(2, 2) = damageTensor.at(2, 2);
1299  Auxiliar.at(1, 2) = damageTensor.at(1, 2);
1300  Auxiliar.at(2, 1) = damageTensor.at(2, 1);
1301 
1302  Auxiliar.jaco_(eVals, eVecs, 40);
1303 
1304  // Change of base of reducedTotalStrainVector from the canonical to the base formed by the eigenvectors of the damageTensor
1305  inPlaneStrain.resize(2, 2);
1306  inPlaneStrain.at(1, 1) = reducedTotalStrainVector.at(1);
1307  inPlaneStrain.at(2, 2) = reducedTotalStrainVector.at(2);
1308  inPlaneStrain.at(1, 2) = reducedTotalStrainVector.at(3) / 2.0;
1309  inPlaneStrain.at(2, 1) = reducedTotalStrainVector.at(3) / 2.0;
1310 
1311  double term1, term2, term3, B1, B2, Bz, trD, h, epsilon11, epsilon22;
1312  B1 = 1.0 - eVals.at(1);
1313  B2 = 1.0 - eVals.at(2);
1314  Bz = 1. - damageTensor.at(3, 3);
1315  FloatArray vector1, vector2, auxVector;
1316  vector1.resize(2);
1317  vector2.resize(2);
1318  vector1.at(1) = eVecs.at(1, 1);
1319  vector1.at(2) = eVecs.at(2, 1);
1320  vector2.at(1) = eVecs.at(1, 2);
1321  vector2.at(2) = eVecs.at(2, 2);
1322  auxVector.beProductOf(inPlaneStrain, vector1);
1323  epsilon11 = vector1.at(1) * auxVector.at(1) + vector1.at(2) * auxVector.at(2);
1324  auxVector.beProductOf(inPlaneStrain, vector2);
1325  epsilon22 = vector2.at(1) * auxVector.at(1) + vector2.at(2) * auxVector.at(2);
1326  trD = damageTensor.at(1, 1) + damageTensor.at(2, 2) + damageTensor.at(3, 3);
1327  // Assuming a Tension state --> h = 1.0
1328  h = 1.0;
1329  term1 = 3. * Bz * B1 * ( 1. - 2. * nu ) - ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu );
1330  term2 = 3. * Bz * B2 * ( 1. - 2. * nu ) - ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu );
1331  term3 = 3. * Bz * ( 1. - 2. * nu ) * ( B1 + B2 ) + ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu );
1332  if ( Bz < 0.00001 ) {
1333  outOfPlaneStrain = -( epsilon11 + epsilon22 );
1334  } else {
1335  outOfPlaneStrain = ( term1 * epsilon11 + term2 * epsilon22 ) / term3;
1336  }
1337  /* if (outOfPlaneStrain != outOfPlaneStrain){
1338  * outOfPlaneStrain=-(epsilon11+epsilon22);
1339  * }*/
1340  double trStrain;
1341  trStrain = inPlaneStrain.at(1, 1) + inPlaneStrain.at(2, 2) + outOfPlaneStrain;
1342  // Check if actually under Tension, if not, recalculate term1, term2 and term3 with h = 0.0
1343  if ( trStrain < 0.0 ) {
1344  h = 0.0;
1345  term1 = 3. * Bz * B1 * ( 1. - 2. * nu ) - ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu );
1346  term2 = 3. * Bz * B2 * ( 1. - 2. * nu ) - ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu );
1347  term3 = 3. * Bz * ( 1. - 2. * nu ) * ( B1 + B2 ) + ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu );
1348  if ( Bz < 0.00001 ) {
1349  outOfPlaneStrain = -( epsilon11 + epsilon22 );
1350  } else {
1351  outOfPlaneStrain = ( term1 * epsilon11 + term2 * epsilon22 ) / term3;
1352  }
1353  }
1354  answer.resize(3, 3);
1355  answer.zero();
1356  answer.at(1, 1) = inPlaneStrain.at(1, 1);
1357  answer.at(1, 2) = inPlaneStrain.at(1, 2);
1358  answer.at(2, 1) = inPlaneStrain.at(2, 1);
1359  answer.at(2, 2) = inPlaneStrain.at(2, 2);
1360  answer.at(3, 3) = outOfPlaneStrain;
1361 }
1362 
1363 void
1364 AnisotropicDamageMaterial :: computePlaneStressSigmaZ(double &answer, FloatMatrix damageTensor, FloatArray reducedTotalStrainVector,
1365  double epsilonZ, GaussPoint *gp, TimeStep *atTime)
1366 //
1367 {
1368  FloatMatrix Auxiliar, inPlaneStrain;
1369  FloatArray eVals;
1370  FloatMatrix eVecs;
1371  Auxiliar.resize(2, 2);
1372  Auxiliar.at(1, 1) = damageTensor.at(1, 1);
1373  Auxiliar.at(2, 2) = damageTensor.at(2, 2);
1374  Auxiliar.at(1, 2) = damageTensor.at(1, 2);
1375  Auxiliar.at(2, 1) = damageTensor.at(2, 1);
1376  Auxiliar.jaco_(eVals, eVecs, 40);
1377  inPlaneStrain.resize(2, 2);
1378  inPlaneStrain.at(1, 1) = reducedTotalStrainVector.at(1);
1379  inPlaneStrain.at(2, 2) = reducedTotalStrainVector.at(2);
1380  inPlaneStrain.at(1, 2) = reducedTotalStrainVector.at(3) / 2.0;
1381  inPlaneStrain.at(2, 1) = reducedTotalStrainVector.at(3) / 2.0;
1382  double term1, term2, termZ, B1, B2, Bz, trD, h, epsilon11, epsilon22;
1383  B1 = 1.0 - eVals.at(1);
1384  B2 = 1.0 - eVals.at(2);
1385  Bz = 1. - damageTensor.at(3, 3);
1386  FloatArray vector1, vector2, auxVector;
1387  vector1.resize(2);
1388  vector2.resize(2);
1389  vector1.at(1) = eVecs.at(1, 1);
1390  vector1.at(2) = eVecs.at(2, 1);
1391  vector2.at(1) = eVecs.at(1, 2);
1392  vector2.at(2) = eVecs.at(2, 2);
1393  auxVector.beProductOf(inPlaneStrain, vector1);
1394  epsilon11 = vector1.at(1) * auxVector.at(1) + vector1.at(2) * auxVector.at(2);
1395  auxVector.beProductOf(inPlaneStrain, vector2);
1396  epsilon22 = vector2.at(1) * auxVector.at(1) + vector2.at(2) * auxVector.at(2);
1397  trD = damageTensor.giveTrace();
1398  double Estar;
1399  Estar = E / ( ( 1. + nu ) * ( 1. - 2. * nu ) );
1400  if ( ( epsilon11 + epsilon22 + epsilonZ ) >= 0. ) {
1401  h = 1.;
1402  } else {
1403  h = 0.;
1404  }
1405  term1 = ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu ) - 3. * Bz * B1 * ( 1. - 2. * nu );
1406  term2 = ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu ) - 3. * Bz * B2 * ( 1. - 2. * nu );
1407  termZ = ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu ) + 3. * Bz * ( 1. - 2. * nu ) * ( B1 + B2 );
1408  // Finally the expression of sigmaZ is composed
1409  answer = ( Estar / ( 3. * ( B1 + B2 + Bz ) ) ) * ( epsilon11 * term1 + epsilon22 * term2 + epsilonZ * termZ );
1410 
1411 #if 0
1413  double B1, B2, Bz, eps11, eps22, Estar, term1, term2, termZ, trD, h;
1414  Estar=E / ((1. + nu)*(1. - 2. * nu));
1415  // Compute the eigenvalues of the in-plane damage tensor
1416  double eVal1, eVal2, aux1, aux2;
1417  aux1 = (damageTensor.at(1,1) + damageTensor.at(2,2))/2.0;
1418  aux2 = sqrt(pow((damageTensor.at(1,1) - damageTensor.at(2,2)) / 2. , 2.) + damageTensor.at(1,2) * damageTensor.at(2,1));
1419  eVal1 = aux1 + aux2 ;
1420  eVal2 = aux1 - aux2 ;
1421  B1 = 1. - eVal1;
1422  B2 = 1. - eVal2;
1423  Bz = 1. - damageTensor.at(3, 3);
1424  eps11 = reducedTotalStrainVector.at(1);
1425  eps22 = reducedTotalStrainVector.at(2);
1426  if ((eps11 + eps22 + epsZ)>=0.) {
1427  h = 1.;
1428  } else {
1429  h = 0.;
1430  }
1431  trD = damageTensor.giveTrace();
1432  term1 = ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu ) - 3. * Bz * B1 * ( 1. - 2. * nu ) ;
1433  term2 = ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu ) - 3. * Bz * B2 * ( 1. - 2. * nu ) ;
1434  termZ = ( 3. - trD ) * ( 1. - h * trD ) * ( 1. + nu ) + 3. * Bz * ( 1. - 2. * nu ) * ( B1 + B2 ) ;
1435  // Finally the expression of sigmaZ is composed
1436  answer = (Estar / (3. * (B1 + B2 + Bz))) * (eps11 * term1 + eps22 * term2 + epsZ * termZ);
1437  Estar = Estar + 0.0;
1438 #endif
1439 }
1440 
1441 void
1443  const FloatArray &reducedTotalStrainVector, double equivStrain,
1444  TimeStep *atTime)
1445 //
1446 {
1447  //
1448  // returns real stress vector in 3d stress space of receiver according to
1449  // previous level of stress and current strain increment, the only way,
1450  // how to correctly update gp records
1451  //
1452  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1453  double Dc = 1.00;
1454  double Kappa;
1455  FloatMatrix tempDamageTensor;
1456  //this->computeEquivalentStrain(equivStrain, reducedTotalStrainVector, gp, atTime);
1457  FloatMatrix Dn = status->giveDamage();
1458  Kappa = this->computeKappa(Dn);
1459  //damageTensor = status->giveDamage();
1460 
1461  if ( equivStrain <= Kappa ) { // damage does not grow. Elastic behaviour
1462  answer.resize(3, 3);
1463  answer.zero();
1464  answer = Dn;
1465  } else { // damage grows
1466  Kappa = equivStrain;
1467  double deltaLambda;
1468  FloatArray eVals, fullStrainVector;
1469  FloatMatrix eVecs, strainTensor, positiveStrainTensor, positiveStrainTensorSquared, tempDamageTensor0;
1470  MaterialMode mode = gp->giveMaterialMode();
1471  // Compute square of positive part of strain tensor
1472  //1.- converts strain vector to full form;
1473  StructuralMaterial :: giveFullSymVectorForm(fullStrainVector, reducedTotalStrainVector, mode);
1474  // The strain vector is turned into a tensor; for that, the elements that are out of the diagonal
1475  // must be divided by 2
1476  strainTensor.resize(3, 3);
1477  strainTensor.zero();
1478  if ( mode == _PlaneStress ) {
1479  this->computePlaneStressStrain(strainTensor, Dn, reducedTotalStrainVector, gp, atTime);
1480  strainTensor.at(3, 3) = status->giveTempStrainZ();
1481  } else {
1482  strainTensor.at(1, 1) = reducedTotalStrainVector.at(1);
1483  strainTensor.at(2, 2) = reducedTotalStrainVector.at(2);
1484  strainTensor.at(3, 3) = reducedTotalStrainVector.at(3);
1485  strainTensor.at(2, 3) = reducedTotalStrainVector.at(4) / 2.0;
1486  strainTensor.at(3, 2) = reducedTotalStrainVector.at(4) / 2.0;
1487  strainTensor.at(1, 3) = reducedTotalStrainVector.at(5) / 2.0;
1488  strainTensor.at(3, 1) = reducedTotalStrainVector.at(5) / 2.0;
1489  strainTensor.at(1, 2) = reducedTotalStrainVector.at(6) / 2.0;
1490  strainTensor.at(2, 1) = reducedTotalStrainVector.at(6) / 2.0;
1491  }
1492  // computes polar decomposition and negative eigenvalues set to zero
1493  //int checker14 = this->checkSymmetry(strainTensor);
1494  strainTensor.jaco_(eVals, eVecs, 40);
1495  for ( int i = 1; i <= 3; i++ ) {
1496  if ( eVals.at(i) < 0 ) {
1497  eVals.at(i) = 0;
1498  }
1499  }
1500  // computes the positive part of the strain tensor
1501  positiveStrainTensor.resize(3, 3);
1502  for ( int i = 1; i <= 3; i++ ) {
1503  for ( int j = 1; j <= 3; j++ ) {
1504  positiveStrainTensor.at(i, j) = eVals.at(1) * eVecs.at(i, 1) * eVecs.at(j, 1) + eVals.at(2) * eVecs.at(i, 2) * eVecs.at(j, 2) + eVals.at(3) * eVecs.at(i, 3) * eVecs.at(j, 3);
1505  }
1506  }
1507  // computes the square of positiveStrainTensor
1508  positiveStrainTensorSquared.beProductOf(positiveStrainTensor, positiveStrainTensor);
1509  //compute delta Lambda
1510  //double traceD = damageTensor.at(1,1) + damageTensor.at(2,2) + damageTensor.at(3,3);
1511  double traceD = Dn.at(1, 1) + Dn.at(2, 2) + Dn.at(3, 3);
1512 
1513  double traceTempD = this->computeTraceD(equivStrain);
1514  // equation 50 of the reference paper
1515  deltaLambda = ( traceTempD - traceD ) / equivStrain / equivStrain;
1516  //compute delta D: equation 48 of the reference paper
1517  FloatMatrix deltaD;
1518  deltaD = positiveStrainTensorSquared;
1519  deltaD.times(deltaLambda);
1520  this->correctBigValues(deltaD);
1521  // compute new damage tensor
1522  tempDamageTensor0 = Dn;
1523  tempDamageTensor0.add(deltaD); //damage tensor is equal to tempDamageTensor+deltaD
1524  // The following loop implements the algorithm for a case in which the maximum damage threshold is reached,
1525  // in such a case, the remaining damage is projected on the other two directions available and, finally,
1526  // if the damage threshold is reached in two of the three possible directions, the remaining damage is projected
1527  // on the remaining third direction. If the threshold is reached in the three possible directions, the damage
1528  // tensor remains unchanged in the future and with all their eigenvalues equal to the damage threshold Dc.
1529  // This part of the code is based on the section 8.2 of the reference paper.
1530  //int checker15 = this->checkSymmetry(tempDamageTensor0);
1531  tempDamageTensor0.jaco_(eVals, eVecs, 20);
1532  if ( ( eVals.at(1) > ( Dc * 1.001 ) ) || ( eVals.at(2) > ( Dc * 1.001 ) ) || ( eVals.at(3) > ( Dc * 1.001 ) ) ) {
1533  double alpha = 0, deltaLambda1 = 0, Aux1 = 0, Aux2 = 0, Aux3 = 0;
1534  FloatMatrix deltaD1(3, 3), positiveStrainTensorSquared(3, 3), tempDamageTensor1(3, 3), deltaD2(3, 3), N11(3, 3), N12(3, 3), N13(3, 3), N12sym(3, 3), N13sym(3, 3), projPosStrainTensor(3, 3);
1535  FloatArray auxVals(3), auxVec1(3), auxVec2(3), auxVec3(3);
1536 
1537  // the percentage alpha of deltaD that needs to be added so the first eigenvalue reaches Dc is obtained
1538  alpha = obtainAlpha1(Dn, deltaLambda, positiveStrainTensor, Dc);
1539 
1540  // deltaD1 is obtained --> deltaD1=alpha*deltaD
1541  positiveStrainTensorSquared.beProductOf(positiveStrainTensor, positiveStrainTensor);
1542  deltaD1 = positiveStrainTensorSquared;
1543  deltaD1.times(alpha * deltaLambda);
1544  this->correctBigValues(deltaD1);
1545  tempDamageTensor1 = Dn;
1546  tempDamageTensor1.add(deltaD1);
1547  // The following lines describe the process to apply the equation 64 of the reference paper. First, the
1548  // eigenvalues and eigenvectors of the damage tensor resulting at the moment when the threshold is reached
1549  // are obtained
1550  // (note: the equation 64 is not correctly written in the paper, it should be as implemented here:
1551  // D_dot = lambda_dot * [ <e>^2-(nI·<e>^2 nI)(nI x nI) - 2(nII·<e>^2 nI)(nI x nII)_sym - 2(nIII·<e>^2 nI)(nI x nIII)_sym ]
1552  //int checker16 = this->checkSymmetry(tempDamageTensor1);
1553 
1554  tempDamageTensor1.jaco_(eVals, eVecs, 40);
1555  // The eigenvalues and eigenvectors are ordered, with the maximum eigenvalue being I, as its corresponding
1556  // eigenvector, and the other two being II and III. This is necessary so the equation 64 of the reference
1557  // paper can be applied
1558  if ( eVals.at(1) >= eVals.at(2) && eVals.at(1) >= eVals.at(3) ) {
1559  auxVals.at(1) = eVals.at(1);
1560  auxVec1.at(1) = eVecs.at(1, 1);
1561  auxVec1.at(2) = eVecs.at(2, 1);
1562  auxVec1.at(3) = eVecs.at(3, 1);
1563  auxVals.at(2) = eVals.at(2);
1564  auxVec2.at(1) = eVecs.at(1, 2);
1565  auxVec2.at(2) = eVecs.at(2, 2);
1566  auxVec2.at(3) = eVecs.at(3, 2);
1567  auxVals.at(3) = eVals.at(3);
1568  auxVec3.at(1) = eVecs.at(1, 3);
1569  auxVec3.at(2) = eVecs.at(2, 3);
1570  auxVec3.at(3) = eVecs.at(3, 3);
1571  } else if ( eVals.at(2) >= eVals.at(1) && eVals.at(2) >= eVals.at(3) ) {
1572  auxVals.at(1) = eVals.at(2);
1573  auxVec1.at(1) = eVecs.at(1, 2);
1574  auxVec1.at(2) = eVecs.at(2, 2);
1575  auxVec1.at(3) = eVecs.at(3, 2);
1576  auxVals.at(2) = eVals.at(1);
1577  auxVec2.at(1) = eVecs.at(1, 1);
1578  auxVec2.at(2) = eVecs.at(2, 1);
1579  auxVec2.at(3) = eVecs.at(3, 1);
1580  auxVals.at(3) = eVals.at(3);
1581  auxVec3.at(1) = eVecs.at(1, 3);
1582  auxVec3.at(2) = eVecs.at(2, 3);
1583  auxVec3.at(3) = eVecs.at(3, 3);
1584  } else {
1585  auxVals.at(1) = eVals.at(3);
1586  auxVec1.at(1) = eVecs.at(1, 3);
1587  auxVec1.at(2) = eVecs.at(2, 3);
1588  auxVec1.at(3) = eVecs.at(3, 3);
1589  auxVals.at(2) = eVals.at(2);
1590  auxVec2.at(1) = eVecs.at(1, 2);
1591  auxVec2.at(2) = eVecs.at(2, 2);
1592  auxVec2.at(3) = eVecs.at(3, 2);
1593  auxVals.at(3) = eVals.at(1);
1594  auxVec3.at(1) = eVecs.at(1, 1);
1595  auxVec3.at(2) = eVecs.at(2, 1);
1596  auxVec3.at(3) = eVecs.at(3, 1);
1597  }
1598 
1599  // The symmetric part of the dyadic product of eigenvectors n1 and n2 is obtained
1600  N11.beDyadicProductOf(auxVec1, auxVec1);
1601  N12.beDyadicProductOf(auxVec1, auxVec2);
1602  for ( int i = 1; i <= 3; i++ ) {
1603  for ( int j = 1; j <= 3; j++ ) {
1604  N12sym.at(i, j) = 0.5 * ( N12.at(i, j) + N12.at(j, i) );
1605  }
1606  }
1607 
1608  // The symmetric part of the dyadic product of eigenvectors n1 and n3 is obtained
1609  N13.beDyadicProductOf(auxVec1, auxVec3);
1610  for ( int i = 1; i <= 3; i++ ) {
1611  for ( int j = 1; j <= 3; j++ ) {
1612  N13sym.at(i, j) = 0.5 * ( N13.at(i, j) + N13.at(j, i) );
1613  }
1614  }
1615 
1616  //The projected positive strain tensor is obtained
1617  for ( int i = 1; i <= 3; i++ ) {
1618  Aux1 = Aux1 + auxVec1.at(i) * ( positiveStrainTensorSquared.at(i, 1) * auxVec1.at(1) + positiveStrainTensorSquared.at(i, 2) * auxVec1.at(2) + positiveStrainTensorSquared.at(i, 3) * auxVec1.at(3) ); //==(n1*(<e>^2*n1)) (eq. 64 of the reference paper)
1619  Aux2 = Aux2 + auxVec2.at(i) * ( positiveStrainTensorSquared.at(i, 1) * auxVec1.at(1) + positiveStrainTensorSquared.at(i, 2) * auxVec1.at(2) + positiveStrainTensorSquared.at(i, 3) * auxVec1.at(3) ); //==(n2*(<e>^2*n1))_sym (eq. 64 of the reference paper)
1620  Aux3 = Aux3 + auxVec3.at(i) * ( positiveStrainTensorSquared.at(i, 1) * auxVec1.at(1) + positiveStrainTensorSquared.at(i, 2) * auxVec1.at(2) + positiveStrainTensorSquared.at(i, 3) * auxVec1.at(3) ); //==(n3*(<e>^2*n1))_sym (eq. 64 of the reference paper)
1621  }
1622  N11.times(Aux1);
1623  N12sym.times(2 * Aux2);
1624  N13sym.times(2 * Aux3);
1625 
1626  // Finally, the expression between brackets in equation 64 is built up and called projPosStrainTensor
1627  projPosStrainTensor = positiveStrainTensorSquared;
1628  projPosStrainTensor.subtract(N11);
1629  projPosStrainTensor.subtract(N12sym);
1630  projPosStrainTensor.subtract(N13sym);
1631 
1632  // The following loop avoids numerical problems in the case that the trace of projPosStrainTensor is very small
1633  if ( ( projPosStrainTensor.at(1, 1) + projPosStrainTensor.at(2, 2) + projPosStrainTensor.at(3, 3) ) < traceTempD * 1e-10 ) {
1634  deltaLambda1 = 0.;
1635  } else {
1636  deltaLambda1 = ( traceTempD - ( tempDamageTensor1.at(1, 1) + tempDamageTensor1.at(2, 2) + tempDamageTensor1.at(3, 3) ) ) / ( projPosStrainTensor.at(1, 1) + projPosStrainTensor.at(2, 2) + projPosStrainTensor.at(3, 3) );
1637  }
1638  //projPosStrainTensor.symmetrized();
1639  deltaD2 = projPosStrainTensor;
1640  deltaD2.times(deltaLambda1);
1641  this->correctBigValues(deltaD2);
1642  tempDamageTensor1.add(deltaD2); //damage tensor is equal to tempDamageTensor+deltaD1+deltaD2
1643  // The following loop checks if after the addition of D2, any other eigenvalue of the damage tensor
1644  // has reached the threshold. If it has, it repeats the process, but this time projecting the
1645  // remaining damage on the direction of the remaining eigenvector
1646  //int checker17 = this->checkSymmetry(tempDamageTensor1);
1647  tempDamageTensor1.jaco_(eVals, eVecs, 40);
1648  if ( ( eVals.at(1) > ( Dc * 1.001 ) ) || ( eVals.at(2) > ( Dc * 1.001 ) ) || ( eVals.at(3) > ( Dc * 1.001 ) ) ) {
1649  FloatMatrix deltaD3(3, 3), projPosStrainTensor_new(3, 3), tempDamageTensor2(3, 3), deltaD4(3, 3);
1650  FloatArray vec3(3);
1651  double alpha2 = 0, deltaLambda2 = 0, Aux4 = 0;
1652  // double val3=0;
1653  // Restoring the value of tempDamageTensor1 = tempDamageTensor + deltaD1
1654  tempDamageTensor1 = Dn;
1655  tempDamageTensor1.add(deltaD1);
1656  // the percentage alpha2 of deltaD2 that needs to be added to (tempDamageTensor+deltaD1) so the second eigenvalue
1657  // reaches Dc is obtained
1658  alpha2 = obtainAlpha2(tempDamageTensor1, deltaLambda1, positiveStrainTensor, projPosStrainTensor, Dc);
1659  deltaD3 = deltaD2;
1660  deltaD3.times(alpha2);
1661  tempDamageTensor2 = tempDamageTensor1;
1662  tempDamageTensor2.add(deltaD3);
1663  // The smallest eigenvalue is detected and its eigenvector is used to build the new projPosStrainTensor
1664  //int checker18 = this->checkSymmetry(tempDamageTensor2);
1665  tempDamageTensor2.jaco_(eVals, eVecs, 40);
1666  if ( eVals.at(1) <= eVals.at(2) && eVals.at(1) <= eVals.at(3) ) {
1667  //val3=eVals.at(1);
1668  vec3.at(1) = eVecs.at(1, 1);
1669  vec3.at(2) = eVecs.at(2, 1);
1670  vec3.at(3) = eVecs.at(3, 1);
1671  } else if ( eVals.at(2) <= eVals.at(1) && eVals.at(2) <= eVals.at(3) ) {
1672  //val3=eVals.at(2);
1673  vec3.at(1) = eVecs.at(1, 2);
1674  vec3.at(2) = eVecs.at(2, 2);
1675  vec3.at(3) = eVecs.at(3, 2);
1676  } else {
1677  //val3=eVals.at(3);
1678  vec3.at(1) = eVecs.at(1, 3);
1679  vec3.at(2) = eVecs.at(2, 3);
1680  vec3.at(3) = eVecs.at(3, 3);
1681  }
1682 
1683  // The following loop computes nIII·<e>^2 nIII
1684  for ( int i = 1; i <= 3; i++ ) {
1685  Aux4 = Aux4 + vec3.at(i) * ( positiveStrainTensorSquared.at(i, 1) * vec3.at(1) + positiveStrainTensorSquared.at(i, 2) * vec3.at(2) + positiveStrainTensorSquared.at(i, 3) * vec3.at(3) );
1686  }
1687  projPosStrainTensor_new.beDyadicProductOf(vec3, vec3);
1688  //
1689  projPosStrainTensor_new.times(Aux4);
1690 
1691  // The following loop avoids numerical problems in the case that the trace of projPosStrainTensor is very small
1692  if ( ( projPosStrainTensor_new.at(1, 1) + projPosStrainTensor_new.at(2, 2) + projPosStrainTensor_new.at(3, 3) ) < traceTempD * 1e-10 ) {
1693  deltaLambda2 = 0;
1694  } else {
1695  deltaLambda2 = ( traceTempD - ( tempDamageTensor2.at(1, 1) + tempDamageTensor2.at(2, 2) + tempDamageTensor2.at(3, 3) ) ) / ( projPosStrainTensor_new.at(1, 1) + projPosStrainTensor_new.at(2, 2) + projPosStrainTensor_new.at(3, 3) );
1696  }
1697  deltaD4 = projPosStrainTensor_new;
1698  deltaD4.times(deltaLambda2);
1699  tempDamageTensor2.add(deltaD4); //damage tensor is equal to tempDamageTensor+deltaD1+deltaD3+deltaD4
1700 
1701  // The following loop checks if after the addition of D4, the remaining eigenvalue of the damage tensor
1702  // has reached the threshold. If it has, it computes a damage tensor with all its eigenvalues equal
1703  // to the damage threshold Dc
1704  //int checker19 = this->checkSymmetry(tempDamageTensor2);
1705  tempDamageTensor2.jaco_(eVals, eVecs, 40);
1706  if ( ( eVals.at(1) > ( Dc * 1.001 ) ) || ( eVals.at(2) > ( Dc * 1.001 ) ) || ( eVals.at(3) > ( Dc * 1.001 ) ) ) {
1707  double alpha3 = 0;
1708  FloatMatrix deltaD5, tempDamageTensor3;
1709  tempDamageTensor2 = Dn;
1710  tempDamageTensor2.add(deltaD1);
1711  tempDamageTensor2.add(deltaD3);
1712  alpha3 = obtainAlpha3(tempDamageTensor2, deltaLambda2, positiveStrainTensor, vec3, Dc);
1713  deltaD5 = deltaD4;
1714  deltaD5.times(alpha3);
1715  tempDamageTensor3 = tempDamageTensor2;
1716  tempDamageTensor3.add(deltaD5);
1717  tempDamageTensor = tempDamageTensor3;
1718  tempDamageTensor3.jaco_(eVals, eVecs, 40);
1719  if ( ( eVals.at(1) > ( Dc * 1.001 ) ) || ( eVals.at(2) > ( Dc * 1.001 ) ) || ( eVals.at(3) > ( Dc * 1.001 ) ) ) {
1720  tempDamageTensor3.zero();
1721  for ( int i = 1; i <= 3; i++ ) {
1722  if ( eVals.at(i) > Dc * 1.001 ) {
1723  eVals.at(i) = Dc;
1724  }
1725  }
1726  for ( int i = 1; i <= 3; i++ ) {
1727  for ( int j = 1; j <= 3; j++ ) {
1728  tempDamageTensor3.at(i, j) = eVals.at(1) * eVecs.at(i, 1) * eVecs.at(j, 1) + eVals.at(2) * eVecs.at(i, 2) * eVecs.at(j, 2) + eVals.at(3) * eVecs.at(i, 3) * eVecs.at(j, 3);
1729  }
1730  }
1731 
1732  /*
1733  * tempDamageTensor3.zero();
1734  * tempDamageTensor3.at(1,1)=Dc;
1735  * tempDamageTensor3.at(2,2)=Dc;
1736  * tempDamageTensor3.at(3,3)=Dc;*/
1737  }
1738  tempDamageTensor = tempDamageTensor3;
1739  } else {
1740  tempDamageTensor = tempDamageTensor2;
1741  }
1742  } else {
1743  tempDamageTensor = tempDamageTensor1;
1744  }
1745  } else {
1746  tempDamageTensor = tempDamageTensor0;
1747  }
1748  answer = tempDamageTensor;
1749  }
1750 }
1751 
1752 void
1754 //
1755 // Implementation of the 3D stiffness matrix, according to the equations 56 and 57 of the reference paper.
1756 {
1757  // AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1758  double G, K;
1759  double traceD, Aux;
1760  FloatMatrix ImD, sqrtImD, eVecs, Imatrix;
1761  FloatArray eVals;
1762  //MaterialMode mode = gp->giveMaterialMode();
1763  G = E / ( 2.0 * ( 1.0 + nu ) );
1764  K = E / ( 3.0 * ( 1.0 - 2.0 * nu ) );
1765  //Compute the trace of the damage tensor, correcting it if necessary (see section 8.1 of the reference paper)
1766  traceD = computeTraceD(damageTensor, strainTensor, gp);
1767 
1768  if ( fabs(3. - traceD) < 0.001 ) {
1769  Aux = 0.0;
1770  } else {
1771  Aux = ( 1. / ( 3. - traceD ) );
1772  }
1773 
1774  // compute square root of (1-D)
1775  ImD.resize(3, 3);
1776  ImD.zero();
1777  ImD.at(1, 1) = ImD.at(2, 2) = ImD.at(3, 3) = 1.0;
1778  ImD.subtract(damageTensor);
1779 
1780  // computes square of positive part of strain tensor
1781  //int checker11=this->checkSymmetry(ImD);
1782  ImD.jaco_(eVals, eVecs, 40);
1783  sqrtImD.resize(3, 3);
1784  for ( int i = 1; i <= 3; i++ ) {
1785  for ( int j = 1; j <= 3; j++ ) {
1786  for ( int k = 1; k <= 3; k++ ) {
1787  if ( eVals.at(k) < 0.0 ) {
1788  eVals.at(k) = 0.0;
1789  }
1790  }
1791  sqrtImD.at(i, j) = sqrt( eVals.at(1) ) * eVecs.at(i, 1) * eVecs.at(j, 1) + sqrt( eVals.at(2) ) * eVecs.at(i, 2) * eVecs.at(j, 2) + sqrt( eVals.at(3) ) * eVecs.at(i, 3) * eVecs.at(j, 3);
1792  }
1793  }
1794  // To compute the expresions 56 and 57 of the reference paper, we need to work with fourth order tensors. To do this,
1795  // a structured called fourthOrderTensor is defined. This structure is composed by nine 3x3 FloatMatrix objects
1796  struct fourthOrderTensor
1797  {
1798  FloatMatrix Matrix_11kl;
1799  FloatMatrix Matrix_12kl;
1800  FloatMatrix Matrix_13kl;
1801  FloatMatrix Matrix_21kl;
1802  FloatMatrix Matrix_22kl;
1803  FloatMatrix Matrix_23kl;
1804  FloatMatrix Matrix_31kl;
1805  FloatMatrix Matrix_32kl;
1806  FloatMatrix Matrix_33kl;
1807  };
1808  // Four fourthOrderTensor structures are defined
1809  fourthOrderTensor Block1, Block2, Block3, secantOperator;
1810  Imatrix.resize(3, 3);
1811  Imatrix.zero();
1812  Imatrix.at(1, 1) = Imatrix.at(2, 2) = Imatrix.at(3, 3) = 1.0;
1813 
1814  // The fourthOrderTensor structures are initialised
1815  Block1.Matrix_11kl.resize(3, 3);
1816  Block1.Matrix_12kl.resize(3, 3);
1817  Block1.Matrix_13kl.resize(3, 3);
1818  Block1.Matrix_21kl.resize(3, 3);
1819  Block1.Matrix_22kl.resize(3, 3);
1820  Block1.Matrix_23kl.resize(3, 3);
1821  Block1.Matrix_31kl.resize(3, 3);
1822  Block1.Matrix_32kl.resize(3, 3);
1823  Block1.Matrix_33kl.resize(3, 3);
1824  Block2.Matrix_11kl.resize(3, 3);
1825  Block2.Matrix_12kl.resize(3, 3);
1826  Block2.Matrix_13kl.resize(3, 3);
1827  Block2.Matrix_21kl.resize(3, 3);
1828  Block2.Matrix_22kl.resize(3, 3);
1829  Block2.Matrix_23kl.resize(3, 3);
1830  Block2.Matrix_31kl.resize(3, 3);
1831  Block2.Matrix_32kl.resize(3, 3);
1832  Block2.Matrix_33kl.resize(3, 3);
1833  Block3.Matrix_11kl.resize(3, 3);
1834  Block3.Matrix_12kl.resize(3, 3);
1835  Block3.Matrix_13kl.resize(3, 3);
1836  Block3.Matrix_21kl.resize(3, 3);
1837  Block3.Matrix_22kl.resize(3, 3);
1838  Block3.Matrix_23kl.resize(3, 3);
1839  Block3.Matrix_31kl.resize(3, 3);
1840  Block3.Matrix_32kl.resize(3, 3);
1841  Block3.Matrix_33kl.resize(3, 3);
1842  secantOperator.Matrix_11kl.resize(3, 3);
1843  secantOperator.Matrix_12kl.resize(3, 3);
1844  secantOperator.Matrix_13kl.resize(3, 3);
1845  secantOperator.Matrix_21kl.resize(3, 3);
1846  secantOperator.Matrix_22kl.resize(3, 3);
1847  secantOperator.Matrix_23kl.resize(3, 3);
1848  secantOperator.Matrix_31kl.resize(3, 3);
1849  secantOperator.Matrix_32kl.resize(3, 3);
1850  secantOperator.Matrix_33kl.resize(3, 3);
1851 
1852  for ( int k = 1; k <= 3; k++ ) {
1853  for ( int l = 1; l <= 3; l++ ) {
1854  //The first block inside the brackets is obtained --> (1-D)^(1/2) _x_ (1-D)^(1/2)
1855  Block1.Matrix_11kl.at(k, l) = sqrtImD.at(1, k) * sqrtImD.at(1, l);
1856  Block1.Matrix_12kl.at(k, l) = sqrtImD.at(1, k) * sqrtImD.at(2, l);
1857  Block1.Matrix_13kl.at(k, l) = sqrtImD.at(1, k) * sqrtImD.at(3, l);
1858  Block1.Matrix_21kl.at(k, l) = sqrtImD.at(2, k) * sqrtImD.at(1, l);
1859  Block1.Matrix_22kl.at(k, l) = sqrtImD.at(2, k) * sqrtImD.at(2, l);
1860  Block1.Matrix_23kl.at(k, l) = sqrtImD.at(2, k) * sqrtImD.at(3, l);
1861  Block1.Matrix_31kl.at(k, l) = sqrtImD.at(3, k) * sqrtImD.at(1, l);
1862  Block1.Matrix_32kl.at(k, l) = sqrtImD.at(3, k) * sqrtImD.at(2, l);
1863  Block1.Matrix_33kl.at(k, l) = sqrtImD.at(3, k) * sqrtImD.at(3, l);
1864  //The second block inside the brackets is obtained --> ((1-D) x (1-D))/(3-trD)
1865  Block2.Matrix_11kl.at(k, l) = ImD.at(1, 1) * ImD.at(k, l) * Aux;
1866  Block2.Matrix_12kl.at(k, l) = ImD.at(1, 2) * ImD.at(k, l) * Aux;
1867  Block2.Matrix_13kl.at(k, l) = ImD.at(1, 3) * ImD.at(k, l) * Aux;
1868  Block2.Matrix_21kl.at(k, l) = ImD.at(2, 1) * ImD.at(k, l) * Aux;
1869  Block2.Matrix_22kl.at(k, l) = ImD.at(2, 2) * ImD.at(k, l) * Aux;
1870  Block2.Matrix_23kl.at(k, l) = ImD.at(2, 3) * ImD.at(k, l) * Aux;
1871  Block2.Matrix_31kl.at(k, l) = ImD.at(3, 1) * ImD.at(k, l) * Aux;
1872  Block2.Matrix_32kl.at(k, l) = ImD.at(3, 2) * ImD.at(k, l) * Aux;
1873  Block2.Matrix_33kl.at(k, l) = ImD.at(3, 3) * ImD.at(k, l) * Aux;
1874  //The crossed-product of two identity tensors is obtained --> 1 x 1
1875  Block3.Matrix_11kl.at(k, l) = Imatrix.at(1, 1) * Imatrix.at(k, l);
1876  Block3.Matrix_12kl.at(k, l) = Imatrix.at(1, 2) * Imatrix.at(k, l);
1877  Block3.Matrix_13kl.at(k, l) = Imatrix.at(1, 3) * Imatrix.at(k, l);
1878  Block3.Matrix_21kl.at(k, l) = Imatrix.at(2, 1) * Imatrix.at(k, l);
1879  Block3.Matrix_22kl.at(k, l) = Imatrix.at(2, 2) * Imatrix.at(k, l);
1880  Block3.Matrix_23kl.at(k, l) = Imatrix.at(2, 3) * Imatrix.at(k, l);
1881  Block3.Matrix_31kl.at(k, l) = Imatrix.at(3, 1) * Imatrix.at(k, l);
1882  Block3.Matrix_32kl.at(k, l) = Imatrix.at(3, 2) * Imatrix.at(k, l);
1883  Block3.Matrix_33kl.at(k, l) = Imatrix.at(3, 3) * Imatrix.at(k, l);
1884  }
1885  }
1886  // equation 56 of the reference paper
1887  if ( ( strainTensor.at(1, 1) + strainTensor.at(2, 2) + strainTensor.at(3, 3) ) > 0.0 ) {
1888  for ( int k = 1; k <= 3; k++ ) {
1889  for ( int l = 1; l <= 3; l++ ) {
1890  secantOperator.Matrix_11kl.at(k, l) = 2 * G * ( Block1.Matrix_11kl.at(k, l) - Block2.Matrix_11kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_11kl.at(k, l);
1891  secantOperator.Matrix_12kl.at(k, l) = 2 * G * ( Block1.Matrix_12kl.at(k, l) - Block2.Matrix_12kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_12kl.at(k, l);
1892  secantOperator.Matrix_13kl.at(k, l) = 2 * G * ( Block1.Matrix_13kl.at(k, l) - Block2.Matrix_13kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_13kl.at(k, l);
1893  secantOperator.Matrix_21kl.at(k, l) = 2 * G * ( Block1.Matrix_21kl.at(k, l) - Block2.Matrix_21kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_21kl.at(k, l);
1894  secantOperator.Matrix_22kl.at(k, l) = 2 * G * ( Block1.Matrix_22kl.at(k, l) - Block2.Matrix_22kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_22kl.at(k, l);
1895  secantOperator.Matrix_23kl.at(k, l) = 2 * G * ( Block1.Matrix_23kl.at(k, l) - Block2.Matrix_23kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_23kl.at(k, l);
1896  secantOperator.Matrix_31kl.at(k, l) = 2 * G * ( Block1.Matrix_31kl.at(k, l) - Block2.Matrix_31kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_31kl.at(k, l);
1897  secantOperator.Matrix_32kl.at(k, l) = 2 * G * ( Block1.Matrix_32kl.at(k, l) - Block2.Matrix_32kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_32kl.at(k, l);
1898  secantOperator.Matrix_33kl.at(k, l) = 2 * G * ( Block1.Matrix_33kl.at(k, l) - Block2.Matrix_33kl.at(k, l) ) + K * ( 1 - traceD ) * Block3.Matrix_33kl.at(k, l);
1899  }
1900  }
1901  // equation 57 of the reference paper
1902  } else {
1903  for ( int k = 1; k <= 3; k++ ) {
1904  for ( int l = 1; l <= 3; l++ ) {
1905  secantOperator.Matrix_11kl.at(k, l) = 2 * G * ( Block1.Matrix_11kl.at(k, l) - Block2.Matrix_11kl.at(k, l) ) + K *Block3.Matrix_11kl.at(k, l);
1906  secantOperator.Matrix_12kl.at(k, l) = 2 * G * ( Block1.Matrix_12kl.at(k, l) - Block2.Matrix_12kl.at(k, l) ) + K *Block3.Matrix_12kl.at(k, l);
1907  secantOperator.Matrix_13kl.at(k, l) = 2 * G * ( Block1.Matrix_13kl.at(k, l) - Block2.Matrix_13kl.at(k, l) ) + K *Block3.Matrix_13kl.at(k, l);
1908  secantOperator.Matrix_21kl.at(k, l) = 2 * G * ( Block1.Matrix_21kl.at(k, l) - Block2.Matrix_21kl.at(k, l) ) + K *Block3.Matrix_21kl.at(k, l);
1909  secantOperator.Matrix_22kl.at(k, l) = 2 * G * ( Block1.Matrix_22kl.at(k, l) - Block2.Matrix_22kl.at(k, l) ) + K *Block3.Matrix_22kl.at(k, l);
1910  secantOperator.Matrix_23kl.at(k, l) = 2 * G * ( Block1.Matrix_23kl.at(k, l) - Block2.Matrix_23kl.at(k, l) ) + K *Block3.Matrix_23kl.at(k, l);
1911  secantOperator.Matrix_31kl.at(k, l) = 2 * G * ( Block1.Matrix_31kl.at(k, l) - Block2.Matrix_31kl.at(k, l) ) + K *Block3.Matrix_31kl.at(k, l);
1912  secantOperator.Matrix_32kl.at(k, l) = 2 * G * ( Block1.Matrix_32kl.at(k, l) - Block2.Matrix_32kl.at(k, l) ) + K *Block3.Matrix_32kl.at(k, l);
1913  secantOperator.Matrix_33kl.at(k, l) = 2 * G * ( Block1.Matrix_33kl.at(k, l) - Block2.Matrix_33kl.at(k, l) ) + K *Block3.Matrix_33kl.at(k, l);
1914  }
1915  }
1916  }
1917  // The resulting material stiffness matrix is built
1918  answer.resize(6, 6);
1919  answer.at(1, 1) = secantOperator.Matrix_11kl.at(1, 1);
1920  answer.at(1, 2) = secantOperator.Matrix_11kl.at(2, 2);
1921  answer.at(1, 3) = secantOperator.Matrix_11kl.at(3, 3);
1922  answer.at(1, 4) = secantOperator.Matrix_11kl.at(2, 3);
1923  answer.at(1, 5) = secantOperator.Matrix_11kl.at(3, 1);
1924  answer.at(1, 6) = secantOperator.Matrix_11kl.at(1, 2);
1925  answer.at(2, 1) = secantOperator.Matrix_22kl.at(1, 1);
1926  answer.at(2, 2) = secantOperator.Matrix_22kl.at(2, 2);
1927  answer.at(2, 3) = secantOperator.Matrix_22kl.at(3, 3);
1928  answer.at(2, 4) = secantOperator.Matrix_22kl.at(2, 3);
1929  answer.at(2, 5) = secantOperator.Matrix_22kl.at(3, 1);
1930  answer.at(2, 6) = secantOperator.Matrix_22kl.at(1, 2);
1931  answer.at(3, 1) = secantOperator.Matrix_33kl.at(1, 1);
1932  answer.at(3, 2) = secantOperator.Matrix_33kl.at(2, 2);
1933  answer.at(3, 3) = secantOperator.Matrix_33kl.at(3, 3);
1934  answer.at(3, 4) = secantOperator.Matrix_33kl.at(2, 3);
1935  answer.at(3, 5) = secantOperator.Matrix_33kl.at(3, 1);
1936  answer.at(3, 6) = secantOperator.Matrix_33kl.at(1, 2);
1937  answer.at(4, 1) = secantOperator.Matrix_23kl.at(1, 1);
1938  answer.at(4, 2) = secantOperator.Matrix_23kl.at(2, 2);
1939  answer.at(4, 3) = secantOperator.Matrix_23kl.at(3, 3);
1940  answer.at(4, 4) = secantOperator.Matrix_23kl.at(2, 3);
1941  answer.at(4, 5) = secantOperator.Matrix_23kl.at(3, 1);
1942  answer.at(4, 6) = secantOperator.Matrix_23kl.at(1, 2);
1943  answer.at(5, 1) = secantOperator.Matrix_31kl.at(1, 1);
1944  answer.at(5, 2) = secantOperator.Matrix_31kl.at(2, 2);
1945  answer.at(5, 3) = secantOperator.Matrix_31kl.at(3, 3);
1946  answer.at(5, 4) = secantOperator.Matrix_31kl.at(2, 3);
1947  answer.at(5, 5) = secantOperator.Matrix_31kl.at(3, 1);
1948  answer.at(5, 6) = secantOperator.Matrix_31kl.at(1, 2);
1949  answer.at(6, 1) = secantOperator.Matrix_12kl.at(1, 1);
1950  answer.at(6, 2) = secantOperator.Matrix_12kl.at(2, 2);
1951  answer.at(6, 3) = secantOperator.Matrix_12kl.at(3, 3);
1952  answer.at(6, 4) = secantOperator.Matrix_12kl.at(2, 3);
1953  answer.at(6, 5) = secantOperator.Matrix_12kl.at(3, 1);
1954  answer.at(6, 6) = secantOperator.Matrix_12kl.at(1, 2);
1955 }
1956 
1957 int
1959 {
1960  AnisotropicDamageMaterialStatus *status = static_cast< AnisotropicDamageMaterialStatus * >( this->giveStatus(gp) );
1961  if ( type == IST_DamageScalar ) { // returning the trace of the damage tensor
1962  answer.resize(1);
1963  answer.at(1) = status->giveDamage().at(1, 1) + status->giveDamage().at(2, 2) + status->giveDamage().at(3, 3);
1964  return 1;
1965  } else if ( type == IST_DamageTensor ) {
1966  answer.resize(6);
1967  answer.zero();
1968  answer.at(1) = status->giveDamage().at(1, 1);
1969  answer.at(2) = status->giveDamage().at(2, 2);
1970  answer.at(3) = status->giveDamage().at(3, 3);
1971  answer.at(4) = status->giveDamage().at(2, 3);
1972  answer.at(5) = status->giveDamage().at(1, 3);
1973  answer.at(6) = status->giveDamage().at(1, 2);
1974  return 1;
1975  } else if ( type == IST_PrincipalDamageTensor ) {
1976  //int checker12=this->checkSymmetry(status->giveDamage());
1977  FloatMatrix dam = status->giveDamage();
1978  FloatMatrix eVecs;
1979  dam.jaco_(answer, eVecs, 20);
1980  return 1;
1981  } else if ( type == IST_DamageTensorTemp ) {
1982  answer.resize(6);
1983  answer.zero();
1984  answer.at(1) = status->giveTempDamage().at(1, 1);
1985  answer.at(2) = status->giveTempDamage().at(2, 2);
1986  answer.at(3) = status->giveTempDamage().at(3, 3);
1987  answer.at(4) = status->giveTempDamage().at(2, 3);
1988  answer.at(5) = status->giveTempDamage().at(1, 3);
1989  answer.at(6) = status->giveTempDamage().at(1, 2);
1990  return 1;
1991  } else if ( type == IST_PrincipalDamageTempTensor ) {
1992  //int checker13=this->checkSymmetry(status->giveTempDamage());
1993  FloatMatrix dam = status->giveTempDamage();
1994  FloatMatrix eVecs;
1995  dam.jaco_(answer, eVecs, 20);
1996  return 1;
1997  } else if ( type == IST_MaxEquivalentStrainLevel ) {
1998  answer.resize(1);
1999  answer.at(1) = status->giveKappa();
2000  return 1;
2001 
2002 #ifdef keep_track_of_dissipated_energy
2003  } else if ( type == IST_StressWorkDensity ) {
2004  answer.resize(1);
2005  answer.at(1) = status->giveStressWork();
2006  return 1;
2007  } else if ( type == IST_DissWorkDensity ) {
2008  answer.resize(1);
2009  answer.at(1) = status->giveDissWork();
2010  } else if ( type == IST_FreeEnergyDensity ) {
2011  answer.resize(1);
2012  answer.at(1) = status->giveStressWork() - status->giveDissWork();
2013  return 1;
2014 
2015 #endif
2016  } else {
2017  return StructuralMaterial :: giveIPValue(answer, gp, type, atTime);
2018  }
2019 
2020  return 1; // to make the compiler happy
2021 }
2022 
2023 
2026 {
2027  IRResultType result; // Required by IR_GIVE_FIELD macro
2028 
2032  int eqStrain = 0;
2033  // specify the type of formula for equivalent strain
2034  // currently only the Mazars formula is allowed !!! (this should be generalized later)
2035  //
2036  // IR_GIVE_OPTIONAL_FIELD(ir, eqStrain, _IFT_AnisotropicDamageMaterial_equivStrainType);
2037  //
2038  switch ( eqStrain ) {
2039  case 1: this->equivStrainType = EST_Rankine_Smooth;
2040  break;
2041  case 2: this->equivStrainType = EST_ElasticEnergy;
2042  break;
2043  case 3: this->equivStrainType = EST_Mises;
2044  // IR_GIVE_FIELD(ir, k, _IFT_IsotropicDamageMaterial1_k);
2045  break;
2046  case 4: this->equivStrainType = EST_Rankine_Standard;
2047  break;
2049  break;
2051  break;
2052  case 7: this->equivStrainType = EST_Griffith;
2053  break;
2054  default: this->equivStrainType = EST_Mazars;
2055  }
2056 
2057  int damlaw = 0;
2058  // specify the type of damage law (which affects the shape of the stress-strain curve)
2060  switch ( damlaw ) {
2061  case 1: this->damageLawType = DLT_Desmorat1;
2062  break;
2063  case 2: this->damageLawType = DLT_Desmorat2;
2064  break;
2065  case 3: this->damageLawType = DLT_Linear;
2066  break;
2067  case 4: this->damageLawType = DLT_Exponential;
2068  break;
2069  default: this->damageLawType = DLT_Desmorat2;
2070  }
2071 
2074  if ( damageLawType == DLT_Desmorat2 ) {
2076  }
2077 
2079 }
2080 
2081 void
2083 {
2086 }
2087 
2088 
2090 {
2091  kappa = tempKappa = 0.0;
2092  damage.resize(3, 3);
2093  damage.zero();
2094  tempDamage.resize(3, 3);
2095  tempDamage.zero();
2096  strainZ = tempStrainZ = 0.0;
2097  flag = tempFlag = 0;
2098  storedFactor = 1.0;
2099  tempStoredFactor = 1.0;
2100 
2101 #ifdef keep_track_of_dissipated_energy
2102  stressWork = tempStressWork = 0.0;
2103  dissWork = tempDissWork = 0.0;
2104 #endif
2105 }
2106 
2108 { }
2109 
2110 void
2112 {
2113  MaterialMode mode = gp->giveMaterialMode();
2114  if ( mode == _PlaneStress ) { // special treatment of the out-of-plane strain
2115  FloatArray helpVec;
2116  MaterialStatus :: printOutputAt(file, tStep);
2117  fprintf(file, " strains ");
2119  helpVec.at(3) = this->strainZ;
2120  for ( auto &v : helpVec ) {
2121  fprintf( file, " %.4e", v );
2122  }
2123  fprintf(file, "\n stresses");
2125  for ( auto &v : helpVec ) {
2126  fprintf( file, " %.4e", v );
2127  }
2128  fprintf(file, "\n");
2129  } else {
2130  StructuralMaterialStatus :: printOutputAt(file, tStep); // standard treatment of strains and stresses
2131  }
2132 
2133  fprintf(file, "status { ");
2134  fprintf(file, "kappa %g", this->kappa);
2135  double damtrace = tempDamage.giveTrace();
2136  if ( damtrace > 0.0 ) {
2137  fprintf(file, ", damage");
2138  int n = tempDamage.giveNumberOfRows();
2139  for ( int i = 1; i <= n; i++ ) {
2140  for ( int j = 1; j <= n; j++ ) {
2141  fprintf( file, " %g", tempDamage.at(i, j) );
2142  }
2143  }
2144  }
2145 
2146 #ifdef keep_track_of_dissipated_energy
2147  fprintf(file, ", dissW %f, freeE %f, stressW %f ", this->dissWork, ( this->stressWork ) - ( this->dissWork ), this->stressWork);
2148 #endif
2149 
2150  fprintf(file, "}\n");
2151 }
2152 
2153 
2154 
2155 void
2157 {
2159  this->tempKappa = this->kappa;
2160  this->tempDamage = this->damage;
2161  this->tempStrainZ = this->strainZ;
2162  this->tempStoredFactor = this->storedFactor;
2163 #ifdef keep_track_of_dissipated_energy
2164  this->tempStressWork = this->stressWork;
2165  this->tempDissWork = this->dissWork;
2166 #endif
2167 }
2168 
2169 
2170 void
2172 {
2174  this->kappa = this->tempKappa;
2175  this->damage = this->tempDamage;
2176  this->strainZ = this->tempStrainZ;
2177  this->flag = this->tempFlag;
2178  this->storedFactor = this->tempStoredFactor;
2179 #ifdef keep_track_of_dissipated_energy
2180  this->stressWork = this->tempStressWork;
2181  this->dissWork = this->tempDissWork;
2182 #endif
2183 }
2184 
2185 
2188 {
2189  /* contextIOResultType iores;
2190  *
2191  * // save parent class status
2192  * if ( ( iores = StructuralMaterialStatus :: saveContext(stream, mode, obj) ) != CIO_OK ) {
2193  * THROW_CIOERR(iores);
2194  * }
2195  *
2196  * // write raw data
2197  * if ( !stream.write(kappa) ) {
2198  * THROW_CIOERR(CIO_IOERR);
2199  * }
2200  *
2201  * if ( !stream.write(damage) ) {
2202  * THROW_CIOERR(CIO_IOERR);
2203  * }
2204  *
2205  * #ifdef keep_track_of_dissipated_energy
2206  * if ( !stream.write(stressWork) ) {
2207  * THROW_CIOERR(CIO_IOERR);
2208  * }
2209  *
2210  * if ( !stream.write(dissWork) ) {
2211  * THROW_CIOERR(CIO_IOERR);
2212  * }
2213  *
2214  * #endif
2215  */
2216  contextIOResultType iores;
2217 
2218  // save parent class status
2219  if ( ( iores = StructuralMaterialStatus :: saveContext(stream, mode, obj) ) != CIO_OK ) {
2220  THROW_CIOERR(iores);
2221  }
2222 
2223  // write raw data
2224  if ( !stream.write(kappa) ) {
2226  }
2227 
2228 
2229  // write damage (vector)
2230  if ( ( iores = damage.storeYourself(stream) ) != CIO_OK ) {
2231  THROW_CIOERR(iores);
2232  }
2233 
2234 #ifdef keep_track_of_dissipated_energy
2235  if ( !stream.write(stressWork) ) {
2237  }
2238 
2239  if ( !stream.write(dissWork) ) {
2241  }
2242 
2243 
2244 #endif
2245 
2246  return CIO_OK;
2247 }
2248 
2249 
2252 {
2253  /* contextIOResultType iores;
2254  *
2255  * // read parent class status
2256  * if ( ( iores = StructuralMaterialStatus :: restoreContext(stream, mode, obj) ) != CIO_OK ) {
2257  * THROW_CIOERR(iores);
2258  * }
2259  *
2260  * // read raw data
2261  * if ( !stream.read(kappa) ) {
2262  * THROW_CIOERR(CIO_IOERR);
2263  * }
2264  *
2265  * if ( !stream.read(damage) ) {
2266  * THROW_CIOERR(CIO_IOERR);
2267  * }
2268  *
2269  * #ifdef keep_track_of_dissipated_energy
2270  * if ( !stream.read(stressWork) ) {
2271  * THROW_CIOERR(CIO_IOERR);
2272  * }
2273  *
2274  * if ( !stream.read(dissWork) ) {
2275  * THROW_CIOERR(CIO_IOERR);
2276  * }
2277  *
2278  * #endif
2279  */
2280 
2281  contextIOResultType iores;
2282 
2283 
2284  // read parent class status
2285  if ( ( iores = StructuralMaterialStatus :: restoreContext(stream, mode, obj) ) != CIO_OK ) {
2286  THROW_CIOERR(iores);
2287  }
2288 
2289  // read raw data
2290  if ( !stream.read(kappa) ) {
2292  }
2293 
2294 
2295  // read damage (vector)
2296  if ( ( iores = damage.restoreYourself(stream) ) != CIO_OK ) {
2297  THROW_CIOERR(iores);
2298  }
2299 
2300 #ifdef keep_track_of_dissipated_energy
2301  if ( !stream.read(stressWork) ) {
2303  }
2304 
2305  if ( !stream.read(dissWork) ) {
2307  }
2308 
2309 #endif
2310 
2311 
2312  return CIO_OK;
2313 }
2314 
2315 #ifdef keep_track_of_dissipated_energy
2316 void
2318 {
2319  /*
2320  * // strain increment
2321  * FloatArray deps;
2322  * deps.beDifferenceOf(tempStrainVector, strainVector);
2323  *
2324  * // increment of stress work density
2325  * double dSW = ( tempStressVector.dotProduct(deps) + stressVector.dotProduct(deps) ) / 2.;
2326  * tempStressWork = stressWork + dSW;
2327  *
2328  * // elastically stored energy density
2329  * double We = tempStressVector.dotProduct(tempStrainVector) / 2.;
2330  *
2331  * // dissipative work density
2332  * tempDissWork = tempStressWork - We;
2333  */
2334 }
2335 #endif
2336 } // end namespace oofem
virtual void updateYourself(TimeStep *tStep)
Update equilibrium history variables according to temp-variables.
Definition: structuralms.C:96
InternalStateType
Type representing the physical meaning of element or constitutive model internal variable.
void setField(int item, InputFieldType id)
static void computePrincipalValues(FloatArray &answer, const FloatArray &s, stressStrainPrincMode mode)
Common functions for convenience.
MaterialMode giveMaterialMode()
Returns corresponding material mode of receiver.
Definition: gausspoint.h:191
double aA
Damage parameter a*A, needed to obtain Kappa(trD), according to eq. 33 in the paper mentioned above...
virtual contextIOResultType saveContext(DataStream &stream, ContextMode mode, void *obj=NULL)
Stores receiver state to output stream.
void letTempStrainVectorBe(const FloatArray &v)
Assigns tempStrainVector to given vector v.
Definition: structuralms.h:137
virtual void computeSecantOperator(FloatMatrix &answer, FloatMatrix strainTensor, FloatMatrix damageTensor, GaussPoint *gp)
double computeDimensionlessOutOfPlaneStress(const FloatArray &inplaneStrain, double epsZ, const FloatMatrix &dam)
virtual MaterialStatus * giveStatus(GaussPoint *gp) const
Returns material status of receiver in given integration point.
Definition: material.C:244
This class implements associated Material Status to AnisotropicDamageMaterial.
void computeInplaneStress(FloatArray &inplaneStress, const FloatArray &inplaneStrain, double epsZ, const FloatMatrix &dam)
GaussPoint * gp
Associated integration point.
Class and object Domain.
Definition: domain.h:115
IsotropicLinearElasticMaterial * linearElasticMaterial
Reference to bulk (undamaged) material.
For computing principal strains from engineering strains.
double tempDissWork
Non-equilibrated density of dissipated work.
double tempStressWork
Non-equilibrated density of total work done by stresses on strain increments.
#define _IFT_AnisotropicDamageMaterial_kappaf
AnisotropicDamageMaterialStatus(int n, Domain *d, GaussPoint *g)
Constructor.
void computePrincValDir2D(double &D1, double &D2, double &c, double &s, double Dx, double Dy, double Dxy)
The purpose of DataStream abstract class is to allow to store/restore context to different streams...
Definition: datastream.h:54
virtual int giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *tStep)
Returns the integration point corresponding value in Reduced form.
double & at(int i)
Coefficient access function.
Definition: floatarray.h:131
bool checkPrincVal2D(double Dx, double Dy, double Dxy)
double obtainAlpha2(FloatMatrix tempDamageTensor, double deltaLambda, FloatMatrix positiveStrainTensor, FloatMatrix ProjMatrix, double damageThreshold)
Obtains the proportion of the damage tensor that is needed to get the second eigenvalue equal to the ...
FloatMatrix tempDamage
Non-equilibrated second order damage tensor.
This class implements a structural material status information.
Definition: structuralms.h:65
double nu
Poisson&#39;s ratio.
virtual ~AnisotropicDamageMaterialStatus()
Destructor.
double giveStressWork()
Returns the density of total work of stress on strain increments.
FloatArray stressVector
Equilibrated stress vector in reduced form.
Definition: structuralms.h:71
double macbra(double x)
Returns the positive part of given float.
Definition: mathfem.h:115
virtual ~AnisotropicDamageMaterial()
Destructor.
virtual void computeDamageTensor(FloatMatrix &answer, GaussPoint *gp, const FloatArray &totalStrain, double equivStrain, TimeStep *atTime)
General IO error.
double giveStoredFactor()
Returns the last Stored Factor.
void setTempFlag(int newflag)
Sets the value of the temporary value of flag.
DamLawType damageLawType
Parameter specifying the damage law.
double obtainAlpha3(FloatMatrix tempDamageTensor, double deltaLambda, FloatMatrix positiveStrainTensor, FloatArray vec3, double damageThreshold)
Obtains the proportion of the damage tensor that is needed to get the third eigenvalue equal to the d...
double stressWork
Density of total work done by stresses on strain increments.
void giveStressDependentPartOfStrainVector(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedStrainVector, TimeStep *tStep, ValueModeType mode)
Method for subtracting from reduced space strain vector its stress-independent parts (caused by tempe...
MaterialMode
Type representing material mode of integration point.
Definition: materialmode.h:89
virtual void printOutputAt(FILE *file, TimeStep *tStep)
Print receiver&#39;s output to given stream.
Definition: structuralms.C:73
virtual int read(int *data, int count)=0
Reads count integer values into array pointed by data.
MatResponseMode
Describes the character of characteristic material matrix.
FloatMatrix damage
Second order damage tensor.
#define THROW_CIOERR(e)
Definition: contextioerr.h:61
const FloatMatrix & giveDamage()
Returns the last equilibrated second order damage tensor.
This class is a abstract base class for all linear elastic material models in a finite element proble...
contextIOResultType storeYourself(DataStream &stream) const
Definition: floatmatrix.C:1852
virtual int giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *atTime)
Returns the integration point corresponding value in Reduced form.
virtual void givePlaneStrainStiffMtrx(FloatMatrix &answer, MatResponseMode mmode, GaussPoint *gp, TimeStep *tStep)
Method for computing plane strain stiffness matrix of receiver.
double dissWork
Density of dissipated work.
virtual void givePlaneStressStiffMtrx(FloatMatrix &answer, MatResponseMode mmode, GaussPoint *gp, TimeStep *tStep)
Method for computing plane stress stiffness matrix of receiver.
static void giveFullSymVectorForm(FloatArray &answer, const FloatArray &vec, MaterialMode matMode)
Converts the reduced unsymmetric Voigt vector (2nd order tensor) to full form.
double tempKappa
Non-equilibrated scalar measure of the largest strain level.
void beMatrixForm(const FloatArray &aArray)
Definition: floatmatrix.C:1657
double givePoissonsRatio()
Returns Poisson&#39;s ratio.
virtual int write(const int *data, int count)=0
Writes count integer values from array pointed by data.
bool jaco_(FloatArray &eval, FloatMatrix &v, int nf)
Computes eigenvalues and eigenvectors of receiver (must be symmetric) The receiver is preserved...
Definition: floatmatrix.C:1912
void setTempStrainZ(double newStrainZ)
Sets the temp scalar measure of the out-of-plane strain to given value (for 2dPlaneStress mode)...
virtual IRResultType initializeFrom(InputRecord *ir)
Initializes receiver according to object description stored in input record.
virtual void giveStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, GaussPoint *gp, TimeStep *tStep)
Computes the stiffness matrix for giveRealStressVector of receiver in given integration point...
void setTempDamage(const FloatMatrix &d)
Assigns temp. damage tensor to given tensor d.
double giveKappa()
Returns the last equilibrated scalar measure of the largest strain level.
static void giveReducedSymVectorForm(FloatArray &answer, const FloatArray &vec, MaterialMode matMode)
Converts the full unsymmetric Voigt vector (2nd order tensor) to reduced form.
virtual void giveRealStressVector_PlaneStress(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedE, TimeStep *tStep)
Plane-stress version of the stress evaluation algorithm.
virtual void initTempStatus()
Initializes the temporary internal variables, describing the current state according to previously re...
virtual void printOutputAt(FILE *file, TimeStep *tStep)
Print receiver&#39;s output to given stream.
This class implements an isotropic linear elastic material in a finite element problem.
virtual void give3dMaterialStiffnessMatrix(FloatMatrix &answer, MatResponseMode mode, GaussPoint *gp, TimeStep *tStep)
Computes full 3d material stiffness matrix at given integration point, time, respecting load history ...
#define OOFEM_ERROR(...)
Definition: error.h:61
virtual void computeEquivalentStrain(double &kappa, const FloatArray &strain, GaussPoint *gp, TimeStep *tStep)
Computes the equivalent strain measure from given strain vector (full form).
double giveTrace() const
Returns the trace of the receiver.
Definition: floatmatrix.C:1443
double giveTempStrainZ()
Returns the temp scalar measure of the out-of-plane strain to given value (for 2dPlaneStress mode)...
virtual void give3dMaterialStiffnessMatrix(FloatMatrix &answer, MatResponseMode, GaussPoint *gp, TimeStep *tStep)
Computes full 3d material stiffness matrix at given integration point, time, respecting load history ...
void times(double f)
Multiplies receiver by factor f.
Definition: floatmatrix.C:1594
double checkSymmetry(FloatMatrix matrix)
virtual int hasMaterialModeCapability(MaterialMode mode)
Tests if material supports material mode.
virtual void giveInputRecord(DynamicInputRecord &input)
Setups the input record string of receiver.
void beProductOf(const FloatMatrix &aMatrix, const FloatArray &anArray)
Receiver becomes the result of the product of aMatrix and anArray.
Definition: floatarray.C:676
double strainZ
Non-equilibrated out-of-plane value for 2dPlaneStress mode.
const FloatArray & giveTempStrainVector() const
Returns the const pointer to receiver&#39;s temporary strain vector.
Definition: structuralms.h:115
virtual void giveRealStressVector(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedStrain, TimeStep *tStep)
Computes the real stress vector for given total strain and integration point.
bool isEmpty() const
Returns true if receiver is empty.
Definition: floatarray.h:222
#define _IFT_AnisotropicDamageMaterial_aA
double at(int i, int j) const
Coefficient access function.
Definition: floatmatrix.h:176
double computeOutOfPlaneStrain(const FloatArray &inplaneStrain, const FloatMatrix &dam, bool tens_flag)
void computeWork(GaussPoint *gp)
Computes the increment of total stress work and of dissipated work.
IsotropicLinearElasticMaterial * giveLinearElasticMaterial()
Returns reference to undamaged (bulk) material.
double giveDissWork()
Returns the density of dissipated work.
virtual contextIOResultType restoreContext(DataStream &stream, ContextMode mode, void *obj=NULL)
Restores the receiver state previously written in stream.
Definition: structuralms.C:157
int giveFlag()
Returns the value of the flag.
double obtainAlpha1(FloatMatrix tempDamageTensor, double deltaLambda, FloatMatrix positiveStrainTensor, double damageThreshold)
Obtains the proportion of the damage tensor that is needed to get the first eigenvalue equal to the d...
void subtract(const FloatMatrix &a)
Subtracts matrix from the receiver.
Definition: floatmatrix.C:1084
contextIOResultType restoreYourself(DataStream &stream)
Definition: floatmatrix.C:1877
#define _IFT_AnisotropicDamageMaterial_kappa0
Class representing vector of real numbers.
Definition: floatarray.h:82
virtual IRResultType initializeFrom(InputRecord *ir)
Initializes receiver according to object description stored in input record.
FloatArray strainVector
Equilibrated strain vector in reduced form.
Definition: structuralms.h:69
void setTempKappa(double newKappa)
Sets the temp scalar measure of the largest strain level to given value.
Implementation of matrix containing floating point numbers.
Definition: floatmatrix.h:94
IRResultType
Type defining the return values of InputRecord reading operations.
Definition: irresulttype.h:47
double kappaf
Damage parameter kappa_f (in the paper denoted as "a")
void letTempStressVectorBe(const FloatArray &v)
Assigns tempStressVector to given vector v.
Definition: structuralms.h:135
double kappa0
Damage threshold kappa0, as defined in the paper mentioned above.
void resize(int rows, int cols)
Checks size of receiver towards requested bounds.
Definition: floatmatrix.C:1358
Class representing the general Input Record.
Definition: inputrecord.h:101
double computeCorrectionFactor(FloatMatrix tempDamageTensor, FloatMatrix strainTensor, GaussPoint *gp)
void add(const FloatMatrix &a)
Adds matrix to the receiver.
Definition: floatmatrix.C:1023
void setTempStoredFactor(double newTempStoredFactor)
Sets the Temp Stored Factor to given value .
virtual IRResultType initializeFrom(InputRecord *ir)
Initializes receiver according to object description stored in input record.
void correctBigValues(FloatMatrix &matrix)
void zero()
Zeroes all coefficients of receiver.
Definition: floatarray.C:658
void beDyadicProductOf(const FloatArray &vec1, const FloatArray &vec2)
Assigns to the receiver the dyadic product .
Definition: floatmatrix.C:492
double kappa
Scalar measure of the largest strain level ever reached in material.
Class representing the a dynamic Input Record.
long ContextMode
Context mode (mask), defining the type of information written/read to/from context.
Definition: contextmode.h:43
void beSymVectorForm(const FloatMatrix &aMatrix)
Reciever will be a vector with 6 components formed from a 3x3 matrix.
Definition: floatarray.C:1035
Abstract base class for all "structural" constitutive models.
AnisotropicDamageMaterial(int n, Domain *d)
Constructor.
double tempStrainZ
Out-of-plane value for 2dPlaneStress mode.
#define _IFT_AnisotropicDamageMaterial_damageLawType
void zero()
Zeroes all coefficient of receiver.
Definition: floatmatrix.C:1326
const FloatMatrix & giveTempDamage()
Returns the temp. second order damage tensor.
virtual void initTempStatus()
Initializes the temporary internal variables, describing the current state according to previously re...
Definition: structuralms.C:108
double E
Young&#39;s modulus.
virtual void giveInputRecord(DynamicInputRecord &input)
Setups the input record string of receiver.
double computeKappa(FloatMatrix damageTensor)
virtual contextIOResultType restoreContext(DataStream &stream, ContextMode mode, void *obj=NULL)
Restores the receiver state previously written in stream.
REGISTER_Material(DummyMaterial)
int flag
This flag turns into 1 and remains 1 when the trace of the damage tensor is >1 in compression (tr(str...
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Macro facilitating the use of input record reading methods.
Definition: inputrecord.h:78
void beProductOf(const FloatMatrix &a, const FloatMatrix &b)
Assigns to the receiver product of .
Definition: floatmatrix.C:337
virtual void computePlaneStressSigmaZ(double &answer, FloatMatrix damageTensor, FloatArray reducedTotalStrainVector, double epsZ, GaussPoint *gp, TimeStep *atTime)
const FloatArray & giveTempStressVector() const
Returns the const pointer to receiver&#39;s temporary stress vector.
Definition: structuralms.h:117
int giveSize() const
Returns the size of receiver.
Definition: floatarray.h:218
virtual contextIOResultType saveContext(DataStream &stream, ContextMode mode, void *obj=NULL)
Stores receiver state to output stream.
Definition: structuralms.C:133
the oofem namespace is to define a context or scope in which all oofem names are defined.
virtual void printOutputAt(FILE *file, TimeStep *tStep)
Print receiver&#39;s output to given stream.
Definition: matstatus.h:97
#define IR_GIVE_FIELD(__ir, __value, __id)
Macro facilitating the use of input record reading methods.
Definition: inputrecord.h:69
virtual void initTempStatus(GaussPoint *gp)
Initializes temporary variables stored in integration point status at the beginning of new time step...
Definition: material.C:267
virtual void computePlaneStressStrain(FloatMatrix &answer, FloatMatrix damageTensor, FloatArray totalStrain, GaussPoint *gp, TimeStep *atTime)
double giveYoungsModulus()
Returns Young&#39;s modulus.
virtual void give1dStressStiffMtrx(FloatMatrix &answer, MatResponseMode mmode, GaussPoint *gp, TimeStep *tStep)
Method for computing 1d stiffness matrix of receiver.
int giveNumberOfRows() const
Returns number of rows of receiver.
Definition: floatmatrix.h:156
#define AD_TOLERANCE
Class representing integration point in finite element program.
Definition: gausspoint.h:93
double computeTraceD(double equivStrain)
Class representing solution step.
Definition: timestep.h:80
virtual void updateYourself(TimeStep *tStep)
Update equilibrium history variables according to temp-variables.
#define AD_MAXITER
void computeDamage(FloatMatrix &tempDamage, const FloatMatrix &damage, double kappa, double eps1, double eps2, double ceps, double seps, double epsZ)
EquivStrainType equivStrainType
Parameter specifying the definition of equivalent strain.
void resize(int s)
Resizes receiver towards requested size.
Definition: floatarray.C:631

This page is part of the OOFEM documentation. Copyright (c) 2011 Borek Patzak
Project e-mail: info@oofem.org
Generated at Tue Jan 2 2018 20:07:27 for OOFEM by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2011