Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
365584b
Perceive bond orders on ghost-free end states rather than with ghosts…
lohedges Nov 10, 2026
faa36f2
Treat sp2 bridges without a double or aromatic bond as sp3.
lohedges Nov 10, 2026
252e2f5
Use angle terms for triple junction planarity.
lohedges Nov 10, 2026
6d99d1a
Keep ring bridge impropers.
lohedges Nov 10, 2026
7fc906d
Stiffen all non-ring bridges.
lohedges Nov 10, 2026
74dc93e
Detect rotatable bonds from angle terms.
lohedges Nov 10, 2026
a42ec06
Add CHANGELOG entry for the perception fix.
lohedges Nov 10, 2026
2cc4ced
Find macrocycle rings and ignore rings closed by ghosts.
lohedges Nov 10, 2026
654ee31
Use safer fallbacks for missing terms and chirality.
lohedges Nov 10, 2026
0b82bc2
Add tests for ring, planarity and RDKit helpers.
lohedges Nov 10, 2026
6caf581
Update CHANGELOG.
lohedges Nov 10, 2026
3ae1285
Simplify ring checks and connectivity handling.
lohedges Nov 10, 2026
76cc0be
Refine missing angle term and chirality fallbacks.
lohedges Nov 10, 2026
3756ee3
Test ghost-closed rings and the chirality fallback.
lohedges Nov 10, 2026
7d0aab8
Use Sire in_ring now that it finds rings of any size.
lohedges Nov 10, 2026
2544091
Only flag rotatable bonds crossed by a surviving anchor dihedral.
lohedges Nov 11, 2026
0d456c0
Stiffen all ghost angles at linear dual bridges.
lohedges Nov 11, 2026
b3adeb6
Remove ghost dihedrals and impropers through linear angles.
lohedges Nov 11, 2026
a3053cc
Avoid linear anchors and extend the linear ghost term tests.
lohedges Nov 11, 2026
ae91e52
Test that terminal junctions avoid linear anchors.
lohedges Nov 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ Changelog
* Added ``--single-well-anchors`` and ``--k-single-well`` to replace surviving anchor dihedrals with a single-well cosine potential whose minimum is the geometry of the end state where the ghost is physical. Multi-well anchors, e.g. the n=2 term of a dummy hydrogen on a carbonyl oxygen, can trap ghosts in an alternative well at intermediate lambda, giving hysteresis between independently equilibrated windows. Anchors with zero force constants or an ill-defined reference dihedral are left unchanged. (Default: False, 5 kcal/mol) [#19](https://github.com/OpenBioSim/ghostly/pull/19).
* Record the options used for each modification in a ``ghostly_options`` property on each modified molecule, and raise an error when modifying a system that has already been modified, unless ``--force`` is used. Forced modifications are applied on top of the existing ones [#20](https://github.com/OpenBioSim/ghostly/pull/20).
* Added support for Python 3.13 and 3.14, and dropped support for Python 3.10 and 3.11.
* Fixed bridge atoms being typed by RDKit on end states with ghost atoms attached, where bond orders often couldn't be inferred, leaving every heavy atom typed as sp3 with no aromaticity. Bridge typing no longer uses RDKit. The chirality check used by ``--linearise-ring-break`` now converts the ghost-free end state, and skips linearisation with a warning if bond orders can't be inferred [#23](https://github.com/OpenBioSim/ghostly/pull/23).
* Decide triple junction planarity from the energy needed to flatten the angle terms between the physical neighbours of the bridge, rather than its RDKit hybridisation. Junctions with a missing angle term are treated as non-planar [#23](https://github.com/OpenBioSim/ghostly/pull/23).
* Decide whether a bridge is in a ring, for stiffening and keeping impropers, from the physical atoms of the end state, so rings closed only by ghost atoms don't count [#23](https://github.com/OpenBioSim/ghostly/pull/23).
* Keep improper dihedrals that hold a single ghost in the plane of a ring bridge, since nothing else stops the ghost crossing the plane when the angles aren't stiffened, and remove the ``--stiffen-ring-bridges`` option [#23](https://github.com/OpenBioSim/ghostly/pull/23).
* Always stiffen ghost angles at bridges that aren't in a ring, and remove the ``--stiffen-sp2-bridges`` option. Without impropers, the angle terms of an sp2 bridge don't hold a ghost in the plane, so skipping stiffening let it cross freely. At linear bridges, angles through poorly-scoring physical neighbours are stiffened too, since the ghost angles can only all be satisfied at 90 degrees [#23](https://github.com/OpenBioSim/ghostly/pull/23).
* Detect rotatable bridge bonds from the angle terms of the bridge, rather than its RDKit hybridisation, so that rotamer detection is consistent with junction planarity [#23](https://github.com/OpenBioSim/ghostly/pull/23).
* Remove dihedrals and impropers involving ghost atoms that pass through an angle that is linear at the end state, e.g. anchor dihedrals at a terminal junction whose physical neighbour is a nitrile carbon. These terms are undefined for collinear atoms, where their forces diverge [#23](https://github.com/OpenBioSim/ghostly/pull/23).

[2026.2.0](https://github.com/openbiosim/ghostly/compare/2026.1.0...2026.2.0) - Sep 2026
----------------------------------------------------------------------------------------
Expand Down
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,24 @@ handle the diversity of perturbations encountered in practice:

- **Anchor selection scoring:** physical anchor atoms are scored to avoid
transmuting or bridge atoms, preventing geometrically inconsistent constraints.
- **Ring and sp2 bridge handling:** angle stiffening is skipped by default for
ring and sp2 bridges, where local geometry already constrains the ghost and
90° stiffening would introduce significant strain. It can be re-enabled via
`--stiffen-ring-bridges` and `--stiffen-sp2-bridges`.
- **Ring bridge handling:** ring bridges are not stiffened. Instead, their
improper dihedrals with a single ghost are kept, holding the ghost in the
plane of the ring, where the rigid ring keeps the coupling acceptable. All
other bridges are stiffened.
- **Junction planarity:** whether a triple junction, or a bridge for rotamer
detection, is planar is decided from the energy needed to flatten the angle
terms between its neighbours.
- **Residual term cleanup:** a post-processing pass removes mixed improper
dihedrals and cross-bridge dihedrals missed by the per-bridge junction
handlers, as well as angles where a ghost atom is the central atom and both
terminal atoms are physical.
dihedrals (other than those at ring bridges) and cross-bridge dihedrals
missed by the per-bridge junction handlers, as well as angles where a ghost
atom is the central atom and both terminal atoms are physical.
- **Mixed dihedral softening:** surviving mixed ghost/physical dihedrals can
be softened via `--soften-anchors` to allow ghost groups to reorient and
avoid steric clashes at small λ.
- **Rotamer stiffening:** `--stiffen-rotamers` replaces rotatable sp3 anchor
dihedrals with a stiff single-well cosine to control ghost orientation
through flexible bonds.
- **Rotamer stiffening:** `--stiffen-rotamers` replaces anchor dihedrals
across rotatable bonds, i.e. those not in a ring whose bridge atom is neither
planar nor linear, with a stiff single-well cosine to control ghost
orientation through flexible bonds.
- **Ring-breaking perturbations:** adjacent bridges with independent ghost
groups retain each other as physical neighbours; angles with a ghost central
atom spanning two physical neighbours are replaced by a linear spacer
Expand Down
32 changes: 1 addition & 31 deletions src/ghostly/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def run():
help="""
Whether to replace rotamer anchor dihedrals with a stiff
single-well cosine potential. When a bridge-physical bond is
rotatable (not in a ring, sp3 bridge), surviving anchor
rotatable (not in a ring, non-planar bridge), surviving anchor
dihedrals can allow rotameric transitions of ghost atoms at
intermediate lambda.
""",
Expand All @@ -202,34 +202,6 @@ def run():
required=False,
)

parser.add_argument(
"--stiffen-ring-bridges",
action="store_true",
help="""
Apply 90 degree angle stiffening when the bridge atom is in a
ring. By default this is skipped since the ring geometry already
constrains the ghost position and stiffening introduces strain.
A warning is logged when this is enabled and a ring bridge is
detected.
""",
default=False,
required=False,
)

parser.add_argument(
"--stiffen-sp2-bridges",
action="store_true",
help="""
Apply 90 degree angle stiffening when the bridge atom is sp2 and
not in a ring. By default this is skipped since sp2 hybridisation
already constrains the ghost to the molecular plane and stiffening
introduces ~30 degrees of strain. A warning is logged when this
is enabled and an sp2 bridge is detected.
""",
default=False,
required=False,
)

parser.add_argument(
"--linearise-ring-break",
action=argparse.BooleanOptionalAction,
Expand Down Expand Up @@ -434,8 +406,6 @@ def run():
k_single_well=k_single_well.value(),
stiffen_rotamers=args.stiffen_rotamers,
k_rotamer=k_rotamer.value(),
stiffen_ring_bridges=args.stiffen_ring_bridges,
stiffen_sp2_bridges=args.stiffen_sp2_bridges,
linearise_ring_break=args.linearise_ring_break,
force=args.force,
)
Expand Down
Loading
Loading