Skip to content

BUG: Cauchy-Born get_shift_gradients (F-rotation) + SinclairCrack update_precon (region order)#320

Open
jameskermode wants to merge 5 commits into
masterfrom
fix/cb-gradient-and-precon-bugs
Open

BUG: Cauchy-Born get_shift_gradients (F-rotation) + SinclairCrack update_precon (region order)#320
jameskermode wants to merge 5 commits into
masterfrom
fix/cb-gradient-and-precon-bugs

Conversation

@jameskermode

Copy link
Copy Markdown
Member

Summary

Two correctness bugs in the multilattice (Cauchy–Born) flexible-boundary-condition crack machinery, found while building a Si(111) Sinclair-crack reference with a Stillinger–Weber multilattice.

1. CubicCauchyBorn.get_shift_gradients drops the F-induced rotation

predict_shifts applies the corrector shift as s_i = Aᵀ R_i χ_i, where R_i is the rotation from the polar decomposition of the deformation gradient F_i. But get_shift_gradients returned ds_i/dde = Aᵀ (dχ_i/dde) — dropping both R_i and dR_i/dde. This is exact only at zero strain (R_i = I); near a crack tip (large F) the analytic shift gradient drifts from the true derivative, growing with load, and breaks the configurational-force identity f_alpha = -dE/dalpha for a flexible-BC crack with a Cauchy–Born corrector (the error flips the sign of the tip force at high K).

Fix: differentiate the full applied shift,
d(Aᵀ R χ)/dde = Aᵀ( (dR/dde) χ + R dχ/dde ),
keeping dχ/dde analytic (regression gradient) and taking dR/dde by the same central difference already used for the strain field.

Test: new test_regression_model_gradient_F_with_rotation uses a rotation-bearing F (R ≠ I) and checks analytic get_shift_gradients against the finite difference of the applied shift (agreement ~1e-9). The existing test_regression_model_gradient_{E,F} use symmetric F (R = I) and so could not catch this. Before the fix the new test fails by ~3e-2; after, ~4e-10.

2. SinclairCrack.update_precon assumes a region-sorted cluster

update_precon selected regions I+II via a = self.atoms[:self.N2], assuming the cluster is ordered region I, II, III. set_regions' default sort ('r_theta_z') is not region-grouped, so the slice is not regions I+II and the region-I preconditioner sub-block is empty/misaligned (→ spilu size mismatch). Select via the boolean mask self.regionI_II (array order), matching how update_atoms/get_forces index the DOFs.

Validation

  • New rotation regression test passes (analytic == FD to ~1e-9); fails on master.
  • get_shift_gradients validated against FD of predict_shifts across a range of crack loads (machine precision after fix; 3–6% and growing before).

🤖 Generated with Claude Code

…rCrack.update_precon (region order)

get_shift_gradients applied only A^T (dchi/dde), dropping the F-induced rotation R (from the polar
decomposition of the deformation gradient) and dR/dde that predict_shifts applies as s = A^T R chi.
This is exact only at R=I; near a crack tip (large F) the analytic shift gradient drifts from the true
derivative, growing with load, which breaks the configurational-force identity f_alpha = -dE/dalpha for a
flexible-BC crack with a multilattice (Cauchy-Born) corrector. Fix differentiates the full applied shift
d(A^T R chi)/dde = A^T((dR/dde)chi + R dchi/dde), dchi/dde analytic, dR/dde by the same finite difference
already taken for the strain field. New regression test test_regression_model_gradient_F_with_rotation
(rotation-bearing F, R!=I) confirms analytic==FD to ~1e-9; the existing gradient tests use symmetric F
(R=I) and could not catch this.

SinclairCrack.update_precon selected regions I+II via self.atoms[:self.N2], assuming the cluster is sorted
region I,II,III. set_regions' default sort ('r_theta_z') is not region-grouped, so the slice is not regions
I+II and the region-I preconditioner block is empty/misaligned (spilu size mismatch). Select via the boolean
mask self.regionI_II (array order), matching how update_atoms/get_forces index the DOFs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jameskermode

Copy link
Copy Markdown
Member Author

@Fraser-Birks please can you take a look at this when you have a chance?

jameskermode and others added 4 commits June 30, 2026 15:39
scipy removed the deprecated disp= keyword from scipy.linalg.sqrtm; disp=True
was the default (return just the matrix), so sqrtm(Usqr) is equivalent and
portable across scipy versions. Fixes the 10 TestPredictCauchyBornShifts
failures (find_grad / fit_taylor).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CubicCrystalDislocation.view_cyl (via _plot_DXA_disloc_line) builds a
colour key and segment name with fractions.Fraction(elem) over the DXA
Burgers vector components. Newer OVITO returns segment.true_burgers_vector
as float32, and Fraction() rejects numpy.float32 (it is not a subclass of
Python float, unlike numpy.float64) with:

    TypeError: argument should be a string or a Rational instance

This broke the documentation build (docs/applications/cylinder_configurations.ipynb).
Convert each component to a native Python float before passing to Fraction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
atomman.defect.differential_displacement still calls matplotlib.cm.get_cmap,
removed in matplotlib>=3.9 (upstream atomman master is not yet compatible).
Skip the test in that case rather than fail; nothing to fix matscipy-side.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test_regression_model_gradient_F_with_rotation's model_prediction precondition
used atol=5e-4, but the regression CB model's intrinsic accuracy floor for the
rotated, 1%-strained shift is ~5.3e-4 (converges there as samples grow; not
noise). This test never actually ran in CI before (the suite died earlier at the
removed scipy sqrtm(disp=) kwarg), so the optimistic dev-machine tolerance went
unnoticed. Relax the precondition to 1e-3; the actual F-rotation correctness is
the analytic-vs-FD gradient check (atol=1e-7), which passes at ~1.6e-10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants