diff --git a/docs/_sass/deflist-flowchart.scss b/docs/_sass/deflist-flowchart.scss new file mode 100644 index 000000000..4c5dadce6 --- /dev/null +++ b/docs/_sass/deflist-flowchart.scss @@ -0,0 +1,388 @@ +:root { + --arrow-thickness: 4px; + --arrow-head-size: 7px; + --arrow-length: 2em; + --arrow-multiple-gap: 20px; + --arrow-color: var(--pst-color-text-muted); + --flowchart-def-bg-color: var(--pst-color-surface); + --flowchart-bg-color: var(--pst-color-background); + --flowchart-def-border-color: var(--pst-color-border); + --flowchart-unit-width: 45px; + --flowchart-spacing: 0.5rem; + --flowchart-column-gap: calc(1.5 * var(--flowchart-spacing)); + --flowchart-top-label-space: 26px; +} +.arrow.thick { + --arrow-thickness: 6px; + --arrow-head-size: 10px; +} + +.deflist-flowchart ul, +ul.deflist-flowchart { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + grid-column-gap: var(--flowchart-column-gap); + margin: 0; + padding: 0; +} + +.deflist-flowchart { + margin: 1em 0; + + p:first-child { + margin-top: 0; + } + + p:last-child { + margin-bottom: 0; + } + + li, + li ul + { + margin: 0; + padding: 0; + } + + li:empty:not([class]) + { + display: None; + } + + li { + list-style: none; + } + + .arrow-down::after, + .arrow-up::after, + .arrow-multiple.arrow-down::before, + .arrow-multiple.arrow-up::before, + .arrow-cycle::after, + .arrow-cycle::before { + content: ""; + } + + .arrow-down, + .arrow-up, + .arrow-cycle + { + --arrow-head-size-clamped: calc(min(var(--arrow-head-size), var(--arrow-length) / 2)); + + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; + min-height: var(--arrow-length); + width: 100%; + margin: calc(2 * var(--flowchart-spacing)) auto; + position: relative; + z-index: 1; + padding: calc(var(--arrow-length) / 4) 0; + + &::before, &::after { + --actual-arrow-length: max(var(--arrow-length), 100%); + --arrow-tail-gradient: + linear-gradient( + 45deg, + transparent calc(50% - var(--arrow-thickness)/2), + var(--arrow-color) calc(50% - var(--arrow-thickness)/2), + var(--arrow-color) calc(50% + var(--arrow-thickness)/2), + transparent calc(50% + var(--arrow-thickness)/2) + ); + --arrow-head-gradient: + linear-gradient( + -45deg, + var(--arrow-color) var(--arrow-head-size-clamped), + transparent var(--arrow-head-size-clamped) + ); + height: calc(var(--actual-arrow-length)/1.4142); + width: auto; + aspect-ratio: 1; + padding: 0; + display: inline-block; + transform: rotate(45deg); + background-image: + var(--arrow-tail-gradient), + var(--arrow-head-gradient); + position: absolute; + top: 0; + left: 50%; + transform-origin: 0 0; + z-index: -1; + } + + &.arrow-tail { + &::before, &::after { + background-image: + var(--arrow-tail-gradient); + } + } + + > p { + background: var(--flowchart-bg-color); + line-height: 1.5; + z-index: 10; + } + } + + .arrow-down:not(.arrow-tail), + .arrow-cycle { + padding-bottom: calc(var(--arrow-head-size-clamped) + var(--arrow-length) / 4); + } + + .arrow-up:not(.arrow-tail), + .arrow-cycle { + padding-top: calc(var(--arrow-head-size-clamped) + var(--arrow-length) / 4); + } + + .arrow-cycle, .arrow-multiple { + &::after { + translate: calc(0.5 * var(--arrow-multiple-gap)) 0; + } + &::before { + translate: calc(-0.5 * var(--arrow-multiple-gap)) 0; + } + } + + .arrow-up::after, + .arrow-multiple.arrow-up::before, + .arrow-cycle::before + { + transform: rotate(-135deg); + translate: 0 calc(var(--actual-arrow-length) + 2 * var(--flowchart-spacing) + var(--arrow-head-size-clamped) / 2); + } + + .arrow-cycle::before { + translate: + calc(-0.5 * var(--arrow-multiple-gap)) + calc(var(--actual-arrow-length) + 2 * var(--flowchart-spacing) + var(--arrow-head-size-clamped) / 2); + } + + .arrow-aside { + margin-left: calc(8 * var(--arrow-head-size-clamped)); + &::after { + left: calc(-4 * var(--arrow-head-size-clamped)); + } + } + + .arrow-multiple-combine { + &::before { + content: ""; + width: var(--arrow-multiple-gap); + border: var(--arrow-thickness) solid var(--arrow-color); + height: calc(var(--arrow-length) / 2); + background: var(--flowchart-bg-color); + transform: none; + left: auto; + z-index: 2; + } + + &.arrow-down { + padding-top: calc(0.75 * var(--arrow-length) - var(--arrow-head-size-clamped) / 2); + padding-bottom: calc(0.5 * var(--arrow-head-size-clamped) + 0.25 * var(--arrow-length)); + &::before { + border-top: 1px solid var(--flowchart-bg-color); + } + } + + &.arrow-up { + &::before { + border-bottom: 1px solid var(--flowchart-bg-color); + top: auto; + bottom: -1px; + } + } + } + + .arrow-tail { + &.arrow-down { + margin-bottom: 0; + } + &.arrow-up { + margin-top: 0; + } + } + + .arrow-head { + &.arrow-up { + margin-bottom: 0; + } + &.arrow-down { + margin-top: 0; + } + } + + .arrow-combine, .arrow-combine-left, .arrow-combine-right { + &.arrow-down.arrow-tail, &.arrow-up.arrow-head { + --arrow-combine-gradient-angle: 0deg; + padding-bottom: calc(0.5 * var(--arrow-thickness)); + margin-bottom: calc(-0.5 * var(--arrow-thickness)); + } + &.arrow-up.arrow-tail, &.arrow-down.arrow-head { + --arrow-combine-gradient-angle: 180deg; + padding-top: calc(0.5 * var(--arrow-thickness)); + margin-top: calc(-0.5 * var(--arrow-thickness)); + } + background-image: + linear-gradient( + var(--arrow-combine-gradient-angle), + var(--arrow-color) var(--arrow-thickness), + transparent var(--arrow-thickness) + ); + background-repeat: no-repeat; + + width: calc(100% + 2 * var(--flowchart-column-gap)); + margin-left: calc(-1 * var(--flowchart-column-gap)); + + &.arrow-combine-left, &.arrow-combine-right { + background-size: 50%; + width: calc(100% + var(--flowchart-column-gap)); + margin-left: calc(-0.5 * var(--flowchart-column-gap)); + + &.arrow-multiple { + background-size: calc(50% + 0.5 * var(--arrow-multiple-gap)); + } + } + + &.arrow-combine-right { + background-position-x: 100%; + } + } + + > ul > li { + &.arrow-down, + &.arrow-up, + &.arrow-cycle { + width: calc(100% - var(--flowchart-top-label-space)); + margin-left: 0; + } + } + + dl { + display: flex; + flex-direction: row-reverse; + margin: 0; + padding: 0 var(--flowchart-spacing); + } + dt { + display: inline-block; + writing-mode: vertical-rl; + margin-top: .25rem; + flex-grow: 0; + width: var(--flowchart-top-label-space); + font-size: 1.1em; + } + dd { + text-align: center; + position: relative; + border: 1px solid var(--flowchart-def-border-color); + border-radius: .25rem; + margin: 0; + display: inline-block; + flex-grow: 1; + container-type: inline-size; + container-name: flowchart; + overflow-x: auto; + } + + dd dl { + background-color: var(--flowchart-def-bg-color); + border-radius: 4px; + box-shadow: 0 6px 10px 0 rgba(0,0,0,0.14), + 0 1px 18px 0 rgba(0,0,0,0.12), + 0 3px 5px -1px rgba(0,0,0,0.4); + display: block; + margin: 0 auto; + padding: calc(var(--flowchart-spacing) / 2); + max-width: calc(100cqw - 2 * var(--flowchart-spacing)); + min-width: calc(2 * var(--flowchart-unit-width) + var(--flowchart-column-gap)); + } + dd dt { + writing-mode: horizontal-tb; + display: block; + margin-top: 0; + width: unset; + font-size: unset; + } + dd dd { + border: none; + display: block; + container-type: unset; + overflow-x: unset; + padding: calc(var(--flowchart-spacing) / 2); + } + + dd > ul { + width: fit-content; + padding: var(--flowchart-spacing); + margin: 0 auto; + } + + dd dd > ul { + min-width: unset; + padding: 0; + margin: 0; + } + + dl a, a { + font-weight: bold; + } + + div.flowchart-sidebyside > ul:only-child { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: center; + } + + .flowchart-spacer { + height: 99999%; + min-height: calc(2 * var(--flowchart-spacing)); + } + + .width-2 { + width: calc(2 * var(--flowchart-unit-width) + var(--flowchart-column-gap)); + } + .width-3 { + width: calc(3 * var(--flowchart-unit-width) + 2 * var(--flowchart-column-gap)); + } + .width-4 { + width: calc(4 * var(--flowchart-unit-width) + 3 * var(--flowchart-column-gap)); + } + .width-5 { + width: calc(5 * var(--flowchart-unit-width) + 4 * var(--flowchart-column-gap)); + } + .width-6 { + width: calc(6 * var(--flowchart-unit-width) + 5 * var(--flowchart-column-gap)); + } + .width-7 { + width: calc(7 * var(--flowchart-unit-width) + 6 * var(--flowchart-column-gap)); + } + .width-8 { + width: calc(8 * var(--flowchart-unit-width) + 7 * var(--flowchart-column-gap)); + } + .width-9 { + width: calc(9 * var(--flowchart-unit-width) + 8 * var(--flowchart-column-gap)); + } + .width-10 { + width: calc(10 * var(--flowchart-unit-width) + 9 * var(--flowchart-column-gap)); + } + li { + &.width-2, + &.width-3, + &.width-4, + &.width-5, + &.width-6, + &.width-7, + &.width-8, + &.width-9, + &.width-10, + &.width-full { + > dl { + max-width: unset; + } + } + } +} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 6bd299063..5ba9932e5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,6 +70,7 @@ autodoc_default_options = { "members": True, "member-order": "bysource", + "inherited-members": "GufeTokenizable,BaseModel" } toc_object_entries_show_parents = "hide" @@ -127,6 +128,7 @@ html_css_files = [ "css/custom.css", "css/custom-api.css", + "css/deflist-flowchart.css", ] # custom-api.css is compiled from custom-api.scss diff --git a/docs/cookbook/index.rst b/docs/cookbook/index.rst index df7406ed1..e62129365 100644 --- a/docs/cookbook/index.rst +++ b/docs/cookbook/index.rst @@ -1,12 +1,121 @@ Cookbook ======== -This will include various how-to guides. +This section describes common tasks involving the OpenFE Python API. -.. toctree:: +The :any:`OpenFE CLI` provides a simple way to perform the most common procedures for free energy calculations, but does not provide much flexibility for fine-tuning your approach or combining OpenFE with other tools. The :any:`Python API` allows that flexibility, but using it is more complex. This cookbook breaks down common steps that would be implemented in Python to help navigate that complexity. + +.. note:: This section is a work-in-progress. + +.. module:: openfe + :noindex: + +The Basic Workflow +------------------ + +The typical way to use the Python API is to load a number of molecules you want to calculate free energies of, construct a :class:`LigandNetwork` connecting them in an efficient way, and then combine that with information for how each ligand should be simulated to construct an :class:`AlchemicalNetwork`, which specifies the entire simulation campaign. This provides a lot of flexibility in how molecules are specified, mapped, connected, and simulated, without exposing a great deal of complexity. OpenFE recommends this workflow for most users. + +.. container:: deflist-flowchart + + * Setup + - .. container:: width-7 + + - Chemical component definition + SDF, PDB, RDKit, OpenFF Molecule, solvent spec, etc. + + - .. container:: flowchart-sidebyside + + - - + + .. rst-class:: arrow-down arrow-multiple + - :any:`Loading proteins`, :any:`Defining solvents` + + .. rst-class:: width-3 + - :class:`SolventComponent` and :class:`ProteinComponent` + Other chemical components needed to simulate the ligand. + + .. rst-class:: arrow-down arrow-multiple arrow-tail arrow-combine-right + - + + - - .. container:: flowchart-sidebyside + + - - + + .. rst-class:: arrow-down arrow-multiple + - :any:`Loading small molecules` + + .. rst-class:: width-4 + - :class:`SmallMoleculeComponent` + The ligands that will be mutated. + + + .. rst-class:: arrow-down arrow-multiple + - + - - + .. rst-class:: flowchart-spacer + - + + - Orion/FEP+ + Atom mappings from another tool. + + .. rst-class:: arrow-down + - + + - - + .. rst-class:: flowchart-spacer + - + + - :class:`dict` or :class:`list` + Hand-write an atom mapping. + + .. rst-class:: arrow-down + - + + - :class:`LigandNetwork` + A network of ligand transformations. + + .. rst-class:: arrow-down arrow-tail arrow-combine + - + + - + - + .. rst-class:: flowchart-spacer + - + + - :class:`Protocol` + Simulation procedure for an alchemic mutation. + + .. rst-class:: arrow-down arrow-tail arrow-combine-left + - + + .. rst-class:: arrow-down arrow-head + - + + - :class:`AlchemicalNetwork` + A complete simulation campaign. + + .. rst-class:: arrow-down + * :any:`dumping_transformations` + + * Run + - :any:`openfe quickrun ` + OpenFE recommends using the ``openfe quickrun`` CLI command to execute a transformation. + + .. rst-class:: arrow-down + * + + * Gather + - :any:`openfe gather ` + OpenFE recommends using the ``openfe gather`` CLI command to collect the results of a transformation. + +List of Cookbooks +----------------- + +.. toctree:: loading_molecules creating_atom_mappings dumping_transformation + under_the_hood diff --git a/docs/cookbook/loading_molecules.rst b/docs/cookbook/loading_molecules.rst index a22a6d1ae..94d12426f 100644 --- a/docs/cookbook/loading_molecules.rst +++ b/docs/cookbook/loading_molecules.rst @@ -1,7 +1,7 @@ .. _Loading Molecules: -Loading your data into ChemicalSystems -====================================== +Loading your data into Components +================================= One of the first tasks you'll likely want to do is loading your various input files. In ``openfe`` the entire contents of a simulation volume, for example the ligand, protein and water is referred to @@ -24,6 +24,8 @@ We will walk through how different items can be loaded, and then how these are assembled to form ``ChemicalSystem`` objects. +.. _Loading small molecules: + Loading small molecules ----------------------- @@ -59,6 +61,7 @@ As these types of structures are typically stored inside sdf files, there is a ` To load multiple molcules, use RDKit's ``Chem.SDMolSupplier`` to iterate over the contents, and create a ``SmallMoleculeComponent`` from each. +.. _Loading proteins: Loading proteins ---------------- @@ -78,6 +81,7 @@ To load a protein, use the :func:`openfe.ProteinComponent.from_pdb_file` or :fun p = openfe.ProteinComponent.from_pdb_file('file.pdb') +.. _Defining solvents: Defining solvents ----------------- @@ -98,6 +102,7 @@ can be freely defined. solv = openfe.SolventComponent(ion_concentation=0.15 * unit.molar) +.. _Assembling into ChemicalSystems: Assembling into ChemicalSystems ------------------------------- diff --git a/docs/cookbook/under_the_hood.rst b/docs/cookbook/under_the_hood.rst new file mode 100644 index 000000000..ddd821adb --- /dev/null +++ b/docs/cookbook/under_the_hood.rst @@ -0,0 +1,145 @@ +.. _under-the-hood: + +Under the Hood +============== + +.. module:: openfe + :noindex: + +If you want to implement your own atom mapper or free energy procedure, or you want to do something a bit more bespoke, it's helpful to understand how OpenFE thinks about individual alchemic mutation specifications. A :class:`Transformation` stores all the information needed to run an alchemic mutation from one chemical system to another and is the basic unit of an OpenFE simulation campaign. Indeed, :class:`Transformation` objects describe the edges of the graph in the :class:`AlchemicalNetwork` class. + +.. container:: deflist-flowchart + + * Setup + - .. container:: flowchart-sidebyside + + - - + .. rst-class:: flowchart-spacer + - + + - :class:`Protocol` + Simulation procedure for an alchemic mutation. + + .. rst-class:: arrow-down arrow-tail arrow-combine-right + - + + - - Chemical component definition + SDF, PDB, RDKit, OpenFF Molecule, solvent spec, etc. + + .. rst-class:: arrow-down arrow-tail + - :any:`Loading Molecules` + + - .. container:: flowchart-sidebyside + + - - + .. rst-class:: arrow-down arrow-head arrow-combine-right + - + + - :class:`SmallMoleculeComponent` + The ligands that will be mutated. + + .. rst-class:: arrow-down + - :any:`Creating Atom Mappings` + + - :class:`LigandAtomMapping` + Corresponds atoms in one small molecule to those in another. + + .. rst-class:: arrow-down arrow-tail arrow-combine + - + + - - + .. rst-class:: arrow-down arrow-head arrow-combine-left + - + + - :class:`SmallMoleculeComponent`, :class:`SolventComponent` and :class:`ProteinComponent` + The components that make up the chemical system. + + .. rst-class:: arrow-down arrow-multiple-combine + - :any:`Assembling into ChemicalSystems` + + - :class:`ChemicalSystem` + Each of the chemical systems, composed of components, that the :class:`Transformation` mutates between. + + .. rst-class:: arrow-down arrow-tail arrow-combine-left arrow-multiple + - + + .. rst-class:: arrow-down arrow-head + - + + - :class:`Transformation` + A single alchemic mutation from one chemical system to another. + + .. rst-class:: arrow-down + * + + * Run + - :class:`Transformation` + A single alchemic mutation from one chemical system to another. + + .. rst-class:: arrow-down + - + + - :class:`ProtocolDAG` + A directed acyclic graph describing how to compute a :class:`Transformation`. + + - .. container:: flowchart-sidebyside + + - + - + .. rst-class:: arrow-down arrow-multiple + - + + - :class:`ProtocolUnit` + A single unit of computation within a :class:`ProtocolDAG` + + .. rst-class:: arrow-down + - + + - :class:`ProtocolUnitResult` + The result of a completed :class:`ProtocolUnit` + + .. rst-class:: arrow-down arrow-multiple-combine + - + + - + - + .. rst-class:: arrow-down + - :any:`executors` + + - :class:`ProtocolDAGResult` + A completed transformation. + + .. rst-class:: arrow-down + * + + * Gather + - .. container:: flowchart-sidebyside + + - + + - :class:`Transformation` + The specification for the alchemic mutation. + + .. rst-class:: arrow-down + - + + - :class:`Protocol` + A completed single run of a transformation. + + .. rst-class:: arrow-down arrow-combine-right arrow-tail + - + + - + + - :class:`ProtocolResult` + A completed single run of a transformation. + + .. rst-class:: arrow-down arrow-combine-left arrow-multiple arrow-tail + - + + .. rst-class:: arrow-down arrow-head + - + + - :class:`ProtocolDAGResult` + A completed transformation with multiple user-defined replicas. + diff --git a/docs/environment.yaml b/docs/environment.yaml index effa35f61..7fcefaf27 100644 --- a/docs/environment.yaml +++ b/docs/environment.yaml @@ -12,11 +12,19 @@ dependencies: - plugcli - pydata-sphinx-theme - python=3.9 -- sphinx +- sphinx<7 - sphinx-click - tqdm - libsass - pip: - sphinx-design - sphinx-toolbox + - sphinx<7 - git+https://github.com/OpenFreeEnergy/gufe@main + +# These are added automatically by RTD, so we include them here +# for a consistent environment. +- mock +- pillow +- sphinx +- sphinx_rtd_theme diff --git a/docs/reference/api/alchemical_data_objects.rst b/docs/reference/api/alchemical_data_objects.rst index 1cc641b2f..925975074 100644 --- a/docs/reference/api/alchemical_data_objects.rst +++ b/docs/reference/api/alchemical_data_objects.rst @@ -11,8 +11,8 @@ We describe a chemical system as being made up of one or more "components," e.g. :noindex: .. autosummary:: - :nosignatures: - :toctree: generated/ + :nosignatures: + :toctree: generated/ SmallMoleculeComponent ProteinComponent @@ -25,15 +25,13 @@ Atom Mappings Tools for mapping atoms in one molecule to those in another. Used to generate efficient ligand networks. -.. module:: openfe - :noindex: - .. autosummary:: - :nosignatures: - :toctree: generated/ + :nosignatures: + :toctree: generated/ LigandAtomMapper LigandAtomMapping + LigandNetwork Alchemical Simulations @@ -41,12 +39,9 @@ Alchemical Simulations Descriptions of anticipated alchemical simulation campaigns. -.. module:: openfe - :noindex: - .. autosummary:: - :nosignatures: - :toctree: generated/ + :nosignatures: + :toctree: generated/ Transformation AlchemicalNetwork diff --git a/docs/reference/api/alchemical_network_planning.rst b/docs/reference/api/alchemical_network_planning.rst index a1167be4c..b8e18431f 100644 --- a/docs/reference/api/alchemical_network_planning.rst +++ b/docs/reference/api/alchemical_network_planning.rst @@ -1,3 +1,5 @@ +.. _Alchemical Network Planning: + Alchemical Network Planning =========================== diff --git a/docs/reference/api/defining_and_executing_simulations.rst b/docs/reference/api/defining_and_executing_simulations.rst index efa15ff16..51cc3df34 100644 --- a/docs/reference/api/defining_and_executing_simulations.rst +++ b/docs/reference/api/defining_and_executing_simulations.rst @@ -1,6 +1,8 @@ Defining and Executing Simulations ================================== +.. _executors: + Executing Simulations --------------------- diff --git a/docs/reference/api/ligand_network.rst b/docs/reference/api/ligand_network.rst index 58089db77..1b4b82a29 100644 --- a/docs/reference/api/ligand_network.rst +++ b/docs/reference/api/ligand_network.rst @@ -15,9 +15,10 @@ Atom Mappers LomapAtomMapper PersesAtomMapper +.. _Atom Map Scorers: -Scorers -------- +Atom Map Scorers +---------------- LOMAP Scorers ~~~~~~~~~~~~~ @@ -58,6 +59,8 @@ PersesScorers default_perses_scorer +.. _Ligand Network Planners: + Network Planners ---------------- diff --git a/docs/reference/api/openmm_rfe.rst b/docs/reference/api/openmm_rfe.rst index 20e34a902..e8b222c08 100644 --- a/docs/reference/api/openmm_rfe.rst +++ b/docs/reference/api/openmm_rfe.rst @@ -4,8 +4,18 @@ 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 ----------------- @@ -124,20 +134,3 @@ Below are the settings which can be tweaked in the protocol. The default setting :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 - - .. automethod:: gather - -.. autoclass:: RelativeHybridTopologyProtocolResult diff --git a/openfe/setup/ligand_network.py b/openfe/setup/ligand_network.py index 948fd6a60..081aee144 100644 --- a/openfe/setup/ligand_network.py +++ b/openfe/setup/ligand_network.py @@ -162,7 +162,7 @@ def enlarge_graph(self, *, edges=None, nodes=None) -> LigandNetwork: Returns ------- - :class:`.Network : + :class:`.Network` : a new network adding the given edges and nodes to this network """ if edges is None: