Week 05 — Viscoelasticity (Prony Series, Creep, Relaxation) · Phase-Field Fracture (AT2, Staggered Solution)
Process Systems Laboratory
Department of Chemical and Biomolecular Engineering, SeoulTech
| Part | Topic | Time |
|---|---|---|
| Quiz on Week 4 (closed-AI) | 10 min | |
| A | Viscoelasticity — the generalized Maxwell model, relaxation and creep, time integration, the correspondence principle | 45 min |
| B | Phase-field fracture — from Griffith to AT2, the length scale \ell, irreversibility, the staggered scheme | 45 min |
| C | Code and verification — internal variables again, a creeping tube, a slit specimen, the original sources re-run | 50 min |
| D | LLM pitfalls · assignment | 20 min |
Lab notebook: W05_lab.ipynb · Assignment: W05_HW5.ipynb (due before Week 6)
Today: two more materials with memory. Viscoelasticity remembers the strain history (linear, rate-dependent); phase-field fracture remembers the largest driving force (nonlinear, irreversible). Both are verified against exact answers that do not come from the code.
A spring E_\infty in parallel with N Maxwell branches (spring E_i + dashpot, relaxation time \tau_i):
\sigma=E_\infty\varepsilon+\sum_i E_i(\varepsilon-\varepsilon^v_i),\qquad \dot\varepsilon^v_i=\frac{\varepsilon-\varepsilon^v_i}{\tau_i} \quad\Rightarrow\quad \sigma(t)=\int_0^tE(t-s)\,\dot\varepsilon(s)\,ds,\qquad E(t)=E_\infty+\sum_iE_ie^{-t/\tau_i}
\hat\sigma=s\hat E(s)\,\hat\varepsilon\quad\Rightarrow\quad \hat J(s)=\frac{1}{s^2\hat E(s)},\qquad s\hat E(s)=E_\infty+\sum_i\frac{E_is}{s+1/\tau_i}=\frac{N(s)}{D(s)}
J(t)= residues at s=0 and at the roots of N (the retardation times, different from the \tau_i). Checks: J(0)=1/E_0=0.055556, J(\infty)=1/E_\infty=0.1, J(10)=0.0999542 — and a 10^5-step integration agrees to 10^{-12}.
visco.Prony.relax(t), visco.Prony.creep(t): both exact, NumPy only.
\dot\varepsilon^v=(\varepsilon-\varepsilon^v)/\tau over [t_n,t_{n+1}], written in one form for two schemes:
\varepsilon^v_{n+1}=a\,\varepsilon^v_n+(1-b)\,\varepsilon_{n+1}+(b-a)\,\varepsilon_n,\qquad \sigma_{n+1}=\Big(E_\infty+\sum_ib_iE_i\Big)\varepsilon_{n+1}-\sum_iE_i\big(a_i\varepsilon^v_{i,n}+(b_i-a_i)\varepsilon_n\big)
| Scheme | a | b | Exact when |
|---|---|---|---|
| backward Euler (BE) | \dfrac{\tau}{\tau+\Delta t} | =a | never (first order) |
| exponential (EXP) | e^{-\Delta t/\tau} | \dfrac{(1-a)\tau}{\Delta t} | the strain is linear in time over the step |
| instantaneous step (\Delta t=0) | 1 | 1 | always: a jump is elastic, \sigma jumps by E_0\Delta\varepsilon |
Relaxation: EXP is exact at every step (10^{-15}); BE is 3.7 % off at \Delta t=0.2 and converges slowly (0.73 % at \Delta t=0.025). Creep: BE first order (2.1\times10^{-3}\to3.8\times10^{-4}), EXP second order (2.3\times10^{-4}\to3.8\times10^{-6}).
If every branch has the same Poisson ratio, \mathbb C(t)=E(t)\,\hat{\mathbb C}(\nu): the viscoelastic problem is the elastic problem with E replaced by the hereditary integral. For loads that are constant in time from t=0:
\mathbf u(\mathbf x,t)=\underbrace{\mathbf u_{\rm el}(\mathbf x;\,E=1,\nu)}_{\text{one elastic solve}}\cdot\sigma_0J(t)\quad\text{(load control)},\qquad \text{reaction}(t)=\text{reaction}_{\rm el}(E=1)\cdot u_0E(t)\quad\text{(displacement control)}
Griffith: a crack grows when the energy released per unit crack area reaches G_c. Total energy of a body with a crack set \Gamma: \mathcal E=\int_{\Omega\setminus\Gamma}\psi(\boldsymbol\varepsilon)\,dA+G_c\,|\Gamma|. Replace the sharp crack by a damage field d\in[0,1] of width \sim\ell (AT2):
\mathcal E_\ell(\mathbf u,d)=\int_\Omega g(d)\,\psi(\boldsymbol\varepsilon(\mathbf u))\,dA+\frac{G_c}{2}\int_\Omega\Big(\frac{d^2}{\ell}+\ell|\nabla d|^2\Big)dA,\qquad g(d)=(1-d)^2+k
1D crack profile. d(0)=1, d'(L)=0, no load: d=\dfrac{\cosh((L-x)/\ell)}{\cosh(L/\ell)}, energy \dfrac{G_c}{2}\tanh\dfrac L\ell.
| h/\ell | \Gamma_h/\Gamma (P1) |
|---|---|
| 1 | 1.04083 |
| 0.5 | 1.01036 |
| 0.25 | 1.00260 |
| 0.125 | 1.00065 |
Second order in h/\ell — if a node sits on the crack.
Homogeneous bar. No gradient; \partial_d\mathcal E=0 gives d=\dfrac{E\varepsilon^2}{G_c/\ell+E\varepsilon^2}, \sigma=(1-d)^2E\varepsilon:
\sigma_{\max}=\frac{3\sqrt3}{16}\sqrt{\frac{EG_c}{\ell}}\quad\text{at}\quad\varepsilon=\sqrt{\frac{G_c}{3E\ell}},\ d=\tfrac14
E=210 GPa, G_c=2.7\times10^{-3} kN/mm, \ell=0.02 mm: \sigma_{\max}=1.7292 GPa. Smaller \ell → stronger. AT2 damages from the first strain (no elastic range); AT1 (w(d)=d) is elastic up to \sqrt{3G_cE/(8\ell)}=3.26 GPa.
Left: the strength of the regularised model scales as \ell^{-1/2}. Right: P1 with h=\ell already follows the exact profile (energy +4 %).
Cracks do not heal. Two common ways to impose \dot d\ge0:
vinewtonrsls) — needed for AT1; not used today.Which energy drives the crack: \psi^+ (a split). Amor: \psi^+=\tfrac K2\langle\operatorname{tr}\boldsymbol\varepsilon\rangle_+^2+\mu\,\mathbf e:\mathbf e (all three normal components, plane strain); compression of the volume does not damage. “Hybrid” form: the \mathbf u-problem keeps g(d)\boldsymbol\sigma(\boldsymbol\varepsilon) (linear), only d sees the split.
For each displacement step U_n:
visco.py (NumPy) |
vtube.py (DOLFINx) |
pfield.py (DOLFINx) |
|---|---|---|
Prony(E_inf, [(E_i, tau_i)], nu) |
annulus_mesh (Weeks 3–4) |
profile_1d(Gc, ell, L, n) |
.relax(t), .creep(t) exact |
ViscoTube(msh, ft, mat, ri, ro, control, scheme) |
slit_mesh(h, a) — no Gmsh |
.coeffs(dt, scheme) → (a_i,b_i) |
.step(dt, load), dt = 0: elastic |
PhaseField(msh, E, nu, Gc, ell, split) |
point(mat, t, eps=… / sig=…) |
.ur_inner(), .pressure_from_reaction() |
.step(U) → (converged, iterations) |
lame_ur |
.force(), .crack_energy(band), .d_max() |
The structure of Week 4 again: internal variables at quadrature points, NumPy updates, forms with quadrature coefficients.
Ceff.x.array[:] = np.tile((Cinf + sum(b * Ci for (a, b), Ci in zip(ab, Cb))).ravel(), nq) # constant for a fixed dt
hist.x.array[:] = sum((a * ev_i + (b - a) * e_old) @ Ci for ...).ravel() # history stress at the points
a = ufl.dot(ufl.dot(Ceff, eps4(du)), eps4(v)) * dx # assembled and factorised once per step size
L = ufl.dot(hist, eps4(v)) * dx - p * ufl.dot(n, v) * ds(INNER)
# after the solve: e_new at the points, then ev_i <- a ev_i + (1 - b) e_new + (b - a) e_old, e_old <- e_new| \Delta t | 0.2 | 0.1 | 0.05 |
|---|---|---|---|
| EXP: \max\lvert u_r-pJ\tilde u\rvert/u_r(\infty) | 2.3\times10^{-3} | 5.9\times10^{-4} | 1.5\times10^{-4} |
| BE | 2.1\times10^{-2} | 1.2\times10^{-2} | 7.2\times10^{-3} |
Relaxation (u_r(r_i) held, pressure from the consistent reaction) matches u_0E(t)/\tilde u to 3\times10^{-6} — the spatial error of the mesh.
g = (1 - d)**2 + k
a_u = g * ufl.inner(sig(du), eps(v)) * dx # u-problem, d fixed (hybrid: isotropic g)
a_d = (Gc / ell + 2 * H) * dd * q * dx + Gc * ell * ufl.inner(ufl.grad(dd), ufl.grad(q)) * dx
L_d = 2 * H * q * dx # H: quadrature Function
for it in range(1, maxit + 1): # one load step
d_old = d.x.array.copy()
solve_u(); psi.interpolate(psi_plus_expr); H.x.array[:] = np.maximum(H_n, psi.x.array); solve_d()
if max_abs(d.x.array - d_old) < tol: break
H_n = H.x.array.copy(); return err < tol, itslit_mesh(h): a structured unit square, h along the crack line, y graded away from it; the nodes on y=0.5, x<0.5 are duplicated, so the slit has two free faces. No Gmsh: the same 4800 cells on every computer (h=0.01).
| slit in the mesh | d=1 on one line of nodes (no slit) | |
|---|---|---|
| crack energy at the start / G_ca | 0 | 1.04 (a profile, not a developed crack) |
| load–displacement | rises, one peak, breaks | a false first peak, a drop, a second peak |
| F_{\max} (\ell=0.02) | 0.7133 | 0.6312 (−11.5 %) |
| staggered iterations | all converged (\le178) | cap of 300 reached |
A one-node line of d=1 is weaker than the crack band the model forms itself; it re-damages under load.
Mode I, E=210 GPa, \nu=0.3, G_c=2.7\times10^{-3} kN/mm, 80 steps to U=8\,\mum. The crack runs straight and unstably (one step); the faint background in the ligament is AT2’s diffuse damage.
| \ell | h | cells | F_{\max} [kN/mm] | \Gamma/(G_ca) total | in the band \lvert y-\tfrac12\rvert<5\ell | max. iterations |
|---|---|---|---|---|---|---|
| 0.04 | 0.02 | 1200 | 0.6366 | 1.538 | 1.436 | 179 |
| 0.04 | 0.01 | 4800 | 0.6131 | 1.338 | 1.250 | 149 |
| 0.02 | 0.01 | 4800 | 0.7133 | 1.426 | 1.346 | 178 |
Viscoelasticity (generalized Maxwell, the same Prony data):
Phase field (shear test):
| Pitfall | Measured symptom (this week) |
|---|---|
| “Analytic” reference computed with the same algorithm | agreement proves only that the code reproduces itself |
| Load applied at the first time step (no elastic step at 0^+) | relaxation starts at 1.5167 instead of 1.8; O(\Delta t) error that does not show up late |
| Long-time limit with the wrong reduced modulus (E/(1-\nu^2) for a free bar) | a 10 % “discrepancy” that is the reference’s |
| Mesh coarser than \ell along the crack path | the crack band and F_{\max} are mesh artefacts |
| Notch as an initial value of d / as one line of nodes | erased by the first solve / false first peak, F_{\max} −11.5 %, iterations at the cap |
| Staggered loop with a silent iteration cap | non-converged steps plotted as results |
| All of \int\gamma(d) reported as crack energy | AT2’s diffuse damage (0.08–0.10\,G_ca here) counted as crack |
| Q | Topic | Points |
|---|---|---|
| 1 | Time integration of a Maxwell branch, the creep compliance of the standard linear solid, AT2 strength and length scale (theory) | 20 |
| 2 | Viscoelasticity: the order of the time schemes in 2D, relaxation under displacement control, creep and recovery | 25 |
| 3 | Phase field: mesh and length-scale study of the slit specimen, the split in compression | 35 |
| 4 | Debugging an LLM-generated phase-field script | 20 |
Week 6 starts with a 10-minute quiz on today’s material (closed-AI).
| Concept | Key point | DOLFINx 0.11 |
|---|---|---|
| Prony series | E(t)=E_\infty+\sum E_ie^{-t/\tau_i}; creep J by Laplace | visco.Prony (NumPy) |
| Time integration | EXP exact for relaxation, order 2; BE order 1; elastic step at 0^+ | constant matrix per \Delta t |
| Correspondence | constant \nu: u(t)=u_{\rm el}(E=1)\,\sigma_0J(t) | exact 2D test |
| AT2 | \Gamma_\ell\to G_c per length; \sigma_{\max}=\frac{3\sqrt3}{16}\sqrt{EG_c/\ell} | pfield.profile_1d, homogeneous bar |
| Irreversibility | \mathcal H=\max\psi^+ (history) — linear d-problem | quadrature Function |
| Staggered scheme | alternate \mathbf u / d until converged; report iterations | PhaseField.step → flag |
Next week: dynamics (Newmark) and buckling (SLEPc eigenvalues).
