FrictionQPotSpringBlock v0.22.7
Loading...
Searching...
No Matches
detail.h
Go to the documentation of this file.
1
7#ifndef FRICTIONQPOTSPRINGBLOCK_DETAIL_H
8#define FRICTIONQPOTSPRINGBLOCK_DETAIL_H
9
10#include <string>
11
12#include <xtensor/xadapt.hpp>
13#include <xtensor/xnorm.hpp>
14#include <xtensor/xtensor.hpp>
15
16#include "config.h"
17
18#include <GooseFEM/Iterate.h>
19#include <GooseFEM/version.h>
20#include <prrng.h>
21
22#include <GMatTensor/version.h>
23
25
26namespace detail {
27
31inline prrng::distribution string_to_distribution(const std::string& str)
32{
33 if (str == "random") {
34 return prrng::distribution::random;
35 }
36
37 if (str == "delta") {
38 return prrng::distribution::delta;
39 }
40
41 if (str == "exponential") {
42 return prrng::distribution::exponential;
43 }
44
45 if (str == "power") {
46 return prrng::distribution::power;
47 }
48
49 if (str == "gamma") {
50 return prrng::distribution::gamma;
51 }
52
53 if (str == "pareto") {
54 return prrng::distribution::pareto;
55 }
56
57 if (str == "weibull") {
58 return prrng::distribution::weibull;
59 }
60
61 if (str == "normal") {
62 return prrng::distribution::normal;
63 }
64
65 throw std::runtime_error("Unknown distribution: " + str);
66}
67
74template <class U, class Y, class I>
75inline bool check_disorder(const U& u, const Y& yield, const I& i)
76{
77 if (i.dimension() != 1 || yield.dimension() != 2) {
78 return false;
79 }
80
81 if (u.size() != i.size() || u.size() != yield.shape(0)) {
82 return false;
83 }
84
85 using index_type = typename I::value_type;
86 index_type n = static_cast<ptrdiff_t>(yield.shape(1));
87
88 for (size_t p = 0; p < yield.shape(0); ++p) {
89 if (i(p) <= 0 || i(p) >= n - 2) {
90 return false;
91 }
92
93 if (u.flat(p) < yield(p, i(p)) || u.flat(p) > yield(p, i(p) + 1)) {
94 return false;
95 }
96
97 if (!std::is_sorted(&yield(p, 0), &yield(p, 0) + yield.shape(1))) {
98 return false;
99 }
100 }
101
102 return true;
103}
104
113template <class Generator>
114class Cuspy {
115protected:
116 using stype = typename Generator::size_type;
118 double m_mu;
119 Generator* m_chunk;
120
121public:
122 Cuspy() = default;
123
129 Cuspy(double mu, Generator* chunk) : m_mu(mu), m_chunk(chunk)
130 {
131 m_N = m_chunk->generators().size();
132 }
133
139 template <class T>
140 void force(const T& u, T& f)
141 {
142 FRICTIONQPOTSPRINGBLOCK_DEBUG((stype)u.size() == m_N && (stype)f.size() == m_N);
143
144 m_chunk->align(u);
145
146 // this does not allocate data, but only creates a view
147 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
148 m_chunk->data().data(),
149 m_chunk->data().size(),
150 xt::no_ownership(),
151 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
152 );
153
154 // this does not allocate data, but only creates a view
155 xt::xtensor_pointer<const ptrdiff_t, 1> i = xt::adapt(
156 m_chunk->chunk_index_at_align().data(),
157 m_chunk->chunk_index_at_align().size(),
158 xt::no_ownership(),
159 std::array<stype, 1>{m_N}
160 );
161
163
164 for (stype p = 0; p < m_N; ++p) {
165 const auto* l = &yield(p, i(p));
166 f.flat(p) = 0.5 * (*(l) + *(l + 1)) - u.flat(p);
167 }
168
169 f *= m_mu;
170 }
171
176 template <class T>
177 double maxUniformDisplacement(const T& u, int direction) const
178 {
179 FRICTIONQPOTSPRINGBLOCK_DEBUG(direction == 1 || direction == -1);
180 m_chunk->align(u);
181
182 if (direction > 0) {
183 return xt::amin(m_chunk->template right_of_align<T>() - u)();
184 }
185
186 return xt::amin(u - m_chunk->template left_of_align<T>())();
187 }
188
193 template <class T>
194 void trigger(T& u, size_t p, double eps, int direction) const
195 {
197 m_chunk->align(u);
198
199 if (direction > 0) {
200 u.flat(p) = m_chunk->template right_of_align<T>().flat(p) + 0.5 * eps;
201 }
202 else {
203 u.flat(p) = m_chunk->template left_of_align<T>().flat(p) - 0.5 * eps;
204 }
205 }
206};
207
212template <class Generator>
214protected:
215 using stype = typename Generator::size_type;
217 double m_mu;
218 double m_kappa;
219 Generator* m_chunk;
220
221public:
222 SemiSmooth() = default;
223
228 SemiSmooth(double mu, double kappa, Generator* chunk) : m_mu(mu), m_kappa(kappa), m_chunk(chunk)
229 {
230 m_N = m_chunk->generators().size();
231 }
232
236 template <class T>
237 void force(const T& u, T& f)
238 {
239 FRICTIONQPOTSPRINGBLOCK_DEBUG((stype)u.size() == m_N && (stype)f.size() == m_N);
240
241 m_chunk->align(u);
242
243 // this does not allocate data, but only creates a view
244 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
245 m_chunk->data().data(),
246 m_chunk->data().size(),
247 xt::no_ownership(),
248 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
249 );
250
251 // this does not allocate data, but only creates a view
252 xt::xtensor_pointer<const ptrdiff_t, 1> i = xt::adapt(
253 m_chunk->chunk_index_at_align().data(),
254 m_chunk->chunk_index_at_align().size(),
255 xt::no_ownership(),
256 std::array<stype, 1>{m_N}
257 );
258
260
261 for (stype p = 0; p < m_N; ++p) {
262 auto* y = &yield(p, i(p));
263 double xi = 0.5 * (*(y) + *(y + 1));
264 double u_r = (m_mu * xi + m_kappa * *(y + 1)) / (m_mu + m_kappa);
265 double u_l = (m_mu * xi + m_kappa * *(y)) / (m_mu + m_kappa);
266 double up = u.flat(p);
267 if (up < u_l) {
268 f.flat(p) = m_kappa * (up - *(y));
269 }
270 else if (up <= u_r) {
271 f.flat(p) = m_mu * (0.5 * (*(y) + *(y + 1)) - up);
272 }
273 else {
274 f.flat(p) = m_kappa * (up - *(y + 1));
275 }
276 }
277 }
278
282 template <class T>
283 double maxUniformDisplacement(const T& u, int direction) const
284 {
285 FRICTIONQPOTSPRINGBLOCK_DEBUG(direction == 1 || direction == -1);
286 m_chunk->align(u);
287
288 bool positive = direction > 0;
289 std::vector<double> du;
290 du.reserve(m_N);
291
292 // this does not allocate data, but only creates a view
293 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
294 m_chunk->data().data(),
295 m_chunk->data().size(),
296 xt::no_ownership(),
297 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
298 );
299
300 // this does not allocate data, but only creates a view
301 xt::xtensor_pointer<const ptrdiff_t, 1> i = xt::adapt(
302 m_chunk->chunk_index_at_align().data(),
303 m_chunk->chunk_index_at_align().size(),
304 xt::no_ownership(),
305 std::array<stype, 1>{m_N}
306 );
307
309
310 for (stype p = 0; p < m_N; ++p) {
311 auto* y = &yield(p, i(p));
312 double xi = 0.5 * (*(y) + *(y + 1));
313 double u_r = (m_mu * xi + m_kappa * *(y + 1)) / (m_mu + m_kappa);
314 double u_l = (m_mu * xi + m_kappa * *(y)) / (m_mu + m_kappa);
315 double up = u.flat(p);
316
317 if (up < u_l) {
318 return 0.0;
319 }
320 else if (up <= u_r) {
321 if (positive) {
322 du.push_back(u_r - up);
323 }
324 else {
325 du.push_back(up - u_l);
326 }
327 }
328 else {
329 return 0.0;
330 }
331 }
332
333 return *std::min_element(du.begin(), du.end());
334 }
335
339 template <class T>
340 void trigger(T& u, size_t p, double eps, int direction) const
341 {
343
344 if (direction > 0) {
345 u.flat(p) = m_chunk->template right_of_align<T>().flat(p) + 0.5 * eps;
346 }
347 else {
348 u.flat(p) = m_chunk->template left_of_align<T>().flat(p) - 0.5 * eps;
349 }
350 }
351};
352
356template <class Generator>
357class Smooth {
358protected:
359 using stype = typename Generator::size_type;
361 double m_mu;
362 Generator* m_chunk;
363
364public:
365 Smooth() = default;
366
371 Smooth(double mu, Generator* chunk) : m_mu(mu), m_chunk(chunk)
372 {
373 m_N = m_chunk->generators().size();
374 }
375
379 template <class T>
380 void force(const T& u, T& f)
381 {
382 FRICTIONQPOTSPRINGBLOCK_DEBUG((stype)u.size() == m_N && (stype)f.size() == m_N);
383
384 m_chunk->align(u);
385
386 // this does not allocate data, but only creates a view
387 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
388 m_chunk->data().data(),
389 m_chunk->data().size(),
390 xt::no_ownership(),
391 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
392 );
393
394 // this does not allocate data, but only creates a view
395 xt::xtensor_pointer<const ptrdiff_t, 1> i = xt::adapt(
396 m_chunk->chunk_index_at_align().data(),
397 m_chunk->chunk_index_at_align().size(),
398 xt::no_ownership(),
399 std::array<stype, 1>{m_N}
400 );
401
402 for (stype p = 0; p < m_N; ++p) {
403 auto* y = &yield(p, i(p));
404 double up = u.flat(p);
405 double umin = 0.5 * (*(y) + *(y + 1));
406 double dy = 0.5 * (*(y + 1) - *(y));
407 f.flat(p) = -m_mu * dy / M_PI * std::sin(M_PI * (up - umin) / dy);
408 }
409 }
410
414 template <class T>
415 double maxUniformDisplacement(const T& u, int direction) const
416 {
417 FRICTIONQPOTSPRINGBLOCK_DEBUG(direction == 1 || direction == -1);
418 (void)(u);
419 (void)(direction);
420 throw std::runtime_error("Operation not possible.");
421 return 0.0;
422 }
423
427 template <class T>
428 void trigger(T& u, size_t p, double eps, int direction) const
429 {
431
432 if (direction > 0) {
433 u.flat(p) = m_chunk->template right_of_align<T>().flat(p) + 0.5 * eps;
434 }
435 else {
436 u.flat(p) = m_chunk->template left_of_align<T>().flat(p) - 0.5 * eps;
437 }
438 }
439};
440
447protected:
449 double m_k;
450
451public:
452 Laplace1d() = default;
453
458 Laplace1d(double k, size_type N) : m_N(N), m_k(k)
459 {
460 }
461
466 double k() const
467 {
468 return m_k;
469 }
470
474 template <class T>
475 void force(const T& u, T& f)
476 {
477 FRICTIONQPOTSPRINGBLOCK_DEBUG(u.dimension() == 1 && f.dimension() == 1);
478 FRICTIONQPOTSPRINGBLOCK_DEBUG((size_type)u.size() == m_N && (size_type)f.size() == m_N);
479
480 for (size_type p = 1; p < m_N - 1; ++p) {
481 f(p) = u(p - 1) - 2 * u(p) + u(p + 1);
482 }
483 f.front() = u.back() - 2 * u.front() + u(1);
484 f.back() = u(m_N - 2) - 2 * u.back() + u.front();
485
486 f *= m_k;
487 }
488};
489
525protected:
528 double m_k;
529
530public:
531 Laplace2d() = default;
532
538 Laplace2d(double k, size_type rows, size_type cols) : m_rows(rows), m_cols(cols), m_k(k)
539 {
540 }
541
545 template <class T>
546 void force(const T& u, T& f)
547 {
548 FRICTIONQPOTSPRINGBLOCK_DEBUG(u.dimension() == 2 && f.dimension() == 2);
549 FRICTIONQPOTSPRINGBLOCK_DEBUG(xt::has_shape(u, f.shape()));
551 (size_type)u.shape(0) == m_rows && (size_type)u.shape(1) == m_cols
552 );
553
554 std::array<size_type, 2> edge_rows = {0, m_rows - 1};
555 std::array<size_type, 2> edge_cols = {0, m_cols - 1};
556
557 // first and last row, all columns
558 for (size_type r = 0; r < 2; ++r) {
559 for (size_type j = 0; j < m_cols; ++j) {
560 size_type i = edge_rows[r];
561 f(i, j) = u.periodic(i - 1, j) + u.periodic(i + 1, j) + u.periodic(i, j - 1) +
562 u.periodic(i, j + 1) - 4 * u(i, j);
563 }
564 }
565
566 // first and last column, 'interior' rows
567 for (size_type i = 1; i < m_rows - 1; ++i) {
568 for (size_type c = 0; c < 2; ++c) {
569 size_type j = edge_cols[c];
570 f(i, j) = u.periodic(i - 1, j) + u.periodic(i + 1, j) + u.periodic(i, j - 1) +
571 u.periodic(i, j + 1) - 4 * u(i, j);
572 }
573 }
574
575 // interior
576 for (size_type i = 1; i < m_rows - 1; ++i) {
577 for (size_type j = 1; j < m_cols - 1; ++j) {
578 f(i, j) = u(i - 1, j) + u(i + 1, j) + u(i, j - 1) + u(i, j + 1) - 4 * u(i, j);
579 }
580 }
581
582 f *= m_k;
583 }
584};
585
617protected:
619 double m_k2;
620 double m_k4;
621 double m_k4_4;
622
623public:
624 QuarticGradient1d() = default;
625
631 QuarticGradient1d(double k2, double k4, size_type N)
632 : m_N(N), m_k2(k2), m_k4(k4), m_k4_4(0.25 * k4)
633 {
634 }
635
639 template <class T>
640 void force(const T& u, T& f)
641 {
642 for (size_type p = 1; p < m_N - 1; ++p) {
643 double du = u(p + 1) - u(p - 1);
644 f(p) = (u(p - 1) - 2 * u(p) + u(p + 1)) * (m_k2 + m_k4_4 * du * du);
645 }
646
647 double duf = u(1) - u.back();
648 f.front() = (u.back() - 2 * u.front() + u(1)) * (m_k2 + m_k4_4 * duf * duf);
649
650 double dub = u.front() - u(m_N - 2);
651 f.back() = (u(m_N - 2) - 2 * u.back() + u.front()) * (m_k2 + m_k4_4 * dub * dub);
652 }
653};
654
659protected:
662 double m_k2;
663 double m_k4;
664
665public:
666 QuarticGradient2d() = default;
667
674 QuarticGradient2d(double k2, double k4, size_type rows, size_type cols)
675 : m_rows(rows), m_cols(cols), m_k2(k2), m_k4(k4)
676 {
677 }
678
682 template <class T>
683 void force(const T& u, T& f)
684 {
685 FRICTIONQPOTSPRINGBLOCK_DEBUG(u.dimension() == 2 && f.dimension() == 2);
686 FRICTIONQPOTSPRINGBLOCK_DEBUG(xt::has_shape(u, f.shape()));
688 (size_type)u.shape(0) == m_rows && (size_type)u.shape(1) == m_cols
689 );
690
691 double mk4_3 = m_k4 / 3.0;
692 double mk4_23 = 2.0 * mk4_3;
693 std::array<size_type, 2> edge_rows = {0, m_rows - 1};
694 std::array<size_type, 2> edge_cols = {0, m_cols - 1};
695
696 // first and last row, all columns
697 for (size_type r = 0; r < 2; ++r) {
698 for (size_type j = 0; j < m_cols; ++j) {
699 size_type i = edge_rows[r];
700 double l = u.periodic(i + 1, j) + u.periodic(i - 1, j) + u.periodic(i, j + 1) +
701 u.periodic(i, j - 1) - 4 * u(i, j);
702 double dudx = 0.5 * (u.periodic(i + 1, j) - u.periodic(i - 1, j));
703 double dudy = 0.5 * (u.periodic(i, j + 1) - u.periodic(i, j - 1));
704 double d2udxdy = 0.25 * (u.periodic(i + 1, j + 1) - u.periodic(i + 1, j - 1) -
705 u.periodic(i - 1, j + 1) + u.periodic(i - 1, j - 1));
706 double d2udx2 = u.periodic(i + 1, j) - 2 * u(i, j) + u.periodic(i - 1, j);
707 double d2udy2 = u.periodic(i, j + 1) - 2 * u(i, j) + u.periodic(i, j - 1);
708
709 f(i, j) =
710 l * (m_k2 + mk4_3) + mk4_23 * (dudx * dudx * d2udx2 + dudy * dudy * d2udy2 +
711 2.0 * dudx * dudy * d2udxdy);
712 }
713 }
714
715 // first and last column, 'interior' rows
716 for (size_type i = 1; i < m_rows - 1; ++i) {
717 for (size_type c = 0; c < 2; ++c) {
718 size_type j = edge_cols[c];
719 double l = u.periodic(i + 1, j) + u.periodic(i - 1, j) + u.periodic(i, j + 1) +
720 u.periodic(i, j - 1) - 4 * u(i, j);
721 double dudx = 0.5 * (u.periodic(i + 1, j) - u.periodic(i - 1, j));
722 double dudy = 0.5 * (u.periodic(i, j + 1) - u.periodic(i, j - 1));
723 double d2udxdy = 0.25 * (u.periodic(i + 1, j + 1) - u.periodic(i + 1, j - 1) -
724 u.periodic(i - 1, j + 1) + u.periodic(i - 1, j - 1));
725 double d2udx2 = u.periodic(i + 1, j) - 2 * u(i, j) + u.periodic(i - 1, j);
726 double d2udy2 = u.periodic(i, j + 1) - 2 * u(i, j) + u.periodic(i, j - 1);
727
728 f(i, j) =
729 l * (m_k2 + mk4_3) + mk4_23 * (dudx * dudx * d2udx2 + dudy * dudy * d2udy2 +
730 2.0 * dudx * dudy * d2udxdy);
731 }
732 }
733
734 // interior
735 for (size_type i = 1; i < m_rows - 1; ++i) {
736 for (size_type j = 1; j < m_cols - 1; ++j) {
737 double l = u(i + 1, j) + u(i - 1, j) + u(i, j + 1) + u(i, j - 1) - 4 * u(i, j);
738 double dudx = 0.5 * (u(i + 1, j) - u(i - 1, j));
739 double dudy = 0.5 * (u(i, j + 1) - u(i, j - 1));
740 double d2udxdy =
741 0.25 * (u(i + 1, j + 1) - u(i + 1, j - 1) - u(i - 1, j + 1) + u(i - 1, j - 1));
742 double d2udx2 = u(i + 1, j) - 2 * u(i, j) + u(i - 1, j);
743 double d2udy2 = u(i, j + 1) - 2 * u(i, j) + u(i, j - 1);
744
745 f(i, j) =
746 l * (m_k2 + mk4_3) + mk4_23 * (dudx * dudx * d2udx2 + dudy * dudy * d2udy2 +
747 2.0 * dudx * dudy * d2udxdy);
748 }
749 }
750 }
751};
752
758protected:
760 double m_a1;
761 double m_a2;
762
763public:
764 Quartic1d() = default;
765
771 Quartic1d(double a1, double a2, size_type N) : m_N(N), m_a1(a1), m_a2(a2)
772 {
773 }
774
778 template <class T>
779 void force(const T& u, T& f)
780 {
781 FRICTIONQPOTSPRINGBLOCK_DEBUG(u.dimension() == 1 && f.dimension() == 1);
782 FRICTIONQPOTSPRINGBLOCK_DEBUG((size_type)u.size() == m_N && (size_type)f.size() == m_N);
783
784 for (size_type p = 1; p < m_N - 1; ++p) {
785 double dup = u(p + 1) - u(p);
786 double dun = u(p - 1) - u(p);
787 f(p) = m_a1 * (u(p - 1) - 2 * u(p) + u(p + 1)) +
788 m_a2 * (dup * dup * dup + dun * dun * dun);
789 }
790
791 {
792 double dup = u(1) - u.front();
793 double dun = u.back() - u.front();
794 f.front() = m_a1 * (u.back() - 2 * u.front() + u(1)) +
795 m_a2 * (dup * dup * dup + dun * dun * dun);
796 }
797
798 {
799 double dup = u.front() - u.back();
800 double dun = u(m_N - 2) - u.back();
801 f.back() = m_a1 * (u(m_N - 2) - 2 * u.back() + u.front()) +
802 m_a2 * (dup * dup * dup + dun * dun * dun);
803 }
804 }
805};
806
813protected:
815 double m_k;
816 double m_alpha;
817 ptrdiff_t m_n;
818 ptrdiff_t m_m;
820
821public:
822 LongRange1d() = default;
823
829 LongRange1d(double k, double alpha, size_type N) : m_N(N), m_k(k), m_alpha(alpha)
830 {
831 m_n = static_cast<ptrdiff_t>(m_N);
832 m_m = (m_n - m_n % 2) / 2;
833
834 m_prefactor = xt::empty<double>({m_N});
835
836 for (ptrdiff_t d = 0; d < m_n; ++d) {
837 if (d == 0) {
838 m_prefactor(0) = 0.0;
839 }
840 else {
841 m_prefactor(d) = m_k / std::pow(d, m_alpha + 1.0);
842 }
843 }
844 }
845
849 template <class T>
850 void force(const T& u, T& f)
851 {
852 for (ptrdiff_t p = 0; p < m_n; ++p) {
853 double fp = 0.0;
854 double up = u(p);
855 for (ptrdiff_t i = 0; i < m_n; ++i) {
856 if (i == p) {
857 continue;
858 }
859 ptrdiff_t d = std::abs(i - p);
860 if (d > m_m) {
861 d = m_n - d;
862 }
863 fp += (u(i) - up) * m_prefactor(d);
864 }
865 f(p) = fp;
866 }
867 }
868};
869
881template <size_t rank>
883protected:
884 std::array<size_type, rank> m_shape;
887 double m_mean;
888 double m_stddev;
891 prrng::pcg32 m_rng;
892
893public:
894 RandomNormalForcing() = default;
895
904 template <class T, class S>
906 const S& shape,
907 double mean,
908 double stddev,
909 uint64_t seed,
910 const T& dinc_init,
911 const T& dinc
912 )
913 {
914 std::copy(shape.cbegin(), shape.cend(), m_shape.begin());
915 m_N = std::accumulate(m_shape.cbegin(), m_shape.cend(), 1, std::multiplies<size_type>{});
916 m_f_thermal = xt::zeros<double>(m_shape);
917 m_rng.seed(seed);
918 m_mean = mean;
919 m_stddev = stddev;
920 m_next = dinc_init;
921 m_dinc = dinc;
922 }
923
930 template <class T, class S>
931 void force(const T& u, T& f, S inc)
932 {
933 (void)(u);
934
935 for (size_type p = 0; p < m_N; ++p) {
936 if (inc >= m_next(p)) {
937 m_f_thermal.flat(p) = m_rng.normal(m_mean, m_stddev);
938 m_next.flat(p) += m_dinc.flat(p);
939 }
940 }
941
942 std::copy(m_f_thermal.begin(), m_f_thermal.end(), f.begin());
943 }
944
949 uint64_t state() const
950 {
951 return m_rng.state();
952 }
953
958 void set_state(uint64_t state)
959 {
960 m_rng.restore(state);
961 }
962
967 const auto& f_thermal() const
968 {
969 return m_f_thermal;
970 }
971
981
986 const auto& next()
987 {
988 return m_next;
989 }
990
996 {
997 FRICTIONQPOTSPRINGBLOCK_ASSERT(xt::has_shape(next, m_next.shape()));
998 m_next = next;
999 }
1000};
1001
1006public:
1007 Overdamped()
1008 {
1009 }
1010};
1011
1015class None {
1016public:
1017 None()
1018 {
1019 }
1020};
1021
1046template <
1047 size_t rank,
1048 class Potential,
1049 class Generator,
1050 class Interactions = void,
1051 class External = void,
1052 class Minimisation = void>
1053class System {
1054protected:
1067 ptrdiff_t m_inc = 0;
1068 ptrdiff_t m_qs_inc_first = 0;
1069 ptrdiff_t m_qs_inc_last = 0;
1070 double m_dt;
1071 double m_eta;
1072 double m_m;
1073 double m_inv_m;
1074 double m_mu;
1075 double m_k_frame;
1076 double m_u_frame = 0.0;
1077 Potential* m_potential;
1078 Generator* m_chunk;
1079 Interactions* m_interactions;
1080 External* m_external;
1081
1082protected:
1097 double m,
1098 double eta,
1099 double k_frame,
1100 double mu,
1101 double dt,
1102 Potential* potential,
1103 Generator* chunk,
1104 Interactions* interactions = nullptr,
1105 External* external = nullptr
1106 )
1107 {
1108 m_N = static_cast<size_type>(chunk->generators().size());
1109 m_m = m;
1110 m_inv_m = 1.0 / m;
1111 m_eta = eta;
1112 m_mu = mu;
1114 m_u_frame = 0.0;
1115 m_dt = dt;
1116
1117 m_f = xt::zeros<double>(chunk->generators().shape());
1118 m_f_potential = xt::zeros<double>(chunk->generators().shape());
1119 m_f_interactions = xt::zeros<double>(chunk->generators().shape());
1120 m_f_frame = xt::zeros<double>(chunk->generators().shape());
1121 m_f_damping = xt::zeros<double>(chunk->generators().shape());
1122
1123 if constexpr (!std::is_same<External, void>::value) {
1124 m_f_thermal = xt::zeros<double>(chunk->generators().shape());
1125 }
1126
1127 m_u = xt::zeros<double>(chunk->generators().shape());
1128 m_v = xt::zeros<double>(chunk->generators().shape());
1129 m_a = xt::zeros<double>(chunk->generators().shape());
1130 m_v_n = xt::zeros<double>(chunk->generators().shape());
1131 m_a_n = xt::zeros<double>(chunk->generators().shape());
1132
1133 m_potential = potential;
1134 m_chunk = chunk;
1135 m_interactions = interactions;
1137
1138 this->refresh();
1139 }
1140
1141public:
1146 const auto& chunk() const
1147 {
1148 return m_chunk;
1149 }
1150
1155 auto size() const
1156 {
1157 return m_chunk->generators().size();
1158 }
1159
1164 const auto& shape() const
1165 {
1166 return m_chunk->generators().shape();
1167 }
1168
1173 auto dt() const
1174 {
1175 return m_dt;
1176 }
1177
1182 auto mu() const
1183 {
1184 return m_mu;
1185 }
1186
1191 auto eta() const
1192 {
1193 return m_eta;
1194 }
1195
1200 auto m() const
1201 {
1202 return m_m;
1203 }
1204
1209 auto k_frame() const
1210 {
1211 return m_k_frame;
1212 }
1213
1218 const auto& external() const
1219 {
1220 return m_external;
1221 }
1222
1231 void set_t(double arg)
1232 {
1233 m_inc = static_cast<decltype(m_inc)>(std::round(arg / m_dt));
1234 FRICTIONQPOTSPRINGBLOCK_ASSERT(xt::allclose(this->t(), arg));
1235 }
1236
1241 void set_inc(ptrdiff_t arg)
1242 {
1243 m_inc = arg;
1244 m_qs_inc_first = arg;
1245 m_qs_inc_last = arg;
1246 this->updated_inc();
1247 }
1248
1253 void set_u_frame(double arg)
1254 {
1255 m_u_frame = arg;
1256 this->computeForceFrame();
1257 this->computeForce();
1258 }
1259
1264 double u_frame() const
1265 {
1266 return m_u_frame;
1267 }
1268
1277 {
1278 FRICTIONQPOTSPRINGBLOCK_ASSERT(xt::has_shape(arg, m_u.shape()));
1279 xt::noalias(m_u) = arg;
1280 this->updated_u();
1281 }
1282
1291 {
1292 FRICTIONQPOTSPRINGBLOCK_ASSERT(xt::has_shape(arg, m_v.shape()));
1293 xt::noalias(m_v) = arg;
1294 this->updated_v();
1295 }
1296
1302 {
1303 FRICTIONQPOTSPRINGBLOCK_ASSERT(xt::has_shape(arg, m_a.shape()));
1304 xt::noalias(m_a) = arg;
1305 }
1306
1310 void refresh()
1311 {
1312 this->updated_u();
1313 this->updated_v();
1314 this->updated_inc();
1315 }
1316
1317protected:
1322 {
1323 if constexpr (std::is_same<External, void>::value) {
1325 }
1326 else {
1327 xt::noalias(m_f) =
1329 }
1330 }
1331
1336 {
1337 m_potential->force(m_u, m_f_potential);
1338 }
1339
1344 {
1345 if constexpr (!std::is_same<Interactions, void>::value) {
1347 }
1348 }
1349
1354 {
1355 xt::noalias(m_f_frame) = m_k_frame * (m_u_frame - m_u);
1356 }
1357
1362 {
1363 xt::noalias(m_f_damping) = -m_eta * m_v;
1364 }
1365
1370 {
1371 if constexpr (!std::is_same<External, void>::value) {
1372 m_external->force(m_u, m_f_thermal, m_inc);
1373 }
1374 this->computeForce();
1375 }
1376
1381 {
1382 this->computeForcePotential();
1384 this->computeForceFrame();
1385 this->computeForce();
1386 }
1387
1392 {
1393 this->computeForceDamping();
1394 this->computeForce();
1395 }
1396
1397public:
1402 const auto& u() const
1403 {
1404 return m_u;
1405 }
1406
1411 const auto& v() const
1412 {
1413 return m_v;
1414 }
1415
1420 const auto& a() const
1421 {
1422 return m_a;
1423 }
1424
1429 const auto& f() const
1430 {
1431 return m_f;
1432 }
1433
1438 const auto& f_potential() const
1439 {
1440 return m_f_potential;
1441 }
1442
1447 const auto& f_frame() const
1448 {
1449 return m_f_frame;
1450 }
1451
1456 const auto& f_interactions() const
1457 {
1458 return m_f_interactions;
1459 }
1460
1465 const auto& f_damping() const
1466 {
1467 return m_f_damping;
1468 }
1469
1477 auto t() const
1478 {
1479 return static_cast<double>(m_inc) * m_dt;
1480 }
1481
1486 auto inc() const
1487 {
1488 return m_inc;
1489 }
1490
1500 double temperature() const
1501 {
1502 return 0.5 * m_m * xt::norm_sq(m_v)() / static_cast<double>(m_N);
1503 }
1504
1512 double residual() const
1513 {
1514 double r_fres = xt::norm_l2(m_f)();
1515 double r_fext = xt::norm_l2(m_f_frame)();
1516 if (r_fext != 0.0) {
1517 return r_fres / r_fext;
1518 }
1519 return r_fres;
1520 }
1521
1527 void quench()
1528 {
1529 m_v.fill(0.0);
1530 m_a.fill(0.0);
1531 this->updated_v();
1532 }
1533
1540 {
1541 m_inc++;
1542 if constexpr (!std::is_same<External, void>::value) {
1543 this->updated_inc();
1544 }
1545
1546 xt::noalias(m_v_n) = m_v;
1547 xt::noalias(m_a_n) = m_a;
1548
1549 xt::noalias(m_u) = m_u + m_dt * m_v + 0.5 * m_dt * m_dt * m_a;
1550 this->updated_u();
1551
1552 xt::noalias(m_v) = m_v_n + m_dt * m_a_n;
1553 this->updated_v();
1554
1555 xt::noalias(m_a) = m_f * m_inv_m;
1556
1557 xt::noalias(m_v) = m_v_n + 0.5 * m_dt * (m_a_n + m_a);
1558 this->updated_v();
1559
1560 xt::noalias(m_a) = m_f * m_inv_m;
1561
1562 xt::noalias(m_v) = m_v_n + 0.5 * m_dt * (m_a_n + m_a);
1563 this->updated_v();
1564
1565 xt::noalias(m_a) = m_f * m_inv_m;
1566
1567 if (xt::any(xt::isnan(m_u))) {
1568 throw std::runtime_error("NaN entries found");
1569 }
1570 }
1571
1577 void timeSteps(size_t n)
1578 {
1579 FRICTIONQPOTSPRINGBLOCK_ASSERT(n + 1 < std::numeric_limits<long>::max());
1580 for (size_t step = 0; step < n; ++step) {
1581 this->timeStep();
1582 }
1583 }
1584
1595 size_t timeStepsUntilEvent(double tol = 1e-5, size_t niter_tol = 10, size_t max_iter = 1e9)
1596 {
1598 FRICTIONQPOTSPRINGBLOCK_ASSERT(max_iter + 1 < std::numeric_limits<long>::max());
1599
1600 double tol2 = tol * tol;
1601 GooseFEM::Iterate::StopList residuals(niter_tol);
1602 auto i_n = m_chunk->index_at_align();
1603 size_t step;
1604
1605 for (step = 1; step < max_iter + 1; ++step) {
1606
1607 this->timeStep();
1608
1609 if (xt::any(xt::not_equal(m_chunk->index_at_align(), i_n))) {
1610 return step;
1611 }
1612
1613 residuals.roll_insert(this->residual());
1614
1615 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1616 this->quench();
1617 return 0;
1618 }
1619 }
1620
1621 return step;
1622 }
1623
1637 void flowSteps(size_t n, double v_frame)
1638 {
1639 FRICTIONQPOTSPRINGBLOCK_ASSERT(n + 1 < std::numeric_limits<long>::max());
1640
1641 for (size_t step = 0; step < n; ++step) {
1642 m_u_frame += v_frame * m_dt;
1643 this->timeStep();
1644 }
1645 }
1646
1676 size_t minimise(
1677 double tol = 1e-5,
1678 size_t niter_tol = 10,
1679 size_t max_iter = 1e9,
1680 bool time_activity = false,
1681 bool max_iter_is_error = true
1682 )
1683 {
1685 FRICTIONQPOTSPRINGBLOCK_ASSERT(max_iter + 1 < std::numeric_limits<long>::max());
1686
1687 size_t step;
1688 double tol2 = tol * tol;
1689 GooseFEM::Iterate::StopList res(niter_tol);
1690
1691 if constexpr (std::is_same<Minimisation, None>::value) {
1692 throw std::runtime_error("Minimisation not implementated");
1693 }
1694 else if constexpr (std::is_same<Minimisation, Overdamped>::value) {
1695 static_assert(std::is_same<Interactions, Laplace1d>::value);
1696 FRICTIONQPOTSPRINGBLOCK_ASSERT(!time_activity);
1697 (void)(time_activity);
1698
1699 double uneigh;
1700 double u;
1701 double umin;
1702 ptrdiff_t i;
1703 ptrdiff_t j;
1704 m_qs_inc_first = m_inc; // unused
1705 m_qs_inc_last = m_inc; // unused
1706 double k = m_interactions->k();
1707
1708 for (step = 1; step < max_iter + 1; ++step) {
1709
1710 // "misuse" unused variable
1711 xt::noalias(m_v_n) = m_u;
1712
1713 for (size_type p = 0; p < m_N; ++p) {
1714
1715 if (p == 0) {
1716 uneigh = m_v_n.back() + m_v_n(1);
1717 }
1718 else if (p == m_N - 1) {
1719 uneigh = m_v_n(m_N - 2) + m_v_n.front();
1720 }
1721 else {
1722 uneigh = m_v_n(p - 1) + m_v_n(p + 1);
1723 }
1724
1725 i = m_chunk->chunk_index_at_align()(p);
1726 auto* y = &m_chunk->data()(p, 0);
1727
1728 while (true) {
1729 umin = 0.5 * (*(y + i) + *(y + i + 1));
1730 u = (k * uneigh + m_k_frame * m_u_frame + m_mu * umin) /
1731 (2 * k + m_k_frame + m_mu);
1732 m_chunk->align(p, u);
1733 j = m_chunk->chunk_index_at_align()(p);
1734 if (j == i) {
1735 break;
1736 }
1737 i = j;
1738 }
1739 m_u(p) = u;
1740 m_f_frame(p) = m_k_frame * (m_u_frame - u);
1741 m_f_potential(p) = m_mu * (umin - u);
1742 }
1743
1745 xt::noalias(m_f) = m_f_potential + m_f_interactions + m_f_frame;
1746 res.roll_insert(this->residual());
1747
1748 if ((res.descending() && res.all_less(tol)) || res.all_less(tol2)) {
1749 this->quench(); // no dynamics are run: make sure that the user is not confused
1750 return 0;
1751 }
1752 }
1753 }
1754 else {
1756 long s = 0;
1757 long s_n = 0;
1758 bool init = true;
1759
1760 if (time_activity) {
1761 i_n = m_chunk->index_at_align();
1762 }
1763
1764 for (step = 1; step < max_iter + 1; ++step) {
1765 this->timeStep();
1766 res.roll_insert(this->residual());
1767
1768 if (time_activity) {
1769 s = xt::sum(xt::abs(m_chunk->index_at_align() - i_n))();
1770 if (s != s_n) {
1771 if (init) {
1772 init = false;
1774 }
1776 }
1777 s_n = s;
1778 }
1779
1780 if ((res.descending() && res.all_less(tol)) || res.all_less(tol2)) {
1781 this->quench();
1782 return 0;
1783 }
1784 }
1785 }
1786
1787 if (max_iter_is_error) {
1788 throw std::runtime_error("No convergence found");
1789 }
1790
1791 return step;
1792 }
1793
1803 {
1804 return m_qs_inc_first;
1805 }
1806
1816 {
1817 return m_qs_inc_last;
1818 }
1819
1835 size_t A_truncate = 0,
1836 size_t S_truncate = 0,
1837 double tol = 1e-5,
1838 size_t niter_tol = 10,
1839 size_t max_iter = 1e9,
1840 bool time_activity = true,
1841 bool max_iter_is_error = true
1842 )
1843 {
1845 FRICTIONQPOTSPRINGBLOCK_ASSERT(max_iter + 1 < std::numeric_limits<long>::max());
1846 FRICTIONQPOTSPRINGBLOCK_ASSERT(xt::has_shape(i_n, m_u.shape()));
1847 FRICTIONQPOTSPRINGBLOCK_ASSERT(time_activity);
1848 (void)(time_activity);
1849
1850 double tol2 = tol * tol;
1851 GooseFEM::Iterate::StopList residuals(niter_tol);
1852
1853 long s = 0;
1854 long s_n = 0;
1855 bool init = true;
1856 size_t step;
1857
1858 for (step = 1; step < max_iter + 1; ++step) {
1859
1860 this->timeStep();
1861 residuals.roll_insert(this->residual());
1862
1863 size_t a = (size_t)xt::sum(xt::not_equal(m_chunk->index_at_align(), i_n))();
1864 s = xt::sum(xt::abs(m_chunk->index_at_align() - i_n))();
1865 if (s != s_n) {
1866 if (init) {
1867 init = false;
1869 }
1871 }
1872 s_n = s;
1873
1874 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1875 this->quench();
1876 return 0;
1877 }
1878
1879 if (A_truncate > 0 && a >= A_truncate) {
1880 return step;
1881 }
1882
1883 if (S_truncate > 0 && s >= (long)S_truncate) {
1884 return step;
1885 }
1886 }
1887
1888 if (max_iter_is_error) {
1889 throw std::runtime_error("No convergence found");
1890 }
1891
1892 return step;
1893 }
1894
1901 double maxUniformDisplacement(int direction)
1902 {
1903 FRICTIONQPOTSPRINGBLOCK_ASSERT(direction == 1 || direction == -1);
1904 return m_potential->maxUniformDisplacement(m_u, direction);
1905 };
1906
1933 double eventDrivenStep(double eps, bool kick, int direction = 1)
1934 {
1935 FRICTIONQPOTSPRINGBLOCK_ASSERT(direction == 1 || direction == -1);
1936
1937 if (direction > 0 && !kick) {
1938 double du = this->maxUniformDisplacement(direction);
1939 if (du < 0.5 * eps) {
1940 return 0.0;
1941 }
1942 return this->advanceUniformly(du - 0.5 * eps, false);
1943 }
1944
1945 if (direction > 0 && kick) {
1946 return this->advanceUniformly(eps, false);
1947 }
1948
1949 // direction < 0
1950
1951 if (!kick) {
1952 double du = this->maxUniformDisplacement(direction);
1953 if (du < 0.5 * eps) {
1954 return 0.0;
1955 }
1956 return this->advanceUniformly(0.5 * eps - du, false);
1957 }
1958
1959 return this->advanceUniformly(-eps, false);
1960 }
1961
1972 void trigger(size_t p, double eps, int direction = 1)
1973 {
1975 return m_potential->trigger(m_u, p, eps, direction);
1976 this->updated_u();
1977 };
1978
1988 void advanceToFixedForce(double f_frame, bool allow_plastic = false)
1989 {
1990 auto i_n = m_chunk->index_at_align();
1991 this->advanceUniformly((f_frame - xt::mean(m_f_frame)()) / m_mu, false);
1993 allow_plastic || xt::all(xt::equal(m_chunk->index_at_align(), i_n))
1994 );
1995 }
1996
1997protected:
2027 double advanceUniformly(double du, bool input_is_frame = true)
2028 {
2029 double du_particles;
2030 double du_frame;
2031
2032 if (input_is_frame) {
2033 du_frame = du;
2034 du_particles = du * m_k_frame / (m_k_frame + m_mu);
2035 }
2036 else {
2037 du_particles = du;
2038 du_frame = du * (m_k_frame + m_mu) / m_k_frame;
2039 }
2040
2041 m_u += du_particles;
2042 m_u_frame += du_frame;
2043 this->updated_u();
2044
2045 if (input_is_frame) {
2046 return du_particles;
2047 }
2048
2049 return du_frame;
2050 }
2051};
2052
2053} // namespace detail
2054} // namespace FrictionQPotSpringBlock
2055
2056#endif
A piece-wise quadratic local potential energy.
Definition detail.h:114
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:140
double maxUniformDisplacement(const T &u, int direction) const
Find maximum particle displacement for which the system is linear and uniform.
Definition detail.h:177
Cuspy(double mu, Generator *chunk)
Definition detail.h:129
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
Definition detail.h:119
void trigger(T &u, size_t p, double eps, int direction) const
Trigger a specific particle.
Definition detail.h:194
stype m_N
Number of particles.
Definition detail.h:117
typename Generator::size_type stype
Size type.
Definition detail.h:116
double m_mu
Curvature of the potentials.
Definition detail.h:118
Short range elastic interactions with other particles.
Definition detail.h:446
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:475
double m_k
Stiffness of the interactions.
Definition detail.h:449
size_type m_N
Number of particles.
Definition detail.h:448
double k() const
Return the stiffness.
Definition detail.h:466
Short range interactions based on the Laplacian .
Definition detail.h:524
size_type m_cols
Number of columns.
Definition detail.h:527
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:546
size_type m_rows
Number of rows.
Definition detail.h:526
Laplace2d(double k, size_type rows, size_type cols)
Definition detail.h:538
double m_k
Stiffness of the interactions.
Definition detail.h:528
LongRange1d(double k, double alpha, size_type N)
Definition detail.h:829
double m_k
Stiffness of the interactions.
Definition detail.h:815
array_type::tensor< double, 1 > m_prefactor
Prefactor for long-range interactions.
Definition detail.h:819
size_type m_N
Number of particles.
Definition detail.h:814
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:850
double m_alpha
Range of interactions.
Definition detail.h:816
Signal none minimisation.
Definition detail.h:1015
Signal overdamped minimisation.
Definition detail.h:1005
Short range interaction based on a quartic potential.
Definition detail.h:757
double m_a1
Stiffness of the interactions.
Definition detail.h:760
Quartic1d(double a1, double a2, size_type N)
Definition detail.h:771
double m_a2
Stiffness of the interactions.
Definition detail.h:761
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:779
size_type m_N
Number of particles.
Definition detail.h:759
Short range interaction based on a quartic potential.
Definition detail.h:616
QuarticGradient1d(double k2, double k4, size_type N)
Definition detail.h:631
double m_k2
Stiffness of the interactions.
Definition detail.h:619
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:640
double m_k4
Stiffness of the interactions.
Definition detail.h:620
Short range interactions based on quartic interactions.
Definition detail.h:658
double m_k2
Stiffness of the interactions.
Definition detail.h:662
double m_k4
Stiffness of the interactions.
Definition detail.h:663
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:683
QuarticGradient2d(double k2, double k4, size_type rows, size_type cols)
Definition detail.h:674
Each particle experiences a random force representing the effect of temperature.
Definition detail.h:882
std::array< size_type, rank > m_shape
Shape of the system.
Definition detail.h:884
void force(const T &u, T &f, S inc)
Update forces based on current slips.
Definition detail.h:931
const auto & next()
Next increment at which the random force is changed.
Definition detail.h:986
RandomNormalForcing(const S &shape, double mean, double stddev, uint64_t seed, const T &dinc_init, const T &dinc)
Definition detail.h:905
array_type::tensor< double, rank > m_f_thermal
Current applied 'random' forces.
Definition detail.h:886
array_type::tensor< ptrdiff_t, rank > m_next
Next increment at to draw.
Definition detail.h:889
double m_mean
Mean of the random distribution.
Definition detail.h:887
uint64_t state() const
State of the random number generator.
Definition detail.h:949
const auto & f_thermal() const
Current random force.
Definition detail.h:967
array_type::tensor< ptrdiff_t, rank > m_dinc
#increments between two draws.
Definition detail.h:890
void set_f_thermal(const array_type::tensor< double, rank > &f_thermal)
Change the random force.
Definition detail.h:976
double m_stddev
Standard deviation of the random distribution.
Definition detail.h:888
void set_state(uint64_t state)
Change the state of the random number generator.
Definition detail.h:958
prrng::pcg32 m_rng
Random number generator.
Definition detail.h:891
void set_next(const array_type::tensor< ptrdiff_t, rank > &next)
Overwrite the next increment at which the random force is changed.
Definition detail.h:995
A potential energy landscape of each particle that is piecewise smooth.
Definition detail.h:213
double m_mu
Curvature of the potentials.
Definition detail.h:217
double maxUniformDisplacement(const T &u, int direction) const
Find maximum particle displacement for which the system is linear and uniform.
Definition detail.h:283
stype m_N
Number of particles.
Definition detail.h:216
typename Generator::size_type stype
Size type.
Definition detail.h:215
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
Definition detail.h:219
void trigger(T &u, size_t p, double eps, int direction) const
Trigger a specific particle.
Definition detail.h:340
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:237
double m_kappa
Softening stiffness.
Definition detail.h:218
SemiSmooth(double mu, double kappa, Generator *chunk)
Definition detail.h:228
A potential energy landscape of each particle that is smooth.
Definition detail.h:357
stype m_N
Number of particles.
Definition detail.h:360
Smooth(double mu, Generator *chunk)
Definition detail.h:371
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
Definition detail.h:362
double maxUniformDisplacement(const T &u, int direction) const
Find maximum particle displacement for which the system is linear and uniform.
Definition detail.h:415
void force(const T &u, T &f)
Update forces based on current slips.
Definition detail.h:380
typename Generator::size_type stype
Size type.
Definition detail.h:359
void trigger(T &u, size_t p, double eps, int direction) const
Trigger a specific particle.
Definition detail.h:428
double m_mu
Curvature of the potentials.
Definition detail.h:361
System in generic number of dimensions.
Definition detail.h:1053
array_type::tensor< double, rank > m_f_frame
Force associated to the load frame acting on each particle.
Definition detail.h:1060
size_t minimise_truncate(array_type::tensor< ptrdiff_t, rank > i_n, size_t A_truncate=0, size_t S_truncate=0, double tol=1e-5, size_t niter_tol=10, size_t max_iter=1e9, bool time_activity=true, bool max_iter_is_error=true)
Minimise energy: run timeStep() until a mechanical equilibrium has been reached.
Definition detail.h:1833
const auto & shape() const
Shape of the system.
Definition detail.h:1164
double eventDrivenStep(double eps, bool kick, int direction=1)
Make event driven step.
Definition detail.h:1933
array_type::tensor< double, rank > m_a_n
Temporary for integration.
Definition detail.h:1066
double u_frame() const
Position of the load frame.
Definition detail.h:1264
double temperature() const
The instantaneous temperature.
Definition detail.h:1500
Interactions * m_interactions
Class to get the forces from particle interaction.
Definition detail.h:1079
const auto & f_damping() const
Force associated to damping on each particle.
Definition detail.h:1465
auto m() const
The mass of each particle (parameter).
Definition detail.h:1200
External * m_external
Add an (time dependent) externally defined force to the residual.
Definition detail.h:1080
const auto & v() const
Velocity of each particle.
Definition detail.h:1411
size_t quasistaticActivityFirst() const
Increment with the first plastic event.
Definition detail.h:1802
const auto & f_frame() const
Force associated to the load frame acting on each particle.
Definition detail.h:1447
Potential * m_potential
Class to get the forces from the local potential energy landscape.
Definition detail.h:1077
ptrdiff_t m_qs_inc_first
Increment with the first plastic event.
Definition detail.h:1068
auto mu() const
The curvature of each well (parameter).
Definition detail.h:1182
void trigger(size_t p, double eps, int direction=1)
Trigger a specific particle.
Definition detail.h:1972
double m_eta
Damping constant (same for all particles).
Definition detail.h:1071
double m_m
Mass (same for all particles).
Definition detail.h:1072
void timeSteps(size_t n)
Make a number of time steps, see timeStep().
Definition detail.h:1577
auto inc() const
The increment number.
Definition detail.h:1486
void computeForceDamping()
Compute force due to damping.
Definition detail.h:1361
void computeForceFrame()
Compute force due to the loading frame.
Definition detail.h:1353
auto eta() const
The damping coefficient (parameter).
Definition detail.h:1191
array_type::tensor< double, rank > m_f_potential
Force associated to potentials acting on each particle.
Definition detail.h:1058
const auto & external() const
Class that generates and external force that is add to the residual force.
Definition detail.h:1218
void updated_v()
Update forces that depend on velocity.
Definition detail.h:1391
array_type::tensor< double, rank > m_u
Slip ('position') of each particle.
Definition detail.h:1062
ptrdiff_t m_inc
The increment number.
Definition detail.h:1067
void set_a(const array_type::tensor< double, rank > &arg)
Set the acceleration of each particle (the second time derivative of the slip).
Definition detail.h:1301
void set_t(double arg)
Set time.
Definition detail.h:1231
size_t quasistaticActivityLast() const
Increment with the last plastic event.
Definition detail.h:1815
void set_u_frame(double arg)
Set position of the load frame.
Definition detail.h:1253
double advanceUniformly(double du, bool input_is_frame=true)
Advance the system uniformly.
Definition detail.h:2027
array_type::tensor< double, rank > m_f_interactions
Force associated to interactions between particles.
Definition detail.h:1059
array_type::tensor< double, rank > m_f_thermal
Force due to thermal fluctuations.
Definition detail.h:1057
const auto & f_interactions() const
Force associated to interactions between particles.
Definition detail.h:1456
const auto & a() const
Acceleration of each particle.
Definition detail.h:1420
array_type::tensor< double, rank > m_f_damping
Force associated to damping on each particle.
Definition detail.h:1061
const auto & f_potential() const
Force associated to potentials acting on each particle.
Definition detail.h:1438
array_type::tensor< double, rank > m_v_n
Temporary for integration.
Definition detail.h:1065
size_type m_N
Number of particles.
Definition detail.h:1055
array_type::tensor< double, rank > m_v
Velocity of each particle.
Definition detail.h:1063
double m_k_frame
Stiffness of the load fame (same for all particles).
Definition detail.h:1075
double m_u_frame
Position of the load frame.
Definition detail.h:1076
auto size() const
Number of particles.
Definition detail.h:1155
array_type::tensor< double, rank > m_f
Resultant force acting on each particle.
Definition detail.h:1056
void updated_u()
Update forces that depend on slip.
Definition detail.h:1380
void computeForceInteractions()
Compute force due to interactions between particles.
Definition detail.h:1343
const auto & f() const
Resultant force acting on each particle.
Definition detail.h:1429
void quench()
Set velocities and accelerations to zero.
Definition detail.h:1527
void updated_inc()
Update forces that depend on time.
Definition detail.h:1369
double residual() const
Residual.
Definition detail.h:1512
void set_u(const array_type::tensor< double, rank > &arg)
Set the slip ('position') of each particle.
Definition detail.h:1276
void flowSteps(size_t n, double v_frame)
Make a number of steps with the frame moving at a constant velocity.
Definition detail.h:1637
void initSystem(double m, double eta, double k_frame, double mu, double dt, Potential *potential, Generator *chunk, Interactions *interactions=nullptr, External *external=nullptr)
Initialise the system.
Definition detail.h:1096
auto k_frame() const
The stiffness of the loading frame (parameter).
Definition detail.h:1209
size_t timeStepsUntilEvent(double tol=1e-5, size_t niter_tol=10, size_t max_iter=1e9)
Perform a series of time-steps until the next plastic event, or equilibrium.
Definition detail.h:1595
array_type::tensor< double, rank > m_a
Acceleration of each particle.
Definition detail.h:1064
size_t minimise(double tol=1e-5, size_t niter_tol=10, size_t max_iter=1e9, bool time_activity=false, bool max_iter_is_error=true)
Minimise energy: run timeStep() until a mechanical equilibrium has been reached.
Definition detail.h:1676
double m_mu
Curvature of the potentials.
Definition detail.h:1074
void set_v(const array_type::tensor< double, rank > &arg)
Set the velocity of each particle (the first time derivative of the slip).
Definition detail.h:1290
void computeForcePotential()
Compute force due to the potential energy.
Definition detail.h:1335
void set_inc(ptrdiff_t arg)
Set increment number.
Definition detail.h:1241
void timeStep()
Effectuate one time step using the velocity Verlet algorithm.
Definition detail.h:1539
void computeForce()
Compute residual force.
Definition detail.h:1321
const auto & u() const
Slip ('position') of each particle.
Definition detail.h:1402
void advanceToFixedForce(double f_frame, bool allow_plastic=false)
Change the position of the particles and of the loading frame such that the mean of f_frame() is equa...
Definition detail.h:1988
void refresh()
Recompute all forces.
Definition detail.h:1310
ptrdiff_t m_qs_inc_last
Increment with the last plastic event.
Definition detail.h:1069
auto dt() const
The time step (parameter).
Definition detail.h:1173
const auto & chunk() const
Chunk of (cumulative sum of) random numbers.
Definition detail.h:1146
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
Definition detail.h:1078
double maxUniformDisplacement(int direction)
Find maximum particle displacement for which the system is linear and uniform.
Definition detail.h:1901
#define FRICTIONQPOTSPRINGBLOCK_ASSERT(expr)
All assertions are implementation as:
Definition config.h:62
#define FRICTIONQPOTSPRINGBLOCK_DEBUG(expr)
Some costly assertions, that are there mostly for debugging, are implemented as:
Definition config.h:83
#define FRICTIONQPOTSPRINGBLOCK_REQUIRE(expr)
Assertions that cannot be disabled.
Definition config.h:37
prrng::distribution string_to_distribution(const std::string &str)
Convert string to prrng::distribution.
Definition detail.h:31
bool check_disorder(const U &u, const Y &yield, const I &i)
Check disorder.
Definition detail.h:75
xt::xarray< T > array
Arbitrary rank array.
Definition config.h:178
Tensor products / operations.
Definition config.h:145
ptrdiff_t size_type
Type using for size and shapes of arrays.
Definition config.h:187