What the paper shows
The article presents a self-contained Python finite element code, under 500 lines, for brittle fracture with the phase-field method, and uses it on three examples: a bar in tension compared with the one-dimensional AT2 solution, a single-edge notched plate in tension (this page), and a three-point bending test. We read the code in full (the article’s text was not accessible to us) and everything below about the method comes from it.
In the replay the damage grows smoothly ahead of the notch while rises linearly to ; at the next increment , after , and the force drops to almost zero. shows the open crack on the deformed plate.
The model
Displacement u and damage d are both bilinear on quadrilaterals, integrated with 2×2 Gauss points; plane strain, small strain, quasi-static loading.
- Elasticity at fixed d: div(g(d) C : ε(u)) = 0 with g(d) = (1 − d)², applied to the whole stress.
- Damage (AT2) at fixed u: (Gc/ℓ + 2H) d − Gc ℓ Δd = 2H.
- Driving energy: H = ψ+ = ½ Σ σi εi over the positive principal strains, with σi the undamaged principal stresses: elasticity is degraded fully while damage is driven by tension only, a “hybrid” formulation.
- Alternating solution per load step: solve u with the current d, then d with the new u, until the elasticity residual ‖K(d)u − f‖ falls below 10−5.
- Irreversibility: none in the reference code; damage is recomputed from the current energy and is not bounded by 1. to keep it on unloading (not in the reference).
Units are kN and mm. The homogeneous AT2 peak stress σc = √(27 E Gc / 256 ℓ) ≈ 2.82 kN/mm² here, so ℓ behaves as a strength as much as a regularisation length: and the peak load falls. The mesh matters too: the crack band needs elements a few times smaller than ℓ; .
How we reproduced it
- The author’s code (commit 61037c6, MIT licence) was run unmodified for its three examples in Python 3.12.15 with numpy 2.1.3 and scipy 1.14.1; every step’s force, iteration count, residual and damage range, and nodal fields at chosen steps, were saved with a manifest of versions and checksums.
- The Rust implementation regenerates the same meshes (bit-identical), applies the same boundary conditions, loop and stopping rule, and solves with the Stabileo engine’s sparse Cholesky factorisation.
- 30 named checks compare the two, each with a stated tolerance, in continuous integration. The browser bundle and the replay on this page are checked separately against the native build.
Comparison with the reference
| Check | Observed | Tolerance | Result |
|---|---|---|---|
| ex1: mesh identical to the reference (node and element fingerprints) | equal | — | ✓ pass |
| ex1: same number of load steps | equal | — | ✓ pass |
| ex1: same number of staggered iterations at every step | equal | — | ✓ pass |
| ex1: maximum damage at every step | 8,3 × 10−12 | 1 × 10−9 | ✓ pass |
| ex1: stress at the bar centre at every step | 1,1 × 10−12 | 1 × 10−9 | ✓ pass |
| ex1: nodal damage at step 50 | 4,5 × 10−10 | 1 × 10−8 | ✓ pass |
| ex1: nodal damage at step 73 | 3,8 × 10−10 | 1 × 10−8 | ✓ pass |
| ex1: nodal displacement at step 50 | 1,6 × 10−10 | 1 × 10−8 | ✓ pass |
| ex1: centre stress vs 1D AT2 homogeneous solution while max damage < 0.25 | 7,3 × 10−5 | 1 × 10−3 | ✓ pass |
| ex2: mesh identical to the reference (node and element fingerprints) | equal | — | ✓ pass |
| ex2: same number of load steps | equal | — | ✓ pass |
| ex2: same number of staggered iterations at every step | equal | — | ✓ pass |
| ex2: peak force at the same load step | equal | — | ✓ pass |
| ex2: peak force | 1,2 × 10−12 | 1 × 10−9 | ✓ pass |
| ex2: force at every step up to the peak | 1,6 × 10−12 | 1 × 10−9 | ✓ pass |
| ex2: maximum damage at every step up to the peak | 4,2 × 10−12 | 1 × 10−9 | ✓ pass |
| ex2: force at every step, including fracture (comparison tolerance) | 2,2 × 10−7 | 1 × 10−5 | ✓ pass |
| ex2: nodal damage at the peak step 56 | 5 × 10−11 | 1 × 10−8 | ✓ pass |
| ex2: nodal displacement at the peak step 56 | 8,5 × 10−11 | 1 × 10−8 | ✓ pass |
| ex2: nodal damage at step 57, reference or its mirror image | 2,9 × 10−5 | 1 × 10−4 | ✓ pass |
| ex2: nodal damage at step 78, reference or its mirror image | 3,1 × 10−10 | 1 × 10−8 | ✓ pass |
| ex3: mesh identical to the reference (node and element fingerprints) | equal | — | ✓ pass |
| ex3: same number of load steps | equal | — | ✓ pass |
| ex3: same number of staggered iterations at every step | equal | — | ✓ pass |
| ex3: peak force at the same load step | equal | — | ✓ pass |
| ex3: force at every step up to the peak | 4 × 10−11 | 1 × 10−9 | ✓ pass |
| ex3: force at every step, including fracture (comparison tolerance) | 1 × 10−6 | 1 × 10−4 | ✓ pass |
| ex3: nodal damage at the peak step 56 | 6,9 × 10−11 | 1 × 10−8 | ✓ pass |
| ex3: nodal displacement at the peak step 56 | 1,1 × 10−10 | 1 × 10−8 | ✓ pass |
| ex3: nodal damage at the last step 98, reference or its mirror image | 4,1 × 10−10 | 1 × 10−8 | ✓ pass |
One finding: the plate is symmetric about the notch plane, and the crack runs along the row of elements just above it in one code and just below it in the other. Which row is chosen is decided by floating-point round-off; against the mirror image the final damage fields differ by 3.085970368132962 × 10−10. The thresholds in the table are comparison tolerances, not mathematical error bounds. Displacement fields are compared at example 1 step 50, example 2 step 56, and example 3 step 56.
Step table (79 steps)
| step | u, mm | F, kN | iterations | residual | max d | reference F, kN |
|---|---|---|---|---|---|---|
| 0 | 0,00010 | 0,01345287 | 1 | 2,8 × 10−8 | 0,0001 | 0,01345287 |
| 1 | 0,00020 | 0,02690475 | 1 | 1,7 × 10−7 | 0,0004 | 0,02690475 |
| 2 | 0,00030 | 0,04035443 | 1 | 4,3 × 10−7 | 0,0009 | 0,04035443 |
| 3 | 0,00040 | 0,0538007 | 1 | 7,9 × 10−7 | 0,0016 | 0,0538007 |
| 4 | 0,00050 | 0,06724236 | 1 | 1,3 × 10−6 | 0,0024 | 0,06724236 |
| 5 | 0,00060 | 0,08067819 | 1 | 1,9 × 10−6 | 0,0035 | 0,08067819 |
| 6 | 0,00070 | 0,09410698 | 1 | 2,6 × 10−6 | 0,0048 | 0,09410698 |
| 7 | 0,00080 | 0,1075275 | 1 | 3,4 × 10−6 | 0,0063 | 0,1075275 |
| 8 | 0,00090 | 0,1209386 | 1 | 4,4 × 10−6 | 0,0079 | 0,1209386 |
| 9 | 0,00100 | 0,134339 | 1 | 5,5 × 10−6 | 0,0098 | 0,134339 |
| 10 | 0,00110 | 0,1477276 | 1 | 6,7 × 10−6 | 0,0119 | 0,1477276 |
| 11 | 0,00120 | 0,161103 | 1 | 8 × 10−6 | 0,0142 | 0,161103 |
| 12 | 0,00130 | 0,1744642 | 1 | 9,4 × 10−6 | 0,0166 | 0,1744642 |
| 13 | 0,00140 | 0,1877887 | 2 | 3,5 × 10−7 | 0,0194 | 0,1877887 |
| 14 | 0,00150 | 0,2011143 | 2 | 4,5 × 10−7 | 0,0223 | 0,2011143 |
| 15 | 0,00160 | 0,2144218 | 2 | 5,9 × 10−7 | 0,0255 | 0,2144218 |
| 16 | 0,00170 | 0,2277098 | 2 | 7,6 × 10−7 | 0,0289 | 0,2277098 |
| 17 | 0,00180 | 0,2409771 | 2 | 9,6 × 10−7 | 0,0324 | 0,2409771 |
| 18 | 0,00190 | 0,2542226 | 2 | 1,2 × 10−6 | 0,0362 | 0,2542226 |
| 19 | 0,00200 | 0,267445 | 2 | 1,5 × 10−6 | 0,0403 | 0,267445 |
| 20 | 0,00210 | 0,2806429 | 2 | 1,8 × 10−6 | 0,0446 | 0,2806429 |
| 21 | 0,00220 | 0,2938153 | 2 | 2,2 × 10−6 | 0,0491 | 0,2938153 |
| 22 | 0,00230 | 0,3069608 | 2 | 2,7 × 10−6 | 0,0539 | 0,3069608 |
| 23 | 0,00240 | 0,3200782 | 2 | 3,2 × 10−6 | 0,0589 | 0,3200782 |
| 24 | 0,00250 | 0,3331662 | 2 | 3,8 × 10−6 | 0,0641 | 0,3331662 |
| 25 | 0,00260 | 0,3462235 | 2 | 4,5 × 10−6 | 0,0697 | 0,3462235 |
| 26 | 0,00270 | 0,3592489 | 2 | 5,3 × 10−6 | 0,0755 | 0,3592489 |
| 27 | 0,00280 | 0,372241 | 2 | 6,1 × 10−6 | 0,0816 | 0,372241 |
| 28 | 0,00290 | 0,3851986 | 2 | 7,1 × 10−6 | 0,0880 | 0,3851986 |
| 29 | 0,00300 | 0,3981203 | 2 | 8,3 × 10−6 | 0,0947 | 0,3981203 |
| 30 | 0,00310 | 0,4110048 | 2 | 9,6 × 10−6 | 0,1017 | 0,4110048 |
| 31 | 0,00320 | 0,4238411 | 3 | 2 × 10−6 | 0,1092 | 0,4238411 |
| 32 | 0,00330 | 0,4366456 | 3 | 2,4 × 10−6 | 0,1168 | 0,4366456 |
| 33 | 0,00340 | 0,4494086 | 3 | 2,9 × 10−6 | 0,1249 | 0,4494086 |
| 34 | 0,00350 | 0,4621286 | 3 | 3,5 × 10−6 | 0,1333 | 0,4621286 |
| 35 | 0,00360 | 0,4748041 | 3 | 4,3 × 10−6 | 0,1421 | 0,4748041 |
| 36 | 0,00370 | 0,4874337 | 3 | 5,1 × 10−6 | 0,1513 | 0,4874337 |
| 37 | 0,00380 | 0,5000156 | 3 | 6,2 × 10−6 | 0,1609 | 0,5000156 |
| 38 | 0,00390 | 0,5125483 | 3 | 7,4 × 10−6 | 0,1710 | 0,5125483 |
| 39 | 0,00400 | 0,52503 | 3 | 8,9 × 10−6 | 0,1816 | 0,52503 |
| 40 | 0,00410 | 0,537452 | 4 | 3,3 × 10−6 | 0,1929 | 0,537452 |
| 41 | 0,00420 | 0,5498249 | 4 | 4,1 × 10−6 | 0,2046 | 0,5498249 |
| 42 | 0,00430 | 0,562141 | 4 | 5,1 × 10−6 | 0,2170 | 0,562141 |
| 43 | 0,00440 | 0,574398 | 4 | 6,5 × 10−6 | 0,2299 | 0,574398 |
| 44 | 0,00450 | 0,5865935 | 4 | 8,2 × 10−6 | 0,2437 | 0,5865935 |
| 45 | 0,00460 | 0,5987187 | 5 | 4,2 × 10−6 | 0,2584 | 0,5987187 |
| 46 | 0,00470 | 0,6107814 | 5 | 5,5 × 10−6 | 0,2739 | 0,6107814 |
| 47 | 0,00480 | 0,6227733 | 5 | 7,4 × 10−6 | 0,2903 | 0,6227733 |
| 48 | 0,00490 | 0,6346904 | 5 | 9,9 × 10−6 | 0,3080 | 0,6346904 |
| 49 | 0,00500 | 0,6465205 | 6 | 6,8 × 10−6 | 0,3272 | 0,6465205 |
| 50 | 0,00510 | 0,65827 | 6 | 9,7 × 10−6 | 0,3479 | 0,65827 |
| 51 | 0,00520 | 0,6699181 | 7 | 8 × 10−6 | 0,3708 | 0,6699181 |
| 52 | 0,00530 | 0,6814596 | 8 | 7,6 × 10−6 | 0,3962 | 0,6814596 |
| 53 | 0,00540 | 0,6928765 | 9 | 8,5 × 10−6 | 0,4250 | 0,6928765 |
| 54 | 0,00550 | 0,704134 | 11 | 8,1 × 10−6 | 0,4588 | 0,704134 |
| 55 | 0,00560 | 0,7151725 | 14 | 8,7 × 10−6 | 0,5006 | 0,7151725 |
| 56 | 0,00570 | 0,7257948 | 22 | 9,3 × 10−6 | 0,5606 | 0,7257948 |
| 57 | 0,00580 | 0,0004754389 | 308 | 8,3 × 10−6 | 1,0081 | 0,0004752194 |
| 58 | 0,00590 | 0,0004541939 | 2 | 4,6 × 10−7 | 1,0081 | 0,0004541974 |
| 59 | 0,00600 | 0,0004334678 | 2 | 2,5 × 10−7 | 1,0083 | 0,0004334679 |
| 60 | 0,00610 | 0,0004139992 | 2 | 2,3 × 10−7 | 1,0085 | 0,0004139992 |
| 61 | 0,00620 | 0,0003957132 | 2 | 2,1 × 10−7 | 1,0087 | 0,0003957132 |
| 62 | 0,00630 | 0,0003785198 | 2 | 2 × 10−7 | 1,0088 | 0,0003785198 |
| 63 | 0,00640 | 0,0003623365 | 2 | 1,9 × 10−7 | 1,0089 | 0,0003623365 |
| 64 | 0,00650 | 0,0003677663 | 1 | 9,6 × 10−6 | 1,0091 | 0,0003677663 |
| 65 | 0,00660 | 0,0003524283 | 1 | 9,2 × 10−6 | 1,0092 | 0,0003524283 |
| 66 | 0,00670 | 0,0003377493 | 1 | 8,9 × 10−6 | 1,0093 | 0,0003377493 |
| 67 | 0,00680 | 0,0003238947 | 1 | 8,5 × 10−6 | 1,0094 | 0,0003238947 |
| 68 | 0,00690 | 0,0003108076 | 1 | 8,2 × 10−6 | 1,0094 | 0,0003108076 |
| 69 | 0,00700 | 0,000298434 | 1 | 7,9 × 10−6 | 1,0095 | 0,000298434 |
| 70 | 0,00710 | 0,0002867248 | 1 | 7,6 × 10−6 | 1,0095 | 0,0002867248 |
| 71 | 0,00720 | 0,0002756351 | 1 | 7,4 × 10−6 | 1,0095 | 0,0002756351 |
| 72 | 0,00730 | 0,0002651233 | 1 | 7,1 × 10−6 | 1,0096 | 0,0002651233 |
| 73 | 0,00740 | 0,0002551516 | 1 | 6,9 × 10−6 | 1,0096 | 0,0002551516 |
| 74 | 0,00750 | 0,0002456849 | 1 | 6,7 × 10−6 | 1,0096 | 0,0002456849 |
| 75 | 0,00760 | 0,000236691 | 1 | 6,4 × 10−6 | 1,0096 | 0,000236691 |
| 76 | 0,00770 | 0,00022814 | 1 | 6,2 × 10−6 | 1,0096 | 0,00022814 |
| 77 | 0,00780 | 0,0002200045 | 1 | 6 × 10−6 | 1,0096 | 0,0002200045 |
| 78 | 0,00790 | 0,000212259 | 1 | 5,8 × 10−6 | 1,0095 | 0,000212259 |
Comparison with the paper
Not done: the article’s full text was not accessible to us, so no number printed in it has been compared. Figures here come from our own runs.
Limitations
- Agreement with a reference code is not validation against experiments, and none of this is an engineering certification.
- The reference mesh refines only a 0.04 × 0.04 mm box around the notch tip; beyond it the crack crosses elements wider than 3ℓ.
- No bound constraints: damage can exceed 1 slightly (the reference reaches 1.0096 here and 1.0021897551918642 in example 1) and undershoot 0. The recorded Python reference outputs have minimum nodal damage 3.076336950017797e-08 (example 1), -0.0031224948220514573 (example 2), and -0.06024191772700118 (example 3). This also occurs in the reference code’s unconstrained AT2 discretization. Negative damage is unphysical: (1-d)² at the example 3 minimum is about 1.124, above intact stiffness. Assembly uses interpolated damage at quadrature points, so this is not a 12.4% assembled-stiffness error. The solver does not clamp damage; the replay’s quantized nodal field and colour scale clamp it for display.
- The alternating scheme is not accelerated; at unstable crack growth it can take hundreds of iterations in one step.
- Browser runs are limited in mesh size and parameter range.
Code and references
- Implementation, tests and reference outputs: shauer-2025 (mesh generators and loop adapted from the MIT reference, credited in the source).
- Reference code: github.com/nathanshauer/phasefield-jr-py, MIT, © 2025 Nathan Shauer.
Cite this
Stabileo Research, “Phase-field fracture of a notched plate”, reproduction of Nathan Shauer (2025), doi:10.1016/j.advengsoft.2025.104013. Implementation: research/fracture/shauer-2025 at commit 0ce459e9eb75. Engine: the Stabileo engine at the same commit. Permanent links to this exact build are planned.