OOFEM 3.0
Loading...
Searching...
No Matches
steelrelaxmat.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "steelrelaxmat.h"
36#include "gausspoint.h"
37#include "floatmatrix.h"
38#include "floatarray.h"
39#include "intarray.h"
40#include "mathfem.h"
41#include "contextioerr.h"
42#include "datastream.h"
43#include "classfactory.h"
44
45namespace oofem {
47
50
51
52bool
54{
55 return mode == _1dMat;
56}
57
58// reads the model parameters from the input file
59void
61{
63
64 IR_GIVE_FIELD(ir, this->E, _IFT_SteelRelaxMat_E); // Young's modulus
65
66 int reinfClass;
67 IR_GIVE_FIELD(ir, reinfClass, _IFT_SteelRelaxMat_reinfClass); // class of reinforcement according to MC2010 or EC2
68
69 // Attention!!! rho1000 must be provided in % and not dimensionless
70 if ( reinfClass == 1 ) { // class 1 (wires or cables with normal relaxation)
71 this->k1 = 5.39;
72 this->k2 = 6.7;
73 this->rho1000 = 8.;
74 } else if ( reinfClass == 2 ) { // class 2 (wires or cables with lowered relaxation)
75 this->k1 = 0.66;
76 this->k2 = 9.1;
77 this->rho1000 = 2.5;
78 } else if ( reinfClass == 3 ) { // class 3 (hot-rolled or modified rods)
79 this->k1 = 1.98;
80 this->k2 = 8.0;
81 this->rho1000 = 4.;
82 } else {
83 OOFEM_ERROR("unsupported value of reinfClass");
84 }
85
86 // possibility to overwrite
90
92
94
95 this->relRelaxBound = 0.;
97
98 int approach;
100
101 this->Approach = ( approachType ) approach;
102
103 // in incremental linear statics it seems that it is necessary to iterate equilibrium at the material point level (for the Bazant approach only) because otherwise the strain relaxation would be calculated from too high stress
104 // tolerance = 1 Pa
105 // MPa -> SF = 1e6 -> tol = 1
106 // Pa -> SF = 1 -> tol = 1
107 this->tolerance = 1. / 1.e6;
109}
110
111// creates a new material status corresponding to this class
112std::unique_ptr<MaterialStatus>
114{
115 return std::make_unique<SteelRelaxMatStatus>(gp);
116}
117
118void
120 GaussPoint *gp,
121 const FloatArray &totalStrain,
122 TimeStep *tStep) const
123{
124 FloatArray reducedStrain, strainIncrement, stressVector;
125 double stressIncrement;
126
127 SteelRelaxMatStatus *status = static_cast< SteelRelaxMatStatus * >( this->giveStatus(gp) );
128
129 if ( !this->isActivated(tStep) ) {
130 stressVector.resize(1);
131 stressVector.zero();
132
133 status->letTempStrainVectorBe(totalStrain);
134 status->letTempStressVectorBe(stressVector);
135
136 answer.resize(1);
137 answer.zero();
138 return;
139 }
140
141 if ( this->Approach == EquivTime_EC2 ) {
142 double lossIncrement;
143
144 if ( status->giveStressVector().giveSize() ) {
145 stressVector = status->giveStressVector();
146 } else {
147 stressVector.resize(1);
148 stressVector.zero();
149 }
150
151 StructuralMaterial::giveStressDependentPartOfStrainVector(reducedStrain, gp, totalStrain, tStep, VM_Incremental);
152
153 strainIncrement.beDifferenceOf(reducedStrain, status->giveStrainVector() );
154 stressIncrement = strainIncrement.at(1) * this->E;
155
156 stressVector.at(1) += stressIncrement;
157
158 if ( stressVector.at(1) > 0. ) {
159 this->computeIncrOfPrestressLossAtVarStrain(lossIncrement, gp, tStep, stressVector.at(1) );
160 stressVector.at(1) -= lossIncrement;
161 }
162
163 status->letTempStrainVectorBe(totalStrain);
164 status->letTempStressVectorBe(stressVector);
165 } else if ( this->Approach == Bazant_EC2 ) {
166 double prevIterTempStress;
167 int i = 0;
168
169 do {
170 prevIterTempStress = status->giveTempStressVector().at(1);
171
172 if ( status->giveStressVector().giveSize() ) {
173 stressVector = status->giveStressVector();
174 } else {
175 stressVector.resize(1);
176 stressVector.zero();
177 }
178
179 // get strain increment without strain due to cable relaxation and thermal strain
180 this->giveStressDependentPartOfStrainVector(reducedStrain, gp, totalStrain, tStep, VM_Incremental);
181
182 strainIncrement.beDifferenceOf(reducedStrain, status->giveStrainVector() );
183 stressIncrement = strainIncrement.at(1) * this->E;
184
185 stressVector.at(1) += stressIncrement;
186
187
188 // store the final strain and stress in the status
189 status->letTempStrainVectorBe(totalStrain);
190 status->letTempStressVectorBe(stressVector);
191
192 i++;
193
194 if ( i > 1000 ) {
195 OOFEM_ERROR("Algorithm not converging");
196 }
197 } while ( fabs(prevIterTempStress - status->giveTempStressVector().at(1) ) >= this->tolerance );
198
199
200 if ( i > 50 ) {
201 OOFEM_WARNING("Criterion of the algorithm reached in %d iterations, consider increasing tolerance", i);
202 }
203 }
204
205 if ( stressVector.at(1) > this->charStrength ) {
206 OOFEM_ERROR("Stress %f exeeds the characteristic strength of the material!", stressVector.at(1) );
207 }
208
209 answer.resize(1);
210 answer.at(1) = stressVector.at(1);
211}
212
213
216 GaussPoint *gp,
217 TimeStep *tStep) const
218{
219 if ( this->isActivated(tStep) ) {
220 return { this->E };
221 } else {
222 return { 0. };
223 }
224}
225
226
227void
228SteelRelaxMat::giveStressDependentPartOfStrainVector(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *tStep, ValueModeType mode) const
229{
230 FloatArray temperatureFreeStrain;
231 FloatArray relaxationStrain;
232
233 // subtracts temperature strain
234 StructuralMaterial::giveStressDependentPartOfStrainVector(temperatureFreeStrain, gp, totalStrain, tStep, mode);
235
236 // strains due to relaxation
237 this->computeStressRelaxationStrainVector(relaxationStrain, gp, totalStrain, tStep, mode);
238
239 answer = temperatureFreeStrain;
240 answer.subtract(relaxationStrain);
241}
242
243
244void
246{
247 double rho;
248 double k;
249 double lambda;
250 double mu;
251 double prestress;
252
253 SteelRelaxMatStatus *status = static_cast< SteelRelaxMatStatus * >( this->giveStatus(gp) );
254 // prestress loss is not calculated in the time step when prestressing is applied
255 prestress = status->givePrestress();
256
257 answer = 0.;
258
259 if ( prestress > this->relRelaxBound * this->charStrength ) {
260 mu = prestress / this->charStrength;
261
262 rho = this->k1 * this->rho1000 * exp(this->k2 * mu) * 1.e-5;
263 k = 0.75 * ( 1. - mu );
264 lambda = 1000. * this->timeFactor / 24.;
265
266 answer = prestress * rho * pow( ( dt / lambda ), k);
267 }
268}
269
270// this method is active only in the case of EC2 approach
271void
272SteelRelaxMat::computeIncrOfPrestressLossAtVarStrain(double &answer, GaussPoint *gp, TimeStep *tStep, double stress) const
273{
274 double rho;
275 double k;
276 double lambda;
277 double mu;
278 double prestress;
279 double lossesUpTillNow;
280 double loss;
281
282 SteelRelaxMatStatus *status = static_cast< SteelRelaxMatStatus * >( this->giveStatus(gp) );
283 lossesUpTillNow = status->giveRelaxIntVariable();
284
285 // "initial" value of prestress is the sum of the current stress plus the cumulative subsequent relaxation
286 prestress = stress + lossesUpTillNow;
287 status->setTempPrestress(prestress);
288
289 answer = 0.;
290
291 if ( prestress > this->relRelaxBound * this->charStrength ) {
292 mu = prestress / this->charStrength;
293 rho = this->k1 * this->rho1000 * exp(this->k2 * mu) * 1.e-5;
294 k = 0.75 * ( 1. - mu );
295 lambda = 1000. * this->timeFactor / 24.;
296
297 // compute total loss for updated prestress and time equiv
298 double t_equiv;
299 t_equiv = pow( ( lossesUpTillNow / ( prestress * rho ) ), ( 1. / k ) ) * lambda;
300 this->evalStressRelaxationAtConstStrain(loss, gp, t_equiv + tStep->giveTimeIncrement() );
301
302 // set temporary sum of losses
303 status->setTempRelaxIntVariable(loss);
304
305 // subtract the preceding sum of losses to get the increment
306 answer = loss - lossesUpTillNow;
307 }
308}
309
310
311
312void
313SteelRelaxMat::computeStressRelaxationStrainVector(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *tStep, ValueModeType mode) const
314{
315 SteelRelaxMatStatus *status = static_cast< SteelRelaxMatStatus * >( this->giveStatus(gp) );
316 double averageStress = 0.;
317 double mu = 0.;
318 double k, rho, lambda;
319 double dt = tStep->giveTimeIncrement();
320
321 // get average strain due to stress relaxation
322 double averageRelaxationStrain = 0.5 * ( status->giveTempRelaxIntVariable() + status->giveRelaxIntVariable() );
323
324 // get average stress
325 int n = 0;
326 if ( status->giveStressVector().at(1) > 0. ) {
327 averageStress += status->giveStressVector().at(1);
328 n++;
329 }
330
331 if ( status->giveTempStressVector().at(1) > 0 ) {
332 averageStress += status->giveTempStressVector().at(1);
333 n++;
334 }
335
336 if ( n > 0 ) {
337 averageStress /= n;
338 }
339
340 if ( !status->givePrestress() ) {
341 status->setTempPrestress(averageStress);
342 }
343
344
345 double averageMechStrain = averageRelaxationStrain + averageStress / this->E;
346
347 double F = averageMechStrain * this->E;
348
349 double relaxStrainIncrement;
350 // different approach for the first step after prestressing and for the following steps
351 // when the prestressing is applied, the losses are assumed as zero
352 if ( status->giveRelaxIntVariable() == 0. ) {
353 // use Eurocode function for the first prestress loss
354 this->evalStressRelaxationAtConstStrain(relaxStrainIncrement, gp, dt);
355 // convert into strain
356 relaxStrainIncrement /= this->E;
357 } else {
358 // governing equations 3.28-3.30 rewritten to the following form
359 //
360 // original:
361 // mu = sigma_0 / fk
362 // t in hours
363 // delta sigma_p / sigma_0 = k1 * rho1000 * exp( k2 * mu) * (t/1000)^(0.75*(1-mu) ) * 1e-5;
364
365 // new: (according to Bazant & Yu 2013)
366 // delta sigma_p / F(epsilon) = rho * (t/lambda)^k;
367 // where ... rho = k1 * rho1000 * exp( k2 * mu) * 1e-5
368 // ... k = 0.75*(1-mu)
369 // ... lambda = 1000 * timeFactor / 24
370 // ... timeFactor = 1 for day / 24 for hour / 86400 for sec, etc.
371
372 relaxStrainIncrement = 0.;
373 double prestress = status->giveTempPrestress();
374
375
376 if ( averageStress > this->relRelaxBound * this->charStrength ) {
377 mu = prestress / this->charStrength;
378 rho = this->k1 * this->rho1000 * exp(this->k2 * mu) * 1.e-5;
379 k = 0.75 * ( 1. - mu );
380 lambda = 1000. * this->timeFactor / 24.;
381 relaxStrainIncrement = k * pow(rho, 1. / k) * F * dt;
382 relaxStrainIncrement /= this->E * lambda * pow( ( 1. - averageStress / F ), 1. / k - 1.);
383 }
384 }
385
386 status->setTempRelaxIntVariable(relaxStrainIncrement + status->giveRelaxIntVariable() );
387
388 answer.resize(1);
389
390 if ( mode == VM_Incremental ) {
391 answer.at(1) = relaxStrainIncrement;
392 } else {
393 answer.at(1) = relaxStrainIncrement + status->giveRelaxIntVariable();
394 }
395
396 return;
397}
398
399
400int
402{
403 return StructuralMaterial::giveIPValue(answer, gp, type, tStep);
404}
405
406//=============================================================================
407
410
411
412void
414{
416
417 fprintf(file, " relaxationInternalVariable ");
418 fprintf(file, "%.4e ", relaxIntVariable);
419 fprintf(file, "\n");
420
421 fprintf(file, " prestress ");
422 fprintf(file, "%.4e ", prestress);
423 fprintf(file, "\n");
424}
425
426
427// initializes temporary variables based on their values at the previous equlibrium state
435
436
437// updates internal variables when equilibrium is reached
438void
440{
442
444
446
447 // if ( this->prestress > 0.) {
448 // prestressFlag = true
449}
450
451
452void
454{
456
457 if ( !stream.write(relaxIntVariable) ) {
459 }
460
461 if ( !stream.write(prestress) ) {
463 }
464}
465
466
467void
469{
471
472 if ( !stream.read(relaxIntVariable) ) {
474 }
475
476 if ( !stream.read(prestress) ) {
478 }
479}
480} // end namespace oofem
#define REGISTER_Material(class)
virtual int read(int *data, std::size_t count)=0
Reads count integer values into array pointed by data.
virtual int write(const int *data, std::size_t count)=0
Writes count integer values from array pointed by data.
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
Index giveSize() const
Returns the size of receiver.
Definition floatarray.h:261
void beDifferenceOf(const FloatArray &a, const FloatArray &b)
Definition floatarray.C:403
void zero()
Zeroes all coefficients of receiver.
Definition floatarray.C:683
void subtract(const FloatArray &src)
Definition floatarray.C:320
virtual MaterialStatus * giveStatus(GaussPoint *gp) const
Definition material.C:206
virtual bool isActivated(TimeStep *tStep) const
Definition material.h:182
void initTempStatus() override
double giveTempPrestress() const
double giveRelaxIntVariable() const
void setTempPrestress(double src)
double giveTempRelaxIntVariable() const
void printOutputAt(FILE *file, TimeStep *tStep) const override
Print receiver's output to given stream.
void saveContext(DataStream &stream, ContextMode mode) override
void restoreContext(DataStream &stream, ContextMode mode) override
SteelRelaxMatStatus(GaussPoint *g)
void setTempRelaxIntVariable(double src)
void updateYourself(TimeStep *tStep) override
double k1
constant depending on the reinforcement class
double tolerance
tolerance specifying the residual in the stress evaluation algorithm, default value is $10^{-6}...
double rho1000
constant depending on the reinforcement class
FloatMatrixF< 1, 1 > give1dStressStiffMtrx(MatResponseMode mode, GaussPoint *gp, TimeStep *tStep) const override
void evalStressRelaxationAtConstStrain(double &answer, GaussPoint *gp, double dt) const
void giveStressDependentPartOfStrainVector(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *tStep, ValueModeType mode) const
int giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *tStep) override
double E
Young's modulus.
SteelRelaxMat(int n, Domain *d)
void computeStressRelaxationStrainVector(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *tStep, ValueModeType mode) const
double mu
ratio of prestress vs. characteristic strength
bool hasMaterialModeCapability(MaterialMode mode) const override
enum oofem::SteelRelaxMat::approachType Approach
double k2
constant depending on the reinforcement class
void initializeFrom(InputRecord &ir) override
void computeIncrOfPrestressLossAtVarStrain(double &answer, GaussPoint *gp, TimeStep *tStep, double stress) const
void giveRealStressVector(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedStrain, TimeStep *tStep) const override
std::unique_ptr< MaterialStatus > CreateStatus(GaussPoint *gp) const override
double charStrength
characteristic strength of prestressing steel in appropriate units (not necessarily MPa)
const FloatArray & giveStrainVector() const
Returns the const pointer to receiver's strain vector.
const FloatArray & giveTempStressVector() const
Returns the const pointer to receiver's temporary stress vector.
void printOutputAt(FILE *file, TimeStep *tStep) const override
Print receiver's output to given stream.
void saveContext(DataStream &stream, ContextMode mode) override
StructuralMaterialStatus(GaussPoint *g)
Constructor. Creates new StructuralMaterialStatus with IntegrationPoint g.
void updateYourself(TimeStep *tStep) override
const FloatArray & giveStressVector() const
Returns the const pointer to receiver's stress vector.
void restoreContext(DataStream &stream, ContextMode mode) override
void letTempStressVectorBe(const FloatArray &v)
Assigns tempStressVector to given vector v.
void letTempStrainVectorBe(const FloatArray &v)
Assigns tempStrainVector to given vector v.
void initializeFrom(InputRecord &ir) override
StructuralMaterial(int n, Domain *d)
void giveStressDependentPartOfStrainVector(FloatArray &answer, GaussPoint *gp, const FloatArray &reducedStrainVector, TimeStep *tStep, ValueModeType mode) const
int giveIPValue(FloatArray &answer, GaussPoint *gp, InternalStateType type, TimeStep *tStep) override
double giveTimeIncrement()
Returns solution step associated time increment.
Definition timestep.h:168
#define THROW_CIOERR(e)
#define OOFEM_WARNING(...)
Definition error.h:80
#define OOFEM_ERROR(...)
Definition error.h:79
#define IR_GIVE_OPTIONAL_FIELD(__ir, __value, __id)
Definition inputrecord.h:75
#define IR_GIVE_FIELD(__ir, __value, __id)
Definition inputrecord.h:67
long ContextMode
Definition contextmode.h:43
@ CIO_IOERR
General IO error.
#define _IFT_SteelRelaxMat_rho1000
#define _IFT_SteelRelaxMat_k2
#define _IFT_SteelRelaxMat_timeFactor
#define _IFT_SteelRelaxMat_charStrength
#define _IFT_SteelRelaxMat_approach
#define _IFT_SteelRelaxMat_relRelaxBound
#define _IFT_SteelRelaxMat_k1
#define _IFT_SteelRelaxMat_E
#define _IFT_SteelRelaxMat_tolerance
#define _IFT_SteelRelaxMat_reinfClass

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011