1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use crate::math::{Matrix, Real, Vector, DIM};
#[cfg(not(feature = "std"))]
use na::ComplexField;
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub struct DruckerPragerPlasticity {
pub h0: Real,
pub h1: Real,
pub h2: Real,
pub h3: Real,
pub lambda: Real,
pub mu: Real,
pub only_active_when_failed: bool,
}
impl DruckerPragerPlasticity {
pub fn new(young_modulus: Real, poisson_ration: Real) -> Self {
let (lambda, mu) = crate::utils::lame_lambda_mu(young_modulus, poisson_ration);
DruckerPragerPlasticity {
h0: (35.0 as Real).to_radians(),
h1: (9.0 as Real).to_radians(),
h2: 0.2,
h3: (10.0 as Real).to_radians(),
lambda,
mu,
only_active_when_failed: false,
}
}
pub fn project_deformation_gradient(
&self,
singular_values: Vector<Real>,
log_vol_gain: Real,
alpha: Real,
) -> Option<(Vector<Real>, Real)> {
let d = DIM as Real;
let strain = singular_values.map(|e| e.ln()) + Vector::repeat(log_vol_gain / d);
let strain_trace = strain.sum();
let deviatoric_strain = strain - Vector::repeat(strain_trace / d);
if deviatoric_strain == Vector::zeros() || strain_trace > 0.0 {
return Some((Vector::repeat(1.0), strain.norm()));
}
let gamma = deviatoric_strain.norm()
+ (d * self.lambda + 2.0 * self.mu) / (2.0 * self.mu) * strain_trace * alpha;
if gamma <= 0.0 {
return None;
}
let h = strain - gamma * deviatoric_strain.normalize();
Some((h.map(|e| e.exp()), gamma))
}
fn alpha(&self, q: Real) -> Real {
let angle = self.h0 + (self.h1 * q - self.h3) * (-self.h2 * q).exp();
let s_angle = angle.sin();
(2.0 as Real / 3.0).sqrt() * (2.0 * s_angle) / (3.0 - s_angle)
}
pub fn update_particle(
&self,
particle_phase: Real,
particle_deformation_gradient: &mut Matrix<Real>,
particle_plastic_deformation_gradient_det: &mut Real,
particle_plastic_hardening: &mut Real,
particle_log_vol_gain: &mut Real,
) {
if self.only_active_when_failed && particle_phase != 0.0 {
return;
}
let mut svd = particle_deformation_gradient.svd_unordered(true, true);
let alpha = self.alpha(*particle_plastic_hardening);
if let Some((new_singular_values, dq)) =
self.project_deformation_gradient(svd.singular_values, *particle_log_vol_gain, alpha)
{
let prev_det = svd.singular_values.product();
let new_det = new_singular_values.product();
*particle_plastic_deformation_gradient_det *= prev_det / new_det;
*particle_log_vol_gain += prev_det.ln() - new_det.ln();
svd.singular_values = new_singular_values;
*particle_plastic_hardening += dq; *particle_deformation_gradient = svd.recompose().unwrap();
} }
}