diff --git a/cookbook/bespoke_parameters_showcase.ipynb b/cookbook/bespoke_parameters_showcase.ipynb index 84b59ea..86a28e8 100644 --- a/cookbook/bespoke_parameters_showcase.ipynb +++ b/cookbook/bespoke_parameters_showcase.ipynb @@ -49,31 +49,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# create the OpenFE RBFE protocol using our bespoke force field\n", - "import copy\n", - "from openff.units import unit\n", "from openfe.protocols.openmm_rfe import RelativeHybridTopologyProtocol\n", "import openfe\n", "\n", - "# create the default protocol settings\n", - "base_settings = RelativeHybridTopologyProtocol.default_settings()\n", "\n", + "# create the default protocol settings\n", + "settings = RelativeHybridTopologyProtocol.default_settings()\n", "# add our new force field as a string\n", "# this avoids the need to move the file around when executing the transformations\n", - "base_settings.forcefield_settings.small_molecule_forcefield = bespoke_force_field.to_string()\n", - "\n", - "# we create a copy of the settings for the complex leg so that we can reduce the solvation cutoff\n", - "complex_settings = copy.deepcopy(base_settings)\n", - "complex_settings.solvation_settings.solvent_padding = 1 * unit.nanometer\n", - "\n", - "# create the protocols\n", - "solvent_protocol = RelativeHybridTopologyProtocol(base_settings)\n", - "complex_protocol = RelativeHybridTopologyProtocol(complex_settings)\n", + "settings.forcefield_settings.small_molecule_forcefield = bespoke_force_field.to_string()\n", "\n", + "# create the protocol\n", + "protocol = RelativeHybridTopologyProtocol(settings)\n", "\n", "# create the solvent and protein components\n", "solvent = openfe.SolventComponent()\n", @@ -90,11 +82,8 @@ " 'solvent': solvent}\n", "\n", " if leg == 'complex':\n", - " protocol = complex_protocol\n", " sysA_dict['protein'] = protein\n", " sysB_dict['protein'] = protein\n", - " else:\n", - " protocol = solvent_protocol\n", "\n", " # we don't have to name objects, but it can make things (like filenames) more convenient\n", " sysA = openfe.ChemicalSystem(sysA_dict, name=f\"{mapping.componentA.name}_{leg}\")\n", @@ -105,7 +94,7 @@ " transformation = openfe.Transformation(\n", " stateA=sysA,\n", " stateB=sysB,\n", - " mapping=mapping,\n", + " mapping={'ligand': mapping},\n", " protocol=protocol, # use protocol created above\n", " name=f\"{prefix}{sysA.name}_{sysB.name}\"\n", " )\n", @@ -123,7 +112,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -134,7 +123,7 @@ "\n", "# then we write out each transformation\n", "for transformation in network.edges:\n", - " transformation.to_json(transformation_dir / f\"{transformation.name}.json\")" + " transformation.dump(transformation_dir / f\"{transformation.name}.json\")" ] }, { @@ -143,8 +132,7 @@ "source": [ "# Recap\n", "\n", - "So to recap the workflow can be reduced to the following steps:\n", - "\n", + "So to recap the workflow can be reduced to the following steps:\n\n", "- Plan the RBFE network\n", "- Create a single SMIRNOFF style force field with all of the bespoke parameters for the network using the BespokeFit `combine` CLI\n", "- Store the force field as a string in the OpenFE protocol under the `settings.forcefield_settings.small_molecule_forcefield` field\n", @@ -156,7 +144,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "asapdiscovery", "language": "python", "name": "python3" }, @@ -170,16 +158,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.11" - }, - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "state": {}, - "version_major": 2, - "version_minor": 0 - } + "version": "3.11.6" } }, "nbformat": 4, - "nbformat_minor": 4 + "nbformat_minor": 2 } diff --git a/cookbook/choose_protocol.ipynb b/cookbook/choose_protocol.ipynb index 65b5df6..7c9a26a 100644 --- a/cookbook/choose_protocol.ipynb +++ b/cookbook/choose_protocol.ipynb @@ -178,82 +178,64 @@ "text": [ "{'alchemical_settings': {'endstate_dispersion_correction': False,\n", " 'explicit_charge_correction': False,\n", - " 'explicit_charge_correction_cutoff': {'unit': 'nanometer',\n", - " 'val': 0.8},\n", + " 'explicit_charge_correction_cutoff': ,\n", " 'softcore_LJ': 'gapsys',\n", " 'softcore_alpha': 0.85,\n", " 'turn_off_core_unique_exceptions': False,\n", " 'use_dispersion_correction': False},\n", - " 'engine_settings': {'compute_platform': 'cuda', 'gpu_device_index': None},\n", + " 'engine_settings': {'compute_platform': None, 'gpu_device_index': None},\n", " 'forcefield_settings': {'constraints': 'hbonds',\n", " 'forcefields': ['amber/ff14SB.xml',\n", " 'amber/tip3p_standard.xml',\n", " 'amber/tip3p_HFE_multivalent.xml',\n", " 'amber/phosaa10.xml'],\n", " 'hydrogen_mass': 3.0,\n", - " 'nonbonded_cutoff': {'unit': 'nanometer', 'val': 0.9},\n", + " 'nonbonded_cutoff': ,\n", " 'nonbonded_method': 'PME',\n", " 'rigid_water': True,\n", - " 'small_molecule_forcefield': 'openff-2.2.1'},\n", - " 'integrator_settings': {'barostat_frequency': {'unit': 'timestep',\n", - " 'val': 25.0},\n", + " 'small_molecule_forcefield': 'openff-2.1.1'},\n", + " 'integrator_settings': {'barostat_frequency': ,\n", " 'constraint_tolerance': 1e-06,\n", - " 'langevin_collision_rate': {'unit': '1 / picosecond',\n", - " 'val': 1.0},\n", + " 'langevin_collision_rate': ,\n", " 'n_restart_attempts': 20,\n", " 'reassign_velocities': False,\n", " 'remove_com': False,\n", - " 'timestep': {'unit': 'femtosecond', 'val': 4.0}},\n", + " 'timestep': },\n", " 'lambda_settings': {'lambda_functions': 'default', 'lambda_windows': 11},\n", - " 'output_settings': {'checkpoint_interval': {'unit': 'nanosecond', 'val': 1.0},\n", + " 'output_settings': {'checkpoint_interval': ,\n", " 'checkpoint_storage_filename': 'checkpoint.chk',\n", " 'forcefield_cache': 'db.json',\n", " 'output_filename': 'simulation.nc',\n", " 'output_indices': 'not water',\n", " 'output_structure': 'hybrid_system.pdb',\n", - " 'positions_write_frequency': {'unit': 'picosecond',\n", - " 'val': 100.0},\n", + " 'positions_write_frequency': ,\n", " 'velocities_write_frequency': None},\n", " 'partial_charge_settings': {'nagl_model': None,\n", " 'number_of_conformers': None,\n", " 'off_toolkit_backend': 'ambertools',\n", " 'partial_charge_method': 'am1bcc'},\n", " 'protocol_repeats': 3,\n", - " 'simulation_settings': {'early_termination_target_error': {'unit': 'kilocalorie_per_mole',\n", - " 'val': 0.0},\n", - " 'equilibration_length': {'unit': 'nanosecond',\n", - " 'val': 1.0},\n", + " 'simulation_settings': {'early_termination_target_error': ,\n", + " 'equilibration_length': ,\n", " 'minimization_steps': 5000,\n", " 'n_replicas': 11,\n", - " 'production_length': {'unit': 'nanosecond',\n", - " 'val': 5.0},\n", - " 'real_time_analysis_interval': {'unit': 'picosecond',\n", - " 'val': 250.0},\n", - " 'real_time_analysis_minimum_time': {'unit': 'picosecond',\n", - " 'val': 500.0},\n", + " 'production_length': ,\n", + " 'real_time_analysis_interval': ,\n", + " 'real_time_analysis_minimum_time': ,\n", " 'sampler_method': 'repex',\n", " 'sams_flatness_criteria': 'logZ-flatness',\n", " 'sams_gamma0': 1.0,\n", - " 'time_per_iteration': {'unit': 'picosecond',\n", - " 'val': 2.5}},\n", - " 'solvation_settings': {'box_shape': 'dodecahedron',\n", + " 'time_per_iteration': },\n", + " 'solvation_settings': {'box_shape': 'cube',\n", " 'box_size': None,\n", " 'box_vectors': None,\n", " 'number_of_solvent_molecules': None,\n", " 'solvent_model': 'tip3p',\n", - " 'solvent_padding': {'unit': 'nanometer', 'val': 1.5}},\n", + " 'solvent_padding': },\n", " 'thermo_settings': {'ph': None,\n", - " 'pressure': {'unit': 'bar', 'val': 1},\n", + " 'pressure': ,\n", " 'redox_potential': None,\n", - " 'temperature': {'unit': 'kelvin', 'val': 298.15}}}\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/atravitz/micromamba/envs/openfe-conda/lib/python3.11/site-packages/gufe/settings/models.py:30: PydanticDeprecatedSince20: The `dict` method is deprecated; use `model_dump` instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.11/migration/\n", - " pprint.pprint(self.dict())\n" + " 'temperature': }}\n" ] } ], @@ -336,11 +318,11 @@ " ],\n", " \n", " # Small molecule force field to use with OpenMM template generator:\n", - " small_molecule_forcefield='openff-2.2.1',\n", + " small_molecule_forcefield='openff-2.1.1',\n", " \n", " # Nonbonded settings\n", " nonbonded_method='PME', # Particle Mesh Ewald for long range electrostatics\n", - " nonbonded_cutoff=0.9 * unit.nm, # Cut off Lennard-Jones interactions beyond 0.9 nm\n", + " nonbonded_cutoff=1.0 * unit.nm, # Cut off Lennard-Jones interactions beyond 1 nm\n", " ),\n", " thermo_settings=equil_rfe_settings.ThermoSettings(\n", " temperature=298.15 * unit.kelvin, # Set thermostat temperature\n", @@ -350,8 +332,8 @@ " ),\n", " solvation_settings=equil_rfe_settings.OpenMMSolvationSettings(\n", " solvent_model='tip3p', # Solvent model to generate starting coords\n", - " solvent_padding=1.5 * unit.nm, # Minimum padding distance from the solute\n", - " box_shape = 'dodecahedron', # Dodecahedron water box\n", + " solvent_padding=1.2 * unit.nm, # Total distance between periodic image starting coords\n", + " box_shape = 'cube', # Cubic water box\n", " box_size = None, # Size of the water box\n", " box_vectors = None, # Box vectors\n", " number_of_solvent_molecules = None, # Number of solvent molecules\n", @@ -390,7 +372,7 @@ " # Alchemical Space Sampling settings\n", " n_replicas=11, # Number of replicas sampling alchemical space\n", " sampler_method='repex', # Sample lambda with Hamiltonian Replica Exchange\n", - " time_per_iteration=2.5*unit.ps, # Time interval between state sampling (MCMC) attempts\n", + " time_per_iteration=1*unit.ps, # Time interval between state sampling (MCMC) attempts\n", " \n", " # SAMS sampling settings (used if sampler_method='sams')\n", " sams_flatness_criteria='logZ-flatness', # Criteria for switch to asymptomatically optimal scheme\n", @@ -405,7 +387,7 @@ " early_termination_target_error=0.0*unit.kilocalorie_per_mole,\n", " ),\n", " engine_settings=equil_rfe_settings.OpenMMEngineSettings(\n", - " compute_platform=\"cuda\", # Force the usage of a CUDA device for compute\n", + " compute_platform=None, # Let OpenMM choose the best platform for your hardware\n", " ),\n", " integrator_settings=equil_rfe_settings.IntegratorSettings(\n", " timestep=4 * unit.femtosecond, # Integration timestep\n", @@ -484,14 +466,6 @@ "source": [ "Unlike `ProtocolSettings`, a `Protocol` instance is immutable. The only way to safely change the settings of a `Protocol` is to recreate it from the modified `ProtocolSettings` object." ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "91e223bc-5dc7-4533-ba5d-da112809be9a", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -510,7 +484,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.14" + "version": "3.12.10" }, "widgets": { "application/vnd.jupyter.widget-state+json": { diff --git a/cookbook/create_alchemical_network.ipynb b/cookbook/create_alchemical_network.ipynb index ce6c81c..edebab0 100644 --- a/cookbook/create_alchemical_network.ipynb +++ b/cookbook/create_alchemical_network.ipynb @@ -90,13 +90,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Create a protocol for the solvent and complex legs\n", - "solvent_protocol = RelativeHybridTopologyProtocol(RelativeHybridTopologyProtocol.default_settings())\n", - "\n", - "# For the complex, we reduce the solvation padding to avoid having too many waters\n", - "complex_settings = RelativeHybridTopologyProtocol.default_settings()\n", - "complex_settings.solvation_settings.solvent_padding = 1 * unit.nanometer\n", - "complex_protocol = RelativeHybridTopologyProtocol(complex_settings)" + "protocol = RelativeHybridTopologyProtocol(RelativeHybridTopologyProtocol.default_settings())" ] }, { @@ -137,19 +131,57 @@ "## Create the Alchemical Network" ] }, + { + "cell_type": "markdown", + "id": "8b2f6271-3c89-4cd6-8283-e617d535b910", + "metadata": {}, + "source": [ + "### Automatically" + ] + }, + { + "cell_type": "markdown", + "id": "cc13516d-92b6-44ac-a3eb-20e7f9e00631", + "metadata": {}, + "source": [ + "The `LigandNetwork.to_rbfe_alchemical_network()` method makes constructing alchemical networks for relative binding free energy calculations very simple: " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "733dee64-d23a-4eb0-87cf-c03065b8d2a6", + "metadata": {}, + "outputs": [], + "source": [ + "alchemical_network_auto = ligand_network.to_rbfe_alchemical_network(\n", + " solvent=solvent,\n", + " protein=protein,\n", + " protocol=protocol,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "35774b4f-83e7-4235-960b-aa591e20e016", + "metadata": {}, + "source": [ + "### Manually" + ] + }, { "cell_type": "markdown", "id": "0da5558b-3894-4c11-aafd-e4478972e161", "metadata": {}, "source": [ - "To manually create a network, you must loop over the `LigandNetwork` edges and manually create the `Transformation` objects for each of them. This gives you full control over the entire network. For more information, see [Under the Hood]:\n", + "If your needs are not catered to by the above method, you can instead loop over the `LigandNetwork` edges and manually create the `Transformation` objects for each of them. This gives you full control over the entire network. For more information, see [Under the Hood]:\n", "\n", "[Under the Hood]: https://docs.openfree.energy/en/stable/cookbook/under_the_hood.html" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "c49f36b1-c3c1-425e-b1de-24da25ed01c3", "metadata": {}, "outputs": [], @@ -187,11 +219,6 @@ " },\n", " name=f\"{mapping.componentB.name}_{leg}\"\n", " )\n", - "\n", - " if leg == \"solvent\":\n", - " protocol = solvent_protocol\n", - " else:\n", - " protocol = complex_protocol\n", " \n", " transformation = openfe.Transformation(\n", " stateA=system_a,\n", @@ -215,7 +242,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "fc6cac68-bdcd-4d51-b4e1-f9bb7169c6f6", "metadata": {}, "outputs": [], @@ -223,6 +250,33 @@ "alchemical_network = openfe.AlchemicalNetwork(transformations)" ] }, + { + "cell_type": "markdown", + "id": "b623d82e-1069-4c69-81af-ccc795ba5690", + "metadata": {}, + "source": [ + "We can confirm that this produces identical results to the previous strategy:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c9baa54c-513a-486a-a06a-fd8fd5d19fa5", + "metadata": { + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "assert alchemical_network == ligand_network.to_rbfe_alchemical_network(\n", + " solvent=solvent,\n", + " protein=protein,\n", + " protocol=protocol,\n", + ")" + ] + }, { "cell_type": "markdown", "id": "b17669f6-a205-420d-96c3-1a9c92d0e13b", @@ -253,7 +307,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "2da4dafb-20d6-4ce7-ab83-4690528097d6", "metadata": { "slideshow": { @@ -270,16 +324,8 @@ "\n", "for n, transformation in enumerate(alchemical_network.edges):\n", " transformation_name = transformation.name or transformation.key\n", - " transformation.to_json(transformations_dir / f\"{n}_{transformation_name}.json\")" + " transformation.dump(transformations_dir / f\"{n}_{transformation_name}.json\")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "86eeead8-7db5-4240-ba30-dbbc218d65b5", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -298,109 +344,11 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.14" + "version": "3.11.6" }, "widgets": { "application/vnd.jupyter.widget-state+json": { - "state": { - "080168055e8d4fb38744e1655591160f": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HBoxModel", - "state": { - "children": [ - "IPY_MODEL_12f05cbed4114aed81798e2ff8aa732c", - "IPY_MODEL_ea486d173f684c82985e5fba88813736", - "IPY_MODEL_0896ab0832af4cdc88b4b041fdb8eb91" - ], - "layout": "IPY_MODEL_d0b9e988953642bf98ec890d68071d08" - } - }, - "0896ab0832af4cdc88b4b041fdb8eb91": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_483b78826369478293aede7c5835951c", - "style": "IPY_MODEL_e04d82d3520641108da5a753540fa09d", - "value": " 21/21 [00:00<00:00, 307.01it/s]" - } - }, - "12f05cbed4114aed81798e2ff8aa732c": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLModel", - "state": { - "layout": "IPY_MODEL_dd33c019e00746a2a2693ae1976e6725", - "style": "IPY_MODEL_ee318b1d4f134ef2b661e761c4794e50", - "value": "Mapping: 100%" - } - }, - "2848e9cf70524c74af6d59c7fbcf04c0": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "ProgressStyleModel", - "state": { - "description_width": "" - } - }, - "2a7a60e91deb4434ad68a7f1d149f611": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "483b78826369478293aede7c5835951c": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "d0b9e988953642bf98ec890d68071d08": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "dd33c019e00746a2a2693ae1976e6725": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "2.0.0", - "model_name": "LayoutModel", - "state": {} - }, - "e04d82d3520641108da5a753540fa09d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - }, - "ea486d173f684c82985e5fba88813736": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "FloatProgressModel", - "state": { - "bar_style": "success", - "layout": "IPY_MODEL_2a7a60e91deb4434ad68a7f1d149f611", - "max": 21, - "style": "IPY_MODEL_2848e9cf70524c74af6d59c7fbcf04c0", - "value": 21 - } - }, - "ee318b1d4f134ef2b661e761c4794e50": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "2.0.0", - "model_name": "HTMLStyleModel", - "state": { - "description_width": "", - "font_size": null, - "text_color": null - } - } - }, + "state": {}, "version_major": 2, "version_minor": 0 }