From b06173167f5208a04e8769ae3e2dc5f9f1ce59f8 Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Wed, 4 Oct 2023 14:41:15 +1100 Subject: [PATCH 1/9] auto API reference backbone --- docs/_templates/autosummary/base.rst | 5 ----- docs/_templates/autosummary/class.rst | 5 ----- docs/conf.py | 25 +++++++++++++++++++++++++ docs/environment.yaml | 1 + docs/reference/api/index.rst | 7 +++++++ 5 files changed, 33 insertions(+), 10 deletions(-) delete mode 100644 docs/_templates/autosummary/base.rst delete mode 100644 docs/_templates/autosummary/class.rst diff --git a/docs/_templates/autosummary/base.rst b/docs/_templates/autosummary/base.rst deleted file mode 100644 index cdb86a616..000000000 --- a/docs/_templates/autosummary/base.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. title:: {{ objname }} - -.. currentmodule:: {{ module }} - -.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst deleted file mode 100644 index cdb86a616..000000000 --- a/docs/_templates/autosummary/class.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. title:: {{ objname }} - -.. currentmodule:: {{ module }} - -.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/conf.py b/docs/conf.py index 33067355f..b4a5b30b0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -93,6 +93,30 @@ "openmmforcefields", ] +# API docs settings +autosummary_generate = True +# Document imported items iff they're in __all__ +autosummary_imported_members = False +autosummary_ignore_module_all = False +# Autosummary template configuration +autosummary_context = { + # Modules to exclude from API docs + "exclude_modules": [ + ], + "show_inheritance": True, + "show_inherited_members": False, + "show_undoc_members": True, +} + +autodoc_preserve_defaults = True +autodoc_inherit_docstrings = True +autodoc_typehints_format = "short" +# Fold the __init__ or __new__ methods' signature into class documentation +autoclass_content = "class" +autodoc_class_signature = "mixed" +# Workaround for autodoc_typehints_format not working for attributes +# see https://github.com/sphinx-doc/sphinx/issues/10290#issuecomment-1079740009 +python_use_unqualified_type_names = True # -- Options for HTML output ------------------------------------------------- @@ -111,6 +135,7 @@ } ], "accent_color": "DarkGoldenYellow", + "navigation_depth": 8, } html_logo = "_static/Squaredcircle.svg" diff --git a/docs/environment.yaml b/docs/environment.yaml index 4f4bfae8d..d40988521 100644 --- a/docs/environment.yaml +++ b/docs/environment.yaml @@ -15,6 +15,7 @@ dependencies: - sphinx-click - tqdm - libsass +- cinnabar - pip: - sphinx-design - sphinx-toolbox diff --git a/docs/reference/api/index.rst b/docs/reference/api/index.rst index 5d0df4f7e..cb3e0b9b0 100644 --- a/docs/reference/api/index.rst +++ b/docs/reference/api/index.rst @@ -12,3 +12,10 @@ OpenFE API Reference alchemical_network_planning defining_and_executing_simulations openmm_rfe + +.. autosummary:: + :nosignatures: + :toctree: generated/ + :recursive: + + openfe From 1027cda579f919a2b981a6c9d4769497aa025764 Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Wed, 4 Oct 2023 17:52:23 +1100 Subject: [PATCH 2/9] Module docstrings and __all__ and moving around re-exports --- .../autosummary/top-level-module.rst | 6 + docs/conf.py | 15 +- .../api/alchemical_network_planning.rst | 41 ------ docs/reference/api/data.rst | 13 -- .../defining_and_executing_simulations.rst | 47 ------ docs/reference/api/index.rst | 30 ++-- docs/reference/api/ligand_network.rst | 129 ----------------- docs/reference/api/openmm_rfe.rst | 136 ------------------ docs/reference/api/systems_and_components.rst | 29 ---- docs/reference/index.rst | 6 +- openfe/__init__.py | 28 ++-- openfe/orchestration/__init__.py | 8 ++ openfe/protocols/__init__.py | 45 ++++++ openfe/protocols/openmm_rfe/__init__.py | 11 ++ openfe/protocols/settings.py | 47 ++++++ openfe/setup/__init__.py | 63 +++++++- openfe/setup/atom_mapping/__init__.py | 16 +++ openfe/setup/ligand_network.py | 0 openfe/setup/system.py | 33 +++++ 19 files changed, 274 insertions(+), 429 deletions(-) create mode 100644 docs/_templates/autosummary/top-level-module.rst delete mode 100644 docs/reference/api/alchemical_network_planning.rst delete mode 100644 docs/reference/api/data.rst delete mode 100644 docs/reference/api/defining_and_executing_simulations.rst delete mode 100644 docs/reference/api/ligand_network.rst delete mode 100644 docs/reference/api/openmm_rfe.rst delete mode 100644 docs/reference/api/systems_and_components.rst create mode 100644 openfe/protocols/settings.py delete mode 100644 openfe/setup/ligand_network.py create mode 100644 openfe/setup/system.py diff --git a/docs/_templates/autosummary/top-level-module.rst b/docs/_templates/autosummary/top-level-module.rst new file mode 100644 index 000000000..f7f0202e5 --- /dev/null +++ b/docs/_templates/autosummary/top-level-module.rst @@ -0,0 +1,6 @@ +{% extends "autosummary/module.rst" %} +{% block title -%} + +{{ ("``" ~ fullname ~ "``") | underline('=')}} + +{%- endblock %} diff --git a/docs/conf.py b/docs/conf.py index b4a5b30b0..d1ddd27b3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -71,9 +71,10 @@ autodoc_default_options = { "members": True, "member-order": "bysource", - "inherited-members": "GufeTokenizable,BaseModel", + "inherited-members": "GufeTokenizable,BaseModel,SettingsBaseModel", "undoc-members": True, "special-members": "__call__", + "exclude-members": "get_defaults", } toc_object_entries_show_parents = "hide" @@ -91,6 +92,8 @@ "openmmtools", "mdtraj", "openmmforcefields", + "netCDF4", + "py3Dmol", ] # API docs settings @@ -102,6 +105,7 @@ autosummary_context = { # Modules to exclude from API docs "exclude_modules": [ + "openfe.tests", ], "show_inheritance": True, "show_inherited_members": False, @@ -118,6 +122,15 @@ # see https://github.com/sphinx-doc/sphinx/issues/10290#issuecomment-1079740009 python_use_unqualified_type_names = True + +autodoc_pydantic_model_show_json=False +autodoc_pydantic_model_show_field_summary=False +autodoc_pydantic_model_show_config_member=False +autodoc_pydantic_model_show_config_summary=False +autodoc_pydantic_model_show_validator_members=False +autodoc_pydantic_model_show_validator_summary=False +autodoc_pydantic_field_list_validators=False + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for diff --git a/docs/reference/api/alchemical_network_planning.rst b/docs/reference/api/alchemical_network_planning.rst deleted file mode 100644 index 8a288404c..000000000 --- a/docs/reference/api/alchemical_network_planning.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. _Alchemical Network Planning: - -Simulation Campaign Planning -============================ - -While a :class:`LigandNetwork` describes a network of ligands and their atom -mappings, a :class:`AlchemicalNetwork` describes a single replicate of a -simulation campaign. It includes all the information needed to perform the -simulation, and so implicitly includes the :class:`LigandNetwork`. - -Alchemical Simulations -~~~~~~~~~~~~~~~~~~~~~~ - -Descriptions of anticipated alchemical simulation campaigns. - -.. module:: openfe - :noindex: - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - Transformation - AlchemicalNetwork - -Alchemical Network Planners ---------------------------- -Alchemical network planners are objects that pull all the ideas in OpenFE -into a quick setup for simulation. The goal is to create the -:class:`.AlchemicalNetwork` that represents an entire simulation campaign, -starting from a bare amount of user input. - -.. module:: openfe.setup - :noindex: - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - RBFEAlchemicalNetworkPlanner - RHFEAlchemicalNetworkPlanner diff --git a/docs/reference/api/data.rst b/docs/reference/api/data.rst deleted file mode 100644 index ef438b2b8..000000000 --- a/docs/reference/api/data.rst +++ /dev/null @@ -1,13 +0,0 @@ -Data Objects and Serialization -============================== - -.. module:: gufe.tokenization - -Almost every OpenFE data object inherits from :class:`GufeTokenizable`, which -enforces immutability and provides functions for data serialization. - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - GufeTokenizable diff --git a/docs/reference/api/defining_and_executing_simulations.rst b/docs/reference/api/defining_and_executing_simulations.rst deleted file mode 100644 index 7adaa16ce..000000000 --- a/docs/reference/api/defining_and_executing_simulations.rst +++ /dev/null @@ -1,47 +0,0 @@ -Defining and Executing Simulations -================================== - -.. _executors: - -Executing Simulations ---------------------- - -.. module:: openfe - :noindex: - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - execute_DAG - -General classes ---------------- - -.. module:: openfe - :noindex: - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - ProtocolDAG - ProtocolUnitResult - ProtocolUnitFailure - ProtocolDAGResult - -Specialised classes -------------------- - -These classes are abstract classes that are specialised (subclassed) for an individual Protocol. - -.. module:: openfe - :noindex: - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - Protocol - ProtocolUnit - ProtocolResult diff --git a/docs/reference/api/index.rst b/docs/reference/api/index.rst index cb3e0b9b0..386a9d96c 100644 --- a/docs/reference/api/index.rst +++ b/docs/reference/api/index.rst @@ -3,19 +3,23 @@ OpenFE API Reference ==================== -.. toctree:: - :maxdepth: 2 +``openfe`` +---------- - data - systems_and_components - ligand_network - alchemical_network_planning - defining_and_executing_simulations - openmm_rfe +.. automodule:: openfe + :no-members: -.. autosummary:: - :nosignatures: - :toctree: generated/ - :recursive: + .. rubric:: Modules - openfe + .. autosummary:: + :nosignatures: + :toctree: generated/ + :recursive: + :template: autosummary/top-level-module.rst + + setup + orchestration + analysis + protocols + storage + utils diff --git a/docs/reference/api/ligand_network.rst b/docs/reference/api/ligand_network.rst deleted file mode 100644 index 1692b53fa..000000000 --- a/docs/reference/api/ligand_network.rst +++ /dev/null @@ -1,129 +0,0 @@ -Ligand Network Tools -==================== - -.. module:: openfe.setup - :noindex: - -Ligand Network --------------- - -A network of mutations between ligands. - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - LigandNetwork - - -.. _Ligand Network Planners: - -Network Planners -~~~~~~~~~~~~~~~~ - -.. module:: openfe.setup.ligand_network_planning - -Functions that build a :class:`.LigandNetwork` from a collection of :class:`SmallMoleculeComponents` by optimizing over a `scoring function `_. - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - generate_radial_network - generate_maximal_network - generate_minimal_spanning_network - -.. _Ligand Network Loaders: - -Network Loaders -~~~~~~~~~~~~~~~ - -Functions to load a :class:`.LigandNetwork` from equivalent classes in other packages, or to specify one by hand. - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - generate_network_from_names - generate_network_from_indices - load_orion_network - load_fepplus_network - -Atom Mappings -------------- - -Tools for mapping atoms in one molecule to those in another. Used to generate efficient ligand networks. - -.. module:: openfe.setup.atom_mapping - -.. rubric:: Abstract Base Class - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - LigandAtomMapper - -.. rubric:: Implementations - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - LomapAtomMapper - PersesAtomMapper - -.. rubric:: Data Types - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - LigandAtomMapping - -.. _Atom Map Scorers: - -Atom Map Scorers ----------------- - -Scoring functions for a mapping between ligands. These are used as objective functions for :any:`Ligand Network Planners`. - -LOMAP Scorers -~~~~~~~~~~~~~ - -Scorers implemented by the `LOMAP `_ package. - -.. apparently we need the atom_mapping because internally autofunction is - trying ``import openfe.setup.lomap_scorers``, which doesn't work (whereas - ``from openfe.setup import lomap_scorers`` does) - -.. module:: openfe.setup.atom_mapping.lomap_scorers - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - default_lomap_score - ecr_score - mcsr_score - mncar_score - atomic_number_score - hybridization_score - sulfonamides_score - heterocycles_score - transmuting_methyl_into_ring_score - transmuting_ring_sizes_score - - -Perses Scorers -~~~~~~~~~~~~~~ - -Scorers implemented by the `Perses `_ package. - -.. module:: openfe.setup.atom_mapping.perses_scorers - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - default_perses_scorer diff --git a/docs/reference/api/openmm_rfe.rst b/docs/reference/api/openmm_rfe.rst deleted file mode 100644 index e8b222c08..000000000 --- a/docs/reference/api/openmm_rfe.rst +++ /dev/null @@ -1,136 +0,0 @@ -OpenMM Relative Free Energy Protocol -==================================== - -This section provides details about the OpenMM Relative Free Energy Protocol -implemented in OpenFE. - -Protocol API specification --------------------------- - -.. module:: openfe.protocols.openmm_rfe - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - RelativeHybridTopologyProtocol - RelativeHybridTopologyProtocolResult - -Protocol Settings ------------------ - - -Below are the settings which can be tweaked in the protocol. The default settings (accessed using :meth:`RelativeHybridTopologyProtocol.default_settings`) will automatically populate a settings which we have found to be useful for running relative binding free energies using explicit solvent. There will however be some cases (such as when doing gas phase calculations) where you will need to tweak some of the following settings. - -.. autopydantic_model:: RelativeHybridTopologyProtocolSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :exclude-members: get_defaults - :member-order: bysource - -.. module:: openfe.protocols.openmm_rfe.equil_rfe_settings - -.. autopydantic_model:: OpenMMSystemGeneratorFFSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: ThermoSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: AlchemicalSamplerSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: AlchemicalSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: OpenMMEngineSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: IntegratorSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: SimulationSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: SolvationSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource - -.. autopydantic_model:: SystemSettings - :model-show-json: False - :model-show-field-summary: False - :model-show-config-member: False - :model-show-config-summary: False - :model-show-validator-members: False - :model-show-validator-summary: False - :field-list-validators: False - :inherited-members: SettingsBaseModel - :member-order: bysource diff --git a/docs/reference/api/systems_and_components.rst b/docs/reference/api/systems_and_components.rst deleted file mode 100644 index 0732f4ce7..000000000 --- a/docs/reference/api/systems_and_components.rst +++ /dev/null @@ -1,29 +0,0 @@ -Chemical Systems and Components -=============================== - -We describe a chemical system as being made up of one or more "components," e.g., solvent, protein, or small molecule. The :class:`.ChemicalSystem` object joins components together into a simulation system. - -.. module:: openfe - :noindex: - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - Component - SmallMoleculeComponent - ProteinComponent - SolventComponent - ChemicalSystem - - -Chemical System Generators --------------------------- - -.. module:: openfe.setup.chemicalsystem_generator - -.. autosummary:: - :nosignatures: - :toctree: generated/ - - EasyChemicalSystemGenerator diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 8853d761f..a9b17a0c9 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -5,7 +5,11 @@ This contains details of the Python API as well as a reference to the command line interface. .. toctree:: - :maxdepth: 2 + :maxdepth: 3 api/index + +.. toctree:: + :maxdepth: 2 + cli/index diff --git a/openfe/__init__.py b/openfe/__init__.py index 0b11ed153..1292440c1 100644 --- a/openfe/__init__.py +++ b/openfe/__init__.py @@ -1,22 +1,16 @@ -from gufe import ( - ChemicalSystem, - Component, - ProteinComponent, - SmallMoleculeComponent, - SolventComponent, - Transformation, - AlchemicalNetwork, - LigandAtomMapping, -) -from gufe.protocols import ( +""" +Open source free energy calculation via molecular mechanics. +""" + +from .protocols import ( Protocol, ProtocolDAG, ProtocolUnit, ProtocolUnitResult, ProtocolUnitFailure, ProtocolDAGResult, ProtocolResult, - execute_DAG, ) +from .orchestration import execute_DAG from . import utils from . import setup @@ -28,6 +22,16 @@ ligand_network_planning, LigandNetwork, LigandAtomMapper, + LigandAtomMapping, + Transformation, + AlchemicalNetwork, +) +from .setup.system import ( + ChemicalSystem, + Component, + ProteinComponent, + SmallMoleculeComponent, + SolventComponent, ) from . import orchestration from . import analysis diff --git a/openfe/orchestration/__init__.py b/openfe/orchestration/__init__.py index e69de29bb..539f4cae1 100644 --- a/openfe/orchestration/__init__.py +++ b/openfe/orchestration/__init__.py @@ -0,0 +1,8 @@ +""" +Tools to execute and orchestrate the execution of protocol DAGs. +""" +from gufe.protocols import execute_DAG + +__all__ = [ + "execute_DAG", +] \ No newline at end of file diff --git a/openfe/protocols/__init__.py b/openfe/protocols/__init__.py index efae32ddb..d0c5c95d3 100644 --- a/openfe/protocols/__init__.py +++ b/openfe/protocols/__init__.py @@ -1,2 +1,47 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Descriptions and implementations of free energy calculation protocols. + +A :class:`.Protocol` describes a methodology for computing a free energy from a +pair of chemical systems. It produces a number of :class:`ProtocolDAG` objects, +which are directed acyclic graphs describing the dependencies between +individual units of work that can otherwise be run in parallel. Each unit of +work is described and implemented by a :class:`ProtocolUnit`. The results of a +``ProtocolUnit`` are described by a :class:`ProtocolUnitResult` when successful +or else a :class:`ProtocolUnitFailure`; these types are then collected into a +:class:`ProtocolDAGResult` to describe the result of a protocol DAG, and +multiple DAGs from different transformations in the same campaign can be +collected into a :class:`ProtocolResult`. + +``Protocol`` instances are configured by Pydantic models describing their +settings.. Base classes and a number of implemented building blocks for complex +configurations are found in the :class:`settings` module. + +Other submodules in this module represent individual implementations of +protocols. +""" + +from gufe.protocols import ( + Protocol, + ProtocolDAG, + ProtocolUnit, + ProtocolUnitResult, + ProtocolUnitFailure, + ProtocolDAGResult, + ProtocolResult, +) + +from . import openmm_rfe, openmm_utils, settings + +__all__ = [ + "settings", + "openmm_rfe", + "Protocol", + "ProtocolDAG", + "ProtocolUnit", + "ProtocolUnitResult", + "ProtocolUnitFailure", + "ProtocolDAGResult", + "ProtocolResult", +] diff --git a/openfe/protocols/openmm_rfe/__init__.py b/openfe/protocols/openmm_rfe/__init__.py index eb50c0712..4d802305d 100644 --- a/openfe/protocols/openmm_rfe/__init__.py +++ b/openfe/protocols/openmm_rfe/__init__.py @@ -1,5 +1,10 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Run relative free energy calculations on hybrid topologies with OpenMM. + + +""" from . import _rfe_utils @@ -13,3 +18,9 @@ RelativeHybridTopologyProtocolUnit, ) +__all__ = [ + "RelativeHybridTopologyProtocolSettings", + "RelativeHybridTopologyProtocol", + "RelativeHybridTopologyProtocolResult", + "RelativeHybridTopologyProtocolUnit", +] diff --git a/openfe/protocols/settings.py b/openfe/protocols/settings.py new file mode 100644 index 000000000..f6f1c9ed2 --- /dev/null +++ b/openfe/protocols/settings.py @@ -0,0 +1,47 @@ +""" +Settings models for Protocols. + +Protocols often permit extensive configuration that would be cumbersome to +configure in an ``__init__`` method and which may want to be independently +recorded and shared. Settings models are Pydantic models that support these use +cases. Each protocol should have an associated settings object; for a protocol +called ``FooProtocol``, the corresponding settings object is called +``FooProtocolSettings``. + +Settings are generally broken up into multiple levels to avoid overwhelming +users with information and to allow settings models to be shared across +multiple protocols. Top level protocol settings models should inherit +from :class:`.Settings`, whereas all other settings models should inherit from +:class:`.SettingsBaseModel`. + +""" + +from .openmm_utils.omm_settings import ( + Settings, + SettingsBaseModel, + SystemSettings, + SolvationSettings, + AlchemicalSamplerSettings, + OpenMMEngineSettings, + IntegratorSettings, + SimulationSettings, + ThermoSettings, + OpenMMSystemGeneratorFFSettings, +) + +from .openmm_rfe.equil_rfe_settings import AlchemicalSettings + +__all__ = [ + "Settings", + "SettingsBaseModel", + "SystemSettings", + "SolvationSettings", + "AlchemicalSamplerSettings", + "OpenMMEngineSettings", + "IntegratorSettings", + "SimulationSettings", + "ThermoSettings", + "OpenMMSystemGeneratorFFSettings", + "AlchemicalSettings", + +] diff --git a/openfe/setup/__init__.py b/openfe/setup/__init__.py index 024680822..4fd940e41 100644 --- a/openfe/setup/__init__.py +++ b/openfe/setup/__init__.py @@ -1,13 +1,62 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Set up a free energy campaign by preparing an :class:`.AlchemicalNetwork`. +Setup consists of preparing an :class:`.AlchemicalNetwork`, which contains a +collection of :class:`.Transformation` objects. Each ``Transformation`` +describes an alchemic mutation from one chemical system to another, including +full descriptions of both chemical systems as well as the simulation protocol +used to compute the change. Descriptions of chemical systems and their +components are found in the :mod:`.system` module. -from .atom_mapping import (LigandAtomMapping, - LigandAtomMapper, - LomapAtomMapper, lomap_scorers, - PersesAtomMapper, perses_scorers) +An ``AlchemicalNetwork`` is usually prepared from a :class:`.LigandNetwork`, +which is an undirected graph of small molecules. Each edge represents a +yet-to-be-calculated mutation including an atom mapping, but without specifying +a simulation protocol or explicit chemical system. A ``LigandNetwork`` is +created by a planner function from the :mod:`.ligand_network_planning` module. +A planner may generate the network layout automatically, load it from another +tool, or require the user to specify it by hand. Most planners generate atom +mappings automatically by optimising over a scorer function +from :mod:`.lomap_scorers` or :mod:`.perses_scorers`; these and other atom +mapping utilities are found in the :mod:`.atom_mapping` module. -from gufe import LigandNetwork -from . import ligand_network_planning +An ``AlchemicalNetwork`` additionally needs a :class:`Protocol` +for each transformation, though it usually uses +the same protocol for all transformations. A protocol describes and implements +the process of computing the free energy from the two chemical systems +described by a transformation. -from .alchemical_network_planner import RHFEAlchemicalNetworkPlanner, RBFEAlchemicalNetworkPlanner \ No newline at end of file +""" + + +from .atom_mapping import ( + LigandAtomMapping, + LigandAtomMapper, + LomapAtomMapper, + lomap_scorers, + PersesAtomMapper, + perses_scorers, +) + +from gufe import ( + LigandNetwork, + Transformation, + AlchemicalNetwork, +) +from . import ligand_network_planning, atom_mapping, system + +from .alchemical_network_planner import ( + RHFEAlchemicalNetworkPlanner, + RBFEAlchemicalNetworkPlanner, +) + +__all__ = [ + "atom_mapping", + "system", + "ligand_network_planning", + "alchemical_network_planner", + "LigandNetwork", + "Transformation", + "AlchemicalNetwork", +] diff --git a/openfe/setup/atom_mapping/__init__.py b/openfe/setup/atom_mapping/__init__.py index 0d19acf64..b231cd237 100644 --- a/openfe/setup/atom_mapping/__init__.py +++ b/openfe/setup/atom_mapping/__init__.py @@ -1,3 +1,19 @@ +""" +Mappings from atoms in one molecule to those in another. + +:class:`LigandAtomMapper` defines the interface of atom mappers, and is +implemented by :class:`LomapAtomMapper` and :class:`PersesAtomMapper`. + +The :mod:`.perses_scorers` and :mod:`.lomap_scorers` modules provide scoring +functions used for both atom mappings and transformations. A scorer takes +a :class:`..mapping.LigandAtomMapping` and possibly some other parameters and +returns a score between 0 and 1. Higher scores represent better mappings. These +scores are used by :class:`LigandNetwork` +planners to select the best mapping for a given transformation and also to +compare different transformations while optimising network topologies. + +""" + from gufe import LigandAtomMapping from .ligandatommapper import LigandAtomMapper diff --git a/openfe/setup/ligand_network.py b/openfe/setup/ligand_network.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/openfe/setup/system.py b/openfe/setup/system.py new file mode 100644 index 000000000..d1b2775eb --- /dev/null +++ b/openfe/setup/system.py @@ -0,0 +1,33 @@ +""" +Chemical systems and their components. + +A :class:`ChemicalSystem` describes a simulation box and its contents. They are +the nodes of an ``AlchemicalNetwork``; two are included in each +``Transformation`` as end states. The abstract base class :class:`Component` +defines the interface for a components of a chemical system. A ``Component`` +need not refer to a single molecule; it may represent a protein of multiple +chains and their cofactors, or the entire solvent including ions. + +.. admonition:: Custom ``Components`` require support from the ``Protocol`` + + ``Component`` types are handled individually by each ``Protocol``; it is + not presently possible to define a custom ``Component`` and have it work + in an existing ``Protocol``. + +""" + +from gufe import ( + ChemicalSystem, + Component, + ProteinComponent, + SmallMoleculeComponent, + SolventComponent, +) + +__all__ = [ + "ChemicalSystem", + "Component", + "ProteinComponent", + "SmallMoleculeComponent", + "SolventComponent", +] From 57a40b6cee2166efcba40fa27285ee4ce606b911 Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Wed, 4 Oct 2023 18:25:24 +1100 Subject: [PATCH 3/9] Temporarily allow warnings on RTD --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 1275754bc..408371728 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ build: sphinx: configuration: docs/conf.py - fail_on_warning: true + # fail_on_warning: true conda: environment: docs/environment.yaml From b8dc173d4e52a1cf8bf2f9f46c9bbacf6d0fcd23 Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Fri, 6 Oct 2023 12:37:41 +1100 Subject: [PATCH 4/9] Format files for pep8 --- docs/conf.py | 16 ++++++++-------- openfe/orchestration/__init__.py | 2 +- openfe/setup/__init__.py | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index d1ddd27b3..5f5767958 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,7 +16,7 @@ from packaging.version import parse -sys.path.insert(0, os.path.abspath('../')) +sys.path.insert(0, os.path.abspath("../")) os.environ["SPHINX"] = "True" @@ -123,13 +123,13 @@ python_use_unqualified_type_names = True -autodoc_pydantic_model_show_json=False -autodoc_pydantic_model_show_field_summary=False -autodoc_pydantic_model_show_config_member=False -autodoc_pydantic_model_show_config_summary=False -autodoc_pydantic_model_show_validator_members=False -autodoc_pydantic_model_show_validator_summary=False -autodoc_pydantic_field_list_validators=False +autodoc_pydantic_model_show_json = False +autodoc_pydantic_model_show_field_summary = False +autodoc_pydantic_model_show_config_member = False +autodoc_pydantic_model_show_config_summary = False +autodoc_pydantic_model_show_validator_members = False +autodoc_pydantic_model_show_validator_summary = False +autodoc_pydantic_field_list_validators = False # -- Options for HTML output ------------------------------------------------- diff --git a/openfe/orchestration/__init__.py b/openfe/orchestration/__init__.py index 539f4cae1..baee118f3 100644 --- a/openfe/orchestration/__init__.py +++ b/openfe/orchestration/__init__.py @@ -5,4 +5,4 @@ __all__ = [ "execute_DAG", -] \ No newline at end of file +] diff --git a/openfe/setup/__init__.py b/openfe/setup/__init__.py index 4fd940e41..cabf64222 100644 --- a/openfe/setup/__init__.py +++ b/openfe/setup/__init__.py @@ -21,11 +21,11 @@ from :mod:`.lomap_scorers` or :mod:`.perses_scorers`; these and other atom mapping utilities are found in the :mod:`.atom_mapping` module. -An ``AlchemicalNetwork`` additionally needs a :class:`Protocol` -for each transformation, though it usually uses -the same protocol for all transformations. A protocol describes and implements -the process of computing the free energy from the two chemical systems -described by a transformation. +An ``AlchemicalNetwork`` additionally needs +a :class:`Protocol` for each transformation, though +it usually uses the same protocol for all transformations. A protocol describes +and implements the process of computing the free energy from the two chemical +systems described by a transformation. """ From 8aa2851a5a96e32a24ca1d37ed0dc9b3bf47223d Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Fri, 6 Oct 2023 12:40:14 +1100 Subject: [PATCH 5/9] More module docstrings --- openfe/analysis/__init__.py | 3 +++ openfe/analysis/plotting.py | 4 ++++ openfe/setup/atom_mapping/__init__.py | 4 ++++ openfe/setup/ligand_network_planning.py | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/openfe/analysis/__init__.py b/openfe/analysis/__init__.py index 99fb0c159..032d435b0 100644 --- a/openfe/analysis/__init__.py +++ b/openfe/analysis/__init__.py @@ -1,3 +1,6 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Analyse the results and outputs of a free energy campaign. +""" from . import plotting diff --git a/openfe/analysis/plotting.py b/openfe/analysis/plotting.py index eba7b7e7f..d4979d097 100644 --- a/openfe/analysis/plotting.py +++ b/openfe/analysis/plotting.py @@ -1,5 +1,9 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Best-practices graphs for visualising free energy results. +""" + import matplotlib.pyplot as plt import numpy.typing as npt from openff.units import unit diff --git a/openfe/setup/atom_mapping/__init__.py b/openfe/setup/atom_mapping/__init__.py index b231cd237..b35088f68 100644 --- a/openfe/setup/atom_mapping/__init__.py +++ b/openfe/setup/atom_mapping/__init__.py @@ -3,6 +3,10 @@ :class:`LigandAtomMapper` defines the interface of atom mappers, and is implemented by :class:`LomapAtomMapper` and :class:`PersesAtomMapper`. +:class:`LigandAtomMapping` is a simple container for an atom maping. It + describes which atoms in one molecule should be transformed into which atoms + in the other, and which atoms should be destroyed or created over the + transformation. The :mod:`.perses_scorers` and :mod:`.lomap_scorers` modules provide scoring functions used for both atom mappings and transformations. A scorer takes diff --git a/openfe/setup/ligand_network_planning.py b/openfe/setup/ligand_network_planning.py index 1c6265868..424b25ab5 100644 --- a/openfe/setup/ligand_network_planning.py +++ b/openfe/setup/ligand_network_planning.py @@ -1,5 +1,9 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Functions for planning a :class:`LigandNetwork` from small molecules. +""" + import math from pathlib import Path from typing import Iterable, Callable, Optional, Union From c936e54df25ef3318f7fd96bdeeece2c2da5eca2 Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Mon, 9 Oct 2023 15:51:21 +1100 Subject: [PATCH 6/9] Fix Sphinx warnings --- .readthedocs.yaml | 2 +- docs/cookbook/index.rst | 4 ++-- docs/cookbook/under_the_hood.rst | 2 +- docs/index.rst | 2 +- .../relative_alchemical_network_planner.py | 1 + openfe/setup/atom_mapping/__init__.py | 6 +++--- openfe/setup/atom_mapping/lomap_scorers.py | 2 +- openfe/storage/resultclient.py | 4 ++-- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 408371728..1275754bc 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ build: sphinx: configuration: docs/conf.py - # fail_on_warning: true + fail_on_warning: true conda: environment: docs/environment.yaml diff --git a/docs/cookbook/index.rst b/docs/cookbook/index.rst index 3551812c3..b9f210564 100644 --- a/docs/cookbook/index.rst +++ b/docs/cookbook/index.rst @@ -60,7 +60,7 @@ The typical way to use the Python API is to load a number of molecules you want Atom mappings from another tool. .. rst-class:: arrow-down - - :any:`Ligand Network Loaders` + - :any:`Ligand Network Loaders ` - - .. rst-class:: flowchart-spacer @@ -70,7 +70,7 @@ The typical way to use the Python API is to load a number of molecules you want Hand-write an atom mapping. .. rst-class:: arrow-down - - :any:`Ligand Network Loaders` + - :any:`Ligand Network Loaders ` - :class:`LigandNetwork` A network of ligand transformations. diff --git a/docs/cookbook/under_the_hood.rst b/docs/cookbook/under_the_hood.rst index ddd821adb..a602a60fe 100644 --- a/docs/cookbook/under_the_hood.rst +++ b/docs/cookbook/under_the_hood.rst @@ -104,7 +104,7 @@ If you want to implement your own atom mapper or free energy procedure, or you w - - .. rst-class:: arrow-down - - :any:`executors` + - :any:`openfe.orchestration` - :class:`ProtocolDAGResult` A completed transformation. diff --git a/docs/index.rst b/docs/index.rst index 14637740b..987b5eb9f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -68,7 +68,7 @@ The **OpenFE** toolkit provides open-source frameworks for calculating alchemica .. grid-item-card:: Relative Free Energy Protocol :img-top: _static/Rocket.svg :text-align: center - :link: reference/api/openmm_rfe + :link: reference/api/generated/openfe.protocols.openmm_rfe :link-type: doc Documentation for OpenFE's OpenMM-based Hybrid Topology Relative Free diff --git a/openfe/setup/alchemical_network_planner/relative_alchemical_network_planner.py b/openfe/setup/alchemical_network_planner/relative_alchemical_network_planner.py index 3b34aa511..7eaf693bb 100644 --- a/openfe/setup/alchemical_network_planner/relative_alchemical_network_planner.py +++ b/openfe/setup/alchemical_network_planner/relative_alchemical_network_planner.py @@ -39,6 +39,7 @@ PROTOCOL_GENERATOR = { RelativeHybridTopologyProtocol: EasyChemicalSystemGenerator, } +"""Mapping from a RFE protocol to the corresponding system generator""" class RelativeAlchemicalNetworkPlanner( diff --git a/openfe/setup/atom_mapping/__init__.py b/openfe/setup/atom_mapping/__init__.py index b35088f68..868df73d5 100644 --- a/openfe/setup/atom_mapping/__init__.py +++ b/openfe/setup/atom_mapping/__init__.py @@ -4,9 +4,9 @@ :class:`LigandAtomMapper` defines the interface of atom mappers, and is implemented by :class:`LomapAtomMapper` and :class:`PersesAtomMapper`. :class:`LigandAtomMapping` is a simple container for an atom maping. It - describes which atoms in one molecule should be transformed into which atoms - in the other, and which atoms should be destroyed or created over the - transformation. +describes which atoms in one molecule should be transformed into which atoms +in the other, and which atoms should be destroyed or created over the +transformation. The :mod:`.perses_scorers` and :mod:`.lomap_scorers` modules provide scoring functions used for both atom mappings and transformations. A scorer takes diff --git a/openfe/setup/atom_mapping/lomap_scorers.py b/openfe/setup/atom_mapping/lomap_scorers.py index bcf3e6516..30f216802 100644 --- a/openfe/setup/atom_mapping/lomap_scorers.py +++ b/openfe/setup/atom_mapping/lomap_scorers.py @@ -20,7 +20,7 @@ # Br to element 35: {53: 0.85}, } - +"""Default ``difficulty`` argument for :func:`.atomic_number_score`.""" def ecr_score(mapping: LigandAtomMapping) -> float: """ diff --git a/openfe/storage/resultclient.py b/openfe/storage/resultclient.py index 012c12f66..cf4cf0268 100644 --- a/openfe/storage/resultclient.py +++ b/openfe/storage/resultclient.py @@ -145,8 +145,8 @@ def _store_gufe_tokenizable(self, prefix, obj): def store_transformation(self, transformation): """Store a :class:`.Transformation`. - Parmeters - --------- + Parameters + ---------- transformation: :class:`.Transformation` the transformation to store """ From b907c2f01e6c6f953edf46fc8aad0fe700548aa7 Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Mon, 9 Oct 2023 17:18:00 +1100 Subject: [PATCH 7/9] More docstrings --- docs/conf.py | 2 +- openfe/protocols/openmm_rfe/equil_rfe_methods.py | 10 ++++++++++ openfe/protocols/openmm_rfe/equil_rfe_settings.py | 8 ++++++++ .../setup/alchemical_network_planner/__init__.py | 7 +++++++ openfe/setup/atom_mapping/__init__.py | 9 +++++++++ openfe/setup/atom_mapping/lomap_scorers.py | 4 ++++ openfe/setup/atom_mapping/perses_scorers.py | 3 +++ openfe/storage/__init__.py | 3 +++ openfe/utils/__init__.py | 15 +++++++++++++++ 9 files changed, 60 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 5f5767958..fa79c077d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -116,7 +116,7 @@ autodoc_inherit_docstrings = True autodoc_typehints_format = "short" # Fold the __init__ or __new__ methods' signature into class documentation -autoclass_content = "class" +autoclass_content = "both" autodoc_class_signature = "mixed" # Workaround for autodoc_typehints_format not working for attributes # see https://github.com/sphinx-doc/sphinx/issues/10290#issuecomment-1079740009 diff --git a/openfe/protocols/openmm_rfe/equil_rfe_methods.py b/openfe/protocols/openmm_rfe/equil_rfe_methods.py index 0f6aa98c6..41021248e 100644 --- a/openfe/protocols/openmm_rfe/equil_rfe_methods.py +++ b/openfe/protocols/openmm_rfe/equil_rfe_methods.py @@ -309,6 +309,16 @@ def production_iterations(self) -> list[float]: class RelativeHybridTopologyProtocol(gufe.Protocol): + """ + Relative free energy calculations with a hybrid topology in OpenMM. + + See Also + -------- + openfe.protocols + openfe.protocols.openmm_rfe.RelativeHybridTopologyProtocolSettings + openfe.protocols.openmm_rfe.RelativeHybridTopologyProtocolResult + openfe.protocols.openmm_rfe.RelativeHybridTopologyProtocolUnit + """ result_cls = RelativeHybridTopologyProtocolResult _settings: RelativeHybridTopologyProtocolSettings diff --git a/openfe/protocols/openmm_rfe/equil_rfe_settings.py b/openfe/protocols/openmm_rfe/equil_rfe_settings.py index 230d05ff6..32c9403a1 100644 --- a/openfe/protocols/openmm_rfe/equil_rfe_settings.py +++ b/openfe/protocols/openmm_rfe/equil_rfe_settings.py @@ -80,6 +80,14 @@ class Config: class RelativeHybridTopologyProtocolSettings(Settings): + """ + Configuration object for ``RelativeHybridTopologyProtocol`` + + See Also + -------- + openfe.protocols.openmm_rfe.RelativeHybridTopologyProtocol + """ + class Config: arbitrary_types_allowed = True diff --git a/openfe/setup/alchemical_network_planner/__init__.py b/openfe/setup/alchemical_network_planner/__init__.py index 7a67e50a9..d56b7b440 100644 --- a/openfe/setup/alchemical_network_planner/__init__.py +++ b/openfe/setup/alchemical_network_planner/__init__.py @@ -1,5 +1,12 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Tools for planning alchemical networks. + +This module is being replaced by methods on :class:`LigandNetwork +` like :meth:`to_rbfe_alchemical_network() +`. +""" from .relative_alchemical_network_planner import ( RHFEAlchemicalNetworkPlanner, diff --git a/openfe/setup/atom_mapping/__init__.py b/openfe/setup/atom_mapping/__init__.py index 868df73d5..262c5dc58 100644 --- a/openfe/setup/atom_mapping/__init__.py +++ b/openfe/setup/atom_mapping/__init__.py @@ -26,3 +26,12 @@ from . import perses_scorers from . import lomap_scorers + +__all__ = [ + "LigandAtomMapping", + "LigandAtomMapper", + "LomapAtomMapper", + "PersesAtomMapper", + "perses_scorers", + "lomap_scorers", +] diff --git a/openfe/setup/atom_mapping/lomap_scorers.py b/openfe/setup/atom_mapping/lomap_scorers.py index 30f216802..d8dca0122 100644 --- a/openfe/setup/atom_mapping/lomap_scorers.py +++ b/openfe/setup/atom_mapping/lomap_scorers.py @@ -1,5 +1,9 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Functions from LOMAP for scoring atom mappings. +""" + from collections import defaultdict from lomap import dbmol as _dbmol from lomap import mcs as lomap_mcs diff --git a/openfe/setup/atom_mapping/perses_scorers.py b/openfe/setup/atom_mapping/perses_scorers.py index 341194dad..95fd11701 100644 --- a/openfe/setup/atom_mapping/perses_scorers.py +++ b/openfe/setup/atom_mapping/perses_scorers.py @@ -1,5 +1,8 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Functions from Perses for scoring atom mappings. +""" from typing import Callable diff --git a/openfe/storage/__init__.py b/openfe/storage/__init__.py index e69de29bb..75a40cbe4 100644 --- a/openfe/storage/__init__.py +++ b/openfe/storage/__init__.py @@ -0,0 +1,3 @@ +""" +Storage of results, data, and artifacts from simulations. +""" \ No newline at end of file diff --git a/openfe/utils/__init__.py b/openfe/utils/__init__.py index 0d276a97e..07f97e901 100644 --- a/openfe/utils/__init__.py +++ b/openfe/utils/__init__.py @@ -1,7 +1,22 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe +""" +Utilities and tools for OpenFE. + +Of particular note is the :class:`.GufeTokenizable` class, which enforces +immutability and provides serialization tools for most OpenFE data types. +""" from . import custom_typing from .optional_imports import requires_package from .remove_oechem import without_oechem_backend from .system_probe import log_system_probe +from gufe.tokenization import GufeTokenizable + +__all__ = [ + "GufeTokenizable", + "custom_typing", + "requires_package", + "without_oechem_backend", + "log_system_probe", +] From 159ddba8da00f4542ed456b339e580412034cfce Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Mon, 9 Oct 2023 17:20:53 +1100 Subject: [PATCH 8/9] Fix last RTD warning? --- docs/reference/api/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/api/index.rst b/docs/reference/api/index.rst index 386a9d96c..3c2bda8cc 100644 --- a/docs/reference/api/index.rst +++ b/docs/reference/api/index.rst @@ -8,6 +8,7 @@ OpenFE API Reference .. automodule:: openfe :no-members: + :noindex: .. rubric:: Modules From 2a8723761dcfb846187babbe213ddec8ef7a3f2f Mon Sep 17 00:00:00 2001 From: Josh Mitchell Date: Wed, 11 Oct 2023 11:49:30 +1100 Subject: [PATCH 9/9] Pep8 --- openfe/storage/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfe/storage/__init__.py b/openfe/storage/__init__.py index 75a40cbe4..ece33ae8e 100644 --- a/openfe/storage/__init__.py +++ b/openfe/storage/__init__.py @@ -1,3 +1,3 @@ """ Storage of results, data, and artifacts from simulations. -""" \ No newline at end of file +"""