7#ifndef FRICTIONQPOTSPRINGBLOCK_DETAIL_H
8#define FRICTIONQPOTSPRINGBLOCK_DETAIL_H
12#include <xtensor/xadapt.hpp>
13#include <xtensor/xnorm.hpp>
14#include <xtensor/xtensor.hpp>
18#include <GooseFEM/Iterate.h>
19#include <GooseFEM/version.h>
22#include <GMatTensor/version.h>
33 if (str ==
"random") {
34 return prrng::distribution::random;
38 return prrng::distribution::delta;
41 if (str ==
"exponential") {
42 return prrng::distribution::exponential;
46 return prrng::distribution::power;
50 return prrng::distribution::gamma;
53 if (str ==
"pareto") {
54 return prrng::distribution::pareto;
57 if (str ==
"weibull") {
58 return prrng::distribution::weibull;
61 if (str ==
"normal") {
62 return prrng::distribution::normal;
65 throw std::runtime_error(
"Unknown distribution: " + str);
74template <
class U,
class Y,
class I>
77 if (i.dimension() != 1 || yield.dimension() != 2) {
81 if (u.size() != i.size() || u.size() != yield.shape(0)) {
85 using index_type =
typename I::value_type;
86 index_type n =
static_cast<ptrdiff_t
>(yield.shape(1));
88 for (
size_t p = 0; p < yield.shape(0); ++p) {
89 if (i(p) <= 0 || i(p) >= n - 2) {
93 if (u.flat(p) < yield(p, i(p)) || u.flat(p) > yield(p, i(p) + 1)) {
97 if (!std::is_sorted(&yield(p, 0), &yield(p, 0) + yield.shape(1))) {
113template <
class Generator>
116 using stype =
typename Generator::size_type;
147 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
151 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
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(),
159 std::array<stype, 1>{m_N}
165 const auto* l = &yield(p, i(p));
166 f.flat(p) = 0.5 * (*(l) + *(l + 1)) - u.flat(p);
183 return xt::amin(
m_chunk->template right_of_align<T>() - u)();
186 return xt::amin(u -
m_chunk->template left_of_align<T>())();
194 void trigger(T& u,
size_t p,
double eps,
int direction)
const
200 u.flat(p) =
m_chunk->template right_of_align<T>().flat(p) + 0.5 * eps;
203 u.flat(p) =
m_chunk->template left_of_align<T>().flat(p) - 0.5 * eps;
212template <
class Generator>
215 using stype =
typename Generator::size_type;
244 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
248 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
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(),
256 std::array<stype, 1>{m_N}
262 auto* y = &yield(p, i(p));
263 double xi = 0.5 * (*(y) + *(y + 1));
266 double up = u.flat(p);
268 f.flat(p) =
m_kappa * (up - *(y));
270 else if (up <= u_r) {
271 f.flat(p) =
m_mu * (0.5 * (*(y) + *(y + 1)) - up);
274 f.flat(p) =
m_kappa * (up - *(y + 1));
288 bool positive = direction > 0;
289 std::vector<double> du;
293 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
297 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
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(),
305 std::array<stype, 1>{m_N}
311 auto* y = &yield(p, i(p));
312 double xi = 0.5 * (*(y) + *(y + 1));
315 double up = u.flat(p);
320 else if (up <= u_r) {
322 du.push_back(u_r - up);
325 du.push_back(up - u_l);
333 return *std::min_element(du.begin(), du.end());
340 void trigger(T& u,
size_t p,
double eps,
int direction)
const
345 u.flat(p) =
m_chunk->template right_of_align<T>().flat(p) + 0.5 * eps;
348 u.flat(p) =
m_chunk->template left_of_align<T>().flat(p) - 0.5 * eps;
356template <
class Generator>
359 using stype =
typename Generator::size_type;
387 xt::xtensor_pointer<const double, 2> yield = xt::adapt(
391 std::array<stype, 2>{m_N, m_chunk->chunk_size()}
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(),
399 std::array<stype, 1>{m_N}
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);
420 throw std::runtime_error(
"Operation not possible.");
428 void trigger(T& u,
size_t p,
double eps,
int direction)
const
433 u.flat(p) =
m_chunk->template right_of_align<T>().flat(p) + 0.5 * eps;
436 u.flat(p) =
m_chunk->template left_of_align<T>().flat(p) - 0.5 * eps;
481 f(p) = u(p - 1) - 2 * u(p) + u(p + 1);
483 f.front() = u.back() - 2 * u.front() + u(1);
484 f.back() = u(
m_N - 2) - 2 * u.back() + u.front();
554 std::array<size_type, 2> edge_rows = {0,
m_rows - 1};
555 std::array<size_type, 2> edge_cols = {0,
m_cols - 1};
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);
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);
578 f(i, j) = u(i - 1, j) + u(i + 1, j) + u(i, j - 1) + u(i, j + 1) - 4 * u(i, j);
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);
647 double duf = u(1) - u.back();
648 f.front() = (u.back() - 2 * u.front() + u(1)) * (
m_k2 +
m_k4_4 * duf * duf);
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);
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};
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);
710 l * (
m_k2 + mk4_3) + mk4_23 * (dudx * dudx * d2udx2 + dudy * dudy * d2udy2 +
711 2.0 * dudx * dudy * d2udxdy);
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);
729 l * (
m_k2 + mk4_3) + mk4_23 * (dudx * dudx * d2udx2 + dudy * dudy * d2udy2 +
730 2.0 * dudx * dudy * d2udxdy);
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));
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);
746 l * (
m_k2 + mk4_3) + mk4_23 * (dudx * dudx * d2udx2 + dudy * dudy * d2udy2 +
747 2.0 * dudx * dudy * d2udxdy);
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);
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);
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);
831 m_n =
static_cast<ptrdiff_t
>(
m_N);
836 for (ptrdiff_t d = 0; d <
m_n; ++d) {
852 for (ptrdiff_t p = 0; p <
m_n; ++p) {
855 for (ptrdiff_t i = 0; i <
m_n; ++i) {
859 ptrdiff_t d = std::abs(i - p);
881template <
size_t rank>
904 template <
class T,
class S>
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>{});
930 template <
class T,
class S>
951 return m_rng.state();
1050 class Interactions = void,
1051 class External = void,
1052 class Minimisation =
void>
1102 Potential* potential,
1104 Interactions* interactions =
nullptr,
1117 m_f = xt::zeros<double>(
chunk->generators().shape());
1123 if constexpr (!std::is_same<External, void>::value) {
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());
1157 return m_chunk->generators().size();
1166 return m_chunk->generators().shape();
1279 xt::noalias(
m_u) = arg;
1293 xt::noalias(
m_v) = arg;
1304 xt::noalias(
m_a) = arg;
1323 if constexpr (std::is_same<External, void>::value) {
1345 if constexpr (!std::is_same<Interactions, void>::value) {
1371 if constexpr (!std::is_same<External, void>::value) {
1402 const auto&
u()
const
1411 const auto&
v()
const
1420 const auto&
a()
const
1429 const auto&
f()
const
1479 return static_cast<double>(
m_inc) * m_dt;
1502 return 0.5 *
m_m * xt::norm_sq(
m_v)() /
static_cast<double>(
m_N);
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;
1542 if constexpr (!std::is_same<External, void>::value) {
1567 if (xt::any(xt::isnan(
m_u))) {
1568 throw std::runtime_error(
"NaN entries found");
1580 for (
size_t step = 0; step < n; ++step) {
1600 double tol2 = tol * tol;
1601 GooseFEM::Iterate::StopList residuals(niter_tol);
1602 auto i_n =
m_chunk->index_at_align();
1605 for (step = 1; step < max_iter + 1; ++step) {
1609 if (xt::any(xt::not_equal(
m_chunk->index_at_align(), i_n))) {
1613 residuals.roll_insert(this->
residual());
1615 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1641 for (
size_t step = 0; step < n; ++step) {
1678 size_t niter_tol = 10,
1679 size_t max_iter = 1e9,
1680 bool time_activity =
false,
1681 bool max_iter_is_error =
true
1688 double tol2 = tol * tol;
1689 GooseFEM::Iterate::StopList res(niter_tol);
1691 if constexpr (std::is_same<Minimisation, None>::value) {
1692 throw std::runtime_error(
"Minimisation not implementated");
1694 else if constexpr (std::is_same<Minimisation, Overdamped>::value) {
1695 static_assert(std::is_same<Interactions, Laplace1d>::value);
1697 (void)(time_activity);
1708 for (step = 1; step < max_iter + 1; ++step) {
1718 else if (p ==
m_N - 1) {
1725 i =
m_chunk->chunk_index_at_align()(p);
1726 auto* y = &
m_chunk->data()(p, 0);
1729 umin = 0.5 * (*(y + i) + *(y + i + 1));
1733 j =
m_chunk->chunk_index_at_align()(p);
1748 if ((res.descending() && res.all_less(tol)) || res.all_less(tol2)) {
1760 if (time_activity) {
1761 i_n =
m_chunk->index_at_align();
1764 for (step = 1; step < max_iter + 1; ++step) {
1768 if (time_activity) {
1769 s = xt::sum(xt::abs(
m_chunk->index_at_align() - i_n))();
1780 if ((res.descending() && res.all_less(tol)) || res.all_less(tol2)) {
1787 if (max_iter_is_error) {
1788 throw std::runtime_error(
"No convergence found");
1835 size_t A_truncate = 0,
1836 size_t S_truncate = 0,
1838 size_t niter_tol = 10,
1839 size_t max_iter = 1e9,
1840 bool time_activity =
true,
1841 bool max_iter_is_error =
true
1848 (void)(time_activity);
1850 double tol2 = tol * tol;
1851 GooseFEM::Iterate::StopList residuals(niter_tol);
1858 for (step = 1; step < max_iter + 1; ++step) {
1861 residuals.roll_insert(this->
residual());
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))();
1874 if ((residuals.descending() && residuals.all_less(tol)) || residuals.all_less(tol2)) {
1879 if (A_truncate > 0 &&
a >= A_truncate) {
1883 if (S_truncate > 0 && s >= (
long)S_truncate) {
1888 if (max_iter_is_error) {
1889 throw std::runtime_error(
"No convergence found");
1937 if (direction > 0 && !kick) {
1939 if (du < 0.5 * eps) {
1945 if (direction > 0 && kick) {
1953 if (du < 0.5 * eps) {
1972 void trigger(
size_t p,
double eps,
int direction = 1)
1990 auto i_n =
m_chunk->index_at_align();
1993 allow_plastic || xt::all(xt::equal(
m_chunk->index_at_align(), i_n))
2029 double du_particles;
2032 if (input_is_frame) {
2041 m_u += du_particles;
2045 if (input_is_frame) {
2046 return du_particles;
A piece-wise quadratic local potential energy.
void force(const T &u, T &f)
Update forces based on current slips.
double maxUniformDisplacement(const T &u, int direction) const
Find maximum particle displacement for which the system is linear and uniform.
Cuspy(double mu, Generator *chunk)
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
void trigger(T &u, size_t p, double eps, int direction) const
Trigger a specific particle.
stype m_N
Number of particles.
typename Generator::size_type stype
Size type.
double m_mu
Curvature of the potentials.
Short range elastic interactions with other particles.
void force(const T &u, T &f)
Update forces based on current slips.
double m_k
Stiffness of the interactions.
Laplace1d(double k, size_type N)
size_type m_N
Number of particles.
double k() const
Return the stiffness.
Short range interactions based on the Laplacian .
size_type m_cols
Number of columns.
void force(const T &u, T &f)
Update forces based on current slips.
size_type m_rows
Number of rows.
Laplace2d(double k, size_type rows, size_type cols)
double m_k
Stiffness of the interactions.
LongRange1d(double k, double alpha, size_type N)
double m_k
Stiffness of the interactions.
array_type::tensor< double, 1 > m_prefactor
Prefactor for long-range interactions.
ptrdiff_t m_n
Alias of m_N.
size_type m_N
Number of particles.
void force(const T &u, T &f)
Update forces based on current slips.
double m_alpha
Range of interactions.
Signal none minimisation.
Signal overdamped minimisation.
Short range interaction based on a quartic potential.
double m_a1
Stiffness of the interactions.
Quartic1d(double a1, double a2, size_type N)
double m_a2
Stiffness of the interactions.
void force(const T &u, T &f)
Update forces based on current slips.
size_type m_N
Number of particles.
Short range interaction based on a quartic potential.
QuarticGradient1d(double k2, double k4, size_type N)
double m_k2
Stiffness of the interactions.
void force(const T &u, T &f)
Update forces based on current slips.
size_type m_N
Number of particles.
double m_k4
Stiffness of the interactions.
double m_k4_4
== 0.25 * m_k4
Short range interactions based on quartic interactions.
double m_k2
Stiffness of the interactions.
double m_k4
Stiffness of the interactions.
void force(const T &u, T &f)
Update forces based on current slips.
size_type m_rows
Number of rows.
QuarticGradient2d(double k2, double k4, size_type rows, size_type cols)
size_type m_cols
Number of columns.
Each particle experiences a random force representing the effect of temperature.
std::array< size_type, rank > m_shape
Shape of the system.
void force(const T &u, T &f, S inc)
Update forces based on current slips.
const auto & next()
Next increment at which the random force is changed.
RandomNormalForcing(const S &shape, double mean, double stddev, uint64_t seed, const T &dinc_init, const T &dinc)
array_type::tensor< double, rank > m_f_thermal
Current applied 'random' forces.
array_type::tensor< ptrdiff_t, rank > m_next
Next increment at to draw.
double m_mean
Mean of the random distribution.
uint64_t state() const
State of the random number generator.
const auto & f_thermal() const
Current random force.
array_type::tensor< ptrdiff_t, rank > m_dinc
#increments between two draws.
void set_f_thermal(const array_type::tensor< double, rank > &f_thermal)
Change the random force.
size_type m_N
Number of particles.
double m_stddev
Standard deviation of the random distribution.
void set_state(uint64_t state)
Change the state of the random number generator.
prrng::pcg32 m_rng
Random number generator.
void set_next(const array_type::tensor< ptrdiff_t, rank > &next)
Overwrite the next increment at which the random force is changed.
A potential energy landscape of each particle that is piecewise smooth.
double m_mu
Curvature of the potentials.
double maxUniformDisplacement(const T &u, int direction) const
Find maximum particle displacement for which the system is linear and uniform.
stype m_N
Number of particles.
typename Generator::size_type stype
Size type.
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
void trigger(T &u, size_t p, double eps, int direction) const
Trigger a specific particle.
void force(const T &u, T &f)
Update forces based on current slips.
double m_kappa
Softening stiffness.
SemiSmooth(double mu, double kappa, Generator *chunk)
A potential energy landscape of each particle that is smooth.
stype m_N
Number of particles.
Smooth(double mu, Generator *chunk)
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
double maxUniformDisplacement(const T &u, int direction) const
Find maximum particle displacement for which the system is linear and uniform.
void force(const T &u, T &f)
Update forces based on current slips.
typename Generator::size_type stype
Size type.
void trigger(T &u, size_t p, double eps, int direction) const
Trigger a specific particle.
double m_mu
Curvature of the potentials.
System in generic number of dimensions.
array_type::tensor< double, rank > m_f_frame
Force associated to the load frame acting on each particle.
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.
const auto & shape() const
Shape of the system.
double eventDrivenStep(double eps, bool kick, int direction=1)
Make event driven step.
array_type::tensor< double, rank > m_a_n
Temporary for integration.
double u_frame() const
Position of the load frame.
double temperature() const
The instantaneous temperature.
Interactions * m_interactions
Class to get the forces from particle interaction.
const auto & f_damping() const
Force associated to damping on each particle.
auto m() const
The mass of each particle (parameter).
External * m_external
Add an (time dependent) externally defined force to the residual.
const auto & v() const
Velocity of each particle.
size_t quasistaticActivityFirst() const
Increment with the first plastic event.
const auto & f_frame() const
Force associated to the load frame acting on each particle.
Potential * m_potential
Class to get the forces from the local potential energy landscape.
ptrdiff_t m_qs_inc_first
Increment with the first plastic event.
auto mu() const
The curvature of each well (parameter).
void trigger(size_t p, double eps, int direction=1)
Trigger a specific particle.
double m_eta
Damping constant (same for all particles).
double m_m
Mass (same for all particles).
void timeSteps(size_t n)
Make a number of time steps, see timeStep().
auto inc() const
The increment number.
void computeForceDamping()
Compute force due to damping.
void computeForceFrame()
Compute force due to the loading frame.
auto eta() const
The damping coefficient (parameter).
array_type::tensor< double, rank > m_f_potential
Force associated to potentials acting on each particle.
const auto & external() const
Class that generates and external force that is add to the residual force.
void updated_v()
Update forces that depend on velocity.
array_type::tensor< double, rank > m_u
Slip ('position') of each particle.
ptrdiff_t m_inc
The increment number.
void set_a(const array_type::tensor< double, rank > &arg)
Set the acceleration of each particle (the second time derivative of the slip).
void set_t(double arg)
Set time.
size_t quasistaticActivityLast() const
Increment with the last plastic event.
void set_u_frame(double arg)
Set position of the load frame.
double advanceUniformly(double du, bool input_is_frame=true)
Advance the system uniformly.
array_type::tensor< double, rank > m_f_interactions
Force associated to interactions between particles.
array_type::tensor< double, rank > m_f_thermal
Force due to thermal fluctuations.
const auto & f_interactions() const
Force associated to interactions between particles.
const auto & a() const
Acceleration of each particle.
array_type::tensor< double, rank > m_f_damping
Force associated to damping on each particle.
const auto & f_potential() const
Force associated to potentials acting on each particle.
array_type::tensor< double, rank > m_v_n
Temporary for integration.
size_type m_N
Number of particles.
array_type::tensor< double, rank > m_v
Velocity of each particle.
double m_k_frame
Stiffness of the load fame (same for all particles).
double m_u_frame
Position of the load frame.
auto size() const
Number of particles.
array_type::tensor< double, rank > m_f
Resultant force acting on each particle.
void updated_u()
Update forces that depend on slip.
void computeForceInteractions()
Compute force due to interactions between particles.
const auto & f() const
Resultant force acting on each particle.
void quench()
Set velocities and accelerations to zero.
void updated_inc()
Update forces that depend on time.
double residual() const
Residual.
void set_u(const array_type::tensor< double, rank > &arg)
Set the slip ('position') of each particle.
void flowSteps(size_t n, double v_frame)
Make a number of steps with the frame moving at a constant velocity.
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.
auto k_frame() const
The stiffness of the loading frame (parameter).
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.
array_type::tensor< double, rank > m_a
Acceleration of each particle.
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.
double m_mu
Curvature of the potentials.
void set_v(const array_type::tensor< double, rank > &arg)
Set the velocity of each particle (the first time derivative of the slip).
void computeForcePotential()
Compute force due to the potential energy.
void set_inc(ptrdiff_t arg)
Set increment number.
void timeStep()
Effectuate one time step using the velocity Verlet algorithm.
void computeForce()
Compute residual force.
const auto & u() const
Slip ('position') of each particle.
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...
void refresh()
Recompute all forces.
ptrdiff_t m_qs_inc_last
Increment with the last plastic event.
auto dt() const
The time step (parameter).
const auto & chunk() const
Chunk of (cumulative sum of) random numbers.
Generator * m_chunk
Pointer to chunk of yield 'positions' (automatically updated if needed)
double maxUniformDisplacement(int direction)
Find maximum particle displacement for which the system is linear and uniform.
#define FRICTIONQPOTSPRINGBLOCK_ASSERT(expr)
All assertions are implementation as:
#define FRICTIONQPOTSPRINGBLOCK_DEBUG(expr)
Some costly assertions, that are there mostly for debugging, are implemented as:
#define FRICTIONQPOTSPRINGBLOCK_REQUIRE(expr)
Assertions that cannot be disabled.
prrng::distribution string_to_distribution(const std::string &str)
Convert string to prrng::distribution.
bool check_disorder(const U &u, const Y &yield, const I &i)
Check disorder.
xt::xarray< T > array
Arbitrary rank array.
Tensor products / operations.
ptrdiff_t size_type
Type using for size and shapes of arrays.