Skip to content

Commit 82d4478

Browse files
authored
Merge pull request #434 from OpenBioSim/fix_ring_break_merge
Fix mergeIntrascale using per-state connectivity
2 parents b9b8062 + 76a90e9 commit 82d4478

3 files changed

Lines changed: 171 additions & 269 deletions

File tree

corelib/src/libs/SireIO/biosimspace.cpp

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,76 +1760,58 @@ namespace SireIO
17601760

17611761
SireBase::PropertyList mergeIntrascale(const CLJNBPairs &nb0,
17621762
const CLJNBPairs &nb1,
1763-
const MoleculeInfoData &merged_info,
1763+
const Connectivity &conn0,
1764+
const Connectivity &conn1,
1765+
const CLJScaleFactor &sf14,
17641766
const QHash<AtomIdx, AtomIdx> &mol0_merged_mapping,
17651767
const QHash<AtomIdx, AtomIdx> &mol1_merged_mapping)
17661768
{
1767-
// Helper lambda: copy scaling factors from 'nb' to 'nb_merged' according
1768-
// to the provided mapping. Takes nb_merged by reference to avoid copies.
1769-
// When copy_all is true, ALL pairs between mapped atoms are written
1770-
// (including the default (1,1)), so that the correct end-state values
1771-
// always overwrite any values set by a prior ghost-topology pass.
1772-
// When copy_all is false, only non-(1,1) pairs are written (sufficient
1773-
// for the first/ghost pass, where unset pairs default to (1,1) anyway).
1774-
auto copyIntrascale = [&](const CLJNBPairs &nb, CLJNBPairs &nb_merged,
1775-
const QHash<AtomIdx, AtomIdx> &mapping,
1776-
bool copy_all = false)
1769+
// Build base CLJNBPairs from the per-state merged connectivity. This
1770+
// correctly captures bonded distances (1-2, 1-3, 1-4) in the merged
1771+
// atom space, including paths that only exist in one end state (e.g.
1772+
// the ring-closure bond for ring-breaking perturbations).
1773+
CLJNBPairs intra0(conn0, sf14);
1774+
CLJNBPairs intra1(conn1, sf14);
1775+
1776+
// Override with per-pair values from the individual molecule intrascales.
1777+
// For standard AMBER molecules these are identical to the connectivity-
1778+
// derived values and the override is a no-op. For force fields with
1779+
// non-default per-pair scale factors (e.g. GLYCAM funct=2 with (1,1)
1780+
// instead of global sf14 for certain 1-4 pairs) the override replaces
1781+
// the global-sf14 value set by the base construction with the correct
1782+
// per-pair value.
1783+
auto overrideIntrascale = [&](const CLJNBPairs &nb, CLJNBPairs &nb_merged,
1784+
const QHash<AtomIdx, AtomIdx> &mapping)
17771785
{
17781786
const int n = nb.nAtoms();
17791787

17801788
for (int i = 0; i < n; ++i)
17811789
{
17821790
const AtomIdx ai(i);
1783-
1784-
// Get the index of this atom in the merged system.
17851791
const AtomIdx merged_ai = mapping.value(ai, AtomIdx(-1));
17861792

1787-
// If this atom hasn't been mapped to the merged system, then we
1788-
// can skip it, as any scaling factors involving this atom will
1789-
// just use the default.
17901793
if (merged_ai == AtomIdx(-1))
17911794
continue;
17921795

17931796
for (int j = i; j < n; ++j)
17941797
{
17951798
const AtomIdx aj(j);
1799+
const AtomIdx merged_aj = mapping.value(aj, AtomIdx(-1));
17961800

1797-
// Get the scaling factor for this pair of atoms.
1798-
const CLJScaleFactor sf = nb.get(ai, aj);
1801+
if (merged_aj == AtomIdx(-1))
1802+
continue;
17991803

1800-
// Copy if this is a non-default scaling factor, or if
1801-
// copy_all is set (second pass: must overwrite ghost-topology
1802-
// values even when the correct end-state value is (1,1)).
1803-
if (copy_all or sf.coulomb() != 1.0 or sf.lj() != 1.0)
1804-
{
1805-
// Get the index of the second atom in the merged system.
1806-
const AtomIdx merged_aj = mapping.value(aj, AtomIdx(-1));
1807-
1808-
// Only set the scaling factor if both atoms have been
1809-
// mapped to the merged system. If one of the atoms
1810-
// hasn't been mapped, then we can just use the default.
1811-
if (merged_aj != AtomIdx(-1))
1812-
nb_merged.set(merged_ai, merged_aj, sf);
1813-
}
1804+
const CLJScaleFactor nb_sf = nb.get(ai, aj);
1805+
const CLJScaleFactor base_sf = nb_merged.get(merged_ai, merged_aj);
1806+
1807+
if (nb_sf.coulomb() != base_sf.coulomb() or nb_sf.lj() != base_sf.lj())
1808+
nb_merged.set(merged_ai, merged_aj, nb_sf);
18141809
}
18151810
}
18161811
};
18171812

1818-
// Create the intrascale objects for the merged end-states.
1819-
CLJNBPairs intra0(merged_info);
1820-
CLJNBPairs intra1(merged_info);
1821-
1822-
// Copy scaling factors from the original intrascale objects to the
1823-
// merged intrascale objects. For each end state, the ghost molecule's
1824-
// topology is written first (non-default pairs only), then the correct
1825-
// end-state topology overwrites with copy_all=true so that (1,1) pairs
1826-
// are also written. This handles ring-breaking perturbations where a
1827-
// pair that is excluded/1-4 in one state becomes fully interacting (1,1)
1828-
// in the other state and must not be left at the ghost state's value.
1829-
copyIntrascale(nb1, intra0, mol1_merged_mapping);
1830-
copyIntrascale(nb0, intra0, mol0_merged_mapping, true);
1831-
copyIntrascale(nb0, intra1, mol0_merged_mapping);
1832-
copyIntrascale(nb1, intra1, mol1_merged_mapping, true);
1813+
overrideIntrascale(nb0, intra0, mol0_merged_mapping);
1814+
overrideIntrascale(nb1, intra1, mol1_merged_mapping);
18331815

18341816
// Assemble the intrascale objects into a property list to return.
18351817
SireBase::PropertyList ret;

corelib/src/libs/SireIO/biosimspace.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "SireMM/cljnbpairs.h"
4242

4343
#include "SireMol/atomidxmapping.h"
44+
#include "SireMol/connectivity.h"
4445
#include "SireMol/moleculeinfodata.h"
4546
#include "SireMol/select.h"
4647

@@ -411,7 +412,9 @@ namespace SireIO
411412
SIREIO_EXPORT SireBase::PropertyList mergeIntrascale(
412413
const SireMM::CLJNBPairs &nb0,
413414
const SireMM::CLJNBPairs &nb1,
414-
const SireMol::MoleculeInfoData &merged_info,
415+
const SireMol::Connectivity &conn0,
416+
const SireMol::Connectivity &conn1,
417+
const SireMM::CLJScaleFactor &sf14,
415418
const QHash<SireMol::AtomIdx, SireMol::AtomIdx> &mol0_merged_mapping,
416419
const QHash<SireMol::AtomIdx, SireMol::AtomIdx> &mol1_merged_mapping);
417420

0 commit comments

Comments
 (0)