merge conflicts

This commit is contained in:
hannahbaumann
2024-02-14 11:15:41 +01:00
18 changed files with 231 additions and 82 deletions

View File

@@ -14,7 +14,12 @@ import json
import logging
import pathlib
import tempfile
from openff.toolkit import Molecule
from openff.toolkit import (
Molecule, RDKitToolkitWrapper, AmberToolsToolkitWrapper
)
from openff.toolkit.utils.toolkit_registry import (
toolkit_registry_manager, ToolkitRegistry
)
from openff.units import unit
from kartograf.atom_aligner import align_mol_shape
from kartograf import KartografAtomMapper
@@ -31,11 +36,16 @@ logger = logging.getLogger(__name__)
LIGA = "[H]C([H])([H])C([H])([H])C(=O)C([H])([H])C([H])([H])[H]"
LIGB = "[H]C([H])([H])C(=O)C([H])([H])C([H])([H])C([H])([H])[H]"
amber_rdkit = ToolkitRegistry(
[RDKitToolkitWrapper(), AmberToolsToolkitWrapper()]
)
def get_molecule(smi, name):
m = Molecule.from_smiles(smi)
m.generate_conformers()
m.assign_partial_charges(partial_charge_method="am1bcc")
with toolkit_registry_manager(amber_rdkit):
m = Molecule.from_smiles(smi)
m.generate_conformers()
m.assign_partial_charges(partial_charge_method="am1bcc")
return openfe.SmallMoleculeComponent.from_openff(m, name=name)

View File

@@ -34,7 +34,7 @@ from openmmtools.states import (SamplerState,
create_thermodynamic_state_protocol,)
from openmmtools.alchemy import (AlchemicalRegion, AbsoluteAlchemicalFactory,
AlchemicalState,)
from typing import Dict, List, Optional
from typing import Optional
from openmm import app
from openmm import unit as omm_unit
from openmmforcefields.generators import SystemGenerator
@@ -50,11 +50,14 @@ from gufe import (
from openfe.protocols.openmm_utils.omm_settings import (
SettingsBaseModel,
)
from openfe.protocols.openmm_utils.omm_settings import (
BasePartialChargeSettings,
)
from openfe.protocols.openmm_afe.equil_afe_settings import (
BaseSolvationSettings,
MultiStateSimulationSettings, OpenMMEngineSettings,
IntegratorSettings, LambdaSettings, OutputSettings,
ThermoSettings,
ThermoSettings, OpenFFPartialChargeSettings,
)
from openfe.protocols.openmm_rfe._rfe_utils import compute
from openfe.protocols.openmm_md.plain_md_methods import PlainMDProtocolUnit
@@ -356,12 +359,37 @@ class BaseAbsoluteUnit(gufe.ProtocolUnit):
)
return system_generator
@staticmethod
def _assign_partial_charges(
partial_charge_settings: OpenFFPartialChargeSettings,
smc_components: dict[SmallMoleculeComponent, OFFMolecule],
) -> None:
"""
Assign partial charges to SMCs.
Parameters
----------
charge_settings : OpenFFPartialChargeSettings
Settings for controlling how the partial charges are assigned.
smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule]
Dictionary of OpenFF Molecules to add, keyed by
SmallMoleculeComponent.
"""
for mol in smc_components.values():
# don't do this if we have user charges
if not (mol.partial_charges is not None and np.any(mol.partial_charges)):
# due to issues with partial charge generation in ambertools
# we default to using the input conformer for charge generation
mol.assign_partial_charges(
'am1bcc', use_conformers=mol.conformers
)
def _get_modeller(
self,
protein_component: Optional[ProteinComponent],
solvent_component: Optional[SolventComponent],
smc_components: dict[SmallMoleculeComponent, OFFMolecule],
system_generator: SystemGenerator,
partial_charge_settings: BasePartialChargeSettings,
solvation_settings: BaseSolvationSettings
) -> tuple[app.Modeller, dict[Component, npt.NDArray]]:
"""
@@ -374,10 +402,14 @@ class BaseAbsoluteUnit(gufe.ProtocolUnit):
Protein Component, if it exists.
solvent_component : Optional[ProteinCompoinent]
Solvent Component, if it exists.
smc_components : list[openff.toolkit.topology.Molecule]
List of openff Molecules to add.
smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule]
Dicationary of OpenFF Molecules to add, keyed by
SmallMoleculeComponent.
system_generator : openmmforcefields.generator.SystemGenerator
System Generator to parameterise this unit.
partial_charge_settings : BasePartialChargeSettings
Settings detailing how to assign partial charges to the
SMCs of the system.
solvation_settings : BaseSolvationSettings
Settings detailing how to solvate the system.
@@ -392,20 +424,15 @@ class BaseAbsoluteUnit(gufe.ProtocolUnit):
if self.verbose:
self.logger.info("Parameterizing molecules")
# Assign partial charges to smcs
self._assign_partial_charges(partial_charge_settings, smc_components)
# force the creation of parameters for the small molecules
# this is necessary because we need to have the FF generated ahead
# of solvating the system.
# Note by default this is cached to ctx.shared/db.json which should
# reduce some of the costs.
for mol in smc_components.values():
# don't do this if we have user charges
if not (mol.partial_charges is not None and np.any(mol.partial_charges)):
# due to issues with partial charge generation in ambertools
# we default to using the input conformer for charge generation
mol.assign_partial_charges(
'am1bcc', use_conformers=mol.conformers
)
system_generator.create_system(
mol.to_topology().to_openmm(), molecules=[mol]
)
@@ -438,7 +465,7 @@ class BaseAbsoluteUnit(gufe.ProtocolUnit):
parametrized.
system_generator : SystemGenerator
SystemGenerator object to create a System with.
smc_components : list
smc_components : list[openff.toolkit.Molecules]
A list of openff Molecules to add to the system.
Returns
@@ -902,7 +929,7 @@ class BaseAbsoluteUnit(gufe.ProtocolUnit):
return None
def run(self, dry=False, verbose=True,
scratch_basepath=None, shared_basepath=None) -> Dict[str, Any]:
scratch_basepath=None, shared_basepath=None) -> dict[str, Any]:
"""Run the absolute free energy calculation.
Parameters
@@ -914,24 +941,16 @@ class BaseAbsoluteUnit(gufe.ProtocolUnit):
verbose : bool
Verbose output of the simulation progress. Output is provided via
INFO level logging.
basepath : Pathlike, optional
Where to run the calculation, defaults to current working directory
scratch_basepath : pathlib.Path
Path to the scratch (temporary) directory space.
shared_basepath : pathlib.Path
Path to the shared (persistent) directory space.
Returns
-------
dict
Outputs created in the basepath directory or the debug objects
(i.e. sampler) if ``dry==True``.
Attributes
----------
solvent : Optional[SolventComponent]
SolventComponent to be applied to the system
protein : Optional[ProteinComponent]
ProteinComponent for the system
openff_mols : List[openff.Molecule]
List of OpenFF Molecule objects for each SmallMoleculeComponent in
the stateA ChemicalSystem
"""
# 0. Generaly preparation tasks
self._prepare(verbose, scratch_basepath, shared_basepath)
@@ -948,7 +967,8 @@ class BaseAbsoluteUnit(gufe.ProtocolUnit):
# 4. Get modeller
system_modeller, comp_resids = self._get_modeller(
prot_comp, solv_comp, smc_comps, system_generator,
settings['solvation_settings']
settings['charge_settings'],
settings['solvation_settings'],
)
# 5. Get OpenMM topology, positions and system

View File

@@ -26,6 +26,7 @@ from openfe.protocols.openmm_utils.omm_settings import (
OpenMMSolvationSettings,
OpenMMEngineSettings,
IntegratorSettings,
OpenFFPartialChargeSettings,
OutputSettings,
MDSimulationSettings,
MDOutputSettings,
@@ -213,3 +214,9 @@ class AbsoluteSolvationSettings(SettingsBaseModel):
"""
Simulation output settings for the solvent transformation.
"""
partial_charge_settings: OpenFFPartialChargeSettings
"""
Settings for controlling how to assign partial charges.
Currently unused.
"""

View File

@@ -54,6 +54,7 @@ from openfe.protocols.openmm_afe.equil_afe_settings import (
MDSimulationSettings, MDOutputSettings,
MultiStateSimulationSettings, OpenMMEngineSettings,
IntegratorSettings, OutputSettings,
OpenFFPartialChargeSettings,
SettingsBaseModel,
)
from ..openmm_utils import system_validation, settings_validation
@@ -416,6 +417,7 @@ class AbsoluteSolvationProtocol(gufe.Protocol):
0.0, 0.0, 0.0, 0.0, 0.0, 0.12, 0.24,
0.36, 0.48, 0.6, 0.7, 0.77, 0.85, 1.0],
),
partial_charge_settings=OpenFFPartialChargeSettings(),
solvation_settings=OpenMMSolvationSettings(),
vacuum_engine_settings=OpenMMEngineSettings(),
solvent_engine_settings=OpenMMEngineSettings(),
@@ -770,6 +772,7 @@ class AbsoluteSolvationVacuumUnit(BaseAbsoluteUnit):
A dictionary with the following entries:
* forcefield_settings : OpenMMSystemGeneratorFFSettings
* thermo_settings : ThermoSettings
* charge_settings: OpenFFPartialChargeSettings
* solvation_settings : OpenMMSolvationSettings
* alchemical_settings : AlchemicalSettings
* lambda_settings : LambdaSettings
@@ -785,6 +788,7 @@ class AbsoluteSolvationVacuumUnit(BaseAbsoluteUnit):
settings = {}
settings['forcefield_settings'] = prot_settings.vacuum_forcefield_settings
settings['thermo_settings'] = prot_settings.thermo_settings
settings['charge_settings'] = prot_settings.partial_charge_settings
settings['solvation_settings'] = prot_settings.solvation_settings
settings['alchemical_settings'] = prot_settings.alchemical_settings
settings['lambda_settings'] = prot_settings.lambda_settings
@@ -858,6 +862,7 @@ class AbsoluteSolvationSolventUnit(BaseAbsoluteUnit):
A dictionary with the following entries:
* forcefield_settings : OpenMMSystemGeneratorFFSettings
* thermo_settings : ThermoSettings
* charge_settings : OpenFFPartialChargeSettings
* solvation_settings : OpenMMSolvationSettings
* alchemical_settings : AlchemicalSettings
* lambda_settings : LambdaSettings
@@ -873,6 +878,7 @@ class AbsoluteSolvationSolventUnit(BaseAbsoluteUnit):
settings = {}
settings['forcefield_settings'] = prot_settings.solvent_forcefield_settings
settings['thermo_settings'] = prot_settings.thermo_settings
settings['charge_settings'] = prot_settings.partial_charge_settings
settings['solvation_settings'] = prot_settings.solvation_settings
settings['alchemical_settings'] = prot_settings.alchemical_settings
settings['lambda_settings'] = prot_settings.lambda_settings

View File

@@ -32,8 +32,12 @@ from gufe import (
settings, ChemicalSystem, SmallMoleculeComponent,
ProteinComponent, SolventComponent
)
from openfe.protocols.openmm_utils.omm_settings import (
BasePartialChargeSettings,
)
from openfe.protocols.openmm_md.plain_md_settings import (
PlainMDProtocolSettings,
OpenFFPartialChargeSettings,
OpenMMSolvationSettings, OpenMMEngineSettings,
IntegratorSettings, MDSimulationSettings, MDOutputSettings,
)
@@ -121,6 +125,7 @@ class PlainMDProtocol(gufe.Protocol):
temperature=298.15 * unit.kelvin,
pressure=1 * unit.bar,
),
partial_charge_settings=OpenFFPartialChargeSettings(),
solvation_settings=OpenMMSolvationSettings(),
engine_settings=OpenMMEngineSettings(),
integrator_settings=IntegratorSettings(),
@@ -391,10 +396,12 @@ class PlainMDProtocolUnit(gufe.ProtocolUnit):
logger.info("running production phase")
# Setup the reporters
# TODO: write_interval should probably not be in units of
# timestep but time - Issue #716
write_interval = output_settings.trajectory_write_interval.m
write_interval = settings_validation.divmod_time_and_check(
output_settings.trajectory_write_interval,
timestep,
"trajectory_write_interval",
"timestep",
)
checkpoint_interval = settings_validation.get_simsteps(
sim_length=output_settings.checkpoint_interval,
@@ -428,6 +435,33 @@ class PlainMDProtocolUnit(gufe.ProtocolUnit):
if verbose:
logger.info(f"Completed simulation in {t1 - t0} seconds")
return None
@staticmethod
def _assign_partial_charges(
charge_settings: OpenFFPartialChargeSettings,
smc_components: dict[SmallMoleculeComponent, OFFMolecule],
) -> None:
"""
Assign partial charges to SMCs.
Parameters
----------
charge_settings : OpenFFPartialChargeSettings
Settings for controlling how the partial charges are assigned.
smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule]
Dictionary of OpenFF Molecules to add, keyed by
SmallMoleculeComponent.
"""
for mol in smc_components.values():
# don't do this if we have user charges
if not (mol.partial_charges is not None and np.any(
mol.partial_charges)):
# due to issues with partial charge generation in ambertools
# we default to using the input conformer for charge generation
mol.assign_partial_charges(
'am1bcc', use_conformers=mol.conformers
)
def run(self, *, dry=False, verbose=True,
scratch_basepath=None,
shared_basepath=None) -> dict[str, Any]:
@@ -473,6 +507,7 @@ class PlainMDProtocolUnit(gufe.ProtocolUnit):
forcefield_settings: settings.OpenMMSystemGeneratorFFSettings = protocol_settings.forcefield_settings
thermo_settings: settings.ThermoSettings = protocol_settings.thermo_settings
solvation_settings: OpenMMSolvationSettings = protocol_settings.solvation_settings
charge_settings: BasePartialChargeSettings = protocol_settings.partial_charge_settings
sim_settings: MDSimulationSettings = protocol_settings.simulation_settings
output_settings: MDOutputSettings = protocol_settings.output_settings
timestep = protocol_settings.integrator_settings.timestep
@@ -516,16 +551,11 @@ class PlainMDProtocolUnit(gufe.ProtocolUnit):
smc_components: dict[SmallMoleculeComponent, OFFMolecule]
smc_components = {i: i.to_openff() for i in small_mols}
for mol in smc_components.values():
# don't do this if we have user charges
if not (mol.partial_charges is not None and np.any(
mol.partial_charges)):
# due to issues with partial charge generation in ambertools
# we default to using the input conformer for charge generation
mol.assign_partial_charges(
'am1bcc', use_conformers=mol.conformers
)
# Assign partial charges to smcs
self._assign_partial_charges(charge_settings, smc_components)
for mol in smc_components.values():
system_generator.create_system(
mol.to_topology().to_openmm(), molecules=[mol]
)

View File

@@ -13,6 +13,7 @@ from openfe.protocols.openmm_utils.omm_settings import (
OpenMMEngineSettings,
MDSimulationSettings,
IntegratorSettings, MDOutputSettings,
OpenFFPartialChargeSettings,
)
from gufe.settings import SettingsBaseModel
try:
@@ -39,6 +40,7 @@ class PlainMDProtocolSettings(Settings):
# Things for creating the systems
solvation_settings: OpenMMSolvationSettings
partial_charge_settings: OpenFFPartialChargeSettings
# MD Engine things
engine_settings: OpenMMEngineSettings

View File

@@ -56,6 +56,10 @@ from .equil_rfe_settings import (
OpenMMSolvationSettings, AlchemicalSettings, LambdaSettings,
MultiStateSimulationSettings, OpenMMEngineSettings,
IntegratorSettings, OutputSettings,
OpenFFPartialChargeSettings,
)
from openfe.protocols.openmm_utils.omm_settings import (
BasePartialChargeSettings,
)
from ..openmm_utils import (
system_validation, settings_validation, system_creation,
@@ -455,6 +459,7 @@ class RelativeHybridTopologyProtocol(gufe.Protocol):
temperature=298.15 * unit.kelvin,
pressure=1 * unit.bar,
),
partial_charge_settings=OpenFFPartialChargeSettings(),
solvation_settings=OpenMMSolvationSettings(),
alchemical_settings=AlchemicalSettings(softcore_LJ='gapsys'),
lambda_settings=LambdaSettings(),
@@ -579,6 +584,33 @@ class RelativeHybridTopologyProtocolUnit(gufe.ProtocolUnit):
generation=generation
)
@staticmethod
def _assign_partial_charges(
charge_settings: OpenFFPartialChargeSettings,
off_small_mols: dict[str, list[tuple[SmallMoleculeComponent, OFFMolecule]]],
) -> None:
"""
Assign partial charges to SMCs.
Parameters
----------
charge_settings : OpenFFPartialChargeSettings
Settings for controlling how the partial charges are assigned.
off_small_mols : dict[str, list[tuple[SmallMoleculeComponent, OFFMolecule]]]
Dictionary of dictionary of OpenFF Molecules to add, keyed by
state and SmallMoleculeComponent.
"""
for smc, mol in chain(off_small_mols['stateA'],
off_small_mols['stateB'],
off_small_mols['both']):
# skip if we already have user charges
if not (mol.partial_charges is not None and np.any(mol.partial_charges)):
# due to issues with partial charge generation in ambertools
# we default to using the input conformer for charge generation
mol.assign_partial_charges(
'am1bcc', use_conformers=mol.conformers
)
def run(self, *, dry=False, verbose=True,
scratch_basepath=None,
shared_basepath=None) -> dict[str, Any]:
@@ -629,6 +661,7 @@ class RelativeHybridTopologyProtocolUnit(gufe.ProtocolUnit):
thermo_settings: settings.ThermoSettings = protocol_settings.thermo_settings
alchem_settings: AlchemicalSettings = protocol_settings.alchemical_settings
lambda_settings: LambdaSettings = protocol_settings.lambda_settings
charge_settings: BasePartialChargeSettings = protocol_settings.partial_charge_settings
solvation_settings: OpenMMSolvationSettings = protocol_settings.solvation_settings
sampler_settings: MultiStateSimulationSettings = protocol_settings.simulation_settings
output_settings: OutputSettings = protocol_settings.output_settings
@@ -702,17 +735,14 @@ class RelativeHybridTopologyProtocolUnit(gufe.ProtocolUnit):
# Note: by default this is cached to ctx.shared/db.json so shouldn't
# incur too large a cost
self.logger.info("Parameterizing molecules")
# Start by assigning partial charges
self._assign_partial_charges(charge_settings, off_small_mols)
# Then register all the templates
for smc, mol in chain(off_small_mols['stateA'],
off_small_mols['stateB'],
off_small_mols['both']):
# skip if we already have user charges
if not (mol.partial_charges is not None and np.any(mol.partial_charges)):
# due to issues with partial charge generation in ambertools
# we default to using the input conformer for charge generation
mol.assign_partial_charges(
'am1bcc', use_conformers=mol.conformers
)
system_generator.create_system(mol.to_topology().to_openmm(),
molecules=[mol])

View File

@@ -24,6 +24,7 @@ from openfe.protocols.openmm_utils.omm_settings import (
OpenMMEngineSettings,
OpenMMSolvationSettings,
OutputSettings,
OpenFFPartialChargeSettings,
)
try:
@@ -133,6 +134,9 @@ class RelativeHybridTopologyProtocolSettings(Settings):
solvation_settings: OpenMMSolvationSettings
"""Settings for solvating the system."""
partial_charge_settings: OpenFFPartialChargeSettings
"""Settings for assigning partial charges to small molecules."""
# Alchemical settings
lambda_settings: LambdaSettings
"""

View File

@@ -64,6 +64,20 @@ class OpenMMSolvationSettings(BaseSolvationSettings):
return v
class BasePartialChargeSettings(SettingsBaseModel):
"""
Base class for partial charge assignment.
"""
class Config:
arbitrary_types_allowed = True
class OpenFFPartialChargeSettings(BasePartialChargeSettings):
"""
Empty placeholder class, will implement OpenFF partial charge assignment.
"""
class OpenMMEngineSettings(SettingsBaseModel):
"""OpenMM MD engine settings"""
@@ -379,7 +393,7 @@ class MDOutputSettings(OutputSettings):
# reporter settings
production_trajectory_filename = 'simulation.xtc'
"""Path to the storage file for analysis. Default 'simulation.xtc'."""
trajectory_write_interval = 5000 * unit.timestep
trajectory_write_interval: FloatQuantity['picosecond'] = 20 * unit.picosecond
"""
Frequency to write the xtc file. Default 5000 * unit.timestep.
"""

View File

@@ -102,6 +102,41 @@ def divmod_time(
return iterations, remainder
def divmod_time_and_check(numerator: unit.Quantity, denominator: unit.Quantity,
numerator_name: str, denominator_name: str) -> int:
"""Perform a division of time, failing if there is a remainder
For example numerator 20.0 ps and denominator 4.0 fs gives 5000
Parameters
----------
numerator, denominator : unit.Quantity
the division to perform
numerator_name, denominator_name : str
used for the error generated if there is any remainder
Returns
-------
iterations : int
the result of the division
Raises
------
ValueError
if the division results in any remainder, will include a formatted error
message
"""
its, rem = divmod_time(numerator, denominator)
if rem:
errmsg = (f"The {numerator_name} ({numerator}) "
"does not evenly divide by the "
f"{denominator_name} ({denominator})")
raise ValueError(errmsg)
return its
def convert_checkpoint_interval_to_iterations(
checkpoint_interval: unit.Quantity,
time_per_iteration: unit.Quantity,
@@ -152,17 +187,13 @@ def convert_steps_per_iteration(
steps_per_iteration : int
suitable for input to Integrator
"""
steps_per_iteration, rem = divmod_time(
return divmod_time_and_check(
simulation_settings.time_per_iteration,
integrator_settings.timestep
integrator_settings.timestep,
"time_per_iteration",
"timestep",
)
if rem:
raise ValueError(f"time_per_iteration ({simulation_settings.time_per_iteration}) "
f"not divisible by timestep ({integrator_settings.timestep})")
return steps_per_iteration
def convert_real_time_analysis_iterations(
simulation_settings: MultiStateSimulationSettings,
@@ -191,25 +222,19 @@ def convert_real_time_analysis_iterations(
# option to turn off real time analysis
return None, None
rta_its, rem = divmod_time(
rta_its = divmod_time_and_check(
simulation_settings.real_time_analysis_interval,
simulation_settings.time_per_iteration,
"real_time_analysis_interval",
"time_per_iteration",
)
if rem:
raise ValueError(f"real_time_analysis_interval ({simulation_settings.real_time_analysis_interval}) "
f"is not divisible by time_per_iteration ({simulation_settings.time_per_iteration})")
# convert RTA_minimum_time to iterations
rta_min_its, rem = divmod_time(
rta_min_its = divmod_time_and_check(
simulation_settings.real_time_analysis_minimum_time,
simulation_settings.time_per_iteration,
"real_time_analysis_minimum_time",
"time_per_iteration",
)
if rem:
raise ValueError(f"real_time_analysis_minimum_time ({simulation_settings.real_time_analysis_minimum_time}) "
f"is not divisible by time_per_iteration ({simulation_settings.time_per_iteration})")
return rta_its, rta_min_its

View File

@@ -1415,7 +1415,7 @@ class TestProtocolResult:
est = protocolresult.get_uncertainty()
assert est
assert est.m == pytest.approx(0.1, abs=0.1)
assert est.m == pytest.approx(0.1, abs=0.2)
assert isinstance(est, unit.Quantity)
assert est.is_compatible_with(unit.kilojoule_per_mole)

View File

@@ -54,8 +54,6 @@ class TestOMMSettingsFromStrings:
assert s.equilibration_length == 2.5 * unit.nanosecond
assert s.production_length == 10.0 * unit.nanosecond
# todo: checkpoint_interval IntQuantity
class TestEquilRFESettingsFromString:
def test_alchemical_settings(self):

View File

@@ -412,7 +412,7 @@ def test_convert_steps_per_iteration_failure():
timestep='3 fs'
)
with pytest.raises(ValueError, match="not divisible"):
with pytest.raises(ValueError, match="does not evenly divide"):
settings_validation.convert_steps_per_iteration(sim, inty)
@@ -440,7 +440,7 @@ def test_convert_real_time_analysis_iterations_interval_fail():
real_time_analysis_minimum_time='500 ps',
)
with pytest.raises(ValueError, match='not divisible'):
with pytest.raises(ValueError, match='does not evenly divide'):
settings_validation.convert_real_time_analysis_iterations(sim)
@@ -454,7 +454,7 @@ def test_convert_real_time_analysis_iterations_min_interval_fail():
real_time_analysis_minimum_time='500.5 ps',
)
with pytest.raises(ValueError, match='not divisible'):
with pytest.raises(ValueError, match='does not evenly divide'):
settings_validation.convert_real_time_analysis_iterations(sim)

View File

@@ -39,7 +39,7 @@ class TestRelativeHybridTopologyProtocolResult(GufeTokenizableTestsMixin):
class TestRelativeHybridTopologyProtocol(GufeTokenizableTestsMixin):
cls = openmm_rfe.RelativeHybridTopologyProtocol
key = "RelativeHybridTopologyProtocol-b6ecbf56c5effbda11d3c10d13f37273"
key = "RelativeHybridTopologyProtocol-d4a4ff534eee7c88d43334c18b428927"
repr = f"<{key}>"
@pytest.fixture()

View File

@@ -49,7 +49,7 @@ def protocol_result(afe_solv_transformation_json):
class TestAbsoluteSolvationProtocol(GufeTokenizableTestsMixin):
cls = openmm_afe.AbsoluteSolvationProtocol
key = "AbsoluteSolvationProtocol-1262bf8cac922568528648aff23a6e73"
key = "AbsoluteSolvationProtocol-e8f575fbe609d60f7e2cb92391c4b83f"
repr = f"<{key}>"
@pytest.fixture()
@@ -85,7 +85,7 @@ class TestAbsoluteSolvationVacuumUnit(GufeTokenizableTestsMixin):
class TestAbsoluteSolvationProtocolResult(GufeTokenizableTestsMixin):
cls = openmm_afe.AbsoluteSolvationProtocolResult
key = "AbsoluteSolvationProtocolResult-c1e7524ca8cda3921c2cbd5b512d1cf0"
key = "AbsoluteSolvationProtocolResult-9b699ca4772043b564468b815ea0851c"
repr = f"<{key}>"
@pytest.fixture()

View File

@@ -145,6 +145,7 @@ solvent lig_ejm_46 lig_jmc_28 23.65 0.03
"""
@pytest.mark.xfail
@pytest.mark.parametrize('report', ["", "dg", "ddg"])
def test_gather(results_dir, report):
expected = {
@@ -184,6 +185,7 @@ def test_generate_bad_legs_error_message(include):
assert string in msg
@pytest.mark.xfail
def test_missing_leg_error(results_dir):
file_to_remove = "easy_rbfe_lig_ejm_31_complex_lig_ejm_42_complex.json"
(pathlib.Path("results") / file_to_remove).unlink()
@@ -197,6 +199,7 @@ def test_missing_leg_error(results_dir):
assert "'lig_ejm_42'" in str(result.exception)
@pytest.mark.xfail
def test_missing_leg_allow_partial(results_dir):
file_to_remove = "easy_rbfe_lig_ejm_31_complex_lig_ejm_42_complex.json"
(pathlib.Path("results") / file_to_remove).unlink()