Skip to content

Commit 0401b90

Browse files
committed
Add ejm49~ejm31 unit test.
1 parent 0a9e9b0 commit 0401b90

1 file changed

Lines changed: 230 additions & 0 deletions

File tree

tests/test_ghostly.py

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,219 @@ def test_acetone_to_propenol():
291291
assert str(p.function()) == expression
292292

293293

294+
def test_ejm49_to_ejm31():
295+
"""
296+
Test ghost atom modifications for the TYK ligands EJM 49 to 31. This is assert
297+
more complex perturbation.
298+
"""
299+
300+
# Load the system. Here pruned means that the atom mapping has pruned
301+
# atoms where the constraint changes between the end states, which is
302+
# what is used by OpenFE.
303+
mols = sr.load_test_files("ejm49_ejm31_pruned.bss")
304+
305+
# Store the orginal angles and dihedrals at lambda = 0 and lambda = 1.
306+
angles0 = mols[0].property("angle0")
307+
angles1 = mols[0].property("angle1")
308+
dihedrals0 = mols[0].property("dihedral0")
309+
dihedrals1 = mols[0].property("dihedral1")
310+
improper0 = mols[0].property("improper0")
311+
improper1 = mols[0].property("improper1")
312+
313+
# Apply the ghost atom modifications.
314+
new_mols, _ = modify(mols)
315+
316+
# Get the new angles and dihedrals.
317+
new_angles0 = new_mols[0].property("angle0")
318+
new_angles1 = new_mols[0].property("angle1")
319+
new_dihedrals0 = new_mols[0].property("dihedral0")
320+
new_dihedrals1 = new_mols[0].property("dihedral1")
321+
new_improper0 = new_mols[0].property("improper0")
322+
new_improper1 = new_mols[0].property("improper1")
323+
324+
# The number of angles should remain the same at lambda = 0.
325+
assert angles0.num_functions() == new_angles0.num_functions()
326+
327+
# The number of dihedrals should be five fewer at lambda = 0.
328+
assert dihedrals0.num_functions() - 5 == new_dihedrals0.num_functions()
329+
330+
# The number of impropers shoudld be three fewer at lambda = 0.
331+
assert improper0.num_functions() - 3 == new_improper0.num_functions()
332+
333+
# The number of angles should remain the same at lambda = 1.
334+
assert angles1.num_functions() == new_angles1.num_functions()
335+
336+
# The number of dihedrals should be four fewer at lambda = 1.
337+
assert dihedrals1.num_functions() - 4 == new_dihedrals1.num_functions()
338+
339+
# The number of impropers should be six fewer at lambda = 1.
340+
assert improper1.num_functions() - 6 == new_improper1.num_functions()
341+
342+
# Create dihedral IDs for the missing dihedrals at lambda = 0.
343+
344+
from sire.legacy.Mol import AtomIdx
345+
346+
missing_dihedrals0 = [
347+
(AtomIdx(18), AtomIdx(17), AtomIdx(39), AtomIdx(40)),
348+
(AtomIdx(18), AtomIdx(17), AtomIdx(39), AtomIdx(41)),
349+
(AtomIdx(18), AtomIdx(17), AtomIdx(39), AtomIdx(42)),
350+
(AtomIdx(33), AtomIdx(16), AtomIdx(17), AtomIdx(39)),
351+
(AtomIdx(14), AtomIdx(16), AtomIdx(17), AtomIdx(39)),
352+
]
353+
354+
# Store the molecular info.
355+
info = mols[0].info()
356+
357+
# Check that the missing dihedrals are in the original dihedrals at lambda = 0.
358+
assert (
359+
all(
360+
check_dihedral(info, dihedrals0.potentials(), *dihedral)
361+
for dihedral in missing_dihedrals0
362+
)
363+
== True
364+
)
365+
366+
# Check that the missing dihedrals are not in the new dihedrals at lambda = 0.
367+
assert (
368+
all(
369+
check_dihedral(info, new_dihedrals0.potentials(), *dihedral)
370+
for dihedral in missing_dihedrals0
371+
)
372+
== False
373+
)
374+
375+
# Create dihedral IDs for the missing dihedrals at lambda = 1.
376+
missing_dihedrals1 = [
377+
(AtomIdx(18), AtomIdx(17), AtomIdx(20), AtomIdx(21)),
378+
(AtomIdx(18), AtomIdx(17), AtomIdx(20), AtomIdx(25)),
379+
(AtomIdx(20), AtomIdx(17), AtomIdx(16), AtomIdx(33)),
380+
(AtomIdx(14), AtomIdx(16), AtomIdx(17), AtomIdx(20)),
381+
]
382+
383+
# Check that the missing dihedrals are in the original dihedrals at lambda = 1.
384+
assert (
385+
all(
386+
check_dihedral(info, dihedrals1.potentials(), *dihedral)
387+
for dihedral in missing_dihedrals1
388+
)
389+
== True
390+
)
391+
392+
# Check that the missing dihedrals are not in the new dihedrals at lambda = 1.
393+
assert (
394+
all(
395+
check_dihedral(info, new_dihedrals1.potentials(), *dihedral)
396+
for dihedral in missing_dihedrals1
397+
)
398+
== False
399+
)
400+
401+
# Create angle IDs for the modified angles at lambda = 0.
402+
modified_angles0 = [
403+
(AtomIdx(16), AtomIdx(17), AtomIdx(39)),
404+
(AtomIdx(18), AtomIdx(17), AtomIdx(39)),
405+
]
406+
407+
# Functional form of the modified angles.
408+
expression = "100 [theta - 1.5708]^2"
409+
410+
# Check that the original angles don't have the modified functional form.
411+
for p in angles0.potentials():
412+
idx0 = info.atom_idx(p.atom0())
413+
idx1 = info.atom_idx(p.atom1())
414+
idx2 = info.atom_idx(p.atom2())
415+
416+
if (idx0, idx1, idx2) in modified_angles0:
417+
assert str(p.function()) != expression
418+
419+
# Check that the modified angles have the correct functional form.
420+
for p in new_angles0.potentials():
421+
idx0 = info.atom_idx(p.atom0())
422+
idx1 = info.atom_idx(p.atom1())
423+
idx2 = info.atom_idx(p.atom2())
424+
425+
if (idx0, idx1, idx2) in modified_angles0:
426+
assert str(p.function()) == expression
427+
428+
# Create angle IDs for the modified angles at lambda = 1.
429+
modified_angles1 = [
430+
(AtomIdx(16), AtomIdx(17), AtomIdx(20)),
431+
(AtomIdx(18), AtomIdx(17), AtomIdx(20)),
432+
]
433+
434+
# Check that the original angles don't have the modified functional form.
435+
for p in angles1.potentials():
436+
idx0 = info.atom_idx(p.atom0())
437+
idx1 = info.atom_idx(p.atom1())
438+
idx2 = info.atom_idx(p.atom2())
439+
440+
if (idx0, idx1, idx2) in modified_angles1:
441+
assert str(p.function()) != expression
442+
443+
# Check that the modified angles have the correct functional form.
444+
for p in new_angles1.potentials():
445+
idx0 = info.atom_idx(p.atom0())
446+
idx1 = info.atom_idx(p.atom1())
447+
idx2 = info.atom_idx(p.atom2())
448+
449+
if (idx0, idx1, idx2) in modified_angles1:
450+
assert str(p.function()) == expression
451+
452+
# Create improper IDs for the missing impropers at lambda = 0.
453+
missing_impropers0 = [
454+
(AtomIdx(17), AtomIdx(16), AtomIdx(18), AtomIdx(39)),
455+
(AtomIdx(16), AtomIdx(39), AtomIdx(18), AtomIdx(17)),
456+
(AtomIdx(17), AtomIdx(39), AtomIdx(16), AtomIdx(18)),
457+
]
458+
459+
# Check that the missing impropers are in the original impropers at lambda = 0.
460+
assert (
461+
all(
462+
check_improper(info, improper0.potentials(), *improper)
463+
for improper in missing_impropers0
464+
)
465+
== True
466+
)
467+
468+
# Check that the missing impropers are not in the new impropers at lambda = 0.
469+
assert (
470+
all(
471+
check_improper(info, new_improper0.potentials(), *improper)
472+
for improper in missing_impropers0
473+
)
474+
== False
475+
)
476+
477+
# Create improper IDs for the missing impropers at lambda = 1.
478+
missing_impropers1 = [
479+
(AtomIdx(17), AtomIdx(25), AtomIdx(21), AtomIdx(20)),
480+
(AtomIdx(17), AtomIdx(20), AtomIdx(16), AtomIdx(18)),
481+
(AtomIdx(16), AtomIdx(20), AtomIdx(18), AtomIdx(17)),
482+
(AtomIdx(17), AtomIdx(20), AtomIdx(16), AtomIdx(18)),
483+
(AtomIdx(20), AtomIdx(25), AtomIdx(17), AtomIdx(21)),
484+
(AtomIdx(16), AtomIdx(20), AtomIdx(18), AtomIdx(17)),
485+
(AtomIdx(20), AtomIdx(17), AtomIdx(21), AtomIdx(25)),
486+
]
487+
488+
# Check that the missing impropers are in the original impropers at lambda = 1.
489+
assert (
490+
all(
491+
check_improper(info, improper1.potentials(), *improper)
492+
for improper in missing_impropers1
493+
)
494+
== True
495+
)
496+
497+
# Check that the missing impropers are not in the new impropers at lambda = 1.
498+
assert (
499+
all(
500+
check_improper(info, new_improper1.potentials(), *improper)
501+
for improper in missing_impropers1
502+
)
503+
== False
504+
)
505+
506+
294507
def check_angle(info, potentials, idx0, idx1, idx2):
295508
"""
296509
Check if an angle potential is in a list of potentials.
@@ -322,3 +535,20 @@ def check_dihedral(info, potentials, idx0, idx1, idx2, idx3):
322535
return True
323536

324537
return False
538+
539+
540+
def check_improper(info, potentials, idx0, idx1, idx2, idx3):
541+
"""
542+
Check if an improper potential is in a list of potentials.
543+
"""
544+
545+
for p in potentials:
546+
if (
547+
idx0 == info.atom_idx(p.atom0())
548+
and idx1 == info.atom_idx(p.atom1())
549+
and idx2 == info.atom_idx(p.atom2())
550+
and idx3 == info.atom_idx(p.atom3())
551+
):
552+
return True
553+
554+
return False

0 commit comments

Comments
 (0)