https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MultiPlasticityLinearSystem.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11#include "RankFourTensor.h"
12
13// Following is for perturbing distances in eliminating linearly-dependent directions
14#include "MooseRandom.h"
15
16// Following is used to access PETSc's LAPACK routines
17#include <petscblaslapack.h>
18
21{
23 params.addRangeCheckedParam<Real>("linear_dependent",
24 1E-4,
25 "linear_dependent>=0 & linear_dependent<1",
26 "Flow directions are considered linearly dependent if the "
27 "smallest singular value is less than linear_dependent times "
28 "the largest singular value");
29 return params;
30}
31
34 _svd_tol(_params.get<Real>("linear_dependent")),
35 _min_f_tol(-1.0)
36{
37 for (unsigned model = 0; model < _num_models; ++model)
38 if (_min_f_tol == -1.0 || _min_f_tol > _f[model]->_f_tol)
39 _min_f_tol = _f[model]->_f_tol;
40
42}
43
44int
45MultiPlasticityLinearSystem::singularValuesOfR(const std::vector<RankTwoTensor> & r,
46 std::vector<Real> & s)
47{
48 PetscBLASInt bm = r.size();
49 PetscBLASInt bn = 6;
50
51 s.resize(std::min(bm, bn));
52
53 // prepare for gesvd or gesdd routine provided by PETSc
54 // Want to find the singular values of matrix
55 // ( r[0](0,0) r[0](0,1) r[0](0,2) r[0](1,1) r[0](1,2) r[0](2,2) )
56 // ( r[1](0,0) r[1](0,1) r[1](0,2) r[1](1,1) r[1](1,2) r[1](2,2) )
57 // a = ( r[2](0,0) r[2](0,1) r[2](0,2) r[2](1,1) r[2](1,2) r[2](2,2) )
58 // ( r[3](0,0) r[3](0,1) r[3](0,2) r[3](1,1) r[3](1,2) r[3](2,2) )
59 // ( r[4](0,0) r[4](0,1) r[4](0,2) r[4](1,1) r[4](1,2) r[4](2,2) )
60 // bm = 5
61
62 std::vector<double> a(bm * 6);
63 // Fill in the a "matrix" by going down columns
64 unsigned ind = 0;
65 for (int col = 0; col < 3; ++col)
66 for (int row = 0; row < bm; ++row)
67 a[ind++] = r[row](0, col);
68 for (int col = 3; col < 5; ++col)
69 for (int row = 0; row < bm; ++row)
70 a[ind++] = r[row](1, col - 2);
71 for (int row = 0; row < bm; ++row)
72 a[ind++] = r[row](2, 2);
73
74 // u and vt are dummy variables because they won't
75 // get referenced due to the "N" and "N" choices
76 PetscBLASInt sizeu = 1;
77 std::vector<double> u(sizeu);
78 PetscBLASInt sizevt = 1;
79 std::vector<double> vt(sizevt);
80
81 PetscBLASInt sizework =
82 16 * (bm + 6); // this is above the lowerbound specified in the LAPACK doco
83 std::vector<double> work(sizework);
84
85 PetscBLASInt info;
86
87 LAPACKgesvd_("N",
88 "N",
89 &bm,
90 &bn,
91 &a[0],
92 &bm,
93 &s[0],
94 &u[0],
95 &sizeu,
96 &vt[0],
97 &sizevt,
98 &work[0],
99 &sizework,
100 &info);
101
102 return info;
103}
104
105void
107 const std::vector<Real> & intnl,
108 const std::vector<Real> & f,
109 const std::vector<RankTwoTensor> & r,
110 const std::vector<bool> & active,
111 std::vector<bool> & deactivated_due_to_ld)
112{
113 deactivated_due_to_ld.resize(_num_surfaces, false);
114
115 unsigned num_active = r.size();
116
117 if (num_active <= 1)
118 return;
119
120 std::vector<double> s;
121 int info = singularValuesOfR(r, s);
122 if (info != 0)
123 mooseError("In finding the SVD in the return-map algorithm, the PETSC LAPACK gesvd routine "
124 "returned with error code ",
125 info);
126
127 // num_lin_dep are the number of linearly dependent
128 // "r vectors", if num_active <= 6
129 unsigned int num_lin_dep = 0;
130
131 unsigned i = s.size();
132 while (i-- > 0)
133 if (s[i] < _svd_tol * s[0])
134 num_lin_dep++;
135 else
136 break;
137
138 if (num_lin_dep == 0 && num_active <= 6)
139 return;
140
141 // From here on, some flow directions are linearly dependent
142
143 // Find the signed "distance" of the current (stress, internal) configuration
144 // from the yield surfaces. This distance will not be precise, but
145 // i want to preferentially deactivate yield surfaces that are close
146 // to the current stress point.
147 std::vector<RankTwoTensor> df_dstress;
148 dyieldFunction_dstress(stress, intnl, active, df_dstress);
149
150 typedef std::pair<Real, unsigned> pair_for_sorting;
151 std::vector<pair_for_sorting> dist(num_active);
152 for (unsigned i = 0; i < num_active; ++i)
153 {
154 dist[i].first = f[i] / df_dstress[i].L2norm();
155 dist[i].second = i;
156 }
157 std::sort(dist.begin(), dist.end()); // sorted in ascending order
158
159 // There is a potential problem when we have equal f[i], for it can give oscillations
160 bool equals_detected = false;
161 for (unsigned i = 0; i < num_active - 1; ++i)
162 if (std::abs(dist[i].first - dist[i + 1].first) < _min_f_tol)
163 {
164 equals_detected = true;
165 dist[i].first += _min_f_tol * (MooseRandom::rand() - 0.5);
166 }
167 if (equals_detected)
168 std::sort(dist.begin(), dist.end()); // sorted in ascending order
169
170 std::vector<bool> scheduled_for_deactivation;
171 scheduled_for_deactivation.assign(num_active, false);
172
173 // In the following loop we go through all the flow directions, from
174 // the one with the largest dist, to the one with the smallest dist,
175 // adding them one-by-one into r_tmp. Upon each addition we check
176 // for linear-dependence. if LD is found, we schedule the most
177 // recently added flow direction for deactivation, and pop it
178 // back off r_tmp
179 unsigned current_yf;
180 current_yf = dist[num_active - 1].second;
181 // the one with largest dist
182 std::vector<RankTwoTensor> r_tmp = {r[current_yf]};
183
184 unsigned num_kept_active = 1;
185 for (unsigned yf_to_try = 2; yf_to_try <= num_active; ++yf_to_try)
186 {
187 current_yf = dist[num_active - yf_to_try].second;
188 if (num_active == 2) // shortcut to we don't have to singularValuesOfR
189 scheduled_for_deactivation[current_yf] = true;
190 else if (num_kept_active >= 6) // shortcut to we don't have to singularValuesOfR: there can
191 // never be > 6 linearly-independent r vectors
192 scheduled_for_deactivation[current_yf] = true;
193 else
194 {
195 r_tmp.push_back(r[current_yf]);
196 info = singularValuesOfR(r_tmp, s);
197 if (info != 0)
198 mooseError("In finding the SVD in the return-map algorithm, the PETSC LAPACK gesvd routine "
199 "returned with error code ",
200 info);
201 if (s[s.size() - 1] < _svd_tol * s[0])
202 {
203 scheduled_for_deactivation[current_yf] = true;
204 r_tmp.pop_back();
205 num_lin_dep--;
206 }
207 else
208 num_kept_active++;
209 if (num_lin_dep == 0 && num_active <= 6)
210 // have taken out all the vectors that were linearly dependent
211 // so no point continuing
212 break;
213 }
214 }
215
216 unsigned int old_active_number = 0;
217 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
218 if (active[surface])
219 {
220 if (scheduled_for_deactivation[old_active_number])
221 deactivated_due_to_ld[surface] = true;
222 old_active_number++;
223 }
224}
225
226void
228 const std::vector<Real> & intnl_old,
229 const std::vector<Real> & intnl,
230 const std::vector<Real> & pm,
231 const RankTwoTensor & delta_dp,
232 std::vector<Real> & f,
233 std::vector<RankTwoTensor> & r,
234 RankTwoTensor & epp,
235 std::vector<Real> & ic,
236 const std::vector<bool> & active)
237{
238 // see comments at the start of .h file
239
240 mooseAssert(intnl_old.size() == _num_models,
241 "Size of intnl_old is " << intnl_old.size()
242 << " which is incorrect in calculateConstraints");
243 mooseAssert(intnl.size() == _num_models,
244 "Size of intnl is " << intnl.size() << " which is incorrect in calculateConstraints");
245 mooseAssert(pm.size() == _num_surfaces,
246 "Size of pm is " << pm.size() << " which is incorrect in calculateConstraints");
247 mooseAssert(active.size() == _num_surfaces,
248 "Size of active is " << active.size()
249 << " which is incorrect in calculateConstraints");
250
251 // yield functions
252 yieldFunction(stress, intnl, active, f);
253
254 // flow directions and "epp"
255 flowPotential(stress, intnl, active, r);
256 epp = RankTwoTensor();
257 unsigned ind = 0;
258 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
259 if (active[surface])
260 epp += pm[surface] * r[ind++]; // note, even the deactivated_due_to_ld must get added in
261 epp -= delta_dp;
262
263 // internal constraints
264 std::vector<Real> h;
265 hardPotential(stress, intnl, active, h);
266 ic.resize(0);
267 ind = 0;
268 std::vector<unsigned int> active_surfaces;
269 std::vector<unsigned int>::iterator active_surface;
270 for (unsigned model = 0; model < _num_models; ++model)
271 {
272 activeSurfaces(model, active, active_surfaces);
273 if (active_surfaces.size() > 0)
274 {
275 // some surfaces are active in this model, so must form an internal constraint
276 ic.push_back(intnl[model] - intnl_old[model]);
277 for (active_surface = active_surfaces.begin(); active_surface != active_surfaces.end();
278 ++active_surface)
279 ic[ic.size() - 1] += pm[*active_surface] * h[ind++]; // we know the correct one is h[ind]
280 // since it was constructed in the same
281 // manner
282 }
283 }
284}
285
286void
288 const std::vector<Real> & intnl_old,
289 const std::vector<Real> & intnl,
290 const std::vector<Real> & pm,
291 const RankTwoTensor & delta_dp,
292 std::vector<Real> & rhs,
293 const std::vector<bool> & active,
294 bool eliminate_ld,
295 std::vector<bool> & deactivated_due_to_ld)
296{
297 // see comments at the start of .h file
298
299 mooseAssert(intnl_old.size() == _num_models,
300 "Size of intnl_old is " << intnl_old.size() << " which is incorrect in calculateRHS");
301 mooseAssert(intnl.size() == _num_models,
302 "Size of intnl is " << intnl.size() << " which is incorrect in calculateRHS");
303 mooseAssert(pm.size() == _num_surfaces,
304 "Size of pm is " << pm.size() << " which is incorrect in calculateRHS");
305 mooseAssert(active.size() == _num_surfaces,
306 "Size of active is " << active.size() << " which is incorrect in calculateRHS");
307
308 std::vector<Real> f; // the yield functions
309 RankTwoTensor epp; // the plastic-strain constraint ("direction constraint")
310 std::vector<Real> ic; // the "internal constraints"
311
312 std::vector<RankTwoTensor> r;
313 calculateConstraints(stress, intnl_old, intnl, pm, delta_dp, f, r, epp, ic, active);
314
315 if (eliminate_ld)
316 eliminateLinearDependence(stress, intnl, f, r, active, deactivated_due_to_ld);
317 else
318 deactivated_due_to_ld.assign(_num_surfaces, false);
319
320 std::vector<bool> active_not_deact(_num_surfaces);
321 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
322 active_not_deact[surface] = (active[surface] && !deactivated_due_to_ld[surface]);
323
324 unsigned num_active_f = 0;
325 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
326 if (active_not_deact[surface])
327 num_active_f++;
328
329 unsigned num_active_ic = 0;
330 for (unsigned model = 0; model < _num_models; ++model)
331 if (anyActiveSurfaces(model, active_not_deact))
332 num_active_ic++;
333
334 unsigned int dim = 3;
335 unsigned int system_size = 6 + num_active_f + num_active_ic; // "6" comes from symmeterizing epp,
336 // num_active_f comes from "f",
337 // num_active_f comes from "ic"
338
339 rhs.resize(system_size);
340
341 unsigned ind = 0;
342 for (unsigned i = 0; i < dim; ++i)
343 for (unsigned j = 0; j <= i; ++j)
344 rhs[ind++] = -epp(i, j);
345 unsigned active_surface = 0;
346 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
347 if (active[surface])
348 {
349 if (!deactivated_due_to_ld[surface])
350 rhs[ind++] = -f[active_surface];
351 active_surface++;
352 }
353 unsigned active_model = 0;
354 for (unsigned model = 0; model < _num_models; ++model)
355 if (anyActiveSurfaces(model, active))
356 {
357 if (anyActiveSurfaces(model, active_not_deact))
358 rhs[ind++] = -ic[active_model];
359 active_model++;
360 }
361
362 mooseAssert(ind == system_size, "Incorrect filling of the rhs in calculateRHS");
363}
364
365void
367 const std::vector<Real> & intnl,
368 const std::vector<Real> & pm,
369 const RankFourTensor & E_inv,
370 const std::vector<bool> & active,
371 const std::vector<bool> & deactivated_due_to_ld,
372 std::vector<std::vector<Real>> & jac)
373{
374 // see comments at the start of .h file
375
376 mooseAssert(intnl.size() == _num_models,
377 "Size of intnl is " << intnl.size() << " which is incorrect in calculateJacobian");
378 mooseAssert(pm.size() == _num_surfaces,
379 "Size of pm is " << pm.size() << " which is incorrect in calculateJacobian");
380 mooseAssert(active.size() == _num_surfaces,
381 "Size of active is " << active.size() << " which is incorrect in calculateJacobian");
382 mooseAssert(deactivated_due_to_ld.size() == _num_surfaces,
383 "Size of deactivated_due_to_ld is " << deactivated_due_to_ld.size()
384 << " which is incorrect in calculateJacobian");
385
386 unsigned ind = 0;
387 unsigned active_surface_ind = 0;
388
389 std::vector<bool> active_surface(_num_surfaces); // active and not deactivated_due_to_ld
390 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
391 active_surface[surface] = (active[surface] && !deactivated_due_to_ld[surface]);
392 unsigned num_active_surface = 0;
393 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
394 if (active_surface[surface])
395 num_active_surface++;
396
397 std::vector<bool> active_model(
398 _num_models); // whether a model has surfaces that are active and not deactivated_due_to_ld
399 for (unsigned model = 0; model < _num_models; ++model)
400 active_model[model] = anyActiveSurfaces(model, active_surface);
401
402 unsigned num_active_model = 0;
403 for (unsigned model = 0; model < _num_models; ++model)
404 if (active_model[model])
405 num_active_model++;
406
407 ind = 0;
408 std::vector<unsigned int> active_model_index(_num_models);
409 for (unsigned model = 0; model < _num_models; ++model)
410 if (active_model[model])
411 active_model_index[model] = ind++;
412 else
413 active_model_index[model] =
414 _num_models + 1; // just a dummy, that will probably cause a crash if something goes wrong
415
416 std::vector<RankTwoTensor> df_dstress;
417 dyieldFunction_dstress(stress, intnl, active_surface, df_dstress);
418
419 std::vector<Real> df_dintnl;
420 dyieldFunction_dintnl(stress, intnl, active_surface, df_dintnl);
421
422 std::vector<RankTwoTensor> r;
423 flowPotential(stress, intnl, active, r);
424
425 std::vector<RankFourTensor> dr_dstress;
426 dflowPotential_dstress(stress, intnl, active, dr_dstress);
427
428 std::vector<RankTwoTensor> dr_dintnl;
429 dflowPotential_dintnl(stress, intnl, active, dr_dintnl);
430
431 std::vector<Real> h;
432 hardPotential(stress, intnl, active, h);
433
434 std::vector<RankTwoTensor> dh_dstress;
435 dhardPotential_dstress(stress, intnl, active, dh_dstress);
436
437 std::vector<Real> dh_dintnl;
438 dhardPotential_dintnl(stress, intnl, active, dh_dintnl);
439
440 // d(epp)/dstress = sum_{active alpha} pm[alpha]*dr_dstress
441 RankFourTensor depp_dstress;
442 ind = 0;
443 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
444 if (active[surface]) // includes deactivated_due_to_ld
445 depp_dstress += pm[surface] * dr_dstress[ind++];
446 depp_dstress += E_inv;
447
448 // d(epp)/dpm_{active_surface_index} = r_{active_surface_index}
449 std::vector<RankTwoTensor> depp_dpm;
450 depp_dpm.resize(num_active_surface);
451 ind = 0;
452 active_surface_ind = 0;
453 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
454 {
455 if (active[surface])
456 {
457 if (active_surface[surface]) // do not include the deactived_due_to_ld, since their pm are not
458 // dofs in the NR
459 depp_dpm[active_surface_ind++] = r[ind];
460 ind++;
461 }
462 }
463
464 // d(epp)/dintnl_{active_model_index} = sum(pm[asdf]*dr_dintnl[fdsa])
465 std::vector<RankTwoTensor> depp_dintnl;
466 depp_dintnl.assign(num_active_model, RankTwoTensor());
467 ind = 0;
468 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
469 {
470 if (active[surface])
471 {
472 unsigned int model_num = modelNumber(surface);
473 if (active_model[model_num]) // only include models with surfaces which are still active after
474 // deactivated_due_to_ld
475 depp_dintnl[active_model_index[model_num]] += pm[surface] * dr_dintnl[ind];
476 ind++;
477 }
478 }
479
480 // df_dstress has been calculated above
481 // df_dpm is always zero
482 // df_dintnl has been calculated above, but only the active_surface+active_model stuff needs to be
483 // included in Jacobian: see below
484
485 std::vector<RankTwoTensor> dic_dstress;
486 dic_dstress.assign(num_active_model, RankTwoTensor());
487 ind = 0;
488 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
489 {
490 if (active[surface])
491 {
492 unsigned int model_num = modelNumber(surface);
493 if (active_model[model_num]) // only include ic for models with active_surface (ie, if model
494 // only contains deactivated_due_to_ld don't include it)
495 dic_dstress[active_model_index[model_num]] += pm[surface] * dh_dstress[ind];
496 ind++;
497 }
498 }
499
500 std::vector<std::vector<Real>> dic_dpm;
501 dic_dpm.resize(num_active_model);
502 ind = 0;
503 active_surface_ind = 0;
504 for (unsigned model = 0; model < num_active_model; ++model)
505 dic_dpm[model].assign(num_active_surface, 0);
506 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
507 {
508 if (active[surface])
509 {
510 if (active_surface[surface]) // only take derivs wrt active-but-not-deactivated_due_to_ld pm
511 {
512 unsigned int model_num = modelNumber(surface);
513 // if (active_model[model_num]) // do not need this check as if the surface has
514 // active_surface, the model must be deemed active!
515 dic_dpm[active_model_index[model_num]][active_surface_ind] = h[ind];
516 active_surface_ind++;
517 }
518 ind++;
519 }
520 }
521
522 std::vector<std::vector<Real>> dic_dintnl;
523 dic_dintnl.resize(num_active_model);
524 for (unsigned model = 0; model < num_active_model; ++model)
525 {
526 dic_dintnl[model].assign(num_active_model, 0);
527 dic_dintnl[model][model] = 1; // deriv wrt internal parameter
528 }
529 ind = 0;
530 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
531 {
532 if (active[surface])
533 {
534 unsigned int model_num = modelNumber(surface);
535 if (active_model[model_num]) // only the models that contain surfaces that are still active
536 // after deactivation_due_to_ld
537 dic_dintnl[active_model_index[model_num]][active_model_index[model_num]] +=
538 pm[surface] * dh_dintnl[ind];
539 ind++;
540 }
541 }
542
543 unsigned int dim = 3;
544 unsigned int system_size =
545 6 + num_active_surface + num_active_model; // "6" comes from symmeterizing epp
546 jac.resize(system_size);
547 for (unsigned i = 0; i < system_size; ++i)
548 jac[i].assign(system_size, 0);
549
550 unsigned int row_num = 0;
551 unsigned int col_num = 0;
552 for (unsigned i = 0; i < dim; ++i)
553 for (unsigned j = 0; j <= i; ++j)
554 {
555 for (unsigned k = 0; k < dim; ++k)
556 for (unsigned l = 0; l <= k; ++l)
557 jac[col_num][row_num++] =
558 depp_dstress(i, j, k, l) +
559 (k != l ? depp_dstress(i, j, l, k)
560 : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
561 for (unsigned surface = 0; surface < num_active_surface; ++surface)
562 jac[col_num][row_num++] = depp_dpm[surface](i, j);
563 for (unsigned a = 0; a < num_active_model; ++a)
564 jac[col_num][row_num++] = depp_dintnl[a](i, j);
565 row_num = 0;
566 col_num++;
567 }
568
569 ind = 0;
570 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
571 if (active_surface[surface])
572 {
573 for (unsigned k = 0; k < dim; ++k)
574 for (unsigned l = 0; l <= k; ++l)
575 jac[col_num][row_num++] =
576 df_dstress[ind](k, l) +
577 (k != l ? df_dstress[ind](l, k)
578 : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
579 for (unsigned beta = 0; beta < num_active_surface; ++beta)
580 jac[col_num][row_num++] = 0; // df_dpm
581 for (unsigned model = 0; model < _num_models; ++model)
582 if (active_model[model]) // only use df_dintnl for models in active_model
583 {
584 if (modelNumber(surface) == model)
585 jac[col_num][row_num++] = df_dintnl[ind];
586 else
587 jac[col_num][row_num++] = 0;
588 }
589 ind++;
590 row_num = 0;
591 col_num++;
592 }
593
594 for (unsigned a = 0; a < num_active_model; ++a)
595 {
596 for (unsigned k = 0; k < dim; ++k)
597 for (unsigned l = 0; l <= k; ++l)
598 jac[col_num][row_num++] =
599 dic_dstress[a](k, l) +
600 (k != l ? dic_dstress[a](l, k)
601 : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
602 for (unsigned alpha = 0; alpha < num_active_surface; ++alpha)
603 jac[col_num][row_num++] = dic_dpm[a][alpha];
604 for (unsigned b = 0; b < num_active_model; ++b)
605 jac[col_num][row_num++] = dic_dintnl[a][b];
606 row_num = 0;
607 col_num++;
608 }
609
610 mooseAssert(col_num == system_size, "Incorrect filling of cols in Jacobian");
611}
612
613void
615 const std::vector<Real> & intnl_old,
616 const std::vector<Real> & intnl,
617 const std::vector<Real> & pm,
618 const RankFourTensor & E_inv,
619 const RankTwoTensor & delta_dp,
620 RankTwoTensor & dstress,
621 std::vector<Real> & dpm,
622 std::vector<Real> & dintnl,
623 const std::vector<bool> & active,
624 std::vector<bool> & deactivated_due_to_ld)
625{
626 // Calculate RHS and Jacobian
627 std::vector<Real> rhs;
628 calculateRHS(stress, intnl_old, intnl, pm, delta_dp, rhs, active, true, deactivated_due_to_ld);
629
630 std::vector<std::vector<Real>> jac;
631 calculateJacobian(stress, intnl, pm, E_inv, active, deactivated_due_to_ld, jac);
632
633 // prepare for LAPACKgesv_ routine provided by PETSc
634 PetscBLASInt system_size = rhs.size();
635
636 std::vector<double> a(system_size * system_size);
637 // Fill in the a "matrix" by going down columns
638 unsigned ind = 0;
639 for (int col = 0; col < system_size; ++col)
640 for (int row = 0; row < system_size; ++row)
641 a[ind++] = jac[row][col];
642
643 PetscBLASInt nrhs = 1;
644 std::vector<PetscBLASInt> ipiv(system_size);
645 PetscBLASInt info;
646 LAPACKgesv_(&system_size, &nrhs, &a[0], &system_size, &ipiv[0], &rhs[0], &system_size, &info);
647
648 if (info != 0)
649 mooseError("In solving the linear system in a Newton-Raphson process, the PETSC LAPACK gsev "
650 "routine returned with error code ",
651 info);
652
653 // Extract the results back to dstress, dpm and dintnl
654 std::vector<bool> active_not_deact(_num_surfaces);
655 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
656 active_not_deact[surface] = (active[surface] && !deactivated_due_to_ld[surface]);
657
658 unsigned int dim = 3;
659 ind = 0;
660
661 for (unsigned i = 0; i < dim; ++i)
662 for (unsigned j = 0; j <= i; ++j)
663 dstress(i, j) = dstress(j, i) = rhs[ind++];
664 dpm.assign(_num_surfaces, 0);
665 for (unsigned surface = 0; surface < _num_surfaces; ++surface)
666 if (active_not_deact[surface])
667 dpm[surface] = rhs[ind++];
668 dintnl.assign(_num_models, 0);
669 for (unsigned model = 0; model < _num_models; ++model)
670 if (anyActiveSurfaces(model, active_not_deact))
671 dintnl[model] = rhs[ind++];
672
673 mooseAssert(static_cast<int>(ind) == system_size,
674 "Incorrect extracting of changes from NR solution in nrStep");
675}
Real f(Real x)
Test function for Brents method.
const PertinentGeochemicalSystem model(database, {"H2O", "H+", "HCO3-", "O2(aq)", "Ca++", ">(s)FeOH", "radius_neg1", "radius_neg1.5"}, {"Calcite"}, {}, {"Calcite_asdf"}, {"CH4(aq)"}, {">(s)FeOCa+"}, "O2(aq)", "e-")
void mooseError(Args &&... args)
unsigned int dim
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
static Real rand()
void seed(std::size_t i, unsigned int seed)
virtual void calculateRHS(const RankTwoTensor &stress, const std::vector< Real > &intnl_old, const std::vector< Real > &intnl, const std::vector< Real > &pm, const RankTwoTensor &delta_dp, std::vector< Real > &rhs, const std::vector< bool > &active, bool eliminate_ld, std::vector< bool > &deactivated_due_to_ld)
Calculate the RHS which is rhs = -(epp(0,0), epp(1,0), epp(1,1), epp(2,0), epp(2,1),...
virtual void calculateJacobian(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< Real > &pm, const RankFourTensor &E_inv, const std::vector< bool > &active, const std::vector< bool > &deactivated_due_to_ld, std::vector< std::vector< Real > > &jac)
d(rhs)/d(dof)
virtual int singularValuesOfR(const std::vector< RankTwoTensor > &r, std::vector< Real > &s)
Performs a singular-value decomposition of r and returns the singular values.
virtual void calculateConstraints(const RankTwoTensor &stress, const std::vector< Real > &intnl_old, const std::vector< Real > &intnl, const std::vector< Real > &pm, const RankTwoTensor &delta_dp, std::vector< Real > &f, std::vector< RankTwoTensor > &r, RankTwoTensor &epp, std::vector< Real > &ic, const std::vector< bool > &active)
The constraints.
MultiPlasticityLinearSystem(const MooseObject *moose_object)
Real _svd_tol
Tolerance on the minimum ratio of singular values before flow-directions are deemed linearly dependen...
virtual void nrStep(const RankTwoTensor &stress, const std::vector< Real > &intnl_old, const std::vector< Real > &intnl, const std::vector< Real > &pm, const RankFourTensor &E_inv, const RankTwoTensor &delta_dp, RankTwoTensor &dstress, std::vector< Real > &dpm, std::vector< Real > &dintnl, const std::vector< bool > &active, std::vector< bool > &deactivated_due_to_ld)
Performs one Newton-Raphson step.
virtual void eliminateLinearDependence(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< Real > &f, const std::vector< RankTwoTensor > &r, const std::vector< bool > &active, std::vector< bool > &deactivated_due_to_ld)
Performs a number of singular-value decompositions to check for linear-dependence of the active direc...
Real _min_f_tol
Minimum value of the _f_tol parameters for the Yield Function User Objects.
MultiPlasticityRawComponentAssembler holds and computes yield functions, flow directions,...
bool anyActiveSurfaces(int model, const std::vector< bool > &active)
returns true if any internal surfaces of the given model are active according to 'active'
virtual void dhardPotential_dintnl(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< Real > &dh_dintnl)
The derivative of the active hardening potentials with respect to the active internal parameters.
virtual void hardPotential(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< Real > &h)
The active hardening potentials (one for each internal parameter and for each yield function) by assu...
void activeSurfaces(int model, const std::vector< bool > &active, std::vector< unsigned int > &active_surfaces)
Returns the external surface number(s) of the active surfaces of the given model This may be of size=...
virtual void dyieldFunction_dstress(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< RankTwoTensor > &df_dstress)
The derivative of the active yield function(s) with respect to stress.
unsigned int _num_surfaces
Number of surfaces within the plastic models.
std::vector< const SolidMechanicsPlasticModel * > _f
User objects that define the yield functions, flow potentials, etc.
virtual void yieldFunction(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< Real > &f)
The active yield function(s)
virtual void flowPotential(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< RankTwoTensor > &r)
The active flow potential(s) - one for each yield function.
virtual void dyieldFunction_dintnl(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< Real > &df_dintnl)
The derivative of active yield function(s) with respect to their internal parameters (the user object...
virtual void dflowPotential_dstress(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< RankFourTensor > &dr_dstress)
The derivative of the active flow potential(s) with respect to stress.
unsigned int modelNumber(unsigned int surface)
returns the model number, given the surface number
virtual void dhardPotential_dstress(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< RankTwoTensor > &dh_dstress)
The derivative of the active hardening potentials with respect to stress By assumption in the Userobj...
virtual void dflowPotential_dintnl(const RankTwoTensor &stress, const std::vector< Real > &intnl, const std::vector< bool > &active, std::vector< RankTwoTensor > &dr_dintnl)
The derivative of the active flow potentials with respect to the active internal parameters The UserO...
unsigned int _num_models
Number of plastic models for this material.