Skip to content

[pull] develop from lammps:develop - #173

Merged
pull[bot] merged 99 commits into
comphy-lab:developfrom
lammps:develop
Jul 21, 2026
Merged

[pull] develop from lammps:develop#173
pull[bot] merged 99 commits into
comphy-lab:developfrom
lammps:develop

Conversation

@pull

@pull pull Bot commented Jul 21, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

jtclemm and others added 30 commits June 17, 2026 15:40
First stage of re-implementing the PERI package on the BPM framework.

Adds BondBPMPeri (bond_style bpm/peri), cloning the bond_bpm_zero structure:
- nhistory=1, update_flag=0; stores the reference bond length r0 via
  FixBondHistory (reference config captured on the first step)
- parses 'bond_coeff <type> pmb <c> <horizon> <s00> <alpha>' (PMB only for now)
- applies ZERO force; the PMB force law and the per-type-pair (#984) breaking
  criterion arrive in Stage 1
- init_style() requires a per-atom d_vfrac property, auto-creates internal
  d_s0/d_smin property/atom storage if absent, and warns (does not error) when
  pair_style bpm/peri is missing (a pure-bond run is legal)
- no new atom style: uses atom_style bond + fix property/atom for per-atom data

Adds examples/bpm/peri/in.bpm.peri.pmb. Validated: builds cleanly, creates the
peridynamic bond set (6220 bonds), and runs 0 timesteps with zero force/energy,
giving identical results at np=1 and np=4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bond_style bpm/peri now requires pair_style bpm/peri (hard error), but
silently accepts pair_style zero so the bond style can be driven in
isolation by the test harness or for a deliberate no-contact run. Detection
uses force->pair_match() so pair_style hybrid and accelerator suffixes also
qualify. There is no strong physical case for bonds-without-contact: the
contact pair is inert when no non-bonded contact occurs, but omitting it
silently allows interpenetration after fracture or large deformation.

Also modernizes the error/warning calls (argument-index and NOLASTLINE forms)
for better input-location reporting.

Validated: the pair_style zero example runs clean; a pair_style lj/cut deck is
rejected at bond_style init.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implement the PMB (prototype microelastic brittle) pairwise bond force on the
single-visit BPM bond loop:
- fbond = -(c * vfrac_eff * vfrac_scale * stretch)/r, applied equal-and-opposite
- vfrac_eff = mean of the two nodal volumes, so the bond is Newton-third-law
  balanced and momentum-conserving; it reduces to legacy's vfrac[j] form for
  uniform nodal volume (the validated regime). Legacy applies vfrac[j] to i and
  vfrac[i] to j, which conserves momentum only for uniform volumes.
- partial-volume horizon taper (vfrac_scale) reproduced from legacy pair_peri_pmb
- bond energy 0.5 * c * vfrac_eff * vfrac_scale * stretch * dr
- init_style now requires a uniform cubic lattice (needed by the taper) and
  resolves the per-atom d_vfrac index

Validated: a single-bond test matches the closed form to full precision (force
f = c*vfrac*stretch equal-and-opposite, energy 0.5*c*vfrac*stretch*dr); the
example builds and runs identically at np=1 and np=4.

Per-type-pair (#984) bond breaking with smin/s0 bookkeeping and the per-step
ghost forward_comm follows in Stage 1b.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the critical-stretch bond-breaking criterion to bond_style bpm/peri,
re-derived for the single-visit BPM loop:
- break when stretch > s00 - alpha*max(smin_i, smin_j), evaluated PER BOND with
  per-type-pair s00/alpha (not collapsed into a per-atom scalar). This is the
  #984 fix: a weak interface bond breaks even when both endpoints also carry
  strong bonds.
- smin (minimum stretch, drives breaking) and s0 (diagnostic critical stretch)
  accumulate per step into the d_smin/d_s0 property/atom arrays, committed with
  the -DBL_MAX no-bond sentinel so a bondless atom cannot trigger a neighbor's
  break.
- the bond style forward-communicates smin each step so the break test reads a
  neighbor's previous-step smin even when the neighbor is a ghost (under newton
  bond off each atom otherwise accumulates its own smin locally, no reverse_comm).
- sentinels are initialized once when the storage is first created; restored
  from restart otherwise. A broken bond exerts no force and does not contribute
  to the new smin/s0.

Validated: single-bond break (energy drops to zero); fracture under strain is
bit-identical at np=1 and np=4 with stretched survivors remaining (confirming the
ghost-smin communication); and the #984 localization test (strong-weak-strong
chain at equal stretch) breaks only the weak interface bond (E_mol drops by
exactly 1/3) where legacy's collapsed-MAX would have suppressed it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add PairBPMPeri, the short-range contact pair that pairs with bond_style
bpm/peri. It supplies the repulsive force between non-bonded near pairs (the
1-2 special weight censors bonded pairs, which the bond force handles):
- fpair = -(rk/r) with rk = 15 * k * vfrac_eff * (dr / horizon),
  dr = r - d_ij, applied equal-and-opposite over the half neighbor list.
- contact onset d_ij = 1.35*lc. Legacy uses min(0.9*r0_ref, 1.35*lc), but for
  non-bonded pairs (reference separation exceeds the horizon) the min is always
  1.35*lc, so the dropped reference positions (x0) are not needed.
- mean nodal volume vfrac_eff keeps the contact Newton-third-law balanced and
  reduces to legacy's vfrac[j] form for uniform nodal volume.
- init_style requires a uniform cubic lattice and the d_vfrac property, and
  rejects a non-bpm/peri bond style (tolerant of force->bond being unset during
  create_bonds, which precedes bond_style in the standard BPM deck order).

The example switches from pair_style zero to pair_style bpm/peri.

Validated: contact force and energy match the closed form exactly (f = -|rk|,
repulsive and equal-and-opposite; E = 0.5*rk*dr); the bond+contact example runs
identically at np=1 and np=4 with the contact correctly inert on the undeformed
(fully bonded) lattice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the linear peridynamic solid (LPS) model to bond_style bpm/peri. The LPS
bond force couples every bond at an atom through the dilatation theta, so the
single compute() runs a three-pass scheme reusing the BPM manybody comm pattern:
- compute_wvolume() builds the static weighted volume
  wvolume[i] = sum_j r0*vfrac[j]*scale once from the reference configuration and
  forward-communicates it (refreshed on each reneighbor).
- compute_dilatation() accumulates theta[i] = (3/wvolume[i]) * sum_j
  dr*vfrac[j]*scale locally (under newton bond off, no reverse_comm) and
  forward-communicates it.
- the force loop reads theta/wvolume of BOTH endpoints, with the isotropic
  influence function omega = 1/r0 and the mean nodal volume for Newton-third-law
  balance. The volumetric energy 0.5*K*theta^2 is per atom; the deviatoric
  energy is per bond.

wvolume/theta are bond-style per-atom arrays (allocated only when LPS is in use);
a commflag selects which array each forward_comm carries (smin/theta/wvolume).
New coeff form: bond_coeff <type> lps K G horizon s00 alpha.

Validated: a periodic crystal under isotropic strain eps gives
E_mol = 0.5*K*(3eps)^2*N = 4.5*K*eps^2*N to full precision (confirming theta=3eps,
the volumetric energy, and the vanishing deviatoric part), net force zero to the
roundoff floor (uniform-strain equilibrium), and bit-identical E_mol at np=1 and
np=4 (confirming the ghost theta/wvolume communication). PMB is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Peridynamics needs a nodal volume on every atom, so the suggested
fix property/atom command uses group 'all' rather than a '<group>' placeholder
that might invite scoping it to a subset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the viscoelastic (VES) model to bond_style bpm/peri -- the first
evolving-history model. It extends the LPS dilatation with a relaxing deviatoric
response governed by a modulus ratio lambda and relaxation time tau:
- nhistory=3 / update_flag=1 are resolved in init_style() before the base class
  creates the bond-history fix, whenever a VES bond type is present. The two
  evolving slots (deviator extension + back extension) are zeroed in store_data()
  and read-prior / written-back per bond each step (bond_bpm_rotational pattern).
- force = elastic dilatation (3K*theta) plus a viscoelastic deviatoric term with
  the back-extension recurrence edb = devExt*(1-decay) + devBack*decay +
  beta*(dev-devExt), decay = exp(-dt/tau). A single symmetric deviatoric extension
  dev = dr - theta_avg*r0/3 per bond keeps the bond Newton-third-law balanced and
  reduces to LPS for lambda=0 (uniform dilatation).
- per-type coeffs lambda, tau. bond_coeff <type> ves K G lambda tau horizon s00 alpha.

Validated: a periodic crystal under uniaxial strain, frozen, relaxes its
deviatoric stress as exp(-t/tau) with the prescribed tau (to the O(dt/tau)
discretization error) toward (1-lambda) times its initial value, and is identical
at np=1 and np=4 (the per-bond history and ghost theta stay consistent across
procs). PMB and LPS are unchanged.

Also parenthesizes chained '&&'/'||' conditional operands for readability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the EPS (elastic-plastic, ordinary state-based) constitutive model to
bond_style bpm/peri, completing the four legacy PERI models (PMB/LPS/VES/EPS).

EPS reuses the LPS/VES state-based dilatation infrastructure and adds a
per-atom return-mapping: a new compute_plastic_state() pass accumulates the
deviatoric force-state norm tdnorm[i] over each atom's bonds, performs the
per-atom yield check and plastic-multiplier increment deltalambda[i], and
forward-comms both to ghosts so the per-bond force loop can read both
endpoints. The per-bond plastic deviator extension (history slot 1,
update_flag=1) evolves each step. The accumulated plastic multiplier is a
public d_lambda property/atom diagnostic. nhistory=2 for EPS.

Validation (periodic surface-free crystal, static change_box loading):
- EPS elastic branch (yield disabled) reduces to LPS bit-for-bit in the
  interior, for G=0 and G=K. Confirmed both the dilatation and deviatoric
  decompositions match.
- Elastic-perfectly-plastic single-shot stress-strain: linear elastic then a
  clean deviatoric-stress plateau at yield, with the plastic multiplier
  growing past onset.
- np=1 == np=4 bit-for-bit (tdnorm/deltalambda forward_comm correct).

Two correctness fixes uncovered during validation (affect all models):

1. Peridynamic virial. The bond force and energy carry one nodal-volume
   factor, but the PD stress integrates over BOTH nodal volumes. ev_tally now
   receives fbond*vfrac_eff (and the contact pair fpair*vfrac_eff), reproducing
   legacy PERI's fbond*vfrac[i] virial. Without this the reported pressure was
   ~10 orders of magnitude too high; it is now physical (~K*strain). Energy is
   unchanged (single vfrac, legacy convention).

2. compute_dilatation() skipped EPS bonds (only matched LPS/VES), leaving
   theta=0 for EPS so the dilatation and deviatoric terms vanished. EPS is now
   included with LPS/VES.

Also: the internal s0/smin/lambda property/atom fields are now auto-created
per-field (only the missing ones), so a user may pre-declare e.g. d_lambda for
dumping and the bond style reuses it.

Known follow-up (documented for Stage 7 bug report): the EPS deviatoric norm
deliberately drops legacy's extra dilatation factor theta (a likely latent
PERI bug); and the legacy plastic-extension update is only conditionally
stable under large step-loading (a gain ~2/r0 overshoots), shared with legacy
peri/eps -- both to be reported with the analytic evidence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the legacy-style plastic deviator-extension update with the
dimensionally-consistent radial-return form. The legacy update
edp += rkNew*deltalambda reduces (uniform case) to
edp += (2/r0)*(dev-edp)*f, whose ~2/r0 gain (~1300 in SI units)
overshoots for any sizeable plastic fraction f and oscillates/diverges
under incremental loading -- a latent PERI bug masked in legacy by the
extra-theta yield norm (which makes legacy barely yield at all).

The radial return scales the trial deviatoric force state onto the yield
surface, t_d^new = (yieldnorm/||t_d||)*t_d^trial; staying consistent, the
elastic deviatoric extension scales by the same factor, so

    edp_new = edp + (dev - edp)*(1 - radial),  radial = yieldnorm/tdnorm_b

The increment is a length times a dimensionless fraction in [0,1) -- a
contraction that lands on the yield surface in one step. The recoverable
deviatoric elastic energy now uses the returned elastic extension
(dev - edp_new).

Because the force loop's radial return needs only the per-atom norm of both
endpoints, the per-bond yield gate no longer reads deltalambda. Drop the
deltalambda per-atom array, its COMM_DELTALAMBDA forward_comm, and the
second ghost exchange; the accumulated plastic multiplier lambdaValue is now
computed locally. One forward_comm per step instead of two.

Validation (periodic crystal, static change_box): incremental uniaxial
loading now shows a clean elastic-perfectly-plastic plateau (deviatoric
stress holds ~3.3e8, plastic multiplier accumulates monotonically) instead
of the prior sign-flipping runaway. Unchanged: EPS-elastic == LPS bit-for-bit
in the interior; single-shot plateau; np=1 == np=4. The legacy edp gain and
the norm extra-theta are both to be reported in Stage 7 with this evidence.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add compute bpm/peri/damage/atom, the per-atom volume-weighted bond damage

    damage[i] = 1 - (sum of nodal volume over surviving bonds) / vinter[i]

where vinter[i] is the reference interaction volume (sum of partner nodal
volumes at the undeformed configuration). damage is 0 for an intact node and
approaches 1 as a node loses bonds. This mirrors legacy compute damage/atom
but reads the BPM bond topology (newton bond off -> every bond is stored at
both endpoints, so the surviving volume is a purely local sum, no comm).

bond_style bpm/peri now computes vinter once in store_data() (the reference
capture hook, guarded by stored_flag) and stores it in a d_vinter
property/atom (ghost yes, restart yes) auto-created alongside d_s0/d_smin,
per-field. Restart-safe: store_data() is skipped on restart, but the d_vinter
values are restored from the restart file, and vinter is never modified after
the reference, so post-restart damage stays correct even if bonds broke before
the checkpoint. The compute resolves vfrac/vinter in init() (not the
constructor) because bond_style creates d_vinter during force->init(), which
precedes the compute's init() in the setup sequence.

The other per-atom diagnostics (s0, smin, lambdaValue) are already d_ property/
atom fields, readable directly via compute property/atom.

Validation (periodic sc crystal, controlled bond deletion, no dynamics):
- reference (all bonds intact): damage == 0 exactly (alive volume == vinter)
- all bonds deleted: damage == 1 exactly
- delete the mutual bond of two adjacent interior atoms: each has damage
  == 1/122 exactly (an interior node has 122 bonds within the 3.0002-lattice
  horizon), max == 1/122, sum == 2/122 -- pins the per-atom vinter normalization
- np=1 == np=4 bit-for-bit; PMB/LPS/VES/EPS forces unchanged

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Documentation:
- bond_bpm_peri.rst, pair_bpm_peri.rst, compute_bpm_peri_damage_atom.rst
- add the new styles to Commands_{bond,pair,compute}.rst and the master
  bond_style.rst / pair_style.rst / compute.rst lists (style_check passes)
- Howto_peri.rst: a "BPM-based peridynamics" section with a worked deck, a
  PERI->BPM migration table, the d_vfrac user-declaration rule, and a note on
  the opt-in fragmentation cleanup (thermo_modify lost / lost/bond ignore)
- false_positives.txt: author surnames + technical terms

Examples (examples/bpm/peri/in.bpm.peri.{pmb,lps,ves,eps}): the legacy
cylinder-and-indenter impact recast on the BPM framework, with a fixed bounded
box and the opt-in lost-atom / lost-bond cleanup so the shattering target runs
to completion (the cleanup replicates legacy PERI's silent flyaway handling but
is explicit and user-controlled).

Attribution and citations:
- contributing-author headers on every bpm/peri style crediting the original
  PERI authors (Parks SNL for PMB/LPS + the shared dilatation/weighted-volume
  infrastructure; Rahman and Foster UTSA for VES/EPS) and the port itself
- carry over the Parks08 CiteMe; additionally surface the Foster, Silling, and
  Chen (2010) viscoplasticity paper at runtime when an eps bond type is used
- docs cite Foster/Silling/Chen (2010, Int J Numer Methods Eng 81:1242-1258)
  and the Rahman & Foster PDLAMMPS implementation reports -- references the
  legacy PERI docs never listed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a YAML-driven regression + analytic test harness for the BPM pair+bond
styles, modeled on the GRANULAR DEM suite (unittest/granular on the
granular-tests branch).  The driver (test_bpm_common.cpp) builds the system
entirely from the YAML -- a variables block for ${var} substitution,
pre_commands for geometry and per-atom storage, pair_style/pair_coeff for the
contact model, post_commands for create_bonds + the run-time special weights +
the integrator, and bond_style/bond_coeff for the model under test -- then runs
the configured run_segments and compares per-atom positions, velocities and
forces (plus any enabled analytic model) against the recorded reference.

The harness is generic over BPM (the styles come from the YAML), so the same
driver serves bpm/peri, the existing bpm/spring family, and styles layered on
BPM such as RHEO.  Bond styles are applied after create_bonds so the BPM
two-stage special_bonds idiom is honored; both pair-newton settings are tested.

Analytic checks (test_analytic_models.cpp) are opt-in via the YAML
analytic_model key: pmb_force verifies the closed-form PMB single-bond law
|f| = c*vfrac*|stretch| from live positions.  References are generated in place
with the -u flag.

Shared-infrastructure move (imported from the granular-tests branch so the two
PRs merge cleanly -- same maintainers): the YAML reader/writer and error_stats
move from unittest/force-styles/ up to unittest/, and force-styles + utils
reference them via ../.  libyaml discovery moves to the unittest top-level
CMakeLists.

Tests: bpmperi-{pmb,lps,ves,eps}-twobody exercise all four constitutive models
(trajectory regression; pmb adds the analytic check).  All pass under CTest;
force-styles tests are unaffected by the move.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Code-review pass over the bpm/peri styles:

- The linear partial-volume taper (Silling 2007) was copy-pasted in five
  places (compute, compute_wvolume, compute_dilatation, compute_plastic_state,
  single).  Extract it to a single vfrac_taper() static helper and drop the
  now-unused 'delta' locals.  Behavior is unchanged: the bit-identical
  unittest/bpm trajectory regression and the run-0 thermo of all four models
  are identical before and after.

- Fix a shutdown-time leak of id_fix_property_peri: the string was freed only
  inside the 'modify->nfix' guard, so it leaked when no fixes remained.  Free
  it unconditionally; only the delete_fix call needs the guard.

No other dead code, unused members, or leftover instrumentation were found.
The test harness deliberately keeps the granular-inherited config fields for
merge-cleanliness and genericity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add examples/bpm/peri/benchmark (legacy + bpm PMB decks and a README with the
full methodology and results) and a performance paragraph to the PERI->BPM
transition guide in Howto_peri.rst.

On a periodic 16^3 simple-cubic block (4096 nodes, 122 bonds/node), measured
from the reference configuration over 200 steps, the bpm/peri pair+bond styles
are 3.6x (pmb), 5.2x (lps), 4.4x (ves) and 5.5x (eps) faster than the legacy
peri/* pair styles on a single rank, and ~4x faster on four ranks.  The gain is
structural: legacy walks a double-counted partner list and does bond+contact in
one pass; BPM visits each bond once and the contact pair carries a separate,
near-empty short-range list.  The per-step dilatation/break-state forward
communication for the state-based models is a negligible fraction of the cost
(the LPS 3-pass comm flagged in planning as the likely bottleneck is not one).

This clears the project's performance acceptance criterion (parity with legacy)
by a wide margin -- bpm/peri is the faster implementation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bond_style bpm/zero (added to support the bpm/peri port, mirroring the other
"zero" styles) had no documentation.  Add doc/src/bond_bpm_zero.rst and the
missing Commands_bond.rst / bond_style.rst index entries (style_check now
passes for it).  The page explains that the style stores the bond reference
state and breaks bonds at a critical strain but applies no force, and is
intended for testing/debugging the BPM machinery (history, breaking,
store/local, the manybody communication) and as a template -- not production
mechanics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- init_style now refuses run_style respa (no respa hooks are implemented and,
  given bpm/peri is several times faster than legacy peri/*, a multi-timescale
  split would never pay off), and warns when the bond horizon differs from the
  contact pair_style bpm/peri cutoff by more than half a lattice spacing -- a
  common pair_coeff/bond_coeff typo.

- The per-step dilatation theta of the state-based models (lps/ves/eps) can now
  be exposed for visualization: if the user declares a d_theta property/atom
  before the bond style, the dilatation of each owned node is written into it
  every step (readable via compute property/atom theta).  It is opt-in (only
  written when present) so a referencing compute can be defined up front, and
  so no storage is spent when it is unused.

Verified: theta == eps_xx for uniaxial strain; the unittest/bpm trajectory
regression for all four models is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- lps_dilatation analytic model: for the two-body system the weighted volume is
  r0*vfrac, so theta = 3*stretch.  The new model reads the per-step dilatation
  from the d_theta property and compares it to three times the live stretch
  (bpmperi-lps-dilatation.yaml), also exercising the d_theta diagnostic.

- restart round-trip: a new restart_segment / restart_commands YAML option makes
  the driver write a restart after a segment, rebuild a fresh LAMMPS instance
  from it (issuing restart_commands to restore the non-restart setup -- lattice
  and integrator), and continue.  The continued trajectory must still match the
  uninterrupted reference, which exercises the restart of the per-type
  coefficients, the auto-created property/atom fields and the FixBondHistory
  reference/evolving state (bpmperi-pmb-restart.yaml).

Both pass for all four models alongside the existing trajectory regression.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…volume)

- pair_style bpm/peri: accumulate the force on atom i in registers across the
  inner neighbor loop and write it back once, instead of repeatedly indexing
  f[i][*].  A standard, safe pair-loop best practice; bit-identical.

- bond_style bpm/peri: precompute winv = 1/wvolume once per atom per step (incl.
  ghosts) so the state-based force and plastic-state loops use multiplies rather
  than ~4 divisions per bond.  Measured ~5% faster bond loop for lps/eps (the
  divisions are not the whole story -- the loop is also sqrt/memory bound), pmb
  unchanged (no weighted volume).  Not bit-identical (a*(1/b) vs a/b rounding),
  so the state-based unittest/bpm references are regenerated; the eps-elastic ==
  lps interior identity is preserved since both use winv consistently.

The pair-style nested-loop pointer/_noalias changes were deliberately not made:
the contact pair is only 6-13% of the runtime (Amdahl), so they would cost
readability for no useful gain.

Updated benchmark: bpm/peri is 3.6x (pmb), 5.4x (lps), 4.4x (ves), 5.9x (eps)
faster than legacy peri/* on a 16^3 block.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New analytic model lps_force: for a single colinear LPS bond the shear term
  vanishes and the force reduces to |f| = 18*K*|stretch|/r0 (G drops out). Gated
  on bpmperi-lps-twobody (tol 1e-9; matches to ~1e-14), complementing
  lps_dilatation which validates theta -- now both theta and the force assembled
  from it are checked.

- New test driver test_bpm_zero (thin copy of test_bpm_peri, BpmZero suite) that
  reuses the shared test_bpm_common driver unchanged, exercising bond_style
  bpm/zero with pair_style zero. This also demonstrates the harness is generic
  over the BPM package, not specific to bpm/peri.

- New analytic model bpm_zero asserts the defining property (force on each bonded
  node is identically zero despite a stretched bond) and the live global bond
  count (variable nbonds_expect), so the breaking machinery is exercised:
  bpmzero-intact-twobody keeps the bond (nbonds_expect 1, ecrit 0.5),
  bpmzero-break-twobody breaks it (nbonds_expect 0, ecrit 0.003). Both pass with
  identical (force-free, ballistic) trajectories, so only the analytic bond-count
  check distinguishes them -- proving the break actually fired.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New test driver test_bpm_spring (BpmSpring suite) reusing the shared
test_bpm_common driver unchanged -- these central-force styles run on plain
atom_style bond, so per-atom pos/vel/force capture suffices.

Two analytic models, both with smooth off / gamma 0 / normalize off for an exact
closed form:
- spring_force: linear central spring, Hooke's law |f| = k*|r - r0|.
- spring_plastic: past yield the plastic strain tracks the total strain so the
  elastic part saturates, giving an elastic-perfectly-plastic plateau
  |f| = k*eplastic*r0 independent of further stretch.

Under identical loading the elastic spring force grows with displacement
(0.0025 -> 0.0050 -> 0.0074) while the plastic bond force plateaus at exactly
k*eplastic*r0 = 0.002, so the two tests differ precisely in the yield plateau
each analytic model checks. bpm/spring reads ghost velocities for its damping
term, so the decks set comm_modify vel yes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stage 8 moved error_stats.{h,cpp} (and the yaml reader/writer) up from
unittest/force-styles/ to unittest/ so the bpm and granular suites can share
them, and updated every CMake source list and the library #includes to "../".
But test_error_stats.cpp directly #includes the implementation ("error_stats.cpp")
to exercise the standalone ErrorStats class without linking, and that bare path
still resolved to the old force-styles/ location -- which no longer exists. The
unittest build therefore failed on every CI platform (the style_tests build is a
prerequisite of all unittest jobs), while local targeted builds that never
compiled this target stayed green.

Point the direct include at the new location ("../error_stats.cpp"); its own
"error_stats.h" resolves relative to the moved file. ErrorStats test passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In the MD framework the special_bonds mechanism that skips pair forces between
bonded particles is referred to as "exclusion", so use "excluded" rather than
"censored" in the bpm/peri contact-pair comments and the benchmark writeup.
Comment/text only; no functional change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to the bpm/peri terminology change, with the BPM author's agreement:
"exclude" is the established MD term for skipping pair interactions (the
special_bonds weights are the exclusion mechanism). Replace the remaining
"censor" wording in the BPM special-bonds checks (bond_bpm.cpp,
fix_update_special_bonds.cpp) and in the pair_tracker time/min doc, where
"exclude short-lived interactions" also pairs naturally with the preceding
"to be included". Comment/text only; no functional change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "censor" -> "exclude" change in pair_tracker.rst is a documentation fix for
a different package, so it does not belong in the peri port PR. It now lives on
the doc-updates-and-fixes collection branch (PR #5039); restore the original
wording here so this branch only touches BPM/peri (plus the two BPM special-bond
comments, which are in scope and the BPM author approved). Forward-only revert;
no history rewrite on the published PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
akohlmey and others added 27 commits July 18, 2026 18:05
BPM-based peridynamics: pair_style/bond_style bpm/peri (PERI models on the BPM framework)
Remove pair style agni and ML-RANN from the distribution
@pull pull Bot locked and limited conversation to collaborators Jul 21, 2026
@pull pull Bot added the ⤵️ pull label Jul 21, 2026
@pull
pull Bot merged commit d3b14f6 into comphy-lab:develop Jul 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants