FrictionQPotFEM 0.23.3
Loading...
Searching...
No Matches
Generic2d.h
Go to the documentation of this file.
1
7#ifndef FRICTIONQPOTFEM_GENERIC2D_H
8#define FRICTIONQPOTFEM_GENERIC2D_H
9
10#include <algorithm>
11#include <string>
12#include <tuple>
13
14#include "config.h"
15
16#include <xtensor/xnorm.hpp>
17#include <xtensor/xset_operation.hpp>
18#include <xtensor/xshape.hpp>
19#include <xtensor/xtensor.hpp>
20
21#include <GooseFEM/GooseFEM.h>
22#include <GooseFEM/Matrix.h>
24
27
29#include <GMatTensor/version.h>
30
31namespace FrictionQPotFEM {
32
33namespace detail {
34
39array_type::tensor<double, 2> myaverage(
40 const array_type::tensor<double, 4>& a,
41 const array_type::tensor<double, 4>& w,
42 const std::array<size_t, 2>& axis)
43{
44 FRICTIONQPOTFEM_ASSERT(axis[0] == 0);
45 FRICTIONQPOTFEM_ASSERT(axis[1] == 1);
46 FRICTIONQPOTFEM_ASSERT(xt::has_shape(a, w.shape()));
47
48 array_type::tensor<double, 2> ret = xt::zeros<double>({a.shape(2), a.shape(3)});
49 array_type::tensor<double, 2> norm = xt::zeros<double>({a.shape(2), a.shape(3)});
50
51 for (size_t i = 0; i < a.shape(0); ++i) {
52 for (size_t j = 0; j < a.shape(1); ++j) {
53 for (size_t k = 0; k < a.shape(2); ++k) {
54 for (size_t l = 0; l < a.shape(3); ++l) {
55 ret(k, l) += a(i, j, k, l) * w(i, j, k, l);
56 norm(k, l) += w(i, j, k, l);
57 }
58 }
59 }
60 }
61
62 return ret / norm;
63}
64
65} // namespace detail
66
80{
81 array_type::tensor<double, 3> ret = xt::empty<double>({arg.shape(0), nip, arg.shape(1) + 1});
82
83 for (size_t e = 0; e < arg.shape(0); ++e) {
84 for (size_t q = 0; q < nip; ++q) {
85 std::copy(&arg(e, 0), &arg(e, 0) + arg.shape(1), &ret(e, q, 1));
86 ret(e, q, 0) = -arg(e, 0);
87 }
88 }
89
90 return ret;
91}
92
104{
105 array_type::tensor<double, 2> ret = xt::empty<double>({arg.shape(0), nip});
106
107 for (size_t e = 0; e < arg.shape(0); ++e) {
108 for (size_t q = 0; q < nip; ++q) {
109 ret(e, q) = arg(e);
110 }
111 }
112
113 return ret;
114}
115
125template <class T>
126inline typename T::value_type getuniform(const T& arg)
127{
128 if (xt::allclose(arg.flat(0), arg)) {
129 return arg.flat(0);
130 }
131
132 throw std::runtime_error("Values not uniform");
133}
134
139namespace Generic2d {
140
141namespace detail {
142
143bool is_same(double a, double b)
144{
145 return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b &&
146 std::nextafter(a, std::numeric_limits<double>::max()) >= b;
147}
148
149} // namespace detail
150
161inline std::vector<std::string> version_dependencies()
162{
164}
165
170inline std::vector<std::string> version_compiler()
171{
173}
174
183class System {
184
185public:
186 System() = default;
187
188public:
189 virtual ~System(){};
190
191public:
214 template <class C, class E, class L, class M, class Y>
216 const C& coor,
217 const E& conn,
218 const E& dofs,
219 const L& iip,
220 const L& elastic_elem,
221 const M& elastic_K,
222 const M& elastic_G,
223 const L& plastic_elem,
224 const M& plastic_K,
225 const M& plastic_G,
226 const Y& plastic_epsy,
227 double dt,
228 double rho,
229 double alpha,
230 double eta)
231 {
232 this->initSystem(
233 coor,
234 conn,
235 dofs,
236 iip,
238 elastic_K,
239 elastic_G,
241 plastic_K,
242 plastic_G,
243 plastic_epsy,
244 dt,
245 rho,
246 alpha,
247 eta);
248 }
249
250protected:
254 template <class C, class E, class L, class M, class Y>
255 void initSystem(
256 const C& coor,
257 const E& conn,
258 const E& dofs,
259 const L& iip,
260 const L& elastic_elem,
261 const M& elastic_K,
262 const M& elastic_G,
263 const L& plastic_elem,
264 const M& plastic_K,
265 const M& plastic_G,
266 const Y& plastic_epsy,
267 double dt,
268 double rho,
269 double alpha,
270 double eta)
271 {
272 FRICTIONQPOTFEM_ASSERT(coor.dimension() == 2);
273 FRICTIONQPOTFEM_ASSERT(coor.shape(1) == 2);
274 FRICTIONQPOTFEM_ASSERT(conn.dimension() == 2);
275 FRICTIONQPOTFEM_ASSERT(dofs.dimension() == 2);
276 FRICTIONQPOTFEM_ASSERT(dofs.shape(1) == 2);
277 FRICTIONQPOTFEM_ASSERT(iip.dimension() == 1);
279 FRICTIONQPOTFEM_ASSERT(elastic_elem.dimension() == 1);
280 FRICTIONQPOTFEM_ASSERT(elastic_K.dimension() == 2);
281 FRICTIONQPOTFEM_ASSERT(elastic_K.shape(0) == elastic_elem.size());
282 FRICTIONQPOTFEM_ASSERT(elastic_G.dimension() == 2);
283 FRICTIONQPOTFEM_ASSERT(elastic_G.shape(0) == elastic_elem.size());
284 FRICTIONQPOTFEM_ASSERT(plastic_elem.dimension() == 1);
285 FRICTIONQPOTFEM_ASSERT(plastic_K.dimension() == 2);
286 FRICTIONQPOTFEM_ASSERT(plastic_K.shape(0) == plastic_elem.size());
287 FRICTIONQPOTFEM_ASSERT(plastic_G.dimension() == 2);
288 FRICTIONQPOTFEM_ASSERT(plastic_G.shape(0) == plastic_elem.size());
289 FRICTIONQPOTFEM_ASSERT(plastic_epsy.dimension() == 3);
290 FRICTIONQPOTFEM_ASSERT(plastic_epsy.shape(0) == plastic_elem.size());
291
292 m_inc = 0;
293 m_full_outdated = true;
294
295 m_coor = coor;
298
299 array_type::tensor<size_t, 2> conn_elas = xt::view(conn, xt::keep(m_elem_elas), xt::all());
300 array_type::tensor<size_t, 2> conn_plas = xt::view(conn, xt::keep(m_elem_plas), xt::all());
301
302 m_nnode = m_coor.shape(0);
303 m_ndim = m_coor.shape(1);
304 m_nelem = conn.shape(0);
305 m_nne = conn.shape(1);
306
307 m_nelem_elas = m_elem_elas.size();
308 m_nelem_plas = m_elem_plas.size();
310
311#ifdef FRICTIONQPOTFEM_ENABLE_ASSERT
312 // check that "elem_plastic" and "elem_plastic" together span all elements
313 array_type::tensor<size_t, 1> elem = xt::concatenate(xt::xtuple(m_elem_elas, m_elem_plas));
314 FRICTIONQPOTFEM_ASSERT(xt::sort(elem) == xt::arange<size_t>(m_nelem));
315 // check that all "iip" or in "dofs"
316 FRICTIONQPOTFEM_ASSERT(xt::all(xt::isin(iip, dofs)));
317#endif
318
322
326 m_nip = m_quad.nip();
327
328 FRICTIONQPOTFEM_ASSERT(elastic_K.shape(1) == m_nip);
329 FRICTIONQPOTFEM_ASSERT(elastic_G.shape(1) == m_nip);
330 FRICTIONQPOTFEM_ASSERT(plastic_K.shape(1) == m_nip);
331 FRICTIONQPOTFEM_ASSERT(plastic_G.shape(1) == m_nip);
332 FRICTIONQPOTFEM_ASSERT(plastic_epsy.shape(1) == m_nip);
333
339
346
356
357 m_Eps = m_quad.allocate_qtensor<2>(0.0);
358 m_Sig = m_quad.allocate_qtensor<2>(0.0);
360
363
364 m_K_elas = GooseFEM::Matrix(conn_elas, dofs);
365
366 // allocated to strain-free state, matching #m_u
368 m_plas = GMatElastoPlasticQPot::Cartesian2d::Cusp<2>(plastic_K, plastic_G, plastic_epsy);
369
371
372 this->setDt(dt);
373 this->setRho(rho);
374 this->setAlpha(alpha);
375 this->setEta(eta);
376 }
381public:
385 virtual size_t N() const
386 {
387 return m_nelem_plas;
388 }
389
390public:
394 virtual std::string type() const
395 {
396 return "FrictionQPotFEM.Generic2d.System";
397 }
398
399public:
406 double rho() const
407 {
408 return m_rho;
409 }
410
411public:
417 void setRho(double rho)
418 {
419 return this->setMassMatrix(xt::eval(rho * xt::ones<double>({m_nelem})));
420 }
421
422public:
430 template <class T>
431 void setMassMatrix(const T& val_elem)
432 {
433 FRICTIONQPOTFEM_ASSERT(val_elem.size() == m_nelem);
434
435 if (xt::allclose(val_elem, val_elem(0))) {
436 m_rho = val_elem(0);
437 }
438 else {
439 m_rho = 0.0;
440 }
441
446
447 array_type::tensor<double, 2> val_quad = xt::empty<double>({m_nelem, nodalQuad.nip()});
448 for (size_t q = 0; q < nodalQuad.nip(); ++q) {
449 xt::view(val_quad, xt::all(), q) = val_elem;
450 }
451
452 m_M.assemble(nodalQuad.Int_N_scalar_NT_dV(val_quad));
453 }
454
455public:
461 void setEta(double eta)
462 {
463 if (detail::is_same(eta, 0.0)) {
464 m_set_visco = false;
465 m_eta = 0.0;
466 }
467 else {
468 m_set_visco = true;
469 m_eta = eta;
470 }
471 }
472
473public:
478 double eta() const
479 {
480 return m_eta;
481 }
482
483public:
489 void setAlpha(double alpha)
490 {
491 if (detail::is_same(alpha, 0.0)) {
492 m_set_D = false;
493 m_alpha = 0.0;
494 return;
495 }
496
497 return this->setDampingMatrix(xt::eval(alpha * xt::ones<double>({m_nelem})));
498 }
499
500public:
507 double alpha() const
508 {
509 return m_alpha;
510 }
511
512public:
520 template <class T>
521 void setDampingMatrix(const T& val_elem)
522 {
523 FRICTIONQPOTFEM_ASSERT(val_elem.size() == m_nelem);
524 m_set_D = true;
525
526 if (xt::allclose(val_elem, val_elem(0))) {
527 m_alpha = val_elem(0);
528 if (detail::is_same(m_alpha, 0.0)) {
529 m_set_D = false;
530 }
531 }
532 else {
533 m_alpha = 0.0;
534 }
535
540
541 array_type::tensor<double, 2> val_quad = xt::empty<double>({m_nelem, nodalQuad.nip()});
542 for (size_t q = 0; q < nodalQuad.nip(); ++q) {
543 xt::view(val_quad, xt::all(), q) = val_elem;
544 }
545
546 m_D.assemble(nodalQuad.Int_N_scalar_NT_dV(val_quad));
547 }
548
549public:
555 {
556 auto k = this->K();
557 auto g = this->G();
558
559 return xt::allclose(k, k.data()[0]) && xt::allclose(g, g.data()[0]);
560 }
561
562public:
566 double dt() const
567 {
568 return m_dt;
569 }
570
574 void setDt(double dt)
575 {
576 m_dt = dt;
577 }
578
579public:
585 template <class T>
586 void setU(const T& u)
587 {
588 FRICTIONQPOTFEM_ASSERT(xt::has_shape(u, {m_nnode, m_ndim}));
589 xt::noalias(m_u) = u;
590 m_full_outdated = true;
591 this->updated_u();
592 }
593
594public:
600 template <class T>
601 void setV(const T& v)
602 {
603 FRICTIONQPOTFEM_ASSERT(xt::has_shape(v, {m_nnode, m_ndim}));
604 xt::noalias(m_v) = v;
605 this->updated_v();
606 }
607
608public:
614 template <class T>
615 void setA(const T& a)
616 {
617 FRICTIONQPOTFEM_ASSERT(xt::has_shape(a, {m_nnode, m_ndim}));
618 xt::noalias(m_a) = a;
619 }
620
621public:
626 virtual void updated_u()
627 {
628 this->computeForceMaterial();
629 }
630
636 {
637 if (m_set_D) {
638 m_D.dot(m_v, m_fdamp);
639 }
640
641 // m_ue_plas, m_fe_plas, m_ftmp are temporaries that can be reused
642 if (m_set_visco) {
646 if (!m_set_D) {
648 m_fdamp *= m_eta;
649 }
650 else {
652 m_ftmp *= m_eta;
653 m_fdamp += m_ftmp;
654 }
655 }
656 }
657
658public:
666 template <class T>
667 void setFext(const T& fext)
668 {
669 FRICTIONQPOTFEM_ASSERT(xt::has_shape(fext, {m_nnode, m_ndim}));
670 xt::noalias(m_fext) = fext;
671 }
672
673public:
678 const auto& elastic_elem() const
679 {
680 return m_elem_elas;
681 }
682
683public:
688 const auto& plastic_elem() const
689 {
690 return m_elem_plas;
691 }
692
693public:
698 const auto& conn() const
699 {
700 return m_vector.conn();
701 }
702
703public:
708 const auto& coor() const
709 {
710 return m_coor;
711 }
712
713public:
718 const auto& dofs() const
719 {
720 return m_vector.dofs();
721 }
722
723public:
728 const auto& u() const
729 {
730 return m_u;
731 }
732
733public:
738 const auto& v() const
739 {
740 return m_v;
741 }
742
743public:
748 const auto& a() const
749 {
750 return m_a;
751 }
752
753public:
758 auto& mass() const
759 {
760 return m_M;
761 }
762
763public:
769 auto& damping() const
770 {
771 return m_D;
772 }
773
774public:
779 const auto& fext()
780 {
782 return m_fext;
783 }
784
789 void applyShearStress(double sigxy)
790 {
791 double t = m_coor(m_coor.shape(0) - 1, 1);
792 double b = m_coor(0, 1);
793 auto top = xt::sort(
794 xt::flatten_indices(xt::argwhere(xt::isclose(xt::view(m_coor, xt::all(), 1), t))));
795 auto bot = xt::sort(
796 xt::flatten_indices(xt::argwhere(xt::isclose(xt::view(m_coor, xt::all(), 1), b))));
797 double h = m_coor(top(1), 0) - m_coor(top(0), 0);
798
799 for (size_t i = 0; i < top.size() - 1; i++) {
800 FRICTIONQPOTFEM_REQUIRE(xt::allclose(m_coor(top(i + 1), 0) - m_coor(top(i), 0), h));
801 }
802
803 for (size_t d = 0; d < 2; d++) {
804 auto dofs = xt::view(m_vector.dofs(), xt::keep(top), d);
805 if (d == 0) {
806 FRICTIONQPOTFEM_REQUIRE(!xt::any(xt::in1d(dofs, m_vector.iip())));
807 }
808 else {
809 FRICTIONQPOTFEM_REQUIRE(xt::all(xt::in1d(dofs, m_vector.iip())));
810 }
811 }
812
813 for (size_t d = 0; d < 2; d++) {
814 auto dofs = xt::view(m_vector.dofs(), xt::keep(bot), d);
815 FRICTIONQPOTFEM_REQUIRE(xt::all(xt::in1d(dofs, m_vector.iip())));
816 }
817
818 m_fext(top.front(), 0) = 0.5 * sigxy * h;
819 m_fext(top.back(), 0) = 0.5 * sigxy * h;
820
821 for (size_t i = 1; i < top.size() - 1; i++) {
822 m_fext(top(i), 0) = sigxy * h;
823 }
824 }
825
826public:
831 const auto& fint()
832 {
834 return m_fint;
835 }
836
837public:
842 const auto& fmaterial() const
843 {
844 return m_fmaterial;
845 }
846
847public:
854 const auto& fdamp() const
855 {
856 return m_fdamp;
857 }
858
859public:
865 double residual() const
866 {
867 double r_fres = xt::norm_l2(m_fres)();
868 double r_fext = xt::norm_l2(m_fext)();
869 if (r_fext != 0.0) {
870 return r_fres / r_fext;
871 }
872 return r_fres;
873 }
874
875public:
880 void quench()
881 {
882 m_v.fill(0.0);
883 m_a.fill(0.0);
884 this->updated_v();
885 }
886
887public:
891 double t() const
892 {
893 return m_inc * m_dt;
894 }
895
899 void setT(double arg)
900 {
901 this->setInc(static_cast<size_t>(std::round(arg / m_dt)));
902 FRICTIONQPOTFEM_REQUIRE(xt::allclose(this->t(), arg));
903 }
904
909 size_t inc() const
910 {
911 return m_inc;
912 }
913
918 virtual void setInc(size_t arg)
919 {
920 m_inc = arg;
921 }
922
923public:
928 const auto& dV() const
929 {
930 return m_quad.dV();
931 }
932
933public:
939 {
940 return m_vector;
941 }
942
943public:
950 {
951 return m_quad;
952 }
953
954public:
960 {
961 return m_elas;
962 }
963
964public:
970 {
971 return m_plas;
972 }
973
974public:
981 {
982 array_type::tensor<double, 2> ret = xt::empty<double>({m_nelem, m_nip});
983
984 const auto& ret_elas = m_elas.K();
985 const auto& ret_plas = m_plas.K();
986 size_t n = xt::strides(ret_elas, 0);
988
989 for (size_t e = 0; e < m_nelem_elas; ++e) {
990 std::copy(
991 &ret_elas(e, xt::missing),
992 &ret_elas(e, xt::missing) + n,
993 &ret(m_elem_elas(e), xt::missing));
994 }
995
996 for (size_t e = 0; e < m_nelem_plas; ++e) {
997 std::copy(
998 &ret_plas(e, xt::missing),
999 &ret_plas(e, xt::missing) + n,
1000 &ret(m_elem_plas(e), xt::missing));
1001 }
1002
1003 return ret;
1004 }
1005
1006public:
1013 {
1014 array_type::tensor<double, 2> ret = xt::empty<double>({m_nelem, m_nip});
1015
1016 const auto& ret_elas = m_elas.G();
1017 const auto& ret_plas = m_plas.G();
1018 size_t n = xt::strides(ret_elas, 0);
1020
1021 for (size_t e = 0; e < m_nelem_elas; ++e) {
1022 std::copy(
1023 &ret_elas(e, xt::missing),
1024 &ret_elas(e, xt::missing) + n,
1025 &ret(m_elem_elas(e), xt::missing));
1026 }
1027
1028 for (size_t e = 0; e < m_nelem_plas; ++e) {
1029 std::copy(
1030 &ret_plas(e, xt::missing),
1031 &ret_plas(e, xt::missing) + n,
1032 &ret(m_elem_plas(e), xt::missing));
1033 }
1034
1035 return ret;
1036 }
1037
1038public:
1044 {
1045 this->computeEpsSig();
1046 return m_Sig;
1047 }
1048
1049public:
1055 {
1056 this->computeEpsSig();
1057 return m_Eps;
1058 }
1059
1060public:
1067 {
1069 }
1070
1071public:
1077 {
1079 }
1080
1081public:
1088 {
1089 auto ret = m_quad.allocate_qtensor<4>(0.0);
1090 const auto& ret_plas = m_plas.C();
1091 const auto& ret_elas = m_elas.C();
1092 size_t n = xt::strides(ret_elas, 0);
1093 FRICTIONQPOTFEM_ASSERT(n == m_nip * 16);
1094
1095 for (size_t e = 0; e < m_nelem_elas; ++e) {
1096 std::copy(
1097 &ret_elas(e, xt::missing),
1098 &ret_elas(e, xt::missing) + n,
1099 &ret(m_elem_elas(e), xt::missing));
1100 }
1101
1102 for (size_t e = 0; e < m_nelem_plas; ++e) {
1103 std::copy(
1104 &ret_plas(e, xt::missing),
1105 &ret_plas(e, xt::missing) + n,
1106 &ret(m_elem_plas(e), xt::missing));
1107 }
1108
1111 return K;
1112 }
1113
1114public:
1120 {
1121 // m_ue_plas, m_fe_plas are temporaries that can be reused
1122 if (!m_set_visco) {
1125 }
1126
1127 return m_Epsdot_plas;
1128 }
1129
1130protected:
1135 {
1136 if (!m_full_outdated) {
1137 return;
1138 }
1139
1140 auto& Eps_elas = m_elas.Eps();
1141 auto& Sig_elas = m_elas.Sig();
1142 const auto& Eps_plas = m_plas.Eps();
1143 const auto& Sig_plas = m_plas.Sig();
1144
1147 m_elas.refresh();
1148
1149 size_t n = xt::strides(Eps_elas, 0);
1150 FRICTIONQPOTFEM_ASSERT(n == m_nip * 4);
1151
1152 for (size_t e = 0; e < m_nelem_elas; ++e) {
1153 std::copy(
1154 &Eps_elas(e, xt::missing),
1155 &Eps_elas(e, xt::missing) + n,
1156 &m_Eps(m_elem_elas(e), xt::missing));
1157 std::copy(
1158 &Sig_elas(e, xt::missing),
1159 &Sig_elas(e, xt::missing) + n,
1160 &m_Sig(m_elem_elas(e), xt::missing));
1161 }
1162 for (size_t e = 0; e < m_nelem_plas; ++e) {
1163 std::copy(
1164 &Eps_plas(e, xt::missing),
1165 &Eps_plas(e, xt::missing) + n,
1166 &m_Eps(m_elem_plas(e), xt::missing));
1167 std::copy(
1168 &Sig_plas(e, xt::missing),
1169 &Sig_plas(e, xt::missing) + n,
1170 &m_Sig(m_elem_plas(e), xt::missing));
1171 }
1172
1173 m_full_outdated = false;
1174 }
1175
1180 {
1181 m_full_outdated = true;
1182
1185 m_plas.refresh();
1188
1190
1191 xt::noalias(m_fmaterial) = m_felas + m_fplas;
1192 }
1193
1194protected:
1204 {
1205 xt::noalias(m_fint) = m_fmaterial + m_fdamp;
1207 xt::noalias(m_fres) = m_fext - m_fint;
1208 }
1209
1210public:
1215 void refresh()
1216 {
1217 this->updated_u();
1218 this->updated_v();
1220 }
1221
1222public:
1233 template <class T>
1234 double eventDriven_setDeltaU(const T& delta_u, bool autoscale = true)
1235 {
1236 FRICTIONQPOTFEM_ASSERT(xt::has_shape(delta_u, m_u.shape()));
1237 m_pert_u = delta_u;
1238
1242
1243 if (!autoscale) {
1244 return 1.0;
1245 }
1246
1248 auto d = xt::amin(xt::diff(m_plas.epsy(), 1))();
1249 double c = 0.1 * d / deps;
1250
1251 m_pert_u *= c;
1253
1254 return c;
1255 }
1256
1261 const auto& eventDriven_deltaU() const
1262 {
1263 return m_pert_u;
1264 }
1265
1300 virtual double eventDrivenStep(
1301 double deps,
1302 bool kick,
1303 int direction = 1,
1304 bool yield_element = false,
1305 bool iterative = false)
1306 {
1307 FRICTIONQPOTFEM_ASSERT(xt::has_shape(m_pert_u, m_u.shape()));
1308 FRICTIONQPOTFEM_ASSERT(direction == 1 || direction == -1);
1309
1311 auto Epsd_plastic = GMatTensor::Cartesian2d::Deviatoric(m_plas.Eps());
1312 auto idx = m_plas.i();
1313 const auto& epsy_l = m_plas.epsy_left();
1314 const auto& epsy_r = m_plas.epsy_right();
1315
1316 FRICTIONQPOTFEM_WIP(iterative || direction > 0 || !xt::any(xt::equal(idx, 0)));
1317
1319
1320 if (direction > 0 && kick) { // direction > 0 && kick
1321 target = epsy_r + 0.5 * deps;
1322 }
1323 else if (direction > 0) { // direction > 0 && !kick
1324 target = epsy_r - 0.5 * deps;
1325 }
1326 else if (kick) { // direction < 0 && kick
1327 target = epsy_l - 0.5 * deps;
1328 }
1329 else { // direction < 0 && !kick
1330 target = epsy_l + 0.5 * deps;
1331 }
1332
1333 if (!kick) {
1334 auto d = target - eps;
1335 if (direction > 0 && xt::any(d < 0.0)) {
1336 return 0.0;
1337 }
1338 if (direction < 0 && xt::any(d > 0.0)) {
1339 return 0.0;
1340 }
1341 }
1342
1343 auto scale = xt::empty_like(target);
1344
1345 for (size_t e = 0; e < m_nelem_plas; ++e) {
1346 for (size_t q = 0; q < m_nip; ++q) {
1347
1348 double e_t = Epsd_plastic(e, q, 0, 0);
1349 double g_t = Epsd_plastic(e, q, 0, 1);
1350 double e_d = m_pert_Epsd_plastic(e, q, 0, 0);
1351 double g_d = m_pert_Epsd_plastic(e, q, 0, 1);
1352 double epsd_target = target(e, q);
1353
1354 double a = e_d * e_d + g_d * g_d;
1355 double b = 2.0 * (e_t * e_d + g_t * g_d);
1356 double c = e_t * e_t + g_t * g_t - epsd_target * epsd_target;
1357 double D = std::sqrt(b * b - 4.0 * a * c);
1358
1359 FRICTIONQPOTFEM_REQUIRE(b >= 0.0 || iterative);
1360 scale(e, q) = (-b + D) / (2.0 * a);
1361 }
1362 }
1363
1364 if (kick) {
1365 size_t nyield = m_plas.epsy().shape(m_plas.epsy().dimension() - 1);
1366 size_t bound = direction > 0 ? nyield - 2 : 0;
1367 if (xt::all(xt::equal(idx, bound))) {
1368 return 0.0;
1369 }
1370 scale = xt::where(xt::equal(idx, bound), std::numeric_limits<double>::max(), scale);
1371 }
1372
1373 double ret;
1374 size_t e;
1375 size_t q;
1376
1377 if (!iterative) {
1378
1379 auto index = xt::unravel_index(xt::argmin(xt::abs(scale))(), scale.shape());
1380 e = index[0];
1381 q = index[1];
1382
1383 if (kick && yield_element) {
1384 q = xt::argmax(xt::view(xt::abs(scale), e, xt::all()))();
1385 }
1386
1387 ret = scale(e, q);
1388
1389 if ((direction > 0 && ret < 0) || (direction < 0 && ret > 0)) {
1390 if (!kick) {
1391 return 0.0;
1392 }
1393 else {
1395 (direction > 0 && ret > 0) || (direction < 0 && ret < 0));
1396 }
1397 }
1398 }
1399
1400 else {
1401
1402 double dir = static_cast<double>(direction);
1403 auto steps = xt::sort(xt::ravel(xt::eval(xt::abs(scale))));
1404 auto u_n = m_u;
1405 xt::xtensor<long, 2> jdx = xt::cast<long>(m_plas.i());
1406 size_t i;
1407 long nip = static_cast<long>(m_nip);
1408
1409 // find first step that:
1410 // if (!kick || (kick && !yield_element)): is plastic for the first time
1411 // if (kick && yield_element): yields the element for the first time
1412
1413 for (i = 0; i < steps.size(); ++i) {
1414 this->setU(u_n + dir * steps(i) * m_pert_u);
1415 auto jdx_new = xt::cast<long>(m_plas.i());
1416 auto S = xt::abs(jdx_new - jdx);
1417 if (!yield_element || !kick) {
1418 if (xt::any(S > 0)) {
1419 break;
1420 }
1421 }
1422 else {
1423 if (xt::any(xt::equal(xt::sum(S > 0, 1), nip))) {
1424 break;
1425 }
1426 }
1427 }
1428
1429 // iterate to acceptable step
1430
1431 double right = steps(i);
1432 double left = 0.0;
1433 ret = right;
1434
1435 if (i > 0) {
1436 left = steps(i - 1);
1437 }
1438
1439 // iterate to actual step
1440
1441 for (size_t step = 0; step < 1100; ++step) {
1442
1443 ret = 0.5 * (right + left);
1444 this->setU(u_n + dir * ret * m_pert_u);
1445 auto jdx_new = xt::cast<long>(m_plas.i());
1446 auto S = xt::abs(jdx_new - jdx);
1447
1448 if (!kick) {
1449 if (xt::any(S > 0)) {
1450 right = ret;
1451 }
1452 else {
1453 left = ret;
1454 }
1455 }
1456 else if (yield_element) {
1457 if (xt::any(xt::equal(xt::sum(S > 0, 1), nip))) {
1458 right = ret;
1459 }
1460 else {
1461 left = ret;
1462 }
1463 }
1464 else {
1465 if (xt::any(S > 0)) {
1466 right = ret;
1467 }
1468 else {
1469 left = ret;
1470 }
1471 }
1472
1473 if ((right - left) / left < 1e-5) {
1474 break;
1475 }
1476 FRICTIONQPOTFEM_REQUIRE(step < 1000);
1477 }
1478
1479 // final assertion: make sure that "left" and "right" are still bounds
1480
1481 {
1482 this->setU(u_n + dir * left * m_pert_u);
1483 auto jdx_new = xt::cast<long>(m_plas.i());
1484 auto S = xt::abs(jdx_new - jdx);
1485
1486 FRICTIONQPOTFEM_REQUIRE(kick || xt::all(xt::equal(S, 0)));
1487 if (kick && yield_element) {
1488 FRICTIONQPOTFEM_REQUIRE(!xt::any(xt::equal(xt::sum(S > 0, 1), nip)));
1489 }
1490 else if (kick) {
1491 FRICTIONQPOTFEM_REQUIRE(xt::all(xt::equal(S, 0)));
1492 }
1493 }
1494 {
1495 this->setU(u_n + dir * right * m_pert_u);
1496 auto jdx_new = xt::cast<long>(m_plas.i());
1497 auto S = xt::abs(jdx_new - jdx);
1498 FRICTIONQPOTFEM_REQUIRE(!xt::all(xt::equal(S, 0)));
1499
1500 FRICTIONQPOTFEM_REQUIRE(kick || !xt::all(xt::equal(S, 0)));
1501 if (kick && yield_element) {
1502 FRICTIONQPOTFEM_REQUIRE(xt::any(xt::equal(xt::sum(S > 0, 1), nip)));
1503 }
1504 else if (kick) {
1505 FRICTIONQPOTFEM_REQUIRE(xt::any(S > 0));
1506 }
1507 }
1508
1509 // "output"
1510
1511 if (!kick) {
1512 ret = dir * left;
1513 }
1514 else {
1515 ret = dir * right;
1516 }
1517 this->setU(u_n);
1518 FRICTIONQPOTFEM_REQUIRE((direction > 0 && ret >= 0) || (direction < 0 && ret <= 0));
1519 }
1520
1521 this->setU(m_u + ret * m_pert_u);
1522
1523 const auto& idx_new = m_plas.i();
1524 FRICTIONQPOTFEM_REQUIRE(kick || xt::all(xt::equal(idx, idx_new)));
1525 FRICTIONQPOTFEM_REQUIRE(!kick || xt::any(xt::not_equal(idx, idx_new)));
1526
1527 if (!iterative) {
1528 auto eps_new = GMatElastoPlasticQPot::Cartesian2d::Epsd(m_plas.Eps())(e, q);
1529 auto eps_target = target(e, q);
1530 FRICTIONQPOTFEM_REQUIRE(xt::allclose(eps_new, eps_target));
1531 }
1532
1533 return ret;
1534 }
1535
1542 {
1543 // history
1544
1545 m_inc++;
1546 xt::noalias(m_v_n) = m_v;
1547 xt::noalias(m_a_n) = m_a;
1548
1549 // new displacement
1550
1551 xt::noalias(m_u) = m_u + m_dt * m_v + 0.5 * std::pow(m_dt, 2.0) * m_a;
1552 this->updated_u();
1553
1554 // estimate new velocity, update corresponding force
1555
1556 xt::noalias(m_v) = m_v_n + m_dt * m_a_n;
1557 this->updated_v();
1558
1559 // compute residual force & solve
1560
1562 m_M.solve(m_fres, m_a);
1563
1564 // re-estimate new velocity, update corresponding force
1565
1566 xt::noalias(m_v) = m_v_n + 0.5 * m_dt * (m_a_n + m_a);
1567 this->updated_v();
1568
1569 // compute residual force & solve
1570
1572 m_M.solve(m_fres, m_a);
1573
1574 // new velocity, update corresponding force
1575
1576 xt::noalias(m_v) = m_v_n + 0.5 * m_dt * (m_a_n + m_a);
1577 this->updated_v();
1578
1579 // compute residual force & solve
1580
1582 m_M.solve(m_fres, m_a);
1583 }
1584
1601 long timeSteps(size_t n, size_t nmargin = 0)
1602 {
1603 FRICTIONQPOTFEM_REQUIRE(n + 1 < std::numeric_limits<long>::max());
1604
1605 size_t nyield = m_plas.epsy().shape(2);
1606 size_t nmax = nyield - nmargin;
1607 long step;
1608
1609 FRICTIONQPOTFEM_ASSERT(nmargin < nyield);
1610 FRICTIONQPOTFEM_REQUIRE(xt::all(m_plas.i() <= nmax));
1611
1612 for (step = 1; step < static_cast<long>(n + 1); ++step) {
1613
1614 this->timeStep();
1615
1616 if (nmargin > 0) {
1617 if (xt::any(m_plas.i() > nmax)) {
1618 return -step;
1619 }
1620 }
1621 }
1622
1623 return step;
1624 }
1625
1639 size_t nmargin = 0,
1640 double tol = 1e-5,
1641 size_t niter_tol = 20,
1642 size_t max_iter = 1e7)
1643 {
1644 FRICTIONQPOTFEM_ASSERT(tol < 1.0);
1645 FRICTIONQPOTFEM_ASSERT(max_iter + 1 < std::numeric_limits<long>::max());
1646
1647 double tol2 = tol * tol;
1648 GooseFEM::Iterate::StopList residuals(niter_tol);
1649 size_t nyield = m_plas.epsy().shape(2);
1650 size_t nmax = nyield - nmargin;
1651 auto i_n = m_plas.i();
1652 size_t step;
1653
1654 FRICTIONQPOTFEM_ASSERT(nmargin < nyield);
1655 FRICTIONQPOTFEM_REQUIRE(xt::all(m_plas.i() <= nmax));
1656
1657 for (step = 1; step < max_iter + 1; ++step) {
1658
1659 this->timeStep();
1660
1661 if (xt::any(xt::not_equal(m_plas.i(), i_n))) {
1662 return step;
1663 }
1664
1665 residuals.roll_insert(this->residual());
1666
1667 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1668 this->quench();
1669 return 0;
1670 }
1671 }
1672
1673 return step;
1674 }
1675
1698 std::tuple<
1703 const array_type::tensor<size_t, 1>& nodes,
1705 size_t t_step = 1,
1706 size_t nmargin = 0,
1707 double tol = 1e-5,
1708 size_t niter_tol = 20,
1709 size_t max_iter = 1e7)
1710 {
1711 FRICTIONQPOTFEM_ASSERT(tol < 1.0);
1712 FRICTIONQPOTFEM_ASSERT(max_iter + 1 < std::numeric_limits<long>::max());
1713
1714 double tol2 = tol * tol;
1715 GooseFEM::Iterate::StopList residuals(niter_tol);
1716
1717 size_t nyield = m_plas.epsy().shape(2);
1718 size_t nmax = nyield - nmargin;
1719
1720 FRICTIONQPOTFEM_ASSERT(nmargin < nyield);
1721 FRICTIONQPOTFEM_REQUIRE(xt::all(m_plas.i() <= nmax));
1722 FRICTIONQPOTFEM_REQUIRE(nmargin == 0 || xt::all(m_plas.i() >= nmargin));
1723
1724 std::vector<double> fext;
1725 std::vector<std::vector<double>> ux(nodes.size());
1726 std::vector<std::vector<double>> uy(nodes.size());
1727
1728 for (size_t step = 1; step < max_iter + 1; ++step) {
1729
1730 this->timeStep();
1731 residuals.roll_insert(this->residual());
1732
1733 if (step % t_step == 0) {
1734
1735 double f = 0.0;
1736 for (auto& n : top) {
1737 f += m_fext(n, 0);
1738 }
1739 fext.push_back(f / static_cast<double>(top.size() - 1)); // account for periodicity
1740
1741 for (size_t i = 0; i < nodes.size(); ++i) {
1742 size_t n = nodes(i);
1743 ux[i].push_back(m_u(n, 0));
1744 uy[i].push_back(m_u(n, 1));
1745 }
1746 }
1747
1748 if (nmargin > 0) {
1749 if (xt::any(m_plas.i() > nmax) || xt::any(m_plas.i() < nmargin)) {
1750 throw std::runtime_error("Out of bounds");
1751 }
1752 }
1753
1754 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1755 this->quench();
1756
1757 size_t n = fext.size();
1758 array_type::tensor<double, 1> ret_fext = xt::empty<double>({n});
1759 std::copy(fext.begin(), fext.end(), ret_fext.begin());
1760 fext.resize(0);
1761
1762 array_type::tensor<double, 2> ret_ux = xt::empty<double>({nodes.size(), n});
1763 for (size_t i = 0; i < nodes.size(); ++i) {
1764 std::copy(ux[i].begin(), ux[i].end(), ret_ux.begin() + i * n);
1765 }
1766 ux.resize(0);
1767
1768 array_type::tensor<double, 2> ret_uy = xt::empty<double>({nodes.size(), n});
1769 for (size_t i = 0; i < nodes.size(); ++i) {
1770 std::copy(uy[i].begin(), uy[i].end(), ret_uy.begin() + i * n);
1771 }
1772 uy.resize(0);
1773
1774 return std::make_tuple(ret_fext, ret_ux, ret_uy);
1775 }
1776 }
1777
1778 throw std::runtime_error("No convergence found");
1779 }
1780
1802 template <class T>
1803 long flowSteps(size_t n, const T& v, size_t nmargin = 0)
1804 {
1805 FRICTIONQPOTFEM_ASSERT(xt::has_shape(v, m_u.shape()));
1806 FRICTIONQPOTFEM_REQUIRE(n + 1 < std::numeric_limits<long>::max());
1807
1808 size_t nyield = m_plas.epsy().shape(2);
1809 size_t nmax = nyield - nmargin;
1810 long step;
1811
1812 FRICTIONQPOTFEM_ASSERT(nmargin < nyield);
1813 FRICTIONQPOTFEM_REQUIRE(xt::all(m_plas.i() <= nmax));
1814
1815 for (step = 1; step < static_cast<long>(n + 1); ++step) {
1816
1817 m_u += v * m_dt;
1818 this->timeStep();
1819
1820 if (nmargin > 0) {
1821 if (xt::any(m_plas.i() > nmax)) {
1822 return -step;
1823 }
1824 }
1825 }
1826
1827 return step;
1828 }
1829
1869 size_t nmargin = 0,
1870 double tol = 1e-5,
1871 size_t niter_tol = 20,
1872 size_t max_iter = 1e7,
1873 bool time_activity = false,
1874 bool max_iter_is_error = true)
1875 {
1876 FRICTIONQPOTFEM_ASSERT(tol < 1.0);
1877 FRICTIONQPOTFEM_ASSERT(max_iter + 1 < std::numeric_limits<long>::max());
1878
1879 double tol2 = tol * tol;
1880 GooseFEM::Iterate::StopList residuals(niter_tol);
1881
1882 size_t nyield = m_plas.epsy().shape(2);
1883 size_t nmax = nyield - nmargin;
1884 array_type::tensor<long, 2> i_n = xt::cast<long>(m_plas.i());
1885 long s = 0;
1886 long s_n = 0;
1887 bool init = true;
1888 long step;
1889
1890 FRICTIONQPOTFEM_ASSERT(nmargin < nyield);
1891 FRICTIONQPOTFEM_REQUIRE(xt::all(m_plas.i() <= nmax));
1892
1893 for (step = 1; step < static_cast<long>(max_iter + 1); ++step) {
1894
1895 this->timeStep();
1896 residuals.roll_insert(this->residual());
1897
1898 if (nmargin > 0) {
1899 if (xt::any(m_plas.i() > nmax)) {
1900 return -step;
1901 }
1902 }
1903
1904 if (time_activity) {
1905 array_type::tensor<long, 2> i = xt::cast<long>(m_plas.i());
1906 s = xt::sum(xt::abs(i - i_n))();
1907 if (s != s_n) {
1908 if (init) {
1909 init = false;
1911 }
1913 }
1914 s_n = s;
1915 }
1916
1917 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1918 this->quench();
1919 return 0;
1920 }
1921 }
1922
1923 if (max_iter_is_error) {
1924 throw std::runtime_error("No convergence found");
1925 }
1926
1927 return step;
1928 }
1929
1937 {
1938 return m_qs_inc_first;
1939 }
1940
1948 {
1949 return m_qs_inc_last;
1950 }
1951
1961 template <class T>
1963 const T& idx_n,
1964 size_t A_truncate = 0,
1965 size_t S_truncate = 0,
1966 double tol = 1e-5,
1967 size_t niter_tol = 20,
1968 size_t max_iter = 1e7)
1969 {
1970 FRICTIONQPOTFEM_REQUIRE(xt::has_shape(idx_n, std::array<size_t, 1>{m_N}));
1971 FRICTIONQPOTFEM_REQUIRE(S_truncate == 0);
1972 FRICTIONQPOTFEM_REQUIRE(A_truncate > 0);
1973 FRICTIONQPOTFEM_ASSERT(tol < 1.0);
1974 double tol2 = tol * tol;
1975 GooseFEM::Iterate::StopList residuals(niter_tol);
1976
1977 for (size_t step = 1; step < max_iter + 1; ++step) {
1978
1979 this->timeStep();
1980 residuals.roll_insert(this->residual());
1981
1982 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1983 this->quench();
1984 return step;
1985 }
1986
1987 array_type::tensor<size_t, 1> idx = xt::view(m_plas.i(), xt::all(), 0);
1988
1989 if (static_cast<size_t>(xt::sum(xt::not_equal(idx_n, idx))()) >= A_truncate) {
1990 return 0;
1991 }
1992 }
1993
1994 std::cout << "residuals = " << xt::adapt(residuals.data()) << std::endl;
1995 bool converged = false;
1996 FRICTIONQPOTFEM_REQUIRE(converged == true);
1997 return 0; // irrelevant, the code never goes here
1998 }
1999
2024 size_t A_truncate = 0,
2025 size_t S_truncate = 0,
2026 double tol = 1e-5,
2027 size_t niter_tol = 20,
2028 size_t max_iter = 1e7)
2029 {
2030 array_type::tensor<size_t, 1> idx_n = xt::view(m_plas.i(), xt::all(), 0);
2031 return this->minimise_truncate(idx_n, A_truncate, S_truncate, tol, niter_tol, max_iter);
2032 }
2033
2042 {
2043 array_type::tensor<double, 2> ret = xt::zeros_like(m_u);
2044
2045 for (size_t n = 0; n < m_nnode; ++n) {
2046 ret(n, 0) += 2.0 * delta_gamma * (m_coor(n, 1) - m_coor(0, 1));
2047 }
2048
2049 return ret;
2050 }
2051
2062 {
2063 array_type::tensor<double, 2> ret = xt::zeros_like(m_u);
2064 size_t ll = m_vector.conn()(m_elem_plas(0), 0);
2065 size_t ul = m_vector.conn()(m_elem_plas(0), 3);
2066 double y0 = (m_coor(ul, 1) + m_coor(ll, 1)) / 2.0;
2067
2068 for (size_t n = 0; n < m_nnode; ++n) {
2069 ret(n, 0) += 2.0 * delta_gamma * (m_coor(n, 1) - y0);
2070 }
2071
2072 return ret;
2073 }
2074
2075protected:
2077 size_t m_N;
2078 size_t m_nelem;
2081 size_t m_nne;
2082 size_t m_nnode;
2083 size_t m_ndim;
2084 size_t m_nip;
2097
2105
2113
2136 size_t m_qs_inc_first = 0;
2137 size_t m_qs_inc_last = 0;
2138 size_t m_inc;
2139 double m_dt;
2140 double m_eta;
2141 double m_rho;
2142 double m_alpha;
2143 bool m_set_D;
2148};
2149
2150} // namespace Generic2d
2151} // namespace FrictionQPotFEM
2152
2153#endif
Basic include of common methods.
Sparse matrix that is partitioned in:
System with elastic elements and plastic elements (GMatElastoPlasticQPot).
Definition: Generic2d.h:183
long minimise(size_t nmargin=0, double tol=1e-5, size_t niter_tol=20, size_t max_iter=1e7, bool time_activity=false, bool max_iter_is_error=true)
Minimise energy: run System::timeStep until a mechanical equilibrium has been reached.
Definition: Generic2d.h:1868
size_t m_nelem_elas
Number of elastic elements.
Definition: Generic2d.h:2079
const GooseFEM::Element::Quad4::Quadrature & quad() const
GooseFEM quadrature definition.
Definition: Generic2d.h:949
array_type::tensor< double, 3 > m_ue_elas
m_ue for elastic element only
Definition: Generic2d.h:2119
size_t m_nne
Number of nodes per element.
Definition: Generic2d.h:2081
array_type::tensor< double, 2 > m_fext
Nodal force: total external force (reaction force)
Definition: Generic2d.h:2130
double eta() const
Get the damping at the interface.
Definition: Generic2d.h:478
double m_rho
Mass density (non-zero only if homogeneous).
Definition: Generic2d.h:2141
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
void computeEpsSig()
Compute m_Sig and m_Eps using m_u.
Definition: Generic2d.h:1134
array_type::tensor< double, 4 > m_Eps
Quad-point tensor: strain.
Definition: Generic2d.h:2132
array_type::tensor< size_t, 1 > m_elem_elas
Elastic elements.
Definition: Generic2d.h:2085
long flowSteps(size_t n, const T &v, size_t nmargin=0)
Make a number of steps with the following protocol.
Definition: Generic2d.h:1803
const array_type::tensor< double, 4 > & Eps()
Strain tensor of each integration point.
Definition: Generic2d.h:1054
array_type::tensor< double, 2 > m_fmaterial
Nodal force, deriving from elasticity.
Definition: Generic2d.h:2123
void setFext(const T &fext)
Overwrite external force.
Definition: Generic2d.h:667
const auto & dV() const
Integration point volume (of each integration point)
Definition: Generic2d.h:928
size_t minimise_truncate(size_t A_truncate=0, size_t S_truncate=0, double tol=1e-5, size_t niter_tol=20, size_t max_iter=1e7)
Like Generic2d::minimise(), but stops when a certain number of blocks has yielded at least once.
Definition: Generic2d.h:2023
size_t minimise_truncate(const T &idx_n, size_t A_truncate=0, size_t S_truncate=0, double tol=1e-5, size_t niter_tol=20, size_t max_iter=1e7)
Like Generic2d::minimise(), but stops when a certain number of blocks has yielded at least once.
Definition: Generic2d.h:1962
auto & damping() const
Damping matrix, see setAlpha() and setDampingMatrix().
Definition: Generic2d.h:769
const auto & elastic_elem() const
List of elastic elements.
Definition: Generic2d.h:678
void setMassMatrix(const T &val_elem)
Overwrite mass matrix, based on certain density that is uniform per element.
Definition: Generic2d.h:431
void setDt(double dt)
Overwrite time step.
Definition: Generic2d.h:574
array_type::tensor< double, 4 > m_pert_Epsd_plastic
Strain deviator for m_pert_u.
Definition: Generic2d.h:2147
void setV(const T &v)
Overwrite nodal velocities.
Definition: Generic2d.h:601
array_type::tensor< double, 2 > m_pert_u
See eventDriven_setDeltaU()
Definition: Generic2d.h:2146
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
array_type::tensor< double, 2 > m_a_n
Nodal accelerations last time-step.
Definition: Generic2d.h:2116
void setAlpha(double alpha)
Overwrite background damping density (proportional to the velocity), To use a non-homogeneous density...
Definition: Generic2d.h:489
const auto & v() const
Nodal velocities.
Definition: Generic2d.h:738
GooseFEM::Element::Quad4::Quadrature m_quad_elas
m_quad for elastic elements only.
Definition: Generic2d.h:2088
size_t m_qs_inc_last
Last increment with plastic activity during minimisation.
Definition: Generic2d.h:2137
size_t m_nelem
Number of elements.
Definition: Generic2d.h:2078
GooseFEM::Element::Quad4::Quadrature m_quad_plas
m_quad for plastic elements only.
Definition: Generic2d.h:2089
array_type::tensor< double, 2 > m_felas
Nodal force from elasticity of elastic elements.
Definition: Generic2d.h:2124
void quench()
Set nodal velocities and accelerations equal to zero.
Definition: Generic2d.h:880
const auto & fdamp() const
Force deriving from damping.
Definition: Generic2d.h:854
size_t m_N
Number of plastic elements, alias of m_nelem_plas.
Definition: Generic2d.h:2077
std::tuple< array_type::tensor< double, 1 >, array_type::tensor< double, 2 >, array_type::tensor< double, 2 > > minimise_highfrequency(const array_type::tensor< size_t, 1 > &nodes, const array_type::tensor< size_t, 1 > &top, size_t t_step=1, size_t nmargin=0, double tol=1e-5, size_t niter_tol=20, size_t max_iter=1e7)
Minimise energy while doing a high-frequency measurement of:
Definition: Generic2d.h:1702
size_t m_qs_inc_first
First increment with plastic activity during minimisation.
Definition: Generic2d.h:2136
const array_type::tensor< double, 4 > & plastic_Epsdot()
Strain-rate tensor of integration points of plastic elements only, see System::plastic.
Definition: Generic2d.h:1119
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.
Definition: Generic2d.h:215
array_type::tensor< double, 2 > m_a
Nodal accelerations.
Definition: Generic2d.h:2114
array_type::tensor< double, 3 > m_ue_plas
m_ue for plastic element only
Definition: Generic2d.h:2121
array_type::tensor< double, 2 > m_fres
Nodal force: residual force.
Definition: Generic2d.h:2131
GooseFEM::MatrixDiagonalPartitioned m_M
Mass matrix (diagonal).
Definition: Generic2d.h:2093
GooseFEM::VectorPartitioned m_vector_plas
m_vector for plastic elements only.
Definition: Generic2d.h:2092
array_type::tensor< double, 2 > m_fplas
Nodal force from elasticity of plastic elements.
Definition: Generic2d.h:2125
double residual() const
Norm of the relative residual force (the external force at the top/bottom boundaries is used for norm...
Definition: Generic2d.h:865
void setEta(double eta)
Overwrite the value of the damping at the interface.
Definition: Generic2d.h:461
void updated_v()
Evaluate relevant forces when m_v is updated.
Definition: Generic2d.h:635
double eventDriven_setDeltaU(const T &delta_u, bool autoscale=true)
Set purely elastic and linear response to specific boundary conditions.
Definition: Generic2d.h:1234
array_type::tensor< double, 3 > m_fe
Element vector (used for forces).
Definition: Generic2d.h:2118
array_type::tensor< double, 4 > m_Epsdot_plas
Quad-point tensor: strain-rate for plastic el.
Definition: Generic2d.h:2134
const auto & plastic_elem() const
List of plastic elements.
Definition: Generic2d.h:688
array_type::tensor< double, 2 > m_ftmp
Temporary for internal use.
Definition: Generic2d.h:2128
array_type::tensor< double, 3 > m_ue
Element vector (used for displacements).
Definition: Generic2d.h:2117
size_t m_ndim
Number of spatial dimensions.
Definition: Generic2d.h:2083
size_t m_inc
Current increment (current time = m_dt * m_inc).
Definition: Generic2d.h:2138
const auto & u() const
Nodal displacements.
Definition: Generic2d.h:728
GooseFEM::MatrixPartitioned stiffness() const
Stiffness tensor of each integration point.
Definition: Generic2d.h:1087
const auto & a() const
Nodal accelerations.
Definition: Generic2d.h:748
GMatElastoPlasticQPot::Cartesian2d::Cusp< 2 > & plastic()
Elastic material mode, used for all elastic elements.
Definition: Generic2d.h:969
double m_alpha
Background damping density (non-zero only if homogeneous).
Definition: Generic2d.h:2142
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
double t() const
Current time.
Definition: Generic2d.h:891
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
array_type::tensor< double, 3 > m_fe_elas
m_fe for elastic element only
Definition: Generic2d.h:2120
const auto & fmaterial() const
Force deriving from elasticity.
Definition: Generic2d.h:842
array_type::tensor< double, 4 > m_Sig
Quad-point tensor: stress.
Definition: Generic2d.h:2133
array_type::tensor< double, 2 > m_v
Nodal velocities.
Definition: Generic2d.h:2112
virtual size_t N() const
Return the linear system size (in number of blocks).
Definition: Generic2d.h:385
const auto & coor() const
Nodal coordinates.
Definition: Generic2d.h:708
GooseFEM::Matrix m_K_elas
Stiffness matrix for elastic elements only.
Definition: Generic2d.h:2135
bool m_set_visco
Use m_eta only if it is non-zero.
Definition: Generic2d.h:2144
void computeForceMaterial()
Update m_fmaterial based on the current displacement field m_u.
Definition: Generic2d.h:1179
size_t quasistaticActivityLast() const
Increment with the last plastic event.
Definition: Generic2d.h:1947
array_type::tensor< double, 2 > m_fint
Nodal force: total internal force.
Definition: Generic2d.h:2129
virtual void setInc(size_t arg)
Set increment.
Definition: Generic2d.h:918
const auto & conn() const
Connectivity.
Definition: Generic2d.h:698
void applyShearStress(double sigxy)
Modify the external force such that a shear stress is applied to the top boundary.
Definition: Generic2d.h:789
GooseFEM::Element::Quad4::Quadrature m_quad
Quadrature for all elements.
Definition: Generic2d.h:2087
array_type::tensor< double, 2 > m_fdamp
Nodal force from damping.
Definition: Generic2d.h:2126
double dt() const
Get time step.
Definition: Generic2d.h:566
array_type::tensor< double, 2 > m_u
Nodal displacements.
Definition: Generic2d.h:2104
double m_eta
Damping at the interface.
Definition: Generic2d.h:2140
virtual void computeInternalExternalResidualForce()
Compute:
Definition: Generic2d.h:1203
void setT(double arg)
Overwrite time.
Definition: Generic2d.h:899
GooseFEM::VectorPartitioned m_vector
Convert vectors between 'nodevec', 'elemvec', ....
Definition: Generic2d.h:2090
GooseFEM::MatrixDiagonal m_D
Damping matrix (diagonal).
Definition: Generic2d.h:2094
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
array_type::tensor< double, 2 > m_fvisco
Nodal force from damping at the interface.
Definition: Generic2d.h:2127
array_type::tensor< double, 3 > m_fe_plas
m_fe for plastic element only
Definition: Generic2d.h:2122
const auto & dofs() const
DOFs per node.
Definition: Generic2d.h:718
bool m_full_outdated
Keep track of the need to recompute fields on full geometry.
Definition: Generic2d.h:2145
const auto & fext()
External force.
Definition: Generic2d.h:779
size_t inc() const
The increment, see setInc().
Definition: Generic2d.h:909
bool m_set_D
Use m_D only if it is non-zero.
Definition: Generic2d.h:2143
virtual std::string type() const
Return the type of system.
Definition: Generic2d.h:394
long timeSteps(size_t n, size_t nmargin=0)
Make a number of time steps, see timeStep().
Definition: Generic2d.h:1601
bool isHomogeneousElastic() const
Check if elasticity is homogeneous.
Definition: Generic2d.h:554
void refresh()
Recompute all forces.
Definition: Generic2d.h:1215
virtual double eventDrivenStep(double deps, bool kick, int direction=1, bool yield_element=false, bool iterative=false)
Add event driven step for the boundary conditions that correspond to the displacement perturbation se...
Definition: Generic2d.h:1300
const auto & eventDriven_deltaU() const
Get displacement perturbation used for event driven code, see eventDriven_setDeltaU().
Definition: Generic2d.h:1261
double alpha() const
Background damping density.
Definition: Generic2d.h:507
void setRho(double rho)
Overwrite the mass density to a homogeneous quantity.
Definition: Generic2d.h:417
void setA(const T &a)
Overwrite nodal accelerations.
Definition: Generic2d.h:615
const auto & fint()
Internal force.
Definition: Generic2d.h:831
auto & mass() const
Mass matrix, see System::m_M.
Definition: Generic2d.h:758
void setDampingMatrix(const T &val_elem)
Overwrite damping matrix, based on certain density (taken uniform per element).
Definition: Generic2d.h:521
const GooseFEM::VectorPartitioned & vector() const
GooseFEM vector definition.
Definition: Generic2d.h:938
size_t quasistaticActivityFirst() const
Increment with the first plastic event.
Definition: Generic2d.h:1936
size_t m_nip
Number of integration points.
Definition: Generic2d.h:2084
GooseFEM::VectorPartitioned m_vector_elas
m_vector for elastic elements only.
Definition: Generic2d.h:2091
array_type::tensor< double, 4 > Epsddot() const
Symmetric gradient of the nodal accelerations of each integration point.
Definition: Generic2d.h:1076
GMatElastoPlasticQPot::Cartesian2d::Elastic< 2 > m_elas
Material for elastic el.
Definition: Generic2d.h:2095
virtual void updated_u()
Evaluate relevant forces when m_u is updated.
Definition: Generic2d.h:626
array_type::tensor< double, 2 > m_v_n
Nodal velocities last time-step.
Definition: Generic2d.h:2115
array_type::tensor< double, 2 > affineSimpleShearCentered(double delta_gamma) const
Get the displacement field that corresponds to an affine simple shear of a certain strain.
Definition: Generic2d.h:2061
size_t timeStepsUntilEvent(size_t nmargin=0, double tol=1e-5, size_t niter_tol=20, size_t max_iter=1e7)
Perform a series of time-steps until the next plastic event, or equilibrium.
Definition: Generic2d.h:1638
void timeStep()
Make a time-step: apply velocity-Verlet integration.
Definition: Generic2d.h:1541
size_t m_nelem_plas
Number of plastic elements.
Definition: Generic2d.h:2080
GMatElastoPlasticQPot::Cartesian2d::Elastic< 2 > & elastic()
Elastic material mode, used for all elastic elements.
Definition: Generic2d.h:959
array_type::tensor< double, 4 > Epsdot() const
Strain-rate tensor (the symmetric gradient of the nodal velocities) of each integration point.
Definition: Generic2d.h:1066
Array of material points with an elasto-plastic material model.
Definition: Cartesian2d.h:342
const array_type::tensor< size_t, N > & i() const
Index of the current yield strain per item.
Definition: Cartesian2d.h:436
const array_type::tensor< double, N+1 > & epsy() const
Yield strains per item.
Definition: Cartesian2d.h:401
void refresh(bool compute_tangent=true) override
Recompute stress from strain.
Definition: Cartesian2d.h:499
array_type::tensor< double, N > epsy_right() const
Current yield strain right per item.
Definition: Cartesian2d.h:471
array_type::tensor< double, N > epsy_left() const
Current yield strain left per item.
Definition: Cartesian2d.h:455
Array of material points with a linear elastic constitutive response.
Definition: Cartesian2d.h:122
const array_type::tensor< double, N+2 > & Sig() const
Stress tensor per item.
Definition: Cartesian2d.h:291
const array_type::tensor< double, N > & G() const
Shear modulus per item.
Definition: Cartesian2d.h:206
const array_type::tensor< double, N+4 > & C() const
Tangent tensor per item.
Definition: Cartesian2d.h:300
const array_type::tensor< double, N+2 > & Eps() const
Strain tensor per item.
Definition: Cartesian2d.h:272
virtual void refresh(bool compute_tangent=true)
Recompute stress from strain.
Definition: Cartesian2d.h:246
const array_type::tensor< double, N > & K() const
Bulk modulus per item.
Definition: Cartesian2d.h:197
Interpolation and quadrature.
Definition: ElementQuad4.h:237
auto Int_N_scalar_NT_dV(const T &qscalar) const -> array_type::tensor< double, 3 >
Element-by-element: integral of the scalar product of the shape function with a scalar.
Definition: Element.h:768
auto SymGradN_vector(const T &elemvec) const -> array_type::tensor< double, 4 >
The symmetric output of GradN_vector().
Definition: Element.h:697
void symGradN_vector(const T &elemvec, R &qtensor) const
Same as SymGradN_vector(), but writing to preallocated return.
Definition: Element.h:711
void int_gradN_dot_tensor2_dV(const T &qtensor, R &elemvec) const
Same as Int_gradN_dot_tensor2_dV(), but writing to preallocated return.
Definition: Element.h:819
auto dV() const -> const array_type::tensor< double, 2 > &
Integration volume.
Definition: Element.h:581
auto Int_gradN_dot_tensor4_dot_gradNT_dV(const T &qtensor) const -> array_type::tensor< double, 3 >
Element-by-element: integral of the dot products of the shape function gradients with a fourth order ...
Definition: Element.h:847
auto nip() const
Number of integration points.
Definition: Element.h:201
auto allocate_qtensor() const
Get an allocated array_type::tensor to store a "qtensor" of a certain rank (0 = scalar,...
Definition: Element.h:441
Class to perform a residual check based on the last "n" iterations.
Definition: Iterate.h:27
void roll_insert(double res)
Roll the list with the residuals, and add a new residual to the end.
Definition: Iterate.h:69
bool all_less(double tol) const
Check of the sequence of n residuals are all below a tolerance.
Definition: Iterate.h:91
bool descending() const
Check of the sequence of n residuals is in descending order.
Definition: Iterate.h:80
const std::vector< double > & data() const
Get the historic residuals.
Definition: Iterate.h:99
void assemble(const T &elemmat)
Assemble from "elemmat".
Definition: Matrix.h:327
void dot(const array_type::tensor< double, 2 > &x, array_type::tensor< double, 2 > &b) const
Dot-product .
Definition: Matrix.h:390
void solve(const array_type::tensor< double, 2 > &b, array_type::tensor< double, 2 > &x)
Solve .
Diagonal and partitioned matrix.
Sparse matrix partitioned in an unknown and a prescribed part.
Sparse matrix.
Definition: Matrix.h:650
Class to switch between storage types, based on a mesh and DOFs that are partitioned in:
const array_type::tensor< size_t, 1 > & iip() const
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":
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
void assembleNode(const T &arg, R &ret) const
Assemble "elemvec" to "nodevec" (adds entries that occur more that once.
Definition: Vector.h:260
array_type::tensor< double, 2 > allocate_nodevec() const
Allocated "nodevec".
Definition: Vector.h:334
array_type::tensor< double, 3 > AsElement(const T &arg) const
Convert "dofval" or "nodevec" to "elemvec" (overwrite entries that occur more than once).
Definition: Vector.h:194
array_type::tensor< double, 3 > allocate_elemvec() const
Allocated "elemvec".
Definition: Vector.h:358
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
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
array_type::tensor< double, 2 > moduli_toquad(const array_type::tensor< double, 1 > &arg, size_t nip=GooseFEM::Element::Quad4::Gauss::nip())
Broadcast array of moduli stored per element [nelem] to be the same for all quadrature points,...
Definition: Generic2d.h:101
array_type::tensor< double, 3 > epsy_initelastic_toquad(const array_type::tensor< double, 2 > &arg, size_t nip=GooseFEM::Element::Quad4::Gauss::nip())
Convert array of yield strains stored per element [nelem, n]:
Definition: Generic2d.h:77
T::value_type getuniform(const T &arg)
Extract uniform value (throw if not uniform):
Definition: Generic2d.h:126
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 Deviatoric(const T &A)
Deviatoric part of a tensor:
Definition: Cartesian2d.h:706
std::vector< std::string > version_dependencies(bool greedy=true)
Return versions of this library and of all of its major dependencies.
Definition: version.h:79
std::vector< std::string > version_compiler()
Return information on the compiler, the platform, the C++ standard, and the compilation data.
Definition: version.h:245
array_type::tensor< double, 1 > w()
Integration point weights.
Definition: ElementHex8.h:92
size_t nip()
Number of integration points:
Definition: ElementQuad4.h:45
array_type::tensor< double, 1 > w()
Integration point weights.
Definition: ElementQuad4.h:149
array_type::tensor< double, 2 > xi()
Integration point coordinates (local coordinates).
Definition: ElementQuad4.h:122
bool is_unique(const T &arg)
Returns true is a list is unique (has not duplicate items).
Definition: assertions.h:20
#define FRICTIONQPOTFEM_REQUIRE(expr)
Assertions that cannot be disabled.
Definition: config.h:70
#define FRICTIONQPOTFEM_WIP(expr)
Assertions on a implementation limitation (that in theory can be resolved)
Definition: config.h:77
#define FRICTIONQPOTFEM_ASSERT(expr)
All assertions are implementation as::
Definition: config.h:62