Skip to content

Commit 3ed96fa

Browse files
committed
MultiParameterPlasticityStressUpdate with no heap allocation that is relevant to explicit time stepping
(cherry picked from commit 2c611d1c533d065c60a53d118e555e5b54557764)
1 parent 280d678 commit 3ed96fa

File tree

2 files changed

+147
-56
lines changed

2 files changed

+147
-56
lines changed

modules/solid_mechanics/include/materials/MultiParameterPlasticityStressUpdate.h

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,19 @@ class MultiParameterPlasticityStressUpdate : public StressUpdateBase
228228
{
229229
}
230230

231+
// Zero everything without resizing/reallocating
232+
void reset()
233+
{
234+
f = 0.0;
235+
std::fill(df.begin(), df.end(), 0.0);
236+
std::fill(df_di.begin(), df_di.end(), 0.0);
237+
std::fill(dg.begin(), dg.end(), 0.0);
238+
for (auto & row : d2g)
239+
std::fill(row.begin(), row.end(), 0.0);
240+
for (auto & row : d2g_di)
241+
std::fill(row.begin(), row.end(), 0.0);
242+
}
243+
231244
// this may be involved in the smoothing of a group of yield functions
232245
bool operator<(const yieldAndFlow & fd) const { return f < fd.f; }
233246
};
@@ -328,7 +341,7 @@ class MultiParameterPlasticityStressUpdate : public StressUpdateBase
328341
const std::vector<Real> & intnl_ok,
329342
std::vector<Real> & intnl,
330343
std::vector<Real> & rhs,
331-
Real & linesearch_needed) const;
344+
Real & linesearch_needed);
332345

333346
/**
334347
* Performs a Newton-Raphson step to attempt to zero rhs
@@ -752,6 +765,13 @@ class MultiParameterPlasticityStressUpdate : public StressUpdateBase
752765
*/
753766
std::vector<Real> _current_intnl;
754767

768+
/**
769+
* Current values of the yield function, derivatives, etc during updateState.
770+
* During Newton-Raphson convergence, this is potentially re-calculated multiple times within the
771+
* loops of updateState and by the lineSearch function that is called within those loops.
772+
*/
773+
yieldAndFlow _smoothed_q;
774+
755775
/**
756776
* d(stress_param[:])/d(stress) used in dstressparam_dstress
757777
* to avoid repeatedly allocating/deallocating this vector
@@ -770,6 +790,48 @@ class MultiParameterPlasticityStressUpdate : public StressUpdateBase
770790
*/
771791
mutable std::vector<RankFourTensor> _d2sp_scratch;
772792

793+
/**
794+
* values of yield functions in yieldF,
795+
* to avoid repeatedly allocating/deallocating this vector
796+
*/
797+
mutable std::vector<Real> _yfs_scratch;
798+
799+
/**
800+
* container to hold old values of old stress_params in lineSearch
801+
* to avoid repeatedly allocating/deallocating this vector
802+
*/
803+
mutable std::vector<Real> _sp_params_old_scratch;
804+
805+
/**
806+
* container to hold initial values of rhs in lineSearch
807+
* to avoid repeatedly allocating/deallocating this vector
808+
*/
809+
mutable std::vector<Real> _delta_nr_params_scratch;
810+
811+
/**
812+
* derivative of internal parameters with respect to stress parameters,
813+
* to avoid repeatedly allocating/deallocating this vector
814+
*/
815+
mutable std::vector<std::vector<Real>> _dintnl_scratch;
816+
817+
/**
818+
* jacobian in the NR process,
819+
* to avoid repeatedly allocating/deallocating this vector
820+
*/
821+
mutable std::vector<double> _jac_scratch;
822+
823+
/**
824+
* container to hold LAPACK ipiv integers,
825+
* to avoid repeatedly allocating/deallocating this vector
826+
*/
827+
mutable std::vector<PetscBLASInt> _ipiv_scratch;
828+
829+
/**
830+
* all the yield function information, for use in smoothAllQuantities,
831+
* to avoid repeatedly allocating/deallocating this vector
832+
*/
833+
mutable std::vector<yieldAndFlow> _all_q_scratch;
834+
773835
private:
774836
/**
775837
* The type of smoother function

modules/solid_mechanics/src/materials/MultiParameterPlasticityStressUpdate.C

Lines changed: 84 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,18 @@ MultiParameterPlasticityStressUpdate::MultiParameterPlasticityStressUpdate(
126126
_del_stress_params(num_sp),
127127
_current_sp(num_sp),
128128
_current_intnl(num_intnl),
129+
_smoothed_q(yieldAndFlow(yieldAndFlow(num_sp, num_intnl))),
129130
_dsp_scratch(num_sp),
130131
_dsp_trial_scratch(num_sp),
131132
_d2sp_scratch(num_sp),
133+
_yfs_scratch(num_yf),
134+
_sp_params_old_scratch(num_sp),
135+
_delta_nr_params_scratch(num_sp + 1),
136+
_dintnl_scratch(num_intnl, std::vector<Real>(num_sp)),
137+
_jac_scratch((num_sp + 1) * (num_sp + 1)),
138+
_ipiv_scratch(num_sp + 1),
139+
_all_q_scratch(num_yf, yieldAndFlow(num_sp, num_intnl)),
140+
132141
_smoother_function_type(
133142
parameters.get<MooseEnum>("smoother_function_type").getEnum<SmootherFunctionType>())
134143
{
@@ -243,11 +252,8 @@ MultiParameterPlasticityStressUpdate::updateState(RankTwoTensor & strain_increme
243252
Real step_size = 1.0; // potentially can apply del_stress_params in substeps
244253
Real gaE_total = 0.0;
245254

246-
// current values of the yield function, derivatives, etc
247-
yieldAndFlow smoothed_q;
248-
249255
// In the following sub-stepping procedure it is possible that
250-
// the last step is an elastic step, and therefore smoothed_q won't
256+
// the last step is an elastic step, and therefore _smoothed_q won't
251257
// be computed on the last step, so we have to compute it.
252258
bool smoothed_q_calculated = false;
253259

@@ -287,16 +293,16 @@ MultiParameterPlasticityStressUpdate::updateState(RankTwoTensor & strain_increme
287293
// initialize current_sp, gaE and current_intnl based on the non-smoothed situation
288294
initializeVarsV(_trial_sp, _ok_intnl, _current_sp, gaE, _current_intnl);
289295
// and find the smoothed yield function, flow potential and derivatives
290-
smoothed_q = smoothAllQuantities(_current_sp, _current_intnl);
296+
_smoothed_q = smoothAllQuantities(_current_sp, _current_intnl);
291297
smoothed_q_calculated = true;
292-
calculateRHS(_trial_sp, _current_sp, gaE, smoothed_q, _rhs);
298+
calculateRHS(_trial_sp, _current_sp, gaE, _smoothed_q, _rhs);
293299
res2 = calculateRes2(_rhs);
294300

295-
// Perform a Newton-Raphson with linesearch to get current_sp, gaE, and also smoothed_q
301+
// Perform a Newton-Raphson with linesearch to get current_sp, gaE, and also _smoothed_q
296302
while (res2 > _f_tol2 && step_iter < _max_nr_its && nr_failure == 0 && ls_failure == 0)
297303
{
298304
// solve the linear system and store the answer (the "updates") in rhs
299-
nr_failure = nrStep(smoothed_q, _trial_sp, _current_sp, _current_intnl, gaE, _rhs);
305+
nr_failure = nrStep(_smoothed_q, _trial_sp, _current_sp, _current_intnl, gaE, _rhs);
300306
if (nr_failure != 0)
301307
break;
302308

@@ -315,12 +321,12 @@ MultiParameterPlasticityStressUpdate::updateState(RankTwoTensor & strain_increme
315321
break;
316322
}
317323

318-
// apply (parts of) the updates, re-calculate smoothed_q, and res2
324+
// apply (parts of) the updates, re-calculate _smoothed_q, and res2
319325
ls_failure = lineSearch(res2,
320326
_current_sp,
321327
gaE,
322328
_trial_sp,
323-
smoothed_q,
329+
_smoothed_q,
324330
_ok_intnl,
325331
_current_intnl,
326332
_rhs,
@@ -343,7 +349,7 @@ MultiParameterPlasticityStressUpdate::updateState(RankTwoTensor & strain_increme
343349
_ok_sp,
344350
gaE,
345351
_ok_intnl,
346-
smoothed_q,
352+
_smoothed_q,
347353
step_size,
348354
compute_full_tangent_operator,
349355
_dvar_dtrial);
@@ -368,14 +374,14 @@ MultiParameterPlasticityStressUpdate::updateState(RankTwoTensor & strain_increme
368374
yieldFunctionValuesV(_ok_sp, _intnl[_qp], _yf[_qp]);
369375

370376
if (!smoothed_q_calculated)
371-
smoothed_q = smoothAllQuantities(_ok_sp, _intnl[_qp]);
377+
_smoothed_q = smoothAllQuantities(_ok_sp, _intnl[_qp]);
372378

373379
setStressAfterReturnV(
374-
_stress_trial, _ok_sp, gaE_total, _intnl[_qp], smoothed_q, elasticity_tensor, stress_new);
380+
_stress_trial, _ok_sp, gaE_total, _intnl[_qp], _smoothed_q, elasticity_tensor, stress_new);
375381

376382
setInelasticStrainIncrementAfterReturn(_stress_trial,
377383
gaE_total,
378-
smoothed_q,
384+
_smoothed_q,
379385
elasticity_tensor,
380386
stress_new,
381387
inelastic_strain_increment);
@@ -390,7 +396,7 @@ MultiParameterPlasticityStressUpdate::updateState(RankTwoTensor & strain_increme
390396
stress_new,
391397
_ok_sp,
392398
gaE_total,
393-
smoothed_q,
399+
_smoothed_q,
394400
elasticity_tensor,
395401
compute_full_tangent_operator,
396402
_dvar_dtrial,
@@ -401,8 +407,11 @@ MultiParameterPlasticityStressUpdate::yieldAndFlow
401407
MultiParameterPlasticityStressUpdate::smoothAllQuantities(const std::vector<Real> & stress_params,
402408
const std::vector<Real> & intnl) const
403409
{
404-
std::vector<yieldAndFlow> all_q(_num_yf, yieldAndFlow(_num_sp, _num_intnl));
405-
computeAllQV(stress_params, intnl, all_q);
410+
mooseAssert(_all_q_scratch.size() == _num_yf,
411+
"_all_q_scratch incorrectly sized in smoothAllQuantities");
412+
for (auto & q : _all_q_scratch)
413+
q.reset();
414+
computeAllQV(stress_params, intnl, _all_q_scratch);
406415

407416
/* This routine holds the key to my smoothing strategy. It
408417
* may be proved that this smoothing strategy produces a
@@ -430,55 +439,61 @@ MultiParameterPlasticityStressUpdate::smoothAllQuantities(const std::vector<Real
430439
// res_f is the index that contains the smoothed yieldAndFlow
431440
std::size_t res_f = 0;
432441

433-
for (std::size_t a = 1; a < all_q.size(); ++a)
442+
for (std::size_t a = 1; a < _all_q_scratch.size(); ++a)
434443
{
435-
if (all_q[res_f].f >= all_q[a].f + _smoothing_tol)
444+
if (_all_q_scratch[res_f].f >= _all_q_scratch[a].f + _smoothing_tol)
436445
// no smoothing is needed: res_f is already indexes the largest yield function
437446
continue;
438-
else if (all_q[a].f >= all_q[res_f].f + _smoothing_tol)
447+
else if (_all_q_scratch[a].f >= _all_q_scratch[res_f].f + _smoothing_tol)
439448
{
440-
// no smoothing is needed, and res_f needs to index to all_q[a]
449+
// no smoothing is needed, and res_f needs to index to _all_q_scratch[a]
441450
res_f = a;
442451
continue;
443452
}
444453
else
445454
{
446455
// smoothing is required
447-
const Real f_diff = all_q[res_f].f - all_q[a].f;
456+
const Real f_diff = _all_q_scratch[res_f].f - _all_q_scratch[a].f;
448457
const Real ism = ismoother(f_diff);
449458
const Real sm = smoother(f_diff);
450459
const Real dsm = dsmoother(f_diff);
451-
// we want: all_q[res_f].f = 0.5 * all_q[res_f].f + all_q[a].f + _smoothing_tol) + ism,
452-
// but we have to do the derivatives first
460+
// we want: _all_q_scratch[res_f].f = 0.5 * _all_q_scratch[res_f].f + _all_q_scratch[a].f +
461+
// _smoothing_tol) + ism, but we have to do the derivatives first
453462
for (unsigned i = 0; i < _num_sp; ++i)
454463
{
455464
for (unsigned j = 0; j < _num_sp; ++j)
456-
all_q[res_f].d2g[i][j] =
457-
0.5 * (all_q[res_f].d2g[i][j] + all_q[a].d2g[i][j]) +
458-
dsm * (all_q[res_f].df[j] - all_q[a].df[j]) * (all_q[res_f].dg[i] - all_q[a].dg[i]) +
459-
sm * (all_q[res_f].d2g[i][j] - all_q[a].d2g[i][j]);
465+
_all_q_scratch[res_f].d2g[i][j] =
466+
0.5 * (_all_q_scratch[res_f].d2g[i][j] + _all_q_scratch[a].d2g[i][j]) +
467+
dsm * (_all_q_scratch[res_f].df[j] - _all_q_scratch[a].df[j]) *
468+
(_all_q_scratch[res_f].dg[i] - _all_q_scratch[a].dg[i]) +
469+
sm * (_all_q_scratch[res_f].d2g[i][j] - _all_q_scratch[a].d2g[i][j]);
460470
for (unsigned j = 0; j < _num_intnl; ++j)
461-
all_q[res_f].d2g_di[i][j] = 0.5 * (all_q[res_f].d2g_di[i][j] + all_q[a].d2g_di[i][j]) +
462-
dsm * (all_q[res_f].df_di[j] - all_q[a].df_di[j]) *
463-
(all_q[res_f].dg[i] - all_q[a].dg[i]) +
464-
sm * (all_q[res_f].d2g_di[i][j] - all_q[a].d2g_di[i][j]);
471+
_all_q_scratch[res_f].d2g_di[i][j] =
472+
0.5 * (_all_q_scratch[res_f].d2g_di[i][j] + _all_q_scratch[a].d2g_di[i][j]) +
473+
dsm * (_all_q_scratch[res_f].df_di[j] - _all_q_scratch[a].df_di[j]) *
474+
(_all_q_scratch[res_f].dg[i] - _all_q_scratch[a].dg[i]) +
475+
sm * (_all_q_scratch[res_f].d2g_di[i][j] - _all_q_scratch[a].d2g_di[i][j]);
465476
}
466477
for (unsigned i = 0; i < _num_sp; ++i)
467478
{
468-
all_q[res_f].df[i] = 0.5 * (all_q[res_f].df[i] + all_q[a].df[i]) +
469-
sm * (all_q[res_f].df[i] - all_q[a].df[i]);
479+
_all_q_scratch[res_f].df[i] =
480+
0.5 * (_all_q_scratch[res_f].df[i] + _all_q_scratch[a].df[i]) +
481+
sm * (_all_q_scratch[res_f].df[i] - _all_q_scratch[a].df[i]);
470482
// whether the following (smoothing g with f's smoother) is a good strategy remains to be
471483
// seen...
472-
all_q[res_f].dg[i] = 0.5 * (all_q[res_f].dg[i] + all_q[a].dg[i]) +
473-
sm * (all_q[res_f].dg[i] - all_q[a].dg[i]);
484+
_all_q_scratch[res_f].dg[i] =
485+
0.5 * (_all_q_scratch[res_f].dg[i] + _all_q_scratch[a].dg[i]) +
486+
sm * (_all_q_scratch[res_f].dg[i] - _all_q_scratch[a].dg[i]);
474487
}
475488
for (unsigned i = 0; i < _num_intnl; ++i)
476-
all_q[res_f].df_di[i] = 0.5 * (all_q[res_f].df_di[i] + all_q[a].df_di[i]) +
477-
sm * (all_q[res_f].df_di[i] - all_q[a].df_di[i]);
478-
all_q[res_f].f = 0.5 * (all_q[res_f].f + all_q[a].f + _smoothing_tol) + ism;
489+
_all_q_scratch[res_f].df_di[i] =
490+
0.5 * (_all_q_scratch[res_f].df_di[i] + _all_q_scratch[a].df_di[i]) +
491+
sm * (_all_q_scratch[res_f].df_di[i] - _all_q_scratch[a].df_di[i]);
492+
_all_q_scratch[res_f].f =
493+
0.5 * (_all_q_scratch[res_f].f + _all_q_scratch[a].f + _smoothing_tol) + ism;
479494
}
480495
}
481-
return all_q[res_f];
496+
return _all_q_scratch[res_f];
482497
}
483498

484499
Real
@@ -559,12 +574,16 @@ MultiParameterPlasticityStressUpdate::lineSearch(Real & res2,
559574
const std::vector<Real> & intnl_ok,
560575
std::vector<Real> & intnl,
561576
std::vector<Real> & rhs,
562-
Real & linesearch_needed) const
577+
Real & linesearch_needed)
563578
{
564579
const Real res2_old = res2;
565-
const std::vector<Real> sp_params_old = stress_params;
580+
mooseAssert(_sp_params_old_scratch.size() == _num_sp,
581+
"_sp_params_old_scratch incorrectly sized in lineSearch");
582+
_sp_params_old_scratch = stress_params;
566583
const Real gaE_old = gaE;
567-
const std::vector<Real> delta_nr_params = rhs;
584+
mooseAssert(_delta_nr_params_scratch.size() == rhs.size(),
585+
"_delta_nr_params_scratch incorrectly sized in lineSearch");
586+
_delta_nr_params_scratch = rhs;
568587

569588
Real lam = 1.0; // line-search parameter
570589
const Real lam_min = 1E-10; // minimum value of lam allowed
@@ -579,8 +598,8 @@ MultiParameterPlasticityStressUpdate::lineSearch(Real & res2,
579598
{
580599
// update variables using the current line-search parameter
581600
for (unsigned i = 0; i < _num_sp; ++i)
582-
stress_params[i] = sp_params_old[i] + lam * delta_nr_params[i];
583-
gaE = gaE_old + lam * delta_nr_params[_num_sp];
601+
stress_params[i] = _sp_params_old_scratch[i] + lam * _delta_nr_params_scratch[i];
602+
gaE = gaE_old + lam * _delta_nr_params_scratch[_num_sp];
584603

585604
// and internal parameters
586605
setIntnlValuesV(trial_stress_params, stress_params, intnl_ok, intnl);
@@ -642,19 +661,26 @@ MultiParameterPlasticityStressUpdate::nrStep(const yieldAndFlow & smoothed_q,
642661
Real gaE,
643662
std::vector<Real> & rhs) const
644663
{
645-
std::vector<std::vector<Real>> dintnl(_num_intnl, std::vector<Real>(_num_sp));
646-
setIntnlDerivativesV(trial_stress_params, stress_params, intnl, dintnl);
664+
mooseAssert(_dintnl_scratch.size() == _num_intnl, "_dintnl_scratch incorrectly sized in nrStep");
665+
setIntnlDerivativesV(trial_stress_params, stress_params, intnl, _dintnl_scratch);
647666

648-
std::vector<double> jac((_num_sp + 1) * (_num_sp + 1));
649-
dnRHSdVar(smoothed_q, dintnl, stress_params, gaE, jac);
667+
mooseAssert(_jac_scratch.size() == (_num_sp + 1) * (_num_sp + 1),
668+
"_jac_scratch incorrectly sized in nrStep");
669+
dnRHSdVar(smoothed_q, _dintnl_scratch, stress_params, gaE, _jac_scratch);
650670

651671
// use LAPACK to solve the linear system
652672
const PetscBLASInt nrhs = 1;
653-
std::vector<PetscBLASInt> ipiv(_num_sp + 1);
673+
mooseAssert(_ipiv_scratch.size() == _num_sp + 1, "_ipiv_scratch incorrectly sized in nrStep");
654674
PetscBLASInt info;
655675
const PetscBLASInt gesv_num_rhs = _num_sp + 1;
656-
LAPACKgesv_(
657-
&gesv_num_rhs, &nrhs, &jac[0], &gesv_num_rhs, &ipiv[0], &rhs[0], &gesv_num_rhs, &info);
676+
LAPACKgesv_(&gesv_num_rhs,
677+
&nrhs,
678+
&_jac_scratch[0],
679+
&gesv_num_rhs,
680+
&_ipiv_scratch[0],
681+
&rhs[0],
682+
&gesv_num_rhs,
683+
&info);
658684
return info;
659685
}
660686

@@ -689,9 +715,9 @@ Real
689715
MultiParameterPlasticityStressUpdate::yieldF(const std::vector<Real> & stress_params,
690716
const std::vector<Real> & intnl) const
691717
{
692-
std::vector<Real> yfs(_num_yf);
693-
yieldFunctionValuesV(stress_params, intnl, yfs);
694-
return yieldF(yfs);
718+
mooseAssert(_yfs_scratch.size() == _num_yf, "_yfs_scratch incorrectly sized in yieldF");
719+
yieldFunctionValuesV(stress_params, intnl, _yfs_scratch);
720+
return yieldF(_yfs_scratch);
695721
}
696722

697723
Real
@@ -939,6 +965,9 @@ MultiParameterPlasticityStressUpdate::dVardTrial(bool elastic_only,
939965

940966
const Real ga = gaE / _En;
941967

968+
// the following uses heap allocations in the belief that the compute time spent on alloc/dealloc
969+
// will be dwarfed by other aspects of implicit time stepping
970+
942971
std::vector<std::vector<Real>> dintnl(_num_intnl, std::vector<Real>(_num_sp));
943972
setIntnlDerivativesV(trial_stress_params, stress_params, intnl, dintnl);
944973

0 commit comments

Comments
 (0)