7#ifndef GOOSEEPM_SYSTEM_H
8#define GOOSEEPM_SYSTEM_H
13#include <xtensor/xset_operation.hpp>
14#include <xtensor/xsort.hpp>
26inline std::string get_namespace()
28 std::string ret =
"GooseEPM";
29#ifdef GOOSEEPM_USE_XTENSOR_PYTHON
41inline std::string shape_to_string(
const T& shape)
43 std::string ret =
"[";
44 for (
size_t i = 0; i < shape.size(); ++i) {
45 ret += std::to_string(shape[i]);
46 if (i < shape.size() - 1) {
60inline void unravel_index(
62 const std::array<ptrdiff_t, 2>& strides,
63 std::array<ptrdiff_t, 2>& indices
66 indices[0] = idx / strides[0];
67 indices[1] = idx % strides[0];
78inline bool check_distances(
const T& distance)
80 using value_type =
typename T::value_type;
81 static_assert(std::numeric_limits<value_type>::is_integer,
"Distances must be integer");
82 static_assert(std::numeric_limits<value_type>::is_signed,
"Distances must be signed");
84 if (distance.dimension() != 1) {
88 value_type lower = xt::amin(distance)();
89 value_type upper = xt::amax(distance)() + 1;
90 auto d = xt::arange<value_type>(lower, upper);
92 if (!xt::all(xt::in1d(distance, d))) {
96 if (
static_cast<value_type
>(distance.size()) != upper - lower) {
127inline T create_distance_lookup(
const T& distance)
129 using value_type =
typename T::value_type;
132 value_type lower = xt::amin(distance)();
133 value_type upper = xt::amax(distance)() + 1;
135 value_type N =
static_cast<value_type
>(distance.size());
136 T ret = xt::empty<value_type>({2 * N - 1});
138 for (value_type i = 0; i < upper; ++i) {
139 ret(i) = xt::argmax(xt::equal(distance, i))();
141 for (value_type i = upper; i < N; ++i) {
142 ret(i) = xt::argmax(xt::equal(distance, i - N))();
144 for (value_type i = -1; i >= lower; --i) {
145 ret.periodic(i) = xt::argmax(xt::equal(distance, i))();
147 for (value_type i = lower; i > -N; --i) {
148 ret.periodic(i) = xt::argmax(xt::equal(distance, N + i))();
163template <
size_t Dim,
class T,
class D>
164inline T reorganise_popagator(
const T& propagator,
const D& distances)
166 static_assert(Dim > 0 && Dim < 3,
"Only 1d/2d systems are supported");
169 T ret = xt::empty_like(propagator);
171 if constexpr (Dim == 1) {
172 auto d = xt::argsort(distances[0]);
173 for (
size_t i = 0; i < propagator.size(); ++i) {
174 ret(i) = propagator(d(i));
177 else if constexpr (Dim == 2) {
178 auto dr = xt::argsort(distances[0]);
179 auto dc = xt::argsort(distances[1]);
181 for (
size_t i = 0; i < propagator.shape(0); ++i) {
182 for (
size_t j = 0; j < propagator.shape(1); ++j) {
183 ret(i, j) = propagator(dr(i), dc(j));
198template <
size_t Dim,
class T,
class D>
199inline T popagator_fix_stress(
const T& propagator,
const D& distances)
201 static_assert(Dim > 0 && Dim < 3,
"Only 1d/2d systems are supported");
206 if constexpr (Dim == 1) {
207 auto i = xt::argwhere(xt::equal(distances[0], 0));
209 for (
size_t k = 0; k < 20; ++k) {
210 ret -= xt::mean(ret);
214 else if constexpr (Dim == 2) {
215 auto i = xt::argwhere(xt::equal(distances[0], 0));
216 auto j = xt::argwhere(xt::equal(distances[1], 0));
219 for (
size_t k = 0; k < 20; ++k) {
220 ret -= xt::mean(ret);
221 ret(i[0][0], j[0][0]) = -1.0;
225 return reorganise_popagator<Dim>(ret, distances);
235template <
size_t Dim,
class T,
class D>
236inline T popagator_fix_strain(
const T& propagator,
const D& distances)
238 static_assert(Dim > 0 && Dim < 3,
"Only 1d/2d systems are supported");
243 if constexpr (Dim == 1) {
244 auto i = xt::argwhere(xt::equal(distances[0], 0));
246 for (
size_t k = 0; k < 20; ++k) {
247 ret -= xt::mean(ret) + 1.0 /
static_cast<double>(ret.size());
251 else if constexpr (Dim == 2) {
252 auto i = xt::argwhere(xt::equal(distances[0], 0));
253 auto j = xt::argwhere(xt::equal(distances[1], 0));
256 for (
size_t k = 0; k < 20; ++k) {
257 ret -= xt::mean(ret) + 1.0 /
static_cast<double>(ret.size());
258 ret(i[0][0], j[0][0]) = -1.0;
262 return reorganise_popagator<Dim>(ret, distances);
359 FixStress(
double sigbar) : m_sigbar(sigbar)
368 void set_average_stress(T& sig)
370 sig -= xt::mean(sig)() - m_sigbar;
377 void set_sigmabar(
double sigbar)
386 double sigmabar()
const
437 Spring(
double k,
double u,
size_t size)
438 : m_u(u), m_k_div_n(k / static_cast<double>(size)), m_kp1_div_k((k + 1.0) / k)
448 void stress_match_frame(T& sig,
double depsp_f)
450 sig -= depsp_f * m_k_div_n;
457 void frame_match_stress(
double delta_sigma)
459 m_u += delta_sigma * m_kp1_div_k;
558template <
size_t Dimension,
class StressFixer,
class Temperature,
class FailureRules>
561 static constexpr size_t Dim = Dimension;
601 StressFixer* stress_fixer =
nullptr
604 static_assert(
Dim > 0 &&
Dim < 3,
"Only 1d/2d systems are supported");
608 m_inv_temp = std::numeric_limits<double>::infinity();
611 for (
size_t i = 0; i <
Dim; ++i) {
618 if constexpr (std::is_same<StressFixer, detail::FixStrain>::value) {
638 for (
size_t i = 0; i <
m_sigy.size(); ++i) {
639 this->drawYieldStress(i);
646 this->stress_updated();
661 template <
class S,
class T>
664 if constexpr (std::is_same<StressFixer, detail::FixStrain>::value) {
670 if constexpr (std::is_same<StressFixer, detail::FixStrain>::value) {
674 for (
size_t i = 0; i < 20; ++i) {
680 if constexpr (std::is_same<StressFixer, detail::Spring>::value) {
684 this->stress_updated();
693 void stress_updated()
695 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
697 if constexpr (std::is_same<Temperature, detail::Finite>::value) {
707 if constexpr (std::is_same<Temperature, detail::Finite>::value) {
721 void stress_updated(
size_t idx)
723 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
730 if constexpr (std::is_same<Temperature, detail::Finite>::value) {
736 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
751 void drawYieldStress(
size_t idx)
753 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
759 while (
m_sigy.flat(idx) < 0) {
772 std::string ret = detail::get_namespace() +
"System";
774 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
778 if constexpr (std::is_same<Temperature, detail::Finite>::value) {
782 if constexpr (std::is_same<StressFixer, detail::FixStrain>::value) {
783 ret +=
"StrainControl";
785 else if constexpr (std::is_same<StressFixer, detail::FixStress>::value) {
786 ret +=
"StressControl";
788 else if constexpr (std::is_same<StressFixer, detail::Spring>::value) {
789 ret +=
"SpringLoading";
792 return ret + std::to_string(
Dim) +
" " + detail::shape_to_string(
m_sig.shape());
902 return m_gen.state();
948 this->stress_updated();
1010 this->stress_updated();
1036 if constexpr (std::is_same<StressFixer, detail::FixStress>::value) {
1040 else if constexpr (std::is_same<StressFixer, detail::Spring>::value) {
1048 this->stress_updated();
1057 if constexpr (std::is_same<StressFixer, detail::FixStress>::value) {
1061 return xt::mean(
m_sig)();
1071 if constexpr (std::is_same<StressFixer, detail::Spring>::value) {
1074 throw std::invalid_argument(
"Only implemented for Spring");
1084 if constexpr (std::is_same<StressFixer, detail::Spring>::value) {
1087 throw std::invalid_argument(
"Only implemented for Spring");
1099 ptrdiff_t d =
static_cast<ptrdiff_t
>(delta_r);
1100 auto dsig =
m_gen.normal<
decltype(
m_sig)>(
m_sig.shape(), 0, sigma_std);
1102 if constexpr (
Dim == 1) {
1103 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(
m_sig.size()); ++i) {
1104 m_sig(i) += dsig(i);
1105 m_sig.periodic(i - d) -= 0.5 * dsig(i);
1106 m_sig.periodic(i + d) -= 0.5 * dsig(i);
1109 else if constexpr (
Dim == 2) {
1110 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(
m_sig.shape(0)); ++i) {
1111 for (ptrdiff_t j = 0; j < static_cast<ptrdiff_t>(
m_sig.shape(1)); ++j) {
1112 m_sig(i, j) += dsig(i, j);
1113 m_sig.periodic(i - d, j) -= 0.5 * dsig(i, j);
1114 m_sig.periodic(i + d, j) -= 0.5 * dsig(i, j);
1115 m_sig.periodic(i, j - d) -= 0.5 * dsig(i, j);
1116 m_sig.periodic(i, j + d) -= 0.5 * dsig(i, j);
1117 m_sig.periodic(i + d, j + d) += 0.25 * dsig(i, j);
1118 m_sig.periodic(i - d, j + d) += 0.25 * dsig(i, j);
1119 m_sig.periodic(i + d, j - d) += 0.25 * dsig(i, j);
1120 m_sig.periodic(i - d, j - d) += 0.25 * dsig(i, j);
1125 this->stress_updated();
1143 auto dsig =
m_gen.normal<
decltype(
m_sig)>(
m_sig.shape(), 0, sigma_std);
1145 if constexpr (
Dim == 1) {
1146 ptrdiff_t ni =
static_cast<ptrdiff_t
>(
m_sig.size());
1147 ptrdiff_t nj =
static_cast<ptrdiff_t
>(
m_propagator.size());
1149 for (ptrdiff_t i = 0; i < ni; ++i) {
1150 for (ptrdiff_t j = 0; j < nj; ++j) {
1155 else if constexpr (
Dim == 2) {
1156 ptrdiff_t ni =
static_cast<ptrdiff_t
>(
m_sig.shape(0));
1157 ptrdiff_t nj =
static_cast<ptrdiff_t
>(
m_sig.shape(1));
1158 ptrdiff_t nk =
static_cast<ptrdiff_t
>(
m_propagator.shape(0));
1159 ptrdiff_t nl =
static_cast<ptrdiff_t
>(
m_propagator.shape(1));
1163 for (ptrdiff_t i = 0; i < ni; ++i) {
1164 for (ptrdiff_t j = 0; j < nj; ++j) {
1165 for (ptrdiff_t k = 0; k < nk; ++k) {
1166 for (ptrdiff_t l = 0; l < nl; ++l) {
1167 m_sig.periodic(i + dk + k, j + dl + l) -=
1176 this->stress_updated();
1192 if (nfailing == 0) {
1202 i =
m_gen.randint(nfailing);
1206 for (idx = 0; idx <
m_sig.size(); ++idx) {
1224 for (
size_t i = 0; i < n; ++i) {
1239 std::chrono::steady_clock::time_point tic = std::chrono::steady_clock::now();
1240 auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(tic - tic).count();
1241 dt =
static_cast<decltype(dt)
>(elapsed * 1e3);
1243 for (
size_t i = 0; i < n; ++i) {
1246 std::chrono::steady_clock::time_point toc = std::chrono::steady_clock::now();
1247 if (std::chrono::duration_cast<std::chrono::milliseconds>(toc - tic).count() > dt) {
1268 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
1277 if (
x > 0 && !allow_stable) {
1293 for (
size_t i = 0; i < n; ++i) {
1309 std::chrono::steady_clock::time_point tic = std::chrono::steady_clock::now();
1310 auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(tic - tic).count();
1311 dt =
static_cast<decltype(dt)
>(elapsed * 1e3);
1313 for (
size_t i = 0; i < n; ++i) {
1316 std::chrono::steady_clock::time_point toc = std::chrono::steady_clock::now();
1317 if (std::chrono::duration_cast<std::chrono::milliseconds>(toc - tic).count() > dt) {
1330 if constexpr (!std::is_same<Temperature, detail::Finite>::value) {
1331 throw std::invalid_argument(
"Only implemented for thermal systems");
1341 if constexpr (!std::is_same<Temperature, detail::Finite>::value) {
1342 throw std::invalid_argument(
"Only implemented for thermal systems");
1346 this->stress_updated();
1355 if constexpr (std::is_same<Temperature, detail::Finite>::value) {
1377 if constexpr (!std::is_same<Temperature, detail::Finite>::value) {
1378 throw std::invalid_argument(
"Only implemented for thermal systems");
1383 size_t idx = xt::argmin(dt)();
1384 m_t += dt.flat(idx);
1394 for (
size_t i = 0; i < n; ++i) {
1409 std::chrono::steady_clock::time_point tic = std::chrono::steady_clock::now();
1410 auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(tic - tic).count();
1411 dt =
static_cast<decltype(dt)
>(elapsed * 1e3);
1413 for (
size_t i = 0; i < n; ++i) {
1416 std::chrono::steady_clock::time_point toc = std::chrono::steady_clock::now();
1417 if (std::chrono::duration_cast<std::chrono::milliseconds>(toc - tic).count() > dt) {
1431 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
1462 if constexpr (std::is_same<FailureRules, detail::Depinning>::value) {
1468 dsig =
m_sig.flat(idx) +
m_gen.normal(0.0, 0.01);
1472 m_epsp.flat(idx) += dsig;
1473 this->drawYieldStress(idx);
1475 if constexpr (
Dim == 1) {
1476 ptrdiff_t di =
static_cast<ptrdiff_t
>(idx) +
m_offset[0];
1477 ptrdiff_t n =
static_cast<ptrdiff_t
>(
m_sig.size());
1479 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(
m_propagator.size()); ++i) {
1481 ptrdiff_t ii = (n + di + i) % n;
1484 if constexpr (!std::is_same<StressFixer, detail::Spring>::value) {
1485 this->stress_updated(ii);
1489 else if constexpr (
Dim == 2) {
1490 auto index = xt::unravel_index(idx,
m_sig.shape());
1491 ptrdiff_t di =
static_cast<ptrdiff_t
>(index[0]) +
m_offset[0];
1492 ptrdiff_t dj =
static_cast<ptrdiff_t
>(index[1]) +
m_offset[1];
1493 ptrdiff_t n =
static_cast<ptrdiff_t
>(
m_sig.shape(0));
1494 ptrdiff_t m =
static_cast<ptrdiff_t
>(
m_sig.shape(1));
1496 for (ptrdiff_t i = 0; i < static_cast<ptrdiff_t>(
m_propagator.shape(0)); ++i) {
1497 for (ptrdiff_t j = 0; j < static_cast<ptrdiff_t>(
m_propagator.shape(1)); ++j) {
1499 ptrdiff_t ii = (n + di + i) % n;
1500 ptrdiff_t jj = (m + dj + j) % m;
1501 ptrdiff_t iidx = ii * m + jj;
1504 if constexpr (!std::is_same<StressFixer, detail::Spring>::value) {
1505 this->stress_updated(iidx);
1511 if constexpr (std::is_same<StressFixer, detail::Spring>::value) {
1513 this->stress_updated();
1531 if (direction > 0) {
1532 dsig = xt::amin(
m_sigy -
m_sig)() + 2.0 * std::numeric_limits<double>::epsilon();
1535 dsig = -xt::amin(
m_sig +
m_sigy)() + 2.0 * std::numeric_limits<double>::epsilon();
1539 this->stress_updated();
1541 if constexpr (std::is_same<StressFixer, detail::Spring>::value) {
1558 for (
size_t i = 0; i < max_steps; ++i) {
1560 if (m_failure_idx ==
m_epsp.size()) {
1565 if (max_steps_is_error) {
1566 throw std::runtime_error(
"Failed to converge.");
1580 size_t relaxWeakest(
size_t max_steps = 1e9,
bool max_steps_is_error =
true)
1582 for (
size_t i = 0; i < max_steps; ++i) {
1584 if (m_failure_idx ==
m_epsp.size()) {
1589 if (max_steps_is_error) {
1590 throw std::runtime_error(
"Failed to converge.");
1604template <
size_t Dim>
1625 bool random_stress =
true
1641template <
size_t Dim>
1644 detail::FixStress m_my_stress_fixer;
1658 bool random_stress =
true
1660 : m_my_stress_fixer(0.0)
1683template <
size_t Dim>
1686 detail::Spring m_my_stress_fixer;
1702 bool random_stress =
true
1723template <
size_t Dim>
1726 detail::FixStress m_my_stress_fixer;
1740 bool random_stress =
true
1742 : m_my_stress_fixer(0.0)
1765template <
size_t Dim>
1768 SystemBase<Dim, GooseEPM::detail::FixStrain, void, GooseEPM::detail::Depinning> {
1797 double failure_rate = 1,
1799 bool random_stress =
true
1805 xt::zeros_like(sigmay_std),
1822template <
size_t Dim>
1825 SystemBase<Dim, GooseEPM::detail::FixStress, void, GooseEPM::detail::Depinning> {
1827 GooseEPM::detail::FixStress m_my_stress_fixer;
1838 double failure_rate = 1,
1840 bool random_stress =
true
1842 : m_my_stress_fixer(0.0)
1847 xt::zeros_like(sigmay_std),
1865template <
size_t Dim>
1868 SystemBase<Dim, GooseEPM::detail::Spring, void, GooseEPM::detail::Depinning> {
1870 GooseEPM::detail::Spring m_my_stress_fixer;
1883 double failure_rate = 1,
1885 bool random_stress =
true
1887 : m_my_stress_fixer(kframe, 0.0, sigmay_std.size())
1892 xt::zeros_like(sigmay_std),
1906template <
size_t Dim>
1909 GooseEPM::detail::FixStress,
1910 GooseEPM::detail::Finite,
1911 GooseEPM::detail::Depinning> {
1913 GooseEPM::detail::FixStress m_my_stress_fixer;
1926 bool random_stress =
true
1928 : m_my_stress_fixer(0.0)
1975 array_type::tensor<size_t, 1>,
1976 array_type::tensor<size_t, 1>,
1977 array_type::tensor<size_t, 1>>
1985 GOOSEEPM_REQUIRE(xt::has_shape(condition, idx.shape()), std::out_of_range);
1987 if (condition.size() == 0) {
1988 return std::make_tuple(
1989 xt::empty<size_t>({0}), xt::empty<size_t>({0}), xt::empty<size_t>({0})
1993 if (xt::all(condition)) {
1994 if (!first || !last) {
1995 return std::make_tuple(
1996 xt::empty<size_t>({0}), xt::empty<size_t>({0}), xt::empty<size_t>({0})
1999 std::sort(idx.begin(), idx.end());
2000 size_t a = std::unique(idx.begin(), idx.end()) - idx.begin();
2004 return std::make_tuple(S, A, index);
2007 size_t n = condition.size();
2009 for (
size_t i = condition.size() - 1; i > 0; --i) {
2010 if (!condition(i)) {
2017 size_t nevent =
static_cast<size_t>(condition(0));
2018 for (
size_t i = 0; i < n - 1; ++i) {
2019 if (!condition(i) && condition(i + 1)) {
2025 if (!first && condition(0)) {
2027 for (; i < condition.size() - 1; ++i) {
2028 if (!condition(i)) {
2040 for (; i < n; ++i) {
2042 for (j = i + 1; j < n; ++j) {
2043 if (!condition(j)) {
2048 auto begin = &idx(i);
2050 std::sort(begin, end);
2052 A(event) = std::unique(begin, end) - begin;
2063 if (last && j == n) {
2064 if (condition(j - 1)) {
2065 auto begin = &idx(i);
2066 auto end = &idx(j - 1) + 1;
2067 std::sort(begin, end);
2069 A(event) = std::unique(begin, end) - begin;
2074 return std::make_tuple(S, A, index);
2091 xt::xtensor<bool, 1> failed = xt::zeros<bool>({xt::amax(idx)() + 1});
2093 if (idx.size() == 0) {
2098 failed(idx(0)) =
true;
2100 for (
size_t i = 1; i < idx.size(); ++i) {
2101 if (!failed(idx(i))) {
2102 failed(idx(i)) =
true;
2103 ret(i) = ret(i - 1) + 1;
2106 ret(i) = ret(i - 1);
2135template <
size_t Dimension>
2138 static constexpr size_t Dim = Dimension;
2141 std::array<size_t, Dim> m_shape;
2147 ptrdiff_t m_new_label = 1;
2159 std::vector<ptrdiff_t> m_renum;
2171 std::vector<ptrdiff_t> m_next;
2173 std::vector<ptrdiff_t> m_connected;
2186 const std::array<size_t, Dim>& shape,
2195 m_s = xt::zeros<size_t>(m_shape);
2196 m_label = xt::zeros<ptrdiff_t>(m_shape);
2197 m_renum.resize(m_s.size() + 1);
2198 m_next.resize(m_s.size() + 1);
2199 std::iota(m_renum.begin(), m_renum.end(), 0);
2203 GOOSEEPM_REQUIRE(std::is_sorted(m_time.begin(), m_time.end()), std::invalid_argument);
2206 if constexpr (Dim == 1) {
2210 else if constexpr (Dim == 2) {
2212 m_dx = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
2214 m_connected.resize(m_dx.shape(0));
2236 ptrdiff_t n =
static_cast<ptrdiff_t
>(m_new_label);
2239 for (ptrdiff_t i = 1; i < n; ++i) {
2240 if (m_renum[i] == i) {
2241 m_renum[i] = m_new_label;
2245 this->private_renumber(m_renum);
2246 std::iota(m_renum.begin(), m_renum.begin() + n, 0);
2255 std::fill(m_next.begin(), m_next.end(), -1);
2263 void private_renumber(
const T& renum)
2265 for (
size_t i = 0; i < m_label.size(); ++i) {
2266 m_label.flat(i) = renum[m_label.flat(i)];
2283 GOOSEEPM_ASSERT(new_label.size() >= this->nlabels(), std::out_of_range);
2285 *std::max_element(new_label.begin(), new_label.end()) < this->size() + 1,
2289 this->private_renumber(new_label);
2290 m_new_label = xt::amax(m_label)() + 1;
2291 std::fill(m_renum.begin(), m_renum.begin() + m_new_label, 0);
2293 for (
size_t i = 0; i < new_label.size(); ++i) {
2294 m_renum[new_label[i]] = new_label[i];
2304 auto maxlab = *std::max_element(labels.begin(), labels.end());
2306#ifdef GOOSEEPM_ENABLE_ASSERT
2309 std::vector<bool> label_in_use(m_new_label,
false);
2310 for (
size_t i = 0; i < m_label.size(); ++i) {
2311 label_in_use[m_label.flat(i)] =
true;
2314 std::vector<bool> label_in_order(m_new_label,
false);
2315 for (
size_t i = 0; i < labels.size(); ++i) {
2316 label_in_order[labels[i]] =
true;
2319 for (ptrdiff_t i = 0; i < m_new_label; ++i) {
2320 if (label_in_use[i]) {
2326 decltype(m_renum) tmp(m_new_label);
2328 for (
size_t i = 0; i < labels.size(); ++i) {
2330 m_renum[labels[i]] = i;
2333 this->private_renumber(tmp);
2334 m_new_label = xt::amax(m_label)() + 1;
2335 std::iota(m_renum.begin(), m_renum.begin() + m_new_label, 0);
2347 void merge_detail(ptrdiff_t a, ptrdiff_t b)
2350 ptrdiff_t i = m_renum[b];
2351 ptrdiff_t target = m_renum[a];
2352 m_renum[b] = target;
2358 m_renum[i] = target;
2361 while (m_next[a] != -1) {
2374 ptrdiff_t merge(ptrdiff_t* labels,
size_t nlabels)
2376 std::sort(labels, labels + nlabels);
2377 nlabels = std::unique(labels, labels + nlabels) - labels;
2378 ptrdiff_t target = labels[0];
2379 for (
size_t i = 1; i < nlabels; ++i) {
2380 this->merge_detail(target, labels[i]);
2395 size_t nsteps = std::min(m_step + n, m_idx.size());
2396 std::array<ptrdiff_t, Dim> index;
2397 std::array<ptrdiff_t, Dim> shape;
2398 std::array<ptrdiff_t, Dim> strides;
2399 for (
size_t i = 0; i < Dim; ++i) {
2400 shape[i] =
static_cast<ptrdiff_t
>(m_shape[i]);
2401 strides[i] =
static_cast<ptrdiff_t
>(m_label.strides()[i]);
2404 for (; m_step < nsteps; ++m_step) {
2405 auto idx =
static_cast<ptrdiff_t
>(m_idx(m_step));
2409 if (m_s.flat(idx) > 1) {
2414 for (
size_t j = 0; j < m_dx.shape(0); ++j) {
2415 if constexpr (Dim == 1) {
2416 ptrdiff_t nn = shape[0];
2417 ptrdiff_t ii = (nn + idx + m_dx(j)) % nn;
2420 else if constexpr (Dim == 2) {
2421 detail::unravel_index(idx, strides, index);
2422 ptrdiff_t nn = shape[0];
2423 ptrdiff_t mm = shape[1];
2424 ptrdiff_t ii = (nn + index[0] + m_dx(j, 0)) % nn;
2425 ptrdiff_t jj = (mm + index[1] + m_dx(j, 1)) % mm;
2426 iidx = ii * mm + jj;
2428 if (m_label.flat(iidx) != 0) {
2429 m_connected[nconnected] = m_renum[m_label.flat(iidx)];
2433 if (nconnected == 0) {
2434 m_label.flat(idx) = m_new_label;
2437 else if (nconnected == 1) {
2438 m_label.flat(idx) = m_connected[0];
2444 m_label.flat(idx) = this->merge(&m_connected[0], nconnected);
2450 this->private_renumber(m_renum);
2460 this->private_renumber(m_renum);
2474 if (t >= m_time.back()) {
2475 return this->advance(m_time.size() - m_step);
2477 if (t <= m_time(m_step)) {
2481 for (
size_t i = 0; i < m_time.size() - m_step; ++i) {
2482 if (m_time(m_step + i) > t) {
2484 return this->advance(i - 1);
2487 if (m_time(m_step + i) - t < t - m_time(m_step + i - 1)) {
2488 return this->advance(i);
2491 return this->advance(i - 1);
2504 return detail::get_namespace() +
"AvalancheSegmenter" + std::to_string(Dim) +
" " +
2505 detail::shape_to_string(m_shape);
2514 return m_label.shape();
2523 return m_label.size();
2530 const auto&
s()
const
2568 return m_time(m_step - 1);
2610 return detail::get_namespace() +
"Avalanche" +
" " +
2611 detail::shape_to_string(std::array<size_t, 1>{m_idx.size()});
2647 template <
class System,
class Func>
2650 m_idx = xt::empty<size_t>({n});
2651 m_x = xt::empty<double>({n});
2652 m_t = xt::empty<double>({n});
2654 for (
size_t i = 0; i < n; ++i) {
2656 m_idx(i) = system.failure_idx();
2657 m_x(i) = system.failure_x();
2658 m_t(i) = system.t();
2670 template <
class System,
class Func>
2673 std::chrono::steady_clock::time_point tic = std::chrono::steady_clock::now();
2674 auto dt = std::chrono::duration_cast<std::chrono::milliseconds>(tic - tic).count();
2675 dt =
static_cast<decltype(dt)
>(elapsed * 1e3);
2677 std::array<size_t, 1> shape = {n};
2678 m_idx.resize(shape);
2682 for (
size_t i = 0; i < n; ++i) {
2684 m_idx(i) = system.failure_idx();
2685 m_x(i) = system.failure_x();
2686 m_t(i) = system.t();
2688 std::chrono::steady_clock::time_point toc = std::chrono::steady_clock::now();
2689 if (std::chrono::duration_cast<std::chrono::milliseconds>(toc - tic).count() > dt) {
2692 size_t nret = i + 1;
2695 std::vector<size_t> tmp(nret);
2696 std::copy(m_idx.begin(), m_idx.begin() + nret, tmp.begin());
2697 m_idx.resize(shape);
2698 std::copy(tmp.begin(), tmp.end(), m_idx.begin());
2701 std::vector<double> tmp(nret);
2702 std::copy(m_x.begin(), m_x.begin() + nret, tmp.begin());
2704 std::copy(tmp.begin(), tmp.end(), m_x.begin());
2707 std::vector<double> tmp(nret);
2708 std::copy(m_t.begin(), m_t.begin() + nret, tmp.begin());
2710 std::copy(tmp.begin(), tmp.end(), m_t.begin());
2724 template <
class System>
2727 this->
makeFailureSteps(system, n, [&system]() {
return system.makeAthermalFailureStep(); });
2736 template <
class System>
2740 return system.makeWeakestFailureStep(allow_stable);
2749 template <
class System>
2752 this->
makeFailureSteps(system, n, [&system]() {
return system.makeThermalFailureStep(); });
2761 template <
class System>
2765 return system.makeAthermalFailureStep();
2776 template <
class System>
2781 bool allow_stable =
false
2785 return system.makeWeakestFailureStep(allow_stable);
2795 template <
class System>
2799 return system.makeThermalFailureStep();
Segment event in spatially correlated avalanches.
size_t nstep()
Number of yielding events taken into account.
const auto & labels() const
Per block, the label (0 for background).
void advance_to(double t, bool floor=false)
Advance to the yielding events closest to a time t.
std::string repr() const
Basic class info.
auto size() const
Size of AvalancheSegmenter::s and AvalancheSegmenter::labels (== prod(shape)).
void change_labels(const array_type::tensor< size_t, 1 > &new_label)
Apply renumbering.
void reorder(const array_type::tensor< ptrdiff_t, 1 > &labels)
Reorder the labels.
size_t nlabels()
Current number of labels (including the background).
void advance(size_t n=1)
Advance n yielding events.
void prune()
Prune: renumber labels to lowest possible label, see also AvalancheSegmenter::nlabels.
const auto & shape() const
Shape of AvalancheSegmenter::s and AvalancheSegmenter::labels.
const auto & s() const
Per block, how many times it has yielded.
auto t() const
Time of each entry in m_idx.
AvalancheSegmenter(const std::array< size_t, Dim > &shape, const array_type::tensor< size_t, 1 > &idx, const array_type::tensor< double, 1 > &t)
Measure avalanches in a system.
size_t makeFailureSteps_chrono(System &system, size_t n, double elapsed, Func func)
Run the measurement.
const array_type::tensor< size_t, 1 > & idx() const
Index of failing block.
size_t makeAthermalFailureSteps_chrono(System &system, size_t n, double elapsed)
Run SystemBase::makeAthermalFailureStep and store the evolution.
const array_type::tensor< double, 1 > & t() const
Time of the failure.
const array_type::tensor< double, 1 > & x() const
Distance to yielding of the failing block before failing.
void makeAthermalFailureSteps(System &system, size_t n)
Run SystemBase::makeAthermalFailureStep and store the evolution.
void makeWeakestFailureSteps(System &system, size_t n, bool allow_stable=false)
Run SystemBase::makeWeakestFailureStep and store the evolution.
void makeFailureSteps(System &system, size_t n, Func func)
Run the measurement.
size_t makeThermalFailureSteps_chrono(System &system, size_t n, double elapsed)
Run SystemBase::makeThermalFailureStep and store the evolution.
size_t makeWeakestFailureSteps_chrono(System &system, size_t n, double elapsed, bool allow_stable=false)
Run SystemBase::makeWeakestFailureStep and store the evolution.
void makeThermalFailureSteps(System &system, size_t n)
Run SystemBase::makeThermalFailureStep and store the evolution.
std::string repr() const
Basic class info.
double shiftImposedShear(int direction=1)
Change the imposed shear strain such that one block fails in the direction of shear.
const auto & shape() const
Return the shape.
void makeThermalFailureStep()
Make a thermal failure step.
array_type::tensor< bool, Dim > m_unstable
Per block: is the block unstable?
void set_sigma(const array_type::tensor< double, Dim > &sigma)
Set the stress.
double m_tau
Inverse failure rate.
std::string repr() const
Basic class info.
void makeWeakestFailureStep(bool allow_stable=false)
Fail weakest block (unstable) and advance the time by one.
auto size() const
Return the size (== prod(shape)).
void set_sigmabar(double sigmabar)
Adjust the stress such that the average stress is equal to the argument.
array_type::tensor< double, Dim > m_sigy_std
Standard deviation of yield stress.
array_type::tensor< double, Dim > m_sig
Stress.
const array_type::tensor< double, Dim > & sigmay() const
Get the yield stress.
uint64_t state() const
Get the state of the random number generator.
array_type::tensor< ptrdiff_t, 1 > distances(size_t axis=0) const
Distances along an axis of the propagator.
const array_type::tensor< double, Dim > & sigmay_mean() const
Get the mean wherefrom the yield stress of each block is drawn.
double m_temperature
Temperature.
void initSigmaPropogator(double sigma_std)
Generate a stress field that is compatible.
array_type::tensor< double, Dim > m_sigy_mu
Mean yield stress.
void makeThermalFailureSteps(size_t n)
Make n steps with SystemBase::makeThermalFailureStep.
StressFixer * m_stress_fixer
Method to fix the average stress.
double epsframe() const
Get the current position of the loading frame.
double t() const
Get the time.
array_type::tensor< double, Dim > m_tau_thermal
Thermal failure rate.
size_t makeAthermalFailureSteps_chrono(size_t n, double elapsed)
Make n steps with SystemBase::makeAthermalFailureStep.
const array_type::tensor< bool, Dim > & unstable() const
If a block is unstable.
size_t makeThermalFailureSteps_chrono(size_t n, double elapsed)
Make n steps with SystemBase::makeThermalFailureStep.
double m_failure_x
For the last failure: distance to yielding before failure.
void set_epsframe(double u)
Overwrite the current position of the loading frame.
const array_type::tensor< double, Dim > & propagator() const
Get the propagator (as used internally: reordered/normalised compared to the input).
size_t relaxWeakest(size_t max_steps=1e9, bool max_steps_is_error=true)
Relax the system by calling SystemBase::makeWeakestFailureStep until there are no more unstable block...
auto failure_idx() const
For the last failure: index of the failing block.
void set_sigmay_std(const array_type::tensor< double, Dim > &value)
Set the standard deviation wherefrom the yield stress of each block is drawn.
array_type::tensor< size_t, Dim > m_nfails
Number of times a block failed.
auto failure_rate() const
Failure rate (parameter).
array_type::tensor< double, Dim > time_to_failure() const
Time to failure.
double m_alpha
Exponent characterising the shape of the potential.
void set_sigmay(const array_type::tensor< double, Dim > &sigmay)
Set the yield stress.
const array_type::tensor< double, Dim > & epsp() const
Get the plastic strain.
void set_epsp(const array_type::tensor< double, Dim > &epsp)
Set the plastic strain.
auto alpha() const
Exponent characterising the shape of the potential.
void makeWeakestFailureSteps(size_t n, bool allow_stable=false)
Make n steps with SystemBase::makeWeakestFailureStep.
void spatialParticleFailure(size_t idx)
Fail a block.
double temperature() const
Get the applied temperature.
array_type::tensor< double, Dim > m_sigy
Yield stress.
void set_sigmay_mean(const array_type::tensor< double, Dim > &value)
Set the mean wherefrom the yield stress of each block is drawn.
void makeAthermalFailureStep()
Fail an unstable block, chosen randomly from all unstable blocks.
void set_t(double t)
Set the time.
auto failure_x() const
For the last failure: distance to yielding before failure.
prrng::pcg32 m_gen
Random number generator.
const array_type::tensor< double, Dim > x() const
Distance to failure.
array_type::tensor< double, Dim > m_propagator
Propagator.
double m_inv_temp
Inverse temperature.
void makeAthermalFailureSteps(size_t n)
Make n steps with SystemBase::makeAthermalFailureStep.
void set_nfails(const array_type::tensor< size_t, Dim > &nfails)
Set the number of times each block failed.
void initSigmaFast(double sigma_std, size_t delta_r)
Generate a stress field that is compatible, using a fast but approximative technique.
std::array< ptrdiff_t, Dim > m_offset
Minimal distance in each direction, used as offset.
const array_type::tensor< size_t, Dim > & nfails() const
Get the number of times each block failed.
void set_temperature(double temperature)
Set the applied temperature.
void set_state(uint64_t state)
Set the state of the random number generator.
size_t m_failure_idx
For the last failure: index of the failing block.
const array_type::tensor< double, Dim > & sigmay_std() const
Get the standard deviation wherefrom the yield stress of each block is drawn.
size_t makeWeakestFailureSteps_chrono(size_t n, double elapsed, bool allow_stable=false)
Make n steps with SystemBase::makeWeakestFailureStep.
size_t relaxAthermal(size_t max_steps=1e9, bool max_steps_is_error=true)
Relax the system by calling SystemBase::makeAthermalFailureStep until there are no more unstable bloc...
static constexpr size_t Dim
Dimensionality of the system.
void initSystem(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_mean, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double failure_rate, double alpha, bool random_stress, StressFixer *stress_fixer=nullptr)
double m_failure_rate
Failure rate (parameter).
array_type::tensor< double, Dim > m_epsp
Plastic strain.
double sigmabar() const
Get the average stress.
const array_type::tensor< double, Dim > & sigma() const
Get the stress.
System loaded using a spring.
SystemDepinningSpringLoading(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double kframe, double failure_rate=1, double alpha=1.5, bool random_stress=true)
Important
System for which the average strain is fixed.
SystemDepinningStrainControl(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double failure_rate=1, double alpha=1.5, bool random_stress=true)
Important
System for which the average stress is fixed.
SystemDepinningStressControl(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double failure_rate=1, double alpha=1.5, bool random_stress=true)
Important
System for which the average stress is fixed.
SystemDepinningThermalStressControl(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double failure_rate=1, double alpha=1.5, bool random_stress=true)
Important
System loaded using a spring.
SystemSpringLoading(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_mean, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double kframe, double failure_rate=1, double alpha=1.5, bool random_stress=true)
System for which the average strain is fixed.
SystemStrainControl(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_mean, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double failure_rate=1, double alpha=1.5, bool random_stress=true)
System for which the average stress is fixed.
SystemStressControl(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_mean, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double failure_rate=1, double alpha=1.5, bool random_stress=true)
System for which the average stress is fixed.
SystemThermalStressControl(const array_type::tensor< double, Dim > &propagator, const std::vector< array_type::tensor< ptrdiff_t, 1 > > &distances, const array_type::tensor< double, Dim > &sigmay_mean, const array_type::tensor< double, Dim > &sigmay_std, uint64_t seed, double failure_rate=1, double alpha=1.5, bool random_stress=true)
#define GOOSEEPM_ASSERT(expr, assertion)
All assertions are implementation as::
#define GOOSEEPM_WARNING(message)
All warnings are implemented as::
#define GOOSEEPM_REQUIRE(expr, assertion)
Assertion that cannot be switched off.
#define GOOSEEPM_WARNING_PYTHON(message)
All warnings specific to the Python API are implemented as::
xt::xtensor< T, N > tensor
Fixed (static) rank array.
std::tuple< array_type::tensor< size_t, 1 >, array_type::tensor< size_t, 1 >, array_type::tensor< size_t, 1 > > segment_avalanche(const array_type::tensor< bool, 1 > &condition, array_type::tensor< size_t, 1 > idx, bool first=true, bool last=true)
Compute avalanche properties of a series of segments.
array_type::tensor< size_t, 1 > cumsum_n_unique(const array_type::tensor< size_t, 1 > &idx)
Cumulative sum of the number of unique items in the slice up to that index.