diff --git a/.gitignore b/.gitignore index 39774d582..7c5d2c4ca 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ instance/ # Sphinx documentation docs/_build/ +docs/reference/api/generated # PyBuilder .pybuilder/ diff --git a/docs/_ext/sass.py b/docs/_ext/sass.py new file mode 100644 index 000000000..43888aa06 --- /dev/null +++ b/docs/_ext/sass.py @@ -0,0 +1,88 @@ +""" +sphinxcontrib-sass +https://github.com/attakei-lab/sphinxcontrib-sass +Kayuza Takei +Apache 2.0 + +Modified to: +- Write directly to Sphinx output directory +- Infer targets if not given +- Ensure ``target: Path`` in ``configure_path()`` +- Return version number and thread safety from ``setup()`` +- Use compressed style by default +- More complete type checking +""" + +from os import PathLike +from pathlib import Path +from typing import Optional, Union + + +import sass +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment +from sphinx.util import logging + + +logger = logging.getLogger(__name__) + + +def configure_path(conf_dir: str, src: Optional[Union[PathLike, Path]]) -> Path: + if src is None: + target = Path(conf_dir) + else: + target = Path(src) + if not target.is_absolute(): + target = Path(conf_dir) / target + return target + + +def get_targets(app: Sphinx) -> dict[Path, Path]: + src_dir = configure_path(app.confdir, app.config.sass_src_dir) + dst_dir = configure_path(app.outdir, app.config.sass_out_dir) + + if isinstance(app.config.sass_targets, dict): + targets = app.config.sass_targets + else: + targets = { + path: path.relative_to(src_dir).with_suffix(".css") + for path in src_dir.glob("**/[!_]*.s[ca]ss") + } + + return {src_dir / src: dst_dir / dst for src, dst in targets.items()} + + +def build_sass_sources(app: Sphinx, env: BuildEnvironment): + logger.debug("Building stylesheet files") + include_paths = [str(p) for p in app.config.sass_include_paths] + targets = get_targets(app) + output_style = app.config.sass_output_style + # Build css files + for src, dst in targets.items(): + content = src.read_text() + css = sass.compile( + string=content, + output_style=output_style, + include_paths=[str(src.parent)] + include_paths, + ) + dst.parent.mkdir(exist_ok=True, parents=True) + dst.write_text(css) + + +def setup(app: Sphinx): + """ + Setup function for this extension. + """ + logger.debug(f"Using {__name__}") + app.add_config_value("sass_include_paths", [], "html") + app.add_config_value("sass_src_dir", None, "html") + app.add_config_value("sass_out_dir", None, "html") + app.add_config_value("sass_targets", None, "html") + app.add_config_value("sass_output_style", "compressed", "html") + app.connect("env-updated", build_sass_sources) + + return { + "version": "0.3.4ofe", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/docs/_sass/custom-api.scss b/docs/_sass/custom-api.scss new file mode 100644 index 000000000..461e36e84 --- /dev/null +++ b/docs/_sass/custom-api.scss @@ -0,0 +1,384 @@ +// The Numpydoc API layout + +html { + --ofe-api-name-color: var(--ofe-color-FeelingSpicy); + --ofe-api-property-color: var(--pst-color-text-muted); + --ofe-api-path-color: var(--pst-color-text-base); + --ofe-api-bg-color: var(--pst-color-on-background); + --ofe-api-param-symbol-color: var(--pst-color-text-base); + --ofe-api-param-name-color: var(--pst-color-text-base); + --ofe-api-param-value-color: var(--pst-color-text-base); + --ofe-api-type-color: var(--pst-color-text-base); + --ofe-api-type-link-color: var(--pst-color-link); + --ofe-api-source-link-color: var(--pst-color-link); + + --ofe-api-header-font-size: 1.1rem; + --ofe-api-header-padding: var(--ofe-api-header-font-size); + --ofe-api-arguments-indent: calc(2 * var(--ofe-api-header-padding)); +} + +// Definition of an object. Hopefully. +// Could also use dl.py, but this would fail +// if we ever wanted to document something that +// isn't Python +// RTD does it like this, but with fewer exceptions, so +// we should be OK +dl:not(.docutils):not(.field-list):not(.simple):not(.citation):not(.option-list):not(.footnote)[class] { + padding-bottom: 0.5em; + border: 1px solid var(--pst-color-border); + border-radius: .25rem; + + // Text specifying class, function, method, pydantic model, etc. + // Usually present in the .property class, but if it's missing + // we can insert it + > dt { + > *:not(.property):first-child::before, > .property { + color: var(--ofe-api-property-color); + font-size: inherit; + font-weight: normal; + font-style: italic; + } + } + &.attribute > dt > *:not(.property):first-child::before { + content: "attribute "; + } + &.method > dt > *:not(.property):first-child::before { + content: "method "; + } + &.function > dt > *:not(.property):first-child::before { + content: "function "; + } + + + // Header and signature + > dt { + font-family: var(--pst-font-family-monospace); + font-size: var(--ofe-api-header-font-size); + padding: var(--ofe-api-header-padding); + background-color: var(--ofe-api-bg-color); + border-radius: .25rem 0; + // Allow words to break anywhere, if necessary + overflow-wrap: break-word; + // Position relative so we can absolutely position source link + position: relative; + &:target { + &::before { + background-color: var(--pst-color-background); + } + } + + // Indent the argument list + padding-left: calc(var(--ofe-api-header-padding) + var(--ofe-api-arguments-indent)); + > :first-child { + margin-left: calc(-1 * var(--ofe-api-arguments-indent)); + } + + // Text providing path to the object + > .sig-prename { + padding: 0; + background-color: transparent; + font-weight: 200; + font-size: inherit; + color: var(--ofe-api-path-color); + display: inline-block; + } + // Text providing the name of the object + > .sig-name { + padding: 0; + background-color: transparent; + color: var(--ofe-api-name-color); + font-weight: 600; + font-size: inherit; + // autodoc_pydantic produces types as properties _after_ the sig name + ~ .property .pre { + color: var(--ofe-api-type-color); + font-style: normal; + } + ~ .property a .pre { + color: var(--ofe-api-type-link-color); + } + + // If the source link immediately follows the name, don't position it absolutely + + a.reference.internal .viewcode-link { + position: static !important; + float: right; + margin-left: 0.5em; + } + } + // Opening and closing parenthesis + > .sig-paren { + font-size: inherit; + + } + // Each parameter + > .sig-param { + font-size: inherit; + font-style: normal; + // Entire parameter if parsing the parameter has failed. Splits on commas + > .pre { + color: var(--ofe-api-param-name-color); + } + // Name of a parameter + > .n > .pre { + color: var(--ofe-api-param-name-color); + } + // Symbols; equals sign, asterisk, etc + > .o > .pre { + color: var(--ofe-api-param-symbol-color); + padding-left: 0.2em; + padding-right: 0.2em; + } + // Type anotation + .p, .p + .n, .p + .w + .n { + font-weight: normal; + .pre { + color: var(--ofe-api-type-color); + } + a .pre { + color: var(--ofe-api-type-link-color); + } + } + // Default values of arguments + > .default_value > .pre { + color: var(--ofe-api-param-value-color); + } + // After each parameter, newline + &::before { + content: "\a"; + white-space: pre; + } + // Links + a { + &:hover { + .pre, pre, code { + color: var(--pst-color-link-hover); + } + } + } + } + // Brackets [] denoting optional arguments + // This is redundant information and I am displeased to have to support it + > .optional { + // Put optional [] brackets on their own lines + &::before { + content: "\a"; + white-space: pre; + } + // Optional parameters need extra indentation + ~ .sig-param::before { + content: "\a "; + } + } + // Closing parenthesis + .sig-param, .optional { + + .sig-paren { + &::before { + content: "\a"; + white-space: pre; + } + + // Unindent closing paren, and everything following (except source link) + position: relative; + left: calc(-1 * var(--ofe-api-arguments-indent)); + ~*:not(a.reference.internal, .headerlink) { + position: relative; + left: calc(-1 * var(--ofe-api-arguments-indent)); + max-width: calc(100% + #{var(--ofe-api-arguments-indent)} - 4em); + display: inline-block; + vertical-align: top; + } + ~ .headerlink { + position: absolute; + bottom: var(--ofe-api-header-padding); + right: var(--ofe-api-header-padding); + } + } + } + // Pydantic validator arrow + .autodoc_pydantic_validator_arrow { + &::before { + content: "\a"; + white-space: pre; + } + // Comma separating validated fields + ~ .property { + &::after { + content: "\a "; + white-space: pre; + } + } + ~ .headerlink { + position: absolute; + bottom: var(--ofe-api-header-padding); + right: var(--ofe-api-header-padding); + } + } + // Link to the source code for the object (not present on inherited objects) + .viewcode-link { + position: absolute; + top: var(--ofe-api-header-padding); + right: var(--ofe-api-header-padding); + color: var(--ofe-api-source-link-color); + &:hover { + color: var(--pst-color-link-hover); + } + } + // Permalink to the object (to here) + > a.headerlink { + font-size: 1em; + opacity: 1; + transform: translate(0); + } + } + // Content + >dd { + margin: 1em; + &:empty { + padding-bottom: 0 !important; + } + // Description/docstring + >p { + + } + // JSON schema for pydantic stuff + >.autodoc_pydantic_collapsable_json { + } + // Parameters, Returns, Other Parameters, Raises sections + >.field-list { + // Headings + >dt { + @extend .rubric; + } + // Content + >dd { + >ul.simple { + margin-left: 0; + } + >ul.simple:first-child>li { + list-style: none; + margin-left: 0; + } + >dl>dt, >ul.simple:first-child>li>p:first-child, >p:first-child { + // Name of the parameter or return value + >strong { + font-family: var(--pst-font-family-monospace); + color: var(--ofe-api-param-name-color); + } + // Type of the parameter, or type of a named return value + >.classifier { + font-family: var(--pst-font-family-monospace); + color: var(--ofe-api-type-color); + overflow-wrap: break-word; + } + >a.reference>em { + font-family: var(--pst-font-family-monospace); + } + } + >dl>dt>strong::after { + content: ": "; + } + // Description of the parameter, return value, or exception + >dl>dd, >ul.simple:first-child>li>p:not(:first-child) { + margin-top: 0; + margin-bottom: 0.5em; + } + } + } + // Notes, References, Methods, Attributes, and Examples headings + >.rubric { + + } + // Reference list (bibliography) + >dl.citation { + + } + // Doctests - already nicely formatted! + >.doctest { + + } + // Tables of methods, attributes, classes, etc. + // Should probably style this globally so it captures the same tables in autosummary directives + >.longtable.docutils { + // A row of the table + tr { + //An odd row + *.row-odd { + + } + //An even row + *.row-even { + + } + // An entry on the LHS of the table - link to another object + possibly a signature + // Signature is a direct child of this element + td:first-child { + // May need to style everything in td:first-child, then re-overwrite things here + a.reference code { + + } + } + // An entry on the RHS of the table - description + td:last-child { + + } + + } + + } + // Child object - recapitulates structure above + >dl:not(.docutils):not(.field-list):not(.simple):not(.citation):not(.option-list):not(.footnote)[class] { + padding-bottom: 0; + box-shadow: 0 4px 5px 0 rgba(black, .14), + 0 1px 10px 0 rgba(black, .12), + 0 2px 4px -1px rgba(black, .40); + border-radius: .25rem; + border: none; + // Inner object body + > dd { + margin-right: 1.5em; + margin-left: 1.5em; + padding-bottom: 0.75em; + } + } + } + + // Don't justify/hyphenate in API + // Undoes styling found by searching "@if hyphenate" in sphinx-api.scss + p { + hyphens: none; + text-align: unset; + } +} + +// Pydantic fields have their own stuff going on +// We still want types to be the right colour +// This works as long as the type annotation is defined, +// but can cause the field's name to be recoloured if eg no +// type is defined and the field has an alias +.pydantic_field .sig { + > .sig-name + .property:not(:last-of-type) { + a { + font-weight: bold; + } + .pre { + color: var(--ofe-api-type-color); + } + } +} + +details.autodoc_pydantic_collapsable_json > summary { + max-width: 42.5rem; + margin-left: auto; + margin-right: auto; +} + +// Break headings wherever, if necessary +h1, h2, h3, h4, h5, h6 { + overflow-wrap: break-word; +} + +// Docs button in source on right +.viewcode-back { + float: right; + color: var(--ofe-api-source-link-color); +} diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css index dfc8c3278..8d6e2cf0b 100644 --- a/docs/_static/css/custom.css +++ b/docs/_static/css/custom.css @@ -14,13 +14,7 @@ html{ --ofe-color-BeastlyLightGrey: #464545; } - -/* -NavBar -*/ -code{ - color: var(--ofe-color-FeelingSick); -} +/* NavBar */ .bd-page-width { max-width: None; } @@ -157,7 +151,7 @@ html[data-theme=light] { --pst-color-text-muted: var(--ofe-color-BadassBlue); --pst-color-shadow: #d8d8d8; --pst-color-border: #c9c9c9; - --pst-color-inline-code: var(--ofe-color-FeelingSpicy); + --pst-color-inline-code: var(--ofe-color-FeelingSick); --pst-color-target: var(--ofe-color-GoldenYellow); --pst-color-background: var(--ofe-color-SergiosBrigtherCousin); --pst-color-on-background: #fff; @@ -244,7 +238,7 @@ html[data-theme=dark] { --pst-color-text-muted: var(--ofe-color-SandySergio); --pst-color-shadow: #212121; --pst-color-border: silver; - --pst-color-inline-code: var(--ofe-color-FeelingSpicy); + --pst-color-inline-code: var(--ofe-color-SergiosCousin); --pst-color-target: var(--ofe-color-DarkGoldenYellow); --pst-color-background: var(--ofe-color-BeastlyLightGrey); --pst-color-on-background: #1e1e1e; diff --git a/docs/_templates/autosummary/base.rst b/docs/_templates/autosummary/base.rst new file mode 100644 index 000000000..cdb86a616 --- /dev/null +++ b/docs/_templates/autosummary/base.rst @@ -0,0 +1,5 @@ +.. title:: {{ objname }} + +.. currentmodule:: {{ module }} + +.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/_templates/autosummary/class.rst b/docs/_templates/autosummary/class.rst new file mode 100644 index 000000000..cdb86a616 --- /dev/null +++ b/docs/_templates/autosummary/class.rst @@ -0,0 +1,5 @@ +.. title:: {{ objname }} + +.. currentmodule:: {{ module }} + +.. auto{{ objtype }}:: {{ objname }} diff --git a/docs/conf.py b/docs/conf.py index 98d6d5c9e..6bd299063 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,54 +14,79 @@ import sys from importlib.metadata import version from packaging.version import parse + + sys.path.insert(0, os.path.abspath('../')) -os.environ['SPHINX'] = 'True' +os.environ["SPHINX"] = "True" # -- Project information ----------------------------------------------------- -project = 'OpenFE' -copyright = '2022, The OpenFE Development Team' -author = 'The OpenFE Development Team' +project = "OpenFE" +copyright = "2022, The OpenFE Development Team" +author = "The OpenFE Development Team" version = parse(version("openfe")).base_version + + # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon', - 'sphinx_click.ext', - 'sphinxcontrib.autodoc_pydantic', - 'sphinx_toolbox.collapse', - 'sphinx.ext.autosectionlabel', - 'sphinx_design', + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", + "sphinx_click.ext", + "sphinxcontrib.autodoc_pydantic", + "sphinx_toolbox.collapse", + "sphinx.ext.autosectionlabel", + "sphinx_design", + "sphinx.ext.intersphinx", + "sphinx.ext.autosummary", + "docs._ext.sass", ] -autoclass_content = 'both' +intersphinx_mapping = { + "python": ("https://docs.python.org/3.9", None), + "numpy": ("https://numpy.org/doc/stable", None), + "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), + "scikit.learn": ("https://scikit-learn.org/stable", None), + "openmm": ("http://docs.openmm.org/latest/api-python/", None), + "rdkit": ("https://www.rdkit.org/docs", None), + "openeye": ("https://docs.eyesopen.com/toolkits/python/", None), + "mdtraj": ("https://www.mdtraj.org/1.9.5/", None), + "openff.units": ("https://docs.openforcefield.org/units/en/stable", None), + "gufe": ("https://gufe.readthedocs.io/en/latest/", None), +} + +autoclass_content = "both" # Make sure labels are unique # https://www.sphinx-doc.org/en/master/usage/extensions/autosectionlabel.html#confval-autosectionlabel_prefix_document autosectionlabel_prefix_document = True autodoc_pydantic_model_show_json = False +autodoc_default_options = { + "members": True, + "member-order": "bysource", +} +toc_object_entries_show_parents = "hide" + # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -autodoc_mock_imports = ['openff.models', - 'rdkit', - 'matplotlib', - 'lomap', - 'openmmtools', - 'mdtraj', - 'openmmforcefields', +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "_ext", "_sass"] + +autodoc_mock_imports = [ + "matplotlib", + "lomap", + "openmmtools", + "mdtraj", + "openmmforcefields", ] @@ -70,11 +95,9 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'pydata_sphinx_theme' +html_theme = "pydata_sphinx_theme" html_theme_options = { - "logo": { - "text": "OpenFE Documentation" - }, + "logo": {"text": "OpenFE Documentation"}, "icon_links": [ { "name": "Github", @@ -82,14 +105,14 @@ "icon": "fa-brands fa-square-github", "type": "fontawesome", } - ] + ], } html_logo = "_static/Squaredcircle.svg" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] +# html_static_path = ['_static'] # replace macros @@ -100,7 +123,12 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] html_css_files = [ - 'css/custom.css', + "css/custom.css", + "css/custom-api.css", ] + +# custom-api.css is compiled from custom-api.scss +sass_src_dir = "_sass" +sass_out_dir = "_static/css" diff --git a/docs/cookbook/loading_molecules.rst b/docs/cookbook/loading_molecules.rst index cb2197cc0..a22a6d1ae 100644 --- a/docs/cookbook/loading_molecules.rst +++ b/docs/cookbook/loading_molecules.rst @@ -27,7 +27,7 @@ and then how these are assembled to form ``ChemicalSystem`` objects. Loading small molecules ----------------------- -Small molecules, such as ligands, are handled using the {py:class}`openfe.SmallMoleculeComponent` class. +Small molecules, such as ligands, are handled using the :py:class:`openfe.SmallMoleculeComponent` class. These are lightweight wrappers around RDKit Molecules and can be created directly from an RDKit molecule: diff --git a/docs/environment.yaml b/docs/environment.yaml index dd6600c95..d389da20b 100644 --- a/docs/environment.yaml +++ b/docs/environment.yaml @@ -15,6 +15,7 @@ dependencies: - sphinx - sphinx-click - tqdm +- libsass - pip: - sphinx-design - sphinx-toolbox diff --git a/docs/guide/introduction.rst b/docs/guide/introduction.rst index 0434ecf21..ba8a0a19a 100644 --- a/docs/guide/introduction.rst +++ b/docs/guide/introduction.rst @@ -14,7 +14,7 @@ Workflow overview The overall workflow of OpenFE involves three stages: 1. **Setup**: Defining the simulation campaign you are going to run. -2. **Executation**: Running and performing initial analysis of your +2. **Execution**: Running and performing initial analysis of your simulation campaign. 3. **Gather results**: Assembling the results from the simulation campaign for further analysis. @@ -34,7 +34,7 @@ The output of **setup** is an :class:`.AlchemicalNetwork`. This contains all the information about what is being simulated (e.g., what ligands, host proteins, solvation details etc) and the information about how to perform the simulation (the Protocol). -The output of the **executation** stage is the basic results from each edge. +The output of the **execution** stage is the basic results from each edge. This can depend of the specific analysis intended, but will either involve a :class:`.ProtocolResult` representing the calculated :math:`\Delta G` for each edge or the :class:`.ProtocolDAGResult` linked to the data needed to diff --git a/docs/installation.rst b/docs/installation.rst index 359510307..970424c68 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -123,8 +123,7 @@ To make sure everything is working, run the tests :: $ openfe test --long -The test suite contains several hundred individual tests. This will take a -few minutes, and all tests should complete with status either passed, +The test suite contains several hundred individual tests. This may take up to an hour, and all tests should complete with status either passed, skipped, or xfailed (expected fail). The very first time you run this, the initial check that you can import ``openfe`` will take a while, because some code is compiled the first time it is encountered. That compilation only diff --git a/docs/reference/api/alchemical_data_objects.rst b/docs/reference/api/alchemical_data_objects.rst index bc01adce1..1cc641b2f 100644 --- a/docs/reference/api/alchemical_data_objects.rst +++ b/docs/reference/api/alchemical_data_objects.rst @@ -5,32 +5,48 @@ Alchemical Data Objects Chemical Systems ~~~~~~~~~~~~~~~~ -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 them together. +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. -.. autoclass:: openfe.SmallMoleculeComponent +.. module:: openfe + :noindex: -.. autoclass:: openfe.ProteinComponent +.. autosummary:: + :nosignatures: + :toctree: generated/ -.. autoclass:: openfe.SolventComponent - -.. autoclass:: openfe.ChemicalSystem + SmallMoleculeComponent + ProteinComponent + SolventComponent + ChemicalSystem Atom Mappings ~~~~~~~~~~~~~ -.. autoclass:: openfe.LigandAtomMapper - :members: +Tools for mapping atoms in one molecule to those in another. Used to generate efficient ligand networks. + +.. module:: openfe + :noindex: + +.. autosummary:: + :nosignatures: + :toctree: generated/ -.. autoclass:: openfe.LigandAtomMapping - :members: + LigandAtomMapper + LigandAtomMapping Alchemical Simulations ~~~~~~~~~~~~~~~~~~~~~~ -.. autoclass:: openfe.Transformation +Descriptions of anticipated alchemical simulation campaigns. + +.. module:: openfe + :noindex: + +.. autosummary:: + :nosignatures: + :toctree: generated/ -.. autoclass:: openfe.AlchemicalNetwork + Transformation + AlchemicalNetwork diff --git a/docs/reference/api/alchemical_network_planning.rst b/docs/reference/api/alchemical_network_planning.rst index ae22e662b..a1167be4c 100644 --- a/docs/reference/api/alchemical_network_planning.rst +++ b/docs/reference/api/alchemical_network_planning.rst @@ -10,11 +10,24 @@ classes along the way. Alchemical Network Planners --------------------------- -.. autoclass:: openfe.setup.RBFEAlchemicalNetworkPlanner -.. autoclass:: openfe.setup.RHFEAlchemicalNetworkPlanner +.. module:: openfe.setup + :noindex: + +.. autosummary:: + :nosignatures: + :toctree: generated/ + + RBFEAlchemicalNetworkPlanner + RHFEAlchemicalNetworkPlanner Chemical System Generators -------------------------- -.. autoclass:: openfe.setup.chemicalsystem_generator.EasyChemicalSystemGenerator +.. module:: openfe.setup.chemicalsystem_generator + +.. autosummary:: + :nosignatures: + :toctree: generated/ + + EasyChemicalSystemGenerator diff --git a/docs/reference/api/defining_and_executing_simulations.rst b/docs/reference/api/defining_and_executing_simulations.rst index 52b371dee..efa15ff16 100644 --- a/docs/reference/api/defining_and_executing_simulations.rst +++ b/docs/reference/api/defining_and_executing_simulations.rst @@ -4,33 +4,42 @@ Defining and Executing Simulations Executing Simulations --------------------- -.. autofunction:: openfe.execute_DAG +.. module:: openfe + :noindex: + +.. autosummary:: + :nosignatures: + :toctree: generated/ + + execute_DAG General classes --------------- -.. autoclass:: openfe.ProtocolDAG - :members: - -.. autoclass:: openfe.ProtocolUnitResult - :members: +.. module:: openfe + :noindex: -.. autoclass:: openfe.ProtocolUnitFailure - :members: +.. autosummary:: + :nosignatures: + :toctree: generated/ -.. autoclass:: openfe.ProtocolDAGResult - :members: + ProtocolDAG + ProtocolUnitResult + ProtocolUnitFailure + ProtocolDAGResult Specialised classes ------------------- These classes are abstract classes that are specialised (subclassed) for an individual Protocol. -.. autoclass:: openfe.Protocol - :members: +.. module:: openfe + :noindex: -.. autoclass:: openfe.ProtocolUnit - :members: +.. autosummary:: + :nosignatures: + :toctree: generated/ -.. autoclass:: openfe.ProtocolResult - :members: + Protocol + ProtocolUnit + ProtocolResult diff --git a/docs/reference/api/index.rst b/docs/reference/api/index.rst index 0374db428..ff12b7a2b 100644 --- a/docs/reference/api/index.rst +++ b/docs/reference/api/index.rst @@ -4,6 +4,7 @@ OpenFE API Reference ==================== .. toctree:: + :maxdepth: 2 alchemical_data_objects ligand_network diff --git a/docs/reference/api/ligand_network.rst b/docs/reference/api/ligand_network.rst index b8b565241..58089db77 100644 --- a/docs/reference/api/ligand_network.rst +++ b/docs/reference/api/ligand_network.rst @@ -5,10 +5,15 @@ Ligand Network Tools Atom Mappers ------------ -.. autoclass:: openfe.setup.LomapAtomMapper - :members: +.. module:: openfe.setup + :noindex: -.. autoclass:: openfe.setup.PersesAtomMapper +.. autosummary:: + :nosignatures: + :toctree: generated/ + + LomapAtomMapper + PersesAtomMapper Scorers @@ -21,17 +26,23 @@ LOMAP Scorers trying ``import openfe.setup.lomap_scorers``, which doesn't work (whereas ``from openfe.setup import lomap_scorers`` does) -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.default_lomap_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.ecr_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.mcsr_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.mncar_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.tmcsr_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.atomic_number_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.hybridization_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.sulfonamides_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.heterocycles_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.transmuting_methyl_into_ring_score -.. autofunction:: openfe.setup.atom_mapping.lomap_scorers.transmuting_ring_sizes_score +.. module:: openfe.setup.atom_mapping.lomap_scorers + +.. autosummary:: + :nosignatures: + :toctree: generated/ + + default_lomap_score + ecr_score + mcsr_score + mncar_score + tmcsr_score + atomic_number_score + hybridization_score + sulfonamides_score + heterocycles_score + transmuting_methyl_into_ring_score + transmuting_ring_sizes_score @@ -39,13 +50,23 @@ LOMAP Scorers PersesScorers ~~~~~~~~~~~~~ -.. autofunction:: openfe.setup.atom_mapping.perses_scorers.default_perses_scorer +.. module:: openfe.setup.atom_mapping.perses_scorers + +.. autosummary:: + :nosignatures: + :toctree: generated/ + + default_perses_scorer Network Planners ---------------- -.. autofunction:: openfe.setup.ligand_network_planning.generate_radial_network +.. module:: openfe.setup.ligand_network_planning -.. autofunction:: openfe.setup.ligand_network_planning.generate_maximal_network +.. autosummary:: + :nosignatures: + :toctree: generated/ -.. autofunction:: openfe.setup.ligand_network_planning.generate_minimal_spanning_network + generate_radial_network + generate_maximal_network + generate_minimal_spanning_network diff --git a/docs/reference/api/openmm_rfe.rst b/docs/reference/api/openmm_rfe.rst index 15c587bd2..20e34a902 100644 --- a/docs/reference/api/openmm_rfe.rst +++ b/docs/reference/api/openmm_rfe.rst @@ -4,103 +4,140 @@ OpenMM Relative Free Energy Protocol This section provides details about the OpenMM Relative Free Energy Protocol implemented in OpenFE. +.. module:: openfe.protocols.openmm_rfe Protocol Settings ----------------- -Below are the settings which can be tweaked in the protocol. The default settings -(accessed using :class:`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. +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_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.RelativeHybridTopologyProtocolSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: False +.. 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.AlchemicalSamplerSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.AlchemicalSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.OpenMMEngineSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.IntegratorSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.SimulationSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.SolvationSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.SystemSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.ThermoSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 - -.. autopydantic_settings:: openfe.protocols.openmm_rfe.equil_rfe_settings.OpenMMSystemGeneratorFFSettings - :settings-show-json: False - :settings-show-config-member: False - :settings-show-config-summary: False - :settings-show-validator-members: False - :settings-show-validator-summary: 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 Protocol API specification -------------------------- +.. module:: openfe.protocols.openmm_rfe + :noindex: + +.. autoclass:: RelativeHybridTopologyProtocol + :no-members: + + .. automethod:: default_settings + + .. automethod:: create -.. autoclass:: openfe.protocols.openmm_rfe.RelativeHybridTopologyProtocol - :members: + .. automethod:: gather +.. autoclass:: RelativeHybridTopologyProtocolResult diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 1e076175e..8853d761f 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -5,6 +5,7 @@ This contains details of the Python API as well as a reference to the command line interface. .. toctree:: + :maxdepth: 2 api/index cli/index diff --git a/openfe/protocols/openmm_rfe/equil_rfe_settings.py b/openfe/protocols/openmm_rfe/equil_rfe_settings.py index 634626ca1..b349b610b 100644 --- a/openfe/protocols/openmm_rfe/equil_rfe_settings.py +++ b/openfe/protocols/openmm_rfe/equil_rfe_settings.py @@ -8,110 +8,17 @@ """ from __future__ import annotations -import abc -from typing import Optional, Union -from pydantic import Extra, validator, BaseModel, PositiveFloat, Field +from typing import Optional +from pydantic import validator from openff.units import unit import os - -if os.environ.get('SPHINX', False): #pragma: no cover - class SettingsBaseModel(BaseModel): - class Config: - extra = Extra.forbid - validate_assignment = True - arbitrary_types_allowed = True - smart_union = True - - - class ThermoSettings(SettingsBaseModel): - """Settings for thermodynamic parameters. - - .. note:: - No checking is done to ensure a valid thermodynamic ensemble is - possible. - """ - - temperature = 298.15 * unit.kelvin - """Simulation temperature, default units kelvin""" - - pressure = 1.0 * unit.bar - """Simulation pressure, default units standard atmosphere (atm)""" - - ph: Union[PositiveFloat, None] = Field(None, description="Simulation pH") - redox_potential: Optional[float] = Field( - None, description="Simulation redox potential" - ) - - - class BaseForceFieldSettings(SettingsBaseModel, abc.ABC): - """Base class for ForceFieldSettings objects""" - ... - - - class OpenMMSystemGeneratorFFSettings(SettingsBaseModel): - """Parameters to set up the force field with OpenMM ForceFields - - .. note:: - Right now we just basically just grab what we need for the - :class:`openmmforcefields.system_generators.SystemGenerator` - signature. See the `OpenMMForceField SystemGenerator documentation`_ - for more details. - - - .. _`OpenMMForceField SystemGenerator documentation`: - https://github.com/openmm/openmmforcefields#automating-force-field-management-with-systemgenerator - """ - constraints: Optional[str] = 'hbonds' - """Constraints to be applied to system. - One of 'hbonds', 'allbonds', 'hangles' or None, default 'hbonds'""" - - rigid_water: bool = True - remove_com: bool = False - hydrogen_mass: float = 3.0 - """Mass to be repartitioned to hydrogens from neighbouring - heavy atoms (in amu), default 3.0""" - - forcefields: list[str] = [ - "amber/ff14SB.xml", # ff14SB protein force field - "amber/tip3p_standard.xml", # TIP3P and recommended monovalent ion parameters - "amber/tip3p_HFE_multivalent.xml", # for divalent ions - "amber/phosaa10.xml", # Handles THE TPO - ] - """List of force field paths for all components except :class:`SmallMoleculeComponent` """ - - small_molecule_forcefield: str = "openff-2.0.0" # other default ideas 'openff-2.0.0', 'gaff-2.11', 'espaloma-0.2.0' - """Name of the force field to be used for :class:`SmallMoleculeComponent` """ - - @validator('constraints') - def constraint_check(cls, v): - allowed = {'hbonds', 'hangles', 'allbonds'} - - if not (v is None or v.lower() in allowed): - raise ValueError(f"Bad constraints value, use one of {allowed}") - - return v - - - class Settings(SettingsBaseModel): - """ - Container for all settings needed by a protocol - - This represents the minimal surface that all settings objects will have. - - Protocols can subclass this to extend this to cater for their additional settings. - """ - forcefield_settings: BaseForceFieldSettings - thermo_settings: ThermoSettings - - @classmethod - def get_defaults(cls): - return cls( - forcefield_settings=OpenMMSystemGeneratorFFSettings(), - thermo_settings=ThermoSettings(temperature=300 * unit.kelvin), - ) -else: - from gufe.settings import Settings, SettingsBaseModel # type: ignore +from gufe.settings import ( + Settings, + SettingsBaseModel, + OpenMMSystemGeneratorFFSettings, + ThermoSettings, +) class SystemSettings(SettingsBaseModel): @@ -519,19 +426,39 @@ class RelativeHybridTopologyProtocolSettings(Settings): class Config: arbitrary_types_allowed = True + # Inherited things + + forcefield_settings: OpenMMSystemGeneratorFFSettings + """Parameters to set up the force field with OpenMM Force Fields.""" + thermo_settings: ThermoSettings + """Settings for thermodynamic parameters.""" + # Things for creating the systems system_settings: SystemSettings + """Simulation system settings including the long-range non-bonded method.""" solvation_settings: SolvationSettings + """Settings for solvating the system.""" # Alchemical settings alchemical_settings: AlchemicalSettings + """ + Alchemical protocol settings including lambda windows and soft core scaling. + """ alchemical_sampler_settings: AlchemicalSamplerSettings + """ + Settings for sampling alchemical space, including the number of repeats. + """ # MD Engine things engine_settings: OpenMMEngineSettings + """Settings specific to the OpenMM engine such as the compute platform.""" # Sampling State defining things integrator_settings: IntegratorSettings + """Settings for the integrator such as timestep and barostat settings.""" # Simulation run settings simulation_settings: SimulationSettings + """ + Simulation control settings, including simulation lengths and record-keeping. + """