FrictionQPotFEM 0.23.3
Loading...
Searching...
No Matches
UniformSingleLayer2d.h
Go to the documentation of this file.
1
7#ifndef FRICTIONQPOTFEM_UNIFORMSINGLELAYER2D_H
8#define FRICTIONQPOTFEM_UNIFORMSINGLELAYER2D_H
9
10#include "Generic2d.h"
11#include "config.h"
12
16#define SQR(x) ((x) * (x))
17
18namespace FrictionQPotFEM {
19
26namespace UniformSingleLayer2d {
27
31inline std::vector<std::string> version_dependencies()
32{
34}
35
39inline std::vector<std::string> version_compiler()
40{
42}
43
47class System : public Generic2d::System {
48
49public:
50 System() = default;
51
52public:
53 virtual ~System(){};
54
55public:
78 template <class C, class E, class L, class M, class Y>
80 const C& coor,
81 const E& conn,
82 const E& dofs,
83 const L& iip,
84 const L& elastic_elem,
85 const M& elastic_K,
86 const M& elastic_G,
87 const L& plastic_elem,
88 const M& plastic_K,
89 const M& plastic_G,
90 const Y& plastic_epsy,
91 double dt,
92 double rho,
93 double alpha,
94 double eta)
95 {
96 this->initSystem(
97 coor,
98 conn,
99 dofs,
100 iip,
102 elastic_K,
103 elastic_G,
105 plastic_K,
106 plastic_G,
107 plastic_epsy,
108 dt,
109 rho,
110 alpha,
111 eta);
112 }
113
114public:
115 std::string type() const override
116 {
117 return "FrictionQPotFEM.UniformSingleLayer2d.System";
118 }
119
120public:
125 double typical_plastic_h() const
126 {
127 auto bot = xt::view(m_vector.conn(), xt::keep(m_elem_plas), 0);
128 auto top = xt::view(m_vector.conn(), xt::keep(m_elem_plas), 3);
129 auto h_plas = xt::view(m_coor, xt::keep(top), 1) - xt::view(m_coor, xt::keep(bot), 1);
130 double h = h_plas(0);
131 FRICTIONQPOTFEM_ASSERT(xt::allclose(h_plas, h));
132 return h;
133 }
134
135public:
140 double typical_plastic_dV() const
141 {
142 auto dV_plas = xt::view(m_quad.dV(), xt::keep(m_elem_plas), xt::all());
143 double dV = dV_plas(0, 0);
144 FRICTIONQPOTFEM_ASSERT(xt::allclose(dV_plas, dV));
145 return dV;
146 }
147
148public:
153 {
156 }
157
158public:
173 double addSimpleShearToFixedStress(double target_stress, bool dry_run = false)
174 {
176
177 auto dV = m_quad.AsTensor<2>(this->dV());
178 double G = m_plas.G().flat(0);
179
180 array_type::tensor<double, 2> Epsbar = detail::myaverage(this->Eps(), dV, {0, 1});
181 array_type::tensor<double, 2> Sigbar = detail::myaverage(this->Sig(), dV, {0, 1});
183 double epsxx = Epsd(0, 0);
184 double epsxy = Epsd(0, 1);
185
186 FRICTIONQPOTFEM_ASSERT(Sigbar(0, 1) >= 0);
187
188 double eps = GMatElastoPlasticQPot::Cartesian2d::Epsd(Epsbar)();
189 double sig = GMatElastoPlasticQPot::Cartesian2d::Sigd(Sigbar)();
190 double direction = +1.0;
191 if (target_stress < sig) {
192 direction = -1.0;
193 }
194
195 double eps_new = eps + (target_stress - sig) / (2.0 * G);
196 double dgamma = 2.0 * (-1.0 * direction * epsxy +
197 std::sqrt(std::pow(eps_new, 2.0) - std::pow(epsxx, 2.0)));
198
199 if (dry_run) {
200 return direction * dgamma;
201 }
202
203 for (size_t n = 0; n < m_nnode; ++n) {
204 m_u(n, 0) += direction * dgamma * (m_coor(n, 1) - m_coor(0, 1));
205 }
206 this->updated_u();
207
208 // sanity check
209 // ------------
210
211 Sigbar = detail::myaverage(this->Sig(), dV, {0, 1});
213 FRICTIONQPOTFEM_REQUIRE(std::abs(target_stress - sig) / sig < 1e-4);
214
215 return direction * dgamma;
216 }
217
218public:
224 double addElasticSimpleShearToFixedStress(double target_stress, bool dry_run = false)
225 {
226 auto idx = m_plas.i();
227 auto ret = this->addSimpleShearToFixedStress(target_stress, dry_run);
228 FRICTIONQPOTFEM_REQUIRE(xt::all(xt::equal(idx, m_plas.i())));
229 return ret;
230 }
231
232public:
256 double deps_kick,
257 size_t plastic_element,
258 bool trigger_weakest = true,
259 double amplify = 1.0)
260 {
261 FRICTIONQPOTFEM_ASSERT(plastic_element < m_nelem_plas);
262
263 auto idx = m_plas.i();
265 auto up = m_vector.AsDofs_p(m_u);
266
267 // distance to yielding on the positive side
268 const auto& epsy = m_plas.epsy_right();
269 auto deps = epsy - eps;
270
271 // find integration point closest to yielding
272 size_t e = m_elem_plas(plastic_element);
273 size_t q = xt::argmin(xt::view(deps, plastic_element, xt::all()))();
274 if (!trigger_weakest) {
275 q = xt::argmax(xt::view(deps, plastic_element, xt::all()))();
276 }
277
278 // deviatoric strain at the selected quadrature-point
279 array_type::tensor<double, 2> Eps = xt::view(m_plas.Eps(), plastic_element, q);
281
282 // new equivalent deviatoric strain: yield strain + small strain kick
283 double eps_new = epsy(plastic_element, q) + deps_kick / 2.0;
284
285 // convert to increment in shear strain (N.B. "dgamma = 2 * Epsd(0,1)")
286 double dgamma =
287 2.0 * (-Epsd(0, 1) + std::sqrt(std::pow(eps_new, 2.0) - std::pow(Epsd(0, 0), 2.0)));
288
289 // apply increment in shear strain as a perturbation to the selected element
290 // - nodes belonging to the current element, from connectivity
291 auto elem = xt::view(m_vector.conn(), e, xt::all());
292 // - displacement-DOFs
293 auto udofs = m_vector.AsDofs(m_u);
294 // - update displacement-DOFs for the element
295 for (size_t n = 0; n < m_nne; ++n) {
296 udofs(m_vector.dofs()(elem(n), 0)) +=
297 dgamma * amplify * (m_coor(elem(n), 1) - m_coor(elem(0), 1));
298 }
299 // - convert displacement-DOFs to (periodic) nodal displacement vector
300 // (N.B. storing to nodes directly does not ensure periodicity)
301 this->setU(m_vector.AsNode(udofs));
302
304 const auto& idx_new = m_plas.i();
305 auto up_new = m_vector.AsDofs_p(m_u);
306
307 FRICTIONQPOTFEM_REQUIRE(dgamma >= 0.0);
308 FRICTIONQPOTFEM_REQUIRE(amplify >= 0.0);
310 std::abs(eps(plastic_element, q) - eps_new) / eps_new < 1e-4 || amplify != 1);
311 FRICTIONQPOTFEM_REQUIRE(xt::any(xt::not_equal(idx, idx_new)));
312 FRICTIONQPOTFEM_REQUIRE(idx(plastic_element, q) != idx_new(plastic_element, q));
313 FRICTIONQPOTFEM_REQUIRE(xt::allclose(up, up_new));
314
315 return dgamma;
316 }
317
318public:
334 plastic_ElementYieldBarrierForSimpleShear(double deps_kick = 0.0, size_t iquad = 0)
335 {
337
339 const auto& epsy = m_plas.epsy_right();
340 auto deps = xt::eval(epsy - eps);
341 array_type::tensor<double, 2> ret = xt::empty<double>({m_N, size_t(2)});
342 auto isort = xt::argsort(deps, 1);
343
345
346 for (size_t e = 0; e < m_N; ++e) {
347 size_t q = isort(e, iquad);
348 double eps_new = epsy(e, q) + deps_kick / 2.0;
349 double gamma = Epsd(e, q, 0, 1);
350 double epsd_xx = Epsd(e, q, 0, 0);
351 ret(e, 0) = deps(e, q);
352 ret(e, 1) = -gamma + std::sqrt(std::pow(eps_new, 2.0) - std::pow(epsd_xx, 2.0));
353 }
354
355 return ret;
356 }
357};
358
375public:
376 LocalTriggerFineLayerFull() = default;
377
388 {
389 // Copy / allocate local variables
390
392
393 auto vector = sys.vector();
394 auto K = sys.stiffness();
395 auto quad = sys.quad();
397
399 m_nelem_plas = m_elem_plas.size();
400 m_nip = quad.nip();
401
402 m_smin = xt::zeros<double>({m_nelem_plas, m_nip});
403 m_pmin = xt::zeros<double>({m_nelem_plas, m_nip});
404 m_Wmin = xt::zeros<double>({m_nelem_plas, m_nip});
405 m_dgamma = xt::zeros<double>({m_nelem_plas, m_nip});
406 m_dE = xt::zeros<double>({m_nelem_plas, m_nip});
407
408 auto coor = sys.coor();
409 auto conn = sys.conn();
410
411 auto u = vector.allocate_nodevec(0.0);
412 auto fint = vector.allocate_nodevec(0.0);
413 auto fext = vector.allocate_nodevec(0.0);
414 auto fres = vector.allocate_nodevec(0.0);
415
416 auto ue = vector.allocate_elemvec(0.0);
417 auto fe = vector.allocate_elemvec(0.0);
418
419 auto Eps = quad.allocate_qtensor<2>(0.0);
420 auto Sig = quad.allocate_qtensor<2>(0.0);
421 std::copy(Eps.shape().cbegin(), Eps.shape().cend(), m_shape_T2.begin());
422
423 m_dV = quad.dV();
424 m_V = xt::sum(xt::view(m_dV, m_elem_plas(0)))();
425
426 // Replicate mesh
427
428 GooseFEM::Mesh::Quad4::FineLayer mesh(sys.coor(), sys.conn());
429
430 auto elmap = mesh.roll(1);
431 size_t nconfig = m_elem_plas(m_nelem_plas - 1) - elmap(m_elem_plas(m_nelem_plas - 1));
432 size_t nroll = m_nelem_plas / nconfig;
433
434 for (size_t roll = 0; roll < nroll; ++roll) {
435 m_elemmap.push_back(mesh.roll(roll));
436 m_nodemap.push_back(GooseFEM::Mesh::elemmap2nodemap(m_elemmap[roll], coor, conn));
437 }
438
439 for (size_t e = 0; e < nconfig; ++e) {
440
441 // Simple shear perturbation
442
443 m_u_s.emplace_back(u.shape());
444 m_Eps_s.emplace_back(Eps.shape());
445 m_Sig_s.emplace_back(Sig.shape());
446
447 array_type::tensor<double, 2> simple_shear = {{0.0, 1.0}, {1.0, 0.0}};
448
450 e,
451 simple_shear,
452 m_u_s[e],
453 m_Eps_s[e],
454 m_Sig_s[e],
455 K,
456 solver,
457 quad,
458 vector,
459 material);
460
461 for (size_t q = 0; q < m_nip; ++q) {
463 xt::eval(xt::view(m_Eps_s[e], m_elem_plas(e), q)));
464 double gamma = Epsd(0, 1);
465 for (size_t roll = 0; roll < nroll; ++roll) {
466 auto map = mesh.roll(roll);
467 m_dgamma(e + map(m_elem_plas(e)) - m_elem_plas(e), q) = gamma;
468 }
469 }
470
471 // Pure shear perturbation
472
473 m_u_p.emplace_back(u.shape());
474 m_Eps_p.emplace_back(Eps.shape());
475 m_Sig_p.emplace_back(Sig.shape());
476
477 array_type::tensor<double, 2> pure_shear = {{1.0, 0.0}, {0.0, -1.0}};
478
480 e, pure_shear, m_u_p[e], m_Eps_p[e], m_Sig_p[e], K, solver, quad, vector, material);
481
482 for (size_t q = 0; q < m_nip; ++q) {
484 xt::eval(xt::view(m_Eps_p[e], m_elem_plas(e), q)));
485 double E = Epsd(0, 0);
486 for (size_t roll = 0; roll < nroll; ++roll) {
487 auto map = mesh.roll(roll);
488 m_dE(e + map(m_elem_plas(e)) - m_elem_plas(e), q) = E;
489 }
490 }
491 }
492 }
493
494 virtual ~LocalTriggerFineLayerFull(){};
495
496protected:
511 template <class T>
513 size_t trigger_plastic,
514 const array_type::tensor<double, 2>& sig_star,
521 const GooseFEM::VectorPartitioned& vector,
522 T& material)
523 {
524 size_t trigger_element = m_elem_plas(trigger_plastic);
525
526 Sig.fill(0.0);
527 u.fill(0.0);
528
529 for (size_t q = 0; q < quad.nip(); ++q) {
530 xt::view(Sig, trigger_element, q) = -sig_star;
531 }
532
533 auto fe = quad.Int_gradN_dot_tensor2_dV(Sig);
534 auto fint = vector.AssembleNode(fe);
535 auto fext = xt::zeros_like(fint);
536 vector.copy_p(fint, fext);
537 auto fres = xt::eval(fext - fint);
538
539 solver.solve(K, fres, u);
540
541 vector.asElement(u, fe);
542 quad.symGradN_vector(fe, Eps);
543 material.set_Eps(Eps);
544 std::copy(material.Sig().begin(), material.Sig().end(), Sig.begin());
545 }
546
547public:
557 array_type::tensor<double, 2> u_s(size_t trigger_plastic) const
558 {
559 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
560 size_t nconfig = m_u_s.size();
561 size_t config = trigger_plastic % nconfig;
562 size_t roll = (trigger_plastic - trigger_plastic % nconfig) / nconfig;
563 return xt::view(m_u_s[config], xt::keep(m_nodemap[roll]));
564 }
565
575 array_type::tensor<double, 2> u_p(size_t trigger_plastic) const
576 {
577 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
578 size_t nconfig = m_u_p.size();
579 size_t config = trigger_plastic % nconfig;
580 size_t roll = (trigger_plastic - trigger_plastic % nconfig) / nconfig;
581 return xt::view(m_u_p[config], xt::keep(m_nodemap[roll]));
582 }
583
593 virtual array_type::tensor<double, 4> Eps_s(size_t trigger_plastic) const
594 {
595 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
596 size_t nconfig = m_u_s.size();
597 size_t config = trigger_plastic % nconfig;
598 size_t roll = (trigger_plastic - trigger_plastic % nconfig) / nconfig;
599 return xt::view(m_Eps_s[config], xt::keep(m_elemmap[roll]));
600 }
601
611 virtual array_type::tensor<double, 4> Eps_p(size_t trigger_plastic) const
612 {
613 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
614 size_t nconfig = m_u_p.size();
615 size_t config = trigger_plastic % nconfig;
616 size_t roll = (trigger_plastic - trigger_plastic % nconfig) / nconfig;
617 return xt::view(m_Eps_p[config], xt::keep(m_elemmap[roll]));
618 }
619
629 virtual array_type::tensor<double, 4> Sig_s(size_t trigger_plastic) const
630 {
631 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
632 size_t nconfig = m_u_s.size();
633 size_t config = trigger_plastic % nconfig;
634 size_t roll = (trigger_plastic - trigger_plastic % nconfig) / nconfig;
635 return xt::view(m_Sig_s[config], xt::keep(m_elemmap[roll]));
636 }
637
647 virtual array_type::tensor<double, 4> Sig_p(size_t trigger_plastic) const
648 {
649 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
650 size_t nconfig = m_u_p.size();
651 size_t config = trigger_plastic % nconfig;
652 size_t roll = (trigger_plastic - trigger_plastic % nconfig) / nconfig;
653 return xt::view(m_Sig_p[config], xt::keep(m_elemmap[roll]));
654 }
655
664 slice(const array_type::tensor<double, 2>& arg, size_t e) const
665 {
666 UNUSED(e);
667 return arg;
668 }
669
678 slice(const array_type::tensor<double, 4>& arg, size_t e) const
679 {
680 UNUSED(e);
681 return arg;
682 }
683
698 size_t N = 100)
699 {
700 FRICTIONQPOTFEM_ASSERT(xt::has_shape(Eps, m_shape_T2));
701 FRICTIONQPOTFEM_ASSERT(xt::has_shape(Sig, m_shape_T2));
702 FRICTIONQPOTFEM_ASSERT(xt::has_shape(epsy, {m_nelem_plas, m_nip}));
703
704 array_type::tensor<double, 2> S = xt::empty<double>({size_t(2), N});
705 array_type::tensor<double, 2> P = xt::empty<double>({size_t(2), N});
706 array_type::tensor<double, 2> W = xt::empty<double>({size_t(2), N});
707
708 for (size_t i = 0; i < S.shape(0); ++i) {
709 S(i, 0) = 0.0;
710 P(i, 0) = 0.0;
711 W(i, 0) = 0.0;
712 }
713
714 for (size_t e = 0; e < m_nelem_plas; ++e) {
715
716 auto Eps_s = this->Eps_s(e);
717 auto Eps_p = this->Eps_p(e);
718 auto Sig_s = this->Sig_s(e);
719 auto Sig_p = this->Sig_p(e);
720 auto Sig_slice = this->slice(Sig, e);
721 auto dV_slice = this->slice(m_dV, e);
722
723 for (size_t q = 0; q < m_nip; ++q) {
724
725 double dgamma = m_dgamma(e, q);
726 double dE = m_dE(e, q);
727
728 auto Epsd =
729 GMatTensor::Cartesian2d::Deviatoric(xt::eval(xt::view(Eps, m_elem_plas(e), q)));
730 double gamma = Epsd(0, 1);
731 double E = Epsd(0, 0);
732 double y = epsy(e, q);
733 double a, b, c, D;
734
735 // solve for "p = 0"
736 a = SQR(dgamma);
737 b = 2.0 * gamma * dgamma;
738 c = SQR(gamma) + SQR(E) - SQR(y);
739 D = SQR(b) - 4.0 * a * c;
740 double smax = (-b + std::sqrt(D)) / (2.0 * a);
741 double smin = (-b - std::sqrt(D)) / (2.0 * a);
742
743 // solve for "s = 0"
744 a = SQR(dE);
745 b = 2.0 * E * dE;
746 c = SQR(E) + SQR(gamma) - SQR(y);
747 D = SQR(b) - 4.0 * a * c;
748 double pmax = (-b + std::sqrt(D)) / (2.0 * a);
749 double pmin = (-b - std::sqrt(D)) / (2.0 * a);
750
751 size_t n = static_cast<size_t>(-smin / (smax - smin) * static_cast<double>(N));
752 size_t m = N - n;
753
754 for (size_t i = 0; i < 2; ++i) {
755 xt::view(S, i, xt::range(0, n)) = xt::linspace<double>(smin, 0, n);
756 xt::view(S, i, xt::range(n, N)) =
757 xt::linspace<double>(smax / double(m), smax, m);
758 P(i, 0) = 0.0;
759 P(i, N - 1) = 0.0;
760 }
761 if (n > 0) {
762 P(0, n - 1) = pmax;
763 P(1, n - 1) = pmin;
764 }
765
766 for (size_t j = 1; j < N - 1; ++j) {
767 if (j == n - 1) {
768 continue;
769 }
770 a = SQR(dE);
771 b = 2.0 * E * dE;
772 c = SQR(E) + std::pow(gamma + S(0, j) * dgamma, 2.0) - SQR(y);
773 D = SQR(b) - 4.0 * a * c;
774 P(0, j) = (-b + std::sqrt(D)) / (2.0 * a);
775 P(1, j) = (-b - std::sqrt(D)) / (2.0 * a);
776 }
777
778 for (size_t i = 0; i < P.shape(0); ++i) {
779 for (size_t j = 0; j < P.shape(1); ++j) {
781 P(i, j) * Sig_p + S(i, j) * Sig_s + Sig_slice;
782
783 array_type::tensor<double, 4> deps = P(i, j) * Eps_p + S(i, j) * Eps_s;
784
787
788 w *= dV_slice;
789 W(i, j) = xt::sum(w)();
790 }
791 }
792
793 auto idx = xt::argmin(W)();
794 m_smin(e, q) = S.flat(idx);
795 m_pmin(e, q) = P.flat(idx);
796 m_Wmin(e, q) = W.flat(idx);
797 }
798 }
799 }
800
814 {
815 FRICTIONQPOTFEM_ASSERT(xt::has_shape(Eps, m_shape_T2));
816 FRICTIONQPOTFEM_ASSERT(xt::has_shape(Sig, m_shape_T2));
817 FRICTIONQPOTFEM_ASSERT(xt::has_shape(epsy, {m_nelem_plas, m_nip}));
818
819 std::array<double, 8> S;
820 std::array<double, 8> P;
821 std::array<double, 8> W;
822
823 for (size_t e = 0; e < m_nelem_plas; ++e) {
824
825 auto Eps_s = this->Eps_s(e);
826 auto Eps_p = this->Eps_p(e);
827 auto Sig_s = this->Sig_s(e);
828 auto Sig_p = this->Sig_p(e);
829 auto Sig_slice = this->slice(Sig, e);
830 auto dV_slice = this->slice(m_dV, e);
831
832 for (size_t q = 0; q < m_nip; ++q) {
833
834 double dgamma = m_dgamma(e, q);
835 double dE = m_dE(e, q);
836
837 auto Epsd =
838 GMatTensor::Cartesian2d::Deviatoric(xt::eval(xt::view(Eps, m_elem_plas(e), q)));
839 double gamma = Epsd(0, 1);
840 double E = Epsd(0, 0);
841 double y = epsy(e, q);
842 double a, b, c, D;
843
844 // solve for "p = 0"
845 a = SQR(dgamma);
846 b = 2.0 * gamma * dgamma;
847 c = SQR(gamma) + SQR(E) - SQR(y);
848 D = SQR(b) - 4.0 * a * c;
849 double smax = (-b + std::sqrt(D)) / (2.0 * a);
850 double smin = (-b - std::sqrt(D)) / (2.0 * a);
851 P[0] = 0.0;
852 P[1] = 0.0;
853 S[0] = smin;
854 S[1] = smax;
855
856 // solve for "s = 0"
857 a = SQR(dE);
858 b = 2.0 * E * dE;
859 c = SQR(E) + SQR(gamma) - SQR(y);
860 D = SQR(b) - 4.0 * a * c;
861 double pmax = (-b + std::sqrt(D)) / (2.0 * a);
862 double pmin = (-b - std::sqrt(D)) / (2.0 * a);
863 P[2] = pmin;
864 P[3] = pmax;
865 S[2] = 0.0;
866 S[3] = 0.0;
867 S[4] = smin / 2.0;
868 S[5] = smin / 2.0;
869 S[6] = smax / 2.0;
870 S[7] = smax / 2.0;
871
872 for (size_t i = 4; i < S.size(); ++i) {
873 if (i % 2 != 0) {
874 continue;
875 }
876 a = SQR(dE);
877 b = 2.0 * E * dE;
878 c = SQR(E) + std::pow(gamma + S[i] * dgamma, 2.0) - SQR(y);
879 D = SQR(b) - 4.0 * a * c;
880 P[i] = (-b + std::sqrt(D)) / (2.0 * a);
881 P[i + 1] = (-b - std::sqrt(D)) / (2.0 * a);
882 }
883
884 for (size_t i = 0; i < S.size(); ++i) {
885 array_type::tensor<double, 4> sig = P[i] * Sig_p + S[i] * Sig_s + Sig_slice;
886 array_type::tensor<double, 4> deps = P[i] * Eps_p + S[i] * Eps_s;
889 w *= dV_slice;
890 W[i] = xt::sum(w)();
891 }
892
893 auto idx = std::distance(W.begin(), std::min_element(W.begin(), W.end()));
894 m_smin(e, q) = S[idx];
895 m_pmin(e, q) = P[idx];
896 m_Wmin(e, q) = W[idx];
897 }
898 }
899 }
900
913 {
914 FRICTIONQPOTFEM_ASSERT(xt::has_shape(Eps, m_shape_T2));
915 FRICTIONQPOTFEM_ASSERT(xt::has_shape(Sig, m_shape_T2));
916 FRICTIONQPOTFEM_ASSERT(xt::has_shape(epsy, {m_nelem_plas, m_nip}));
917
918 std::array<double, 2> S;
919 std::array<double, 2> W;
920
921 for (size_t e = 0; e < m_nelem_plas; ++e) {
922
923 auto Eps_s = this->Eps_s(e);
924 auto Sig_s = this->Sig_s(e);
925 auto Sig_slice = this->slice(Sig, e);
926 auto dV_slice = this->slice(m_dV, e);
927
928 for (size_t q = 0; q < m_nip; ++q) {
929
930 double dgamma = m_dgamma(e, q);
931
932 auto Epsd =
933 GMatTensor::Cartesian2d::Deviatoric(xt::eval(xt::view(Eps, m_elem_plas(e), q)));
934 double gamma = Epsd(0, 1);
935 double E = Epsd(0, 0);
936 double y = epsy(e, q);
937 double a, b, c, D;
938
939 // solve for "p = 0"
940 a = SQR(dgamma);
941 b = 2.0 * gamma * dgamma;
942 c = SQR(gamma) + SQR(E) - SQR(y);
943 D = SQR(b) - 4.0 * a * c;
944 S[1] = (-b + std::sqrt(D)) / (2.0 * a);
945 S[0] = (-b - std::sqrt(D)) / (2.0 * a);
946
947 for (size_t i = 0; i < S.size(); ++i) {
948 array_type::tensor<double, 4> sig = S[i] * Sig_s + Sig_slice;
952 w *= dV_slice;
953 W[i] = xt::sum(w)();
954 }
955
956 size_t idx = 0;
957 if (W[1] < W[0]) {
958 idx = 1;
959 }
960
961 m_smin(e, q) = S[idx];
962 m_pmin(e, q) = 0.0;
963 m_Wmin(e, q) = W[idx];
964 }
965 }
966 }
967
977 {
978 return m_Wmin / m_V;
979 }
980
993 {
994 return m_pmin;
995 }
996
1009 {
1010 return m_smin;
1011 }
1012
1022 {
1023 return m_dgamma;
1024 }
1025
1035 {
1036 return m_dE;
1037 }
1038
1051 array_type::tensor<double, 2> delta_u(size_t e, size_t q) const
1052 {
1053 return m_pmin(e, q) * this->u_p(e) + m_smin(e, q) * this->u_s(e);
1054 }
1055
1056protected:
1057 size_t m_nip;
1060
1068 std::vector<array_type::tensor<double, 2>>
1070 std::vector<array_type::tensor<double, 2>>
1072 std::vector<array_type::tensor<double, 4>>
1074 std::vector<array_type::tensor<double, 4>>
1076 std::vector<array_type::tensor<double, 4>>
1078 std::vector<array_type::tensor<double, 4>>
1080 std::vector<array_type::tensor<size_t, 1>> m_nodemap;
1081 std::vector<array_type::tensor<size_t, 1>> m_elemmap;
1082
1084 double m_V;
1085 std::array<size_t, 4> m_shape_T2;
1086
1090
1098};
1099
1106public:
1107 LocalTriggerFineLayer() = default;
1108
1119 LocalTriggerFineLayer(const System& sys, size_t roi = 5)
1121 {
1122 GooseFEM::Mesh::Quad4::FineLayer mesh(sys.coor(), sys.conn());
1123
1124 m_elemslice.resize(m_nelem_plas);
1129
1130 for (size_t e = 0; e < m_nelem_plas; ++e) {
1131
1132 auto slice = xt::sort(mesh.elementgrid_around_ravel(m_elem_plas(e), roi));
1133 m_elemslice[e] = slice;
1134
1136 m_Eps_s_slice[e] = xt::view(Eps, xt::keep(slice));
1137
1139 m_Eps_p_slice[e] = xt::view(Eps, xt::keep(slice));
1140
1142 m_Sig_s_slice[e] = xt::view(Sig, xt::keep(slice));
1143
1145 m_Sig_p_slice[e] = xt::view(Sig, xt::keep(slice));
1146 }
1147 }
1148
1157 slice(const array_type::tensor<double, 2>& arg, size_t e) const override
1158 {
1159 return xt::view(arg, xt::keep(m_elemslice[e]));
1160 }
1161
1170 slice(const array_type::tensor<double, 4>& arg, size_t e) const override
1171 {
1172 return xt::view(arg, xt::keep(m_elemslice[e]));
1173 }
1174
1175 array_type::tensor<double, 4> Eps_s(size_t trigger_plastic) const override
1176 {
1177 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
1178 return m_Eps_s_slice[trigger_plastic];
1179 }
1180
1181 array_type::tensor<double, 4> Eps_p(size_t trigger_plastic) const override
1182 {
1183 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
1184 return m_Eps_p_slice[trigger_plastic];
1185 }
1186
1187 array_type::tensor<double, 4> Sig_s(size_t trigger_plastic) const override
1188 {
1189 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
1190 return m_Sig_s_slice[trigger_plastic];
1191 }
1192
1193 array_type::tensor<double, 4> Sig_p(size_t trigger_plastic) const override
1194 {
1195 FRICTIONQPOTFEM_ASSERT(trigger_plastic < m_nelem_plas);
1196 return m_Sig_p_slice[trigger_plastic];
1197 }
1198
1199protected:
1200 std::vector<array_type::tensor<size_t, 1>>
1202 std::vector<array_type::tensor<double, 4>>
1204 std::vector<array_type::tensor<double, 4>>
1206 std::vector<array_type::tensor<double, 4>>
1208 std::vector<array_type::tensor<double, 4>>
1210};
1211
1212} // namespace UniformSingleLayer2d
1213} // namespace FrictionQPotFEM
1214
1215#endif
#define SQR(x)
System with elastic elements and plastic elements (GMatElastoPlasticQPot).
Definition: Generic2d.h:183
const GooseFEM::Element::Quad4::Quadrature & quad() const
GooseFEM quadrature definition.
Definition: Generic2d.h:949
size_t m_nne
Number of nodes per element.
Definition: Generic2d.h:2081
double eta() const
Get the damping at the interface.
Definition: Generic2d.h:478
double rho() const
Mass density.
Definition: Generic2d.h:406
array_type::tensor< double, 2 > G() const
Shear modulus per integration point.
Definition: Generic2d.h:1012
const array_type::tensor< double, 4 > & Eps()
Strain tensor of each integration point.
Definition: Generic2d.h:1054
const auto & dV() const
Integration point volume (of each integration point)
Definition: Generic2d.h:928
const auto & elastic_elem() const
List of elastic elements.
Definition: Generic2d.h:678
array_type::tensor< double, 2 > m_coor
Nodal coordinates, see coor().
Definition: Generic2d.h:2076
GMatElastoPlasticQPot::Cartesian2d::Cusp< 2 > m_plas
Material for plastic el.
Definition: Generic2d.h:2096
size_t m_nnode
Number of nodes.
Definition: Generic2d.h:2082
size_t m_N
Number of plastic elements, alias of m_nelem_plas.
Definition: Generic2d.h:2077
double eventDriven_setDeltaU(const T &delta_u, bool autoscale=true)
Set purely elastic and linear response to specific boundary conditions.
Definition: Generic2d.h:1234
const auto & plastic_elem() const
List of plastic elements.
Definition: Generic2d.h:688
GooseFEM::MatrixPartitioned stiffness() const
Stiffness tensor of each integration point.
Definition: Generic2d.h:1087
const array_type::tensor< double, 4 > & Sig()
Stress tensor of each integration point.
Definition: Generic2d.h:1043
void setU(const T &u)
Overwrite nodal displacements.
Definition: Generic2d.h:586
array_type::tensor< double, 2 > K() const
Bulk modulus per integration point.
Definition: Generic2d.h:980
array_type::tensor< size_t, 1 > m_elem_plas
Plastic elements.
Definition: Generic2d.h:2086
const auto & coor() const
Nodal coordinates.
Definition: Generic2d.h:708
const auto & conn() const
Connectivity.
Definition: Generic2d.h:698
GooseFEM::Element::Quad4::Quadrature m_quad
Quadrature for all elements.
Definition: Generic2d.h:2087
double dt() const
Get time step.
Definition: Generic2d.h:566
array_type::tensor< double, 2 > m_u
Nodal displacements.
Definition: Generic2d.h:2104
GooseFEM::VectorPartitioned m_vector
Convert vectors between 'nodevec', 'elemvec', ....
Definition: Generic2d.h:2090
array_type::tensor< double, 2 > affineSimpleShear(double delta_gamma) const
Get the displacement field that corresponds to an affine simple shear of a certain strain.
Definition: Generic2d.h:2041
const auto & dofs() const
DOFs per node.
Definition: Generic2d.h:718
bool isHomogeneousElastic() const
Check if elasticity is homogeneous.
Definition: Generic2d.h:554
double alpha() const
Background damping density.
Definition: Generic2d.h:507
const GooseFEM::VectorPartitioned & vector() const
GooseFEM vector definition.
Definition: Generic2d.h:938
size_t m_nip
Number of integration points.
Definition: Generic2d.h:2084
virtual void updated_u()
Evaluate relevant forces when m_u is updated.
Definition: Generic2d.h:626
size_t m_nelem_plas
Number of plastic elements.
Definition: Generic2d.h:2080
Trigger element by a linear combination of simple shear and a pure shear perturbations.
double m_V
Volume of a plastic element: assumed homogeneous!
std::vector< array_type::tensor< double, 2 > > m_u_s
Perturbation for each plastic element.
LocalTriggerFineLayerFull(const System &sys)
Constructor, reading the basic properties of the System, and computing the perturbation for all plast...
std::vector< array_type::tensor< double, 4 > > m_Sig_s
Stress field for simple shear perturbation.
virtual array_type::tensor< double, 4 > Sig_s(size_t trigger_plastic) const
Integration point stress tensors for LocalTriggerFineLayerFull::u_s.
void setStateMinimalSearch(const array_type::tensor< double, 4 > &Eps, const array_type::tensor< double, 4 > &Sig, const array_type::tensor< double, 2 > &epsy)
Set current state and compute energy barriers to reach the specified yield surface (for all plastic e...
array_type::tensor< double, 2 > barriers() const
Get all energy barriers, as energy density.
array_type::tensor< double, 2 > m_pmin
value of "p" at minimal work "W" [nip, N]
const array_type::tensor< double, 2 > & s() const
The energy barrier in LocalTriggerFineLayerFull::barriers is reached with a displacement LocalTrigger...
std::vector< array_type::tensor< size_t, 1 > > m_elemmap
Element-map for the roll.
virtual array_type::tensor< double, 4 > Sig_p(size_t trigger_plastic) const
Integration point stress tensors for LocalTriggerFineLayerFull::u_p.
array_type::tensor< double, 2 > m_dgamma
Strain change in the element for each plastic element::
std::vector< array_type::tensor< double, 2 > > m_u_p
Displacement field for pure shear perturbation.
std::vector< array_type::tensor< size_t, 1 > > m_nodemap
Node-map for the roll.
virtual array_type::tensor< double, 4 > Eps_p(size_t trigger_plastic) const
Integration point strain tensors for LocalTriggerFineLayerFull::u_p.
array_type::tensor< double, 2 > m_dV
Integration point volume.
const array_type::tensor< double, 2 > & p() const
The energy barrier in LocalTriggerFineLayerFull::barriers is reached with a displacement LocalTrigger...
array_type::tensor< double, 2 > m_dE
== Eps_p(plastic(e), q, 0, 0) [nip, N]
virtual array_type::tensor< double, 2 > slice(const array_type::tensor< double, 2 > &arg, size_t e) const
Empty function, used by LocalTriggerFineLayer.
virtual array_type::tensor< double, 4 > slice(const array_type::tensor< double, 4 > &arg, size_t e) const
Empty function, used by LocalTriggerFineLayer.
array_type::tensor< double, 2 > u_p(size_t trigger_plastic) const
Displacement field for the pure shear eigen-stress applied to a specific element.
array_type::tensor< size_t, 1 > m_elem_plas
Plastic elements.
void computePerturbation(size_t trigger_plastic, const array_type::tensor< double, 2 > &sig_star, array_type::tensor< double, 2 > &u, array_type::tensor< double, 4 > &Eps, array_type::tensor< double, 4 > &Sig, GooseFEM::MatrixPartitioned &K, GooseFEM::MatrixPartitionedSolver<> &solver, const GooseFEM::Element::Quad4::Quadrature &quad, const GooseFEM::VectorPartitioned &vector, T &material)
Compute the displacement response to an eigen-stress applied to a plastic element.
void setState(const array_type::tensor< double, 4 > &Eps, const array_type::tensor< double, 4 > &Sig, const array_type::tensor< double, 2 > &epsy, size_t N=100)
Set current state and compute energy barriers to reach the specified yield surface (for all plastic e...
std::vector< array_type::tensor< double, 4 > > m_Eps_p
Strain field for pure shear perturbation.
virtual array_type::tensor< double, 4 > Eps_s(size_t trigger_plastic) const
Integration point strain tensors for LocalTriggerFineLayerFull::u_s.
array_type::tensor< double, 2 > delta_u(size_t e, size_t q) const
The energy barrier in LocalTriggerFineLayerFull::barriers is reached with this displacement field.
void setStateSimpleShear(const array_type::tensor< double, 4 > &Eps, const array_type::tensor< double, 4 > &Sig, const array_type::tensor< double, 2 > &epsy)
Set current state and compute energy barriers to reach the specified yield surface,...
std::array< size_t, 4 > m_shape_T2
Shape of an integration point tensor.
array_type::tensor< double, 2 > u_s(size_t trigger_plastic) const
Displacement field for the simple shear eigen-stress applied to a specific element.
const array_type::tensor< double, 2 > & dgamma() const
Simple shear mode for all integration points of the triggered element, for all elements.
const array_type::tensor< double, 2 > & dE() const
Pure shear mode for all integration points of the triggered element, for all elements.
std::vector< array_type::tensor< double, 4 > > m_Eps_s
Strain field for simple shear perturbation.
std::vector< array_type::tensor< double, 4 > > m_Sig_p
Stress field for pure shear perturbation.
array_type::tensor< double, 2 > m_Wmin
value of minimal work "W" [nip, N]
array_type::tensor< double, 2 > m_smin
value of "s" at minimal work "W" [nip, N]
Similar to LocalTriggerFineLayerFull, with the difference that only a (small) group of elements aroun...
array_type::tensor< double, 4 > Sig_s(size_t trigger_plastic) const override
Integration point stress tensors for LocalTriggerFineLayerFull::u_s.
array_type::tensor< double, 2 > slice(const array_type::tensor< double, 2 > &arg, size_t e) const override
Select values in the region of interest around a plastic element.
std::vector< array_type::tensor< double, 4 > > m_Eps_s_slice
LocalTriggerFineLayerFull::m_Eps_s for the ROI only.
std::vector< array_type::tensor< size_t, 1 > > m_elemslice
Region-of-interest (ROI) per plastic element.
array_type::tensor< double, 4 > slice(const array_type::tensor< double, 4 > &arg, size_t e) const override
Select values in the region of interest around a plastic element.
LocalTriggerFineLayer(const System &sys, size_t roi=5)
Constructor.
std::vector< array_type::tensor< double, 4 > > m_Sig_p_slice
LocalTriggerFineLayerFull::m_Sig_p for the ROI only.
std::vector< array_type::tensor< double, 4 > > m_Eps_p_slice
LocalTriggerFineLayerFull::m_Eps_p for the ROI only.
array_type::tensor< double, 4 > Sig_p(size_t trigger_plastic) const override
Integration point stress tensors for LocalTriggerFineLayerFull::u_p.
array_type::tensor< double, 4 > Eps_s(size_t trigger_plastic) const override
Integration point strain tensors for LocalTriggerFineLayerFull::u_s.
array_type::tensor< double, 4 > Eps_p(size_t trigger_plastic) const override
Integration point strain tensors for LocalTriggerFineLayerFull::u_p.
std::vector< array_type::tensor< double, 4 > > m_Sig_s_slice
LocalTriggerFineLayerFull::m_Sig_s for the ROI only.
Class that uses GMatElastoPlasticQPot to evaluate stress everywhere.
double triggerElementWithLocalSimpleShear(double deps_kick, size_t plastic_element, bool trigger_weakest=true, double amplify=1.0)
Apply local strain to the right to a specific plastic element.
double typical_plastic_dV() const
Integration point volume of all elements along the weak layer.
double typical_plastic_h() const
Element height of all elements along the weak layer.
std::string type() const override
Return the type of system.
double addElasticSimpleShearToFixedStress(double target_stress, bool dry_run=false)
Add simple shear until a target equivalent macroscopic stress has been reached.
array_type::tensor< double, 2 > plastic_ElementYieldBarrierForSimpleShear(double deps_kick=0.0, size_t iquad=0)
Read the distance to overcome the first cusp in the element.
double addSimpleShearToFixedStress(double target_stress, bool dry_run=false)
Add simple shear until a target equivalent macroscopic stress has been reached.
System(const C &coor, const E &conn, const E &dofs, const L &iip, const L &elastic_elem, const M &elastic_K, const M &elastic_G, const L &plastic_elem, const M &plastic_K, const M &plastic_G, const Y &plastic_epsy, double dt, double rho, double alpha, double eta)
Define the geometry, including boundary conditions and element sets.
void initEventDrivenSimpleShear()
Initialise event driven protocol for affine simple shear.
const array_type::tensor< size_t, N > & i() const
Index of the current yield strain per item.
Definition: Cartesian2d.h:436
array_type::tensor< double, N > epsy_right() const
Current yield strain right per item.
Definition: Cartesian2d.h:471
Array of material points with a linear elastic constitutive response.
Definition: Cartesian2d.h:122
const array_type::tensor< double, N > & G() const
Shear modulus per item.
Definition: Cartesian2d.h:206
const array_type::tensor< double, N+2 > & Eps() const
Strain tensor per item.
Definition: Cartesian2d.h:272
Interpolation and quadrature.
Definition: ElementQuad4.h:237
auto Int_gradN_dot_tensor2_dV(const T &qtensor) const -> array_type::tensor< double, 3 >
Element-by-element: integral of the dot product of the shape function gradients with a second order t...
Definition: Element.h:805
void symGradN_vector(const T &elemvec, R &qtensor) const
Same as SymGradN_vector(), but writing to preallocated return.
Definition: Element.h:711
auto dV() const -> const array_type::tensor< double, 2 > &
Integration volume.
Definition: Element.h:581
auto nip() const
Number of integration points.
Definition: Element.h:201
auto AsTensor(const T &arg) const
Convert "qscalar" to "qtensor" of certain rank.
Definition: Element.h:227
Solve for A of the MatrixPartitioned() class.
Sparse matrix partitioned in an unknown and a prescribed part.
Mesh with fine middle layer, and coarser elements towards the top and bottom.
Definition: MeshQuad4.h:200
array_type::tensor< size_t, 1 > roll(size_t n)
Mapping to 'roll' periodically in the x-direction,.
Definition: MeshQuad4.h:538
array_type::tensor< size_t, 1 > elementgrid_around_ravel(size_t e, size_t size, bool periodic=true)
Select region of elements from 'matrix' of element numbers around an element: square box with edge-si...
Definition: MeshQuad4.h:409
Class to switch between storage types, based on a mesh and DOFs that are partitioned in:
void copy_p(const array_type::tensor< double, 2 > &nodevec_src, array_type::tensor< double, 2 > &nodevec_dest) const
Copy prescribed DOFs from "nodevec" to another "nodvec":
array_type::tensor< double, 1 > AsDofs_p(const array_type::tensor< double, 1 > &dofval) const
Extract the prescribed "dofval":
const array_type::tensor< size_t, 2 > & conn() const
Definition: Vector.h:92
void asElement(const T &arg, R &ret) const
Convert "dofval" or "nodevec" to "elemvec" (overwrite entries that occur more than once).
Definition: Vector.h:208
array_type::tensor< double, 2 > AsNode(const T &arg) const
Convert "dofval" or "elemvec" to "nodevec" (overwrite entries that occur more than once).
Definition: Vector.h:168
array_type::tensor< double, 1 > AsDofs(const T &arg) const
Convert "nodevec" or "elemvec" to "dofval" (overwrite entries that occur more than once).
Definition: Vector.h:142
array_type::tensor< double, 2 > AssembleNode(const T &arg) const
Assemble "elemvec" to "nodevec" (adds entries that occur more that once.
Definition: Vector.h:246
const array_type::tensor< size_t, 2 > & dofs() const
Definition: Vector.h:100
std::vector< std::string > version_dependencies()
Return versions of this library and of all of its dependencies.
Definition: Generic2d.h:161
std::vector< std::string > version_compiler()
Version information of the compilers.
Definition: Generic2d.h:170
std::vector< std::string > version_compiler()
Version information of the compilers.
std::vector< std::string > version_dependencies()
Return versions of this library and of all of its dependencies.
xt::xtensor< T, N > tensor
Fixed (static) rank array.
Definition: config.h:160
Friction simulations based on a disorder potential energy landscape and the finite element method.
Definition: config.h:139
auto Epsd(const T &A) -> typename GMatTensor::allocate< xt::get_rank< T >::value - 2, T >::type
Equivalent strain: norm of strain deviator.
Definition: Cartesian2d.h:46
auto Sigd(const T &A) -> typename GMatTensor::allocate< xt::get_rank< T >::value - 2, T >::type
Equivalent stress: norm of strain deviator.
Definition: Cartesian2d.h:87
auto Deviatoric(const T &A)
Deviatoric part of a tensor:
Definition: Cartesian2d.h:706
auto A2s_ddot_B2s(const T &A, const T &B)
Same as A2_ddot_B2(const T& A, const T& B, R& ret) but for symmetric tensors.
Definition: Cartesian2d.h:645
array_type::tensor< size_t, 1 > elemmap2nodemap(const T &elem_map, const C &coor, const E &conn, ElementType type)
Convert an element-map to a node-map.
Definition: Mesh.h:2675
#define FRICTIONQPOTFEM_REQUIRE(expr)
Assertions that cannot be disabled.
Definition: config.h:70
#define FRICTIONQPOTFEM_ASSERT(expr)
All assertions are implementation as::
Definition: config.h:62