rowan-python 3.0.7__py3-none-any.whl → 3.0.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rowan/__init__.py +1 -0
- rowan/api_keys.py +144 -0
- rowan/workflows/__init__.py +4 -0
- rowan/workflows/base.py +6 -0
- rowan/workflows/bde.py +8 -6
- rowan/workflows/conformer_search.py +83 -27
- rowan/workflows/electronic_properties.py +18 -0
- rowan/workflows/multistage_optimization.py +24 -15
- rowan/workflows/protein_cofolding.py +19 -2
- rowan/workflows/redox_potential.py +7 -5
- rowan/workflows/spin_states.py +20 -14
- rowan/workflows/strain.py +4 -3
- {rowan_python-3.0.7.dist-info → rowan_python-3.0.9.dist-info}/METADATA +2 -2
- {rowan_python-3.0.7.dist-info → rowan_python-3.0.9.dist-info}/RECORD +16 -15
- {rowan_python-3.0.7.dist-info → rowan_python-3.0.9.dist-info}/WHEEL +0 -0
- {rowan_python-3.0.7.dist-info → rowan_python-3.0.9.dist-info}/licenses/LICENSE +0 -0
rowan/__init__.py
CHANGED
rowan/api_keys.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import uuid
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import Literal, Self
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from .utils import api_client
|
|
8
|
+
|
|
9
|
+
APIKeyScope = Literal["read", "read_write", "read_write_delete"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class APIKey(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Rowan API key.
|
|
15
|
+
|
|
16
|
+
:ivar uuid: UUID of the API key.
|
|
17
|
+
:ivar name: Human-readable name of the API key.
|
|
18
|
+
:ivar created_at: When the key was created.
|
|
19
|
+
:ivar expires_at: When the key expires.
|
|
20
|
+
:ivar is_expired: Whether the key has expired.
|
|
21
|
+
:ivar is_revoked: Whether the key has been revoked.
|
|
22
|
+
:ivar scope: Permission scope ("read", "read_write", or "read_write_delete").
|
|
23
|
+
:ivar can_manage_api_keys: Whether this key can create/list/revoke other API keys.
|
|
24
|
+
:ivar scoped_project_uuid: If set, the key can only access this project.
|
|
25
|
+
:ivar created_by_key_uuid: UUID of the API key used to create this one (if any).
|
|
26
|
+
:ivar revoked_at: When the key was revoked, if applicable.
|
|
27
|
+
:ivar last_used_at: When the key was last used, if known.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
uuid: str
|
|
31
|
+
name: str
|
|
32
|
+
created_at: datetime
|
|
33
|
+
expires_at: datetime
|
|
34
|
+
is_expired: bool
|
|
35
|
+
is_revoked: bool
|
|
36
|
+
scope: str
|
|
37
|
+
can_manage_api_keys: bool
|
|
38
|
+
scoped_project_uuid: str | None = None
|
|
39
|
+
created_by_key_uuid: str | None = None
|
|
40
|
+
revoked_at: datetime | None = None
|
|
41
|
+
last_used_at: datetime | None = None
|
|
42
|
+
|
|
43
|
+
def __repr__(self) -> str:
|
|
44
|
+
return (
|
|
45
|
+
f"<APIKey name='{self.name}' scope='{self.scope}' "
|
|
46
|
+
f"scoped_project_uuid={self.scoped_project_uuid!r} uuid='{self.uuid}'>"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def revoke(self) -> Self:
|
|
50
|
+
"""
|
|
51
|
+
Revoke this API key.
|
|
52
|
+
|
|
53
|
+
:returns: Updated APIKey object.
|
|
54
|
+
"""
|
|
55
|
+
with api_client() as client:
|
|
56
|
+
response = client.post(f"/api_key/{self.uuid}/revoke")
|
|
57
|
+
response.raise_for_status()
|
|
58
|
+
return type(self)(**response.json())
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class CreatedAPIKey(BaseModel):
|
|
62
|
+
"""
|
|
63
|
+
Result of creating a new API key.
|
|
64
|
+
|
|
65
|
+
The plaintext ``key`` is only available at creation time — store it now,
|
|
66
|
+
it cannot be retrieved later.
|
|
67
|
+
|
|
68
|
+
:ivar key: Plaintext API key. Save this; it is only returned once.
|
|
69
|
+
:ivar api_key: Metadata for the newly-created key.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
key: str
|
|
73
|
+
api_key: APIKey
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def create_api_key(
|
|
77
|
+
name: str = "api-key",
|
|
78
|
+
scope: APIKeyScope = "read_write",
|
|
79
|
+
valid_days: int = 365,
|
|
80
|
+
scoped_project_uuid: str | None = None,
|
|
81
|
+
) -> CreatedAPIKey:
|
|
82
|
+
"""
|
|
83
|
+
Create a new API key.
|
|
84
|
+
|
|
85
|
+
The caller must currently authenticate with an unscoped key that has
|
|
86
|
+
``can_manage_api_keys`` permission.
|
|
87
|
+
|
|
88
|
+
:param name: Human-readable name for the key.
|
|
89
|
+
:param scope: Permission scope. One of "read", "read_write", "read_write_delete".
|
|
90
|
+
:param valid_days: Number of days until the key expires.
|
|
91
|
+
:param scoped_project_uuid: If provided, restrict the key to a single project.
|
|
92
|
+
:returns: plaintext key together with its metadata; the plaintext key is
|
|
93
|
+
only returned once — store it immediately.
|
|
94
|
+
"""
|
|
95
|
+
plaintext_key = f"rowan-sk{uuid.uuid4()}"
|
|
96
|
+
payload = {
|
|
97
|
+
"api_key": plaintext_key,
|
|
98
|
+
"name": name,
|
|
99
|
+
"scope": scope,
|
|
100
|
+
"valid_days": valid_days,
|
|
101
|
+
"scoped_project_uuid": scoped_project_uuid,
|
|
102
|
+
}
|
|
103
|
+
with api_client() as client:
|
|
104
|
+
response = client.post("/api_key", json=payload)
|
|
105
|
+
if response.status_code == 403:
|
|
106
|
+
raise PermissionError(
|
|
107
|
+
"API key creation rejected by the server (403). The key you are "
|
|
108
|
+
"authenticating with must be unscoped and have `can_manage_api_keys` "
|
|
109
|
+
"permission. Create a manager key from the Rowan web UI "
|
|
110
|
+
"(Account → API keys) and retry with that key."
|
|
111
|
+
)
|
|
112
|
+
response.raise_for_status()
|
|
113
|
+
return CreatedAPIKey(key=plaintext_key, api_key=APIKey(**response.json()))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def list_api_keys(active: bool | None = True) -> list[APIKey]:
|
|
117
|
+
"""
|
|
118
|
+
List API keys belonging to the current user.
|
|
119
|
+
|
|
120
|
+
:param active: If True (default), only return non-revoked, non-expired keys.
|
|
121
|
+
If False, only return revoked or expired keys. If None, return all keys.
|
|
122
|
+
:returns: List of APIKey objects.
|
|
123
|
+
"""
|
|
124
|
+
params: dict[str, str] = {}
|
|
125
|
+
if active is not None:
|
|
126
|
+
params["active"] = "true" if active else "false"
|
|
127
|
+
|
|
128
|
+
with api_client() as client:
|
|
129
|
+
response = client.get("/api_key", params=params)
|
|
130
|
+
response.raise_for_status()
|
|
131
|
+
return [APIKey(**item) for item in response.json()]
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def revoke_api_key(uuid: str) -> APIKey:
|
|
135
|
+
"""
|
|
136
|
+
Revoke an API key by UUID.
|
|
137
|
+
|
|
138
|
+
:param uuid: UUID of the key to revoke.
|
|
139
|
+
:returns: Updated APIKey object.
|
|
140
|
+
"""
|
|
141
|
+
with api_client() as client:
|
|
142
|
+
response = client.post(f"/api_key/{uuid}/revoke")
|
|
143
|
+
response.raise_for_status()
|
|
144
|
+
return APIKey(**response.json())
|
rowan/workflows/__init__.py
CHANGED
|
@@ -92,7 +92,11 @@ from .protein_binder_design import (
|
|
|
92
92
|
submit_protein_binder_design_workflow,
|
|
93
93
|
)
|
|
94
94
|
from .protein_cofolding import (
|
|
95
|
+
CofoldingModel,
|
|
95
96
|
CofoldingResult,
|
|
97
|
+
ConstraintTarget,
|
|
98
|
+
ContactConstraint,
|
|
99
|
+
PocketConstraint,
|
|
96
100
|
ProteinCofoldingResult,
|
|
97
101
|
submit_protein_cofolding_workflow,
|
|
98
102
|
)
|
rowan/workflows/base.py
CHANGED
|
@@ -25,6 +25,12 @@ logger.setLevel(logging.INFO)
|
|
|
25
25
|
Mode = stjames.Mode
|
|
26
26
|
Solvent = stjames.Solvent
|
|
27
27
|
MessageType = stjames.MessageType
|
|
28
|
+
Method = stjames.Method
|
|
29
|
+
Task = stjames.Task
|
|
30
|
+
Settings = stjames.Settings
|
|
31
|
+
MultiStageOptSettings = stjames.MultiStageOptSettings
|
|
32
|
+
ETKDGSettings = stjames.ETKDGSettings
|
|
33
|
+
ConformerGenSettings = stjames.conformers.ConformerGenSettings
|
|
28
34
|
|
|
29
35
|
|
|
30
36
|
@dataclass(frozen=True, slots=True)
|
rowan/workflows/bde.py
CHANGED
|
@@ -90,12 +90,14 @@ def submit_bde_workflow(
|
|
|
90
90
|
folder_uuid = folder.uuid
|
|
91
91
|
initial_molecule = molecule_to_dict(initial_molecule)
|
|
92
92
|
|
|
93
|
-
workflow = stjames.BDEWorkflow(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
workflow = stjames.BDEWorkflow.model_validate(
|
|
94
|
+
{
|
|
95
|
+
"initial_molecule": initial_molecule,
|
|
96
|
+
"mode": mode,
|
|
97
|
+
"atoms": atoms or [],
|
|
98
|
+
"all_CH": all_CH,
|
|
99
|
+
"all_CX": all_CX,
|
|
100
|
+
}
|
|
99
101
|
)
|
|
100
102
|
|
|
101
103
|
data = {
|
|
@@ -8,6 +8,13 @@ from ..molecule import Molecule
|
|
|
8
8
|
from ..types import MoleculeInput, SolventInput
|
|
9
9
|
from ..utils import api_client
|
|
10
10
|
from .base import (
|
|
11
|
+
ConformerGenSettings,
|
|
12
|
+
ETKDGSettings,
|
|
13
|
+
Method,
|
|
14
|
+
Mode,
|
|
15
|
+
MultiStageOptSettings,
|
|
16
|
+
Settings,
|
|
17
|
+
Task,
|
|
11
18
|
Workflow,
|
|
12
19
|
WorkflowResult,
|
|
13
20
|
molecule_to_dict,
|
|
@@ -114,12 +121,68 @@ class ConformerSearchResult(WorkflowResult):
|
|
|
114
121
|
return self._cache[cache_key]
|
|
115
122
|
|
|
116
123
|
|
|
124
|
+
_FINAL_METHOD_TO_MSO_RECIPE: dict[Method, tuple[Method, Method | None]] = {
|
|
125
|
+
Method.AIMNET2_WB97MD3: (Method.AIMNET2_WB97MD3, None),
|
|
126
|
+
Method.OMOL25_CONSERVING_S: (Method.OMOL25_CONSERVING_S, None),
|
|
127
|
+
Method.GFN2_XTB: (Method.GFN2_XTB, None),
|
|
128
|
+
Method.G_XTB: (Method.GFN2_XTB, Method.G_XTB),
|
|
129
|
+
Method.R2SCAN3C: (Method.GFN2_XTB, Method.R2SCAN3C),
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _mso_for_final_method(
|
|
134
|
+
final_method: Method,
|
|
135
|
+
solvent: SolventInput = None,
|
|
136
|
+
transition_state: bool = False,
|
|
137
|
+
) -> MultiStageOptSettings:
|
|
138
|
+
"""Build a `MultiStageOptSettings` for `final_method` matching tinbergen's
|
|
139
|
+
conformer-search MSO presets. Falls back to a single opt stage at
|
|
140
|
+
`final_method` for methods without a named preset.
|
|
141
|
+
|
|
142
|
+
`solvent` and `transition_state` are merged into each stage's `Settings`
|
|
143
|
+
when supplied; the named preset itself is independent of them (mirrors how
|
|
144
|
+
tinbergen's form keeps the preset dropdown separate from the solvent / TS
|
|
145
|
+
toggles).
|
|
146
|
+
"""
|
|
147
|
+
opt_method, sp_method = _FINAL_METHOD_TO_MSO_RECIPE.get(final_method, (final_method, None))
|
|
148
|
+
|
|
149
|
+
def _solvent_settings_for(method: Method) -> dict | None:
|
|
150
|
+
if not solvent:
|
|
151
|
+
return None
|
|
152
|
+
return {
|
|
153
|
+
"solvent": solvent,
|
|
154
|
+
"model": "alpb" if method in stjames.XTB_METHODS else "cpcm",
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
opt_stage = Settings(
|
|
158
|
+
method=opt_method,
|
|
159
|
+
tasks=[Task.OPTIMIZE],
|
|
160
|
+
mode=Mode.AUTO,
|
|
161
|
+
solvent_settings=_solvent_settings_for(opt_method),
|
|
162
|
+
opt_settings={"transition_state": transition_state, "constraints": []},
|
|
163
|
+
)
|
|
164
|
+
sp_stage: Settings | None = None
|
|
165
|
+
if sp_method is not None:
|
|
166
|
+
sp_stage = Settings(
|
|
167
|
+
method=sp_method,
|
|
168
|
+
tasks=[Task.ENERGY],
|
|
169
|
+
mode=Mode.AUTO,
|
|
170
|
+
solvent_settings=_solvent_settings_for(sp_method),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
return MultiStageOptSettings(
|
|
174
|
+
optimization_settings=[opt_stage],
|
|
175
|
+
singlepoint_settings=sp_stage,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
117
179
|
def submit_conformer_search_workflow(
|
|
118
180
|
initial_molecule: MoleculeInput,
|
|
119
|
-
conf_gen_settings:
|
|
120
|
-
final_method:
|
|
181
|
+
conf_gen_settings: ConformerGenSettings | None = None,
|
|
182
|
+
final_method: Method | str = "aimnet2_wb97md3",
|
|
121
183
|
solvent: SolventInput = None,
|
|
122
184
|
transition_state: bool = False,
|
|
185
|
+
multistage_opt_settings: MultiStageOptSettings | None = None,
|
|
123
186
|
name: str = "Conformer Search Workflow",
|
|
124
187
|
folder_uuid: str | None = None,
|
|
125
188
|
folder: Folder | None = None,
|
|
@@ -138,9 +201,16 @@ def submit_conformer_search_workflow(
|
|
|
138
201
|
- ``LyrebirdSettings`` -- Rowan ML model
|
|
139
202
|
- ``iMTDGCSettings`` -- CREST iMTD-GC metadynamics, more thorough
|
|
140
203
|
- ``MonteCarloMultipleMinimumSettings`` -- MCMM conformer search
|
|
141
|
-
:param final_method: Method to use for the final optimization.
|
|
142
|
-
|
|
143
|
-
:param
|
|
204
|
+
:param final_method: Method to use for the final optimization. Ignored if
|
|
205
|
+
`multistage_opt_settings` is provided.
|
|
206
|
+
:param solvent: Solvent to use for the final optimization. Ignored if
|
|
207
|
+
`multistage_opt_settings` is provided.
|
|
208
|
+
:param transition_state: Whether to optimize the transition state. Ignored
|
|
209
|
+
if `multistage_opt_settings` is provided.
|
|
210
|
+
:param multistage_opt_settings: Optimization stages and singlepoint settings
|
|
211
|
+
for ranking conformers. When provided, takes precedence over
|
|
212
|
+
`final_method` / `solvent` / `transition_state`. When omitted, an MSO is
|
|
213
|
+
built from those three params.
|
|
144
214
|
:param name: Name of the workflow.
|
|
145
215
|
:param folder_uuid: UUID of the folder to place the workflow in.
|
|
146
216
|
:param folder: Folder object to store the workflow in.
|
|
@@ -155,34 +225,20 @@ def submit_conformer_search_workflow(
|
|
|
155
225
|
if folder:
|
|
156
226
|
folder_uuid = folder.uuid
|
|
157
227
|
if conf_gen_settings is None:
|
|
158
|
-
conf_gen_settings =
|
|
228
|
+
conf_gen_settings = ETKDGSettings()
|
|
159
229
|
|
|
160
230
|
mol_dict = molecule_to_dict(initial_molecule)
|
|
161
231
|
|
|
162
|
-
if
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
opt_settings = stjames.Settings(
|
|
170
|
-
method=final_method,
|
|
171
|
-
tasks=["optimize"],
|
|
172
|
-
mode=stjames.Mode.AUTO,
|
|
173
|
-
solvent_settings={"solvent": solvent, "model": solvent_model} if solvent else None,
|
|
174
|
-
opt_settings={"transition_state": transition_state, "constraints": []},
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
msos = stjames.MultiStageOptSettings(
|
|
178
|
-
mode=stjames.Mode.MANUAL,
|
|
179
|
-
xtb_preopt=True,
|
|
180
|
-
optimization_settings=[opt_settings],
|
|
181
|
-
)
|
|
232
|
+
if multistage_opt_settings is None:
|
|
233
|
+
if isinstance(final_method, str):
|
|
234
|
+
final_method = Method(final_method)
|
|
235
|
+
multistage_opt_settings = _mso_for_final_method(
|
|
236
|
+
final_method, solvent=solvent, transition_state=transition_state
|
|
237
|
+
)
|
|
182
238
|
|
|
183
239
|
workflow = stjames.ConformerSearchWorkflow(
|
|
184
240
|
initial_molecule=mol_dict,
|
|
185
|
-
multistage_opt_settings=
|
|
241
|
+
multistage_opt_settings=multistage_opt_settings,
|
|
186
242
|
conf_gen_settings=conf_gen_settings,
|
|
187
243
|
solvent=solvent,
|
|
188
244
|
transition_state=transition_state,
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
4
|
|
|
5
|
+
import httpx
|
|
5
6
|
import stjames
|
|
7
|
+
from pydantic import ValidationError
|
|
6
8
|
from stjames import ENGINE_METHODS, Engine, Method
|
|
7
9
|
|
|
8
10
|
from ..folder import Folder
|
|
@@ -31,6 +33,22 @@ class ElectronicPropertiesResult(WorkflowResult):
|
|
|
31
33
|
|
|
32
34
|
_stjames_class = stjames.ElectronicPropertiesWorkflow
|
|
33
35
|
|
|
36
|
+
def __post_init__(self) -> None:
|
|
37
|
+
# Computed results (dipole, charges, cubes, orbitals, ...) live only in
|
|
38
|
+
# the gzipped S3 blob, not in the workflow's object_data row. Fetch and
|
|
39
|
+
# parse it once on construction so accessors below see populated data.
|
|
40
|
+
super().__post_init__()
|
|
41
|
+
if not self.complete:
|
|
42
|
+
return
|
|
43
|
+
try:
|
|
44
|
+
with api_client() as client:
|
|
45
|
+
response = client.get(f"/orbitals/{self.workflow_uuid}/compressed_json")
|
|
46
|
+
response.raise_for_status()
|
|
47
|
+
populated = stjames.ElectronicPropertiesWorkflow.model_validate(response.json())
|
|
48
|
+
object.__setattr__(self, "_workflow", populated)
|
|
49
|
+
except (httpx.HTTPError, ValidationError):
|
|
50
|
+
pass
|
|
51
|
+
|
|
34
52
|
def __repr__(self) -> str:
|
|
35
53
|
return f"<ElectronicPropertiesResult dipole={self.dipole} D>"
|
|
36
54
|
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
"""Multistage optimization workflow - optimize molecules with staged methods."""
|
|
2
2
|
|
|
3
|
+
from typing import Sequence
|
|
4
|
+
|
|
3
5
|
import stjames
|
|
4
6
|
|
|
5
7
|
from ..calculation import Calculation, retrieve_calculation
|
|
6
8
|
from ..folder import Folder
|
|
7
9
|
from ..molecule import Molecule
|
|
8
|
-
from ..types import MoleculeInput
|
|
10
|
+
from ..types import MoleculeInput
|
|
9
11
|
from ..utils import api_client
|
|
10
12
|
from .base import (
|
|
11
|
-
|
|
13
|
+
Method,
|
|
14
|
+
Settings,
|
|
15
|
+
Task,
|
|
12
16
|
Workflow,
|
|
13
17
|
WorkflowResult,
|
|
14
18
|
molecule_to_dict,
|
|
@@ -116,10 +120,8 @@ class MultiStageOptResult(WorkflowResult):
|
|
|
116
120
|
|
|
117
121
|
def submit_multistage_optimization_workflow(
|
|
118
122
|
initial_molecule: MoleculeInput,
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
xtb_preopt: bool = True,
|
|
122
|
-
transition_state: bool = False,
|
|
123
|
+
optimization_settings: Sequence[Settings] | None = None,
|
|
124
|
+
singlepoint_settings: Settings | None = None,
|
|
123
125
|
frequencies: bool = False,
|
|
124
126
|
name: str = "Multistage Optimization Workflow",
|
|
125
127
|
folder_uuid: str | None = None,
|
|
@@ -131,12 +133,13 @@ def submit_multistage_optimization_workflow(
|
|
|
131
133
|
"""
|
|
132
134
|
Submits a multistage-optimization workflow to the API.
|
|
133
135
|
|
|
136
|
+
Defaults to a 3-stage `r2scan_3c//gfn2_xtb//gfn_ff` stack.
|
|
137
|
+
|
|
134
138
|
:param initial_molecule: Molecule to optimize.
|
|
135
|
-
:param
|
|
136
|
-
:param
|
|
137
|
-
|
|
138
|
-
:param
|
|
139
|
-
:param frequencies: Whether to calculate frequencies.
|
|
139
|
+
:param optimization_settings: Optimization stages to apply in order.
|
|
140
|
+
:param singlepoint_settings: Final singlepoint settings, applied after the
|
|
141
|
+
last optimization stage.
|
|
142
|
+
:param frequencies: Whether to calculate frequencies on the last optimization step.
|
|
140
143
|
:param name: Name of the workflow.
|
|
141
144
|
:param folder_uuid: UUID of the folder to place the workflow in.
|
|
142
145
|
:param folder: Folder object to store the workflow in.
|
|
@@ -152,12 +155,18 @@ def submit_multistage_optimization_workflow(
|
|
|
152
155
|
folder_uuid = folder.uuid
|
|
153
156
|
mol_dict = molecule_to_dict(initial_molecule)
|
|
154
157
|
|
|
158
|
+
if optimization_settings is None:
|
|
159
|
+
optimization_settings = [
|
|
160
|
+
Settings(method=Method.GFN_FF, tasks=[Task.OPTIMIZE]),
|
|
161
|
+
Settings(method=Method.GFN2_XTB, tasks=[Task.OPTIMIZE]),
|
|
162
|
+
]
|
|
163
|
+
if singlepoint_settings is None:
|
|
164
|
+
singlepoint_settings = Settings(method=Method.R2SCAN3C, tasks=[Task.ENERGY])
|
|
165
|
+
|
|
155
166
|
workflow = stjames.MultiStageOptWorkflow(
|
|
156
167
|
initial_molecule=mol_dict,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
xtb_preopt=xtb_preopt,
|
|
160
|
-
transition_state=transition_state,
|
|
168
|
+
optimization_settings=optimization_settings or (),
|
|
169
|
+
singlepoint_settings=singlepoint_settings,
|
|
161
170
|
frequencies=frequencies,
|
|
162
171
|
)
|
|
163
172
|
|
|
@@ -9,8 +9,12 @@ from ..protein import Protein, retrieve_protein
|
|
|
9
9
|
from ..utils import api_client
|
|
10
10
|
from .base import Message, Workflow, WorkflowResult, parse_messages, register_result
|
|
11
11
|
|
|
12
|
-
# Re-export cofolding model enum from stjames
|
|
13
12
|
CofoldingModel = stjames.CofoldingModel
|
|
13
|
+
# `ConstraintTarget` aliases stjames's `Token` - one position in an input
|
|
14
|
+
# (a protein/nucleic-acid residue or a ligand atom) addressable by a constraint.
|
|
15
|
+
ConstraintTarget = stjames.workflows.protein_cofolding.Token
|
|
16
|
+
ContactConstraint = stjames.workflows.protein_cofolding.ContactConstraint
|
|
17
|
+
PocketConstraint = stjames.workflows.protein_cofolding.PocketConstraint
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
@dataclass(frozen=True, slots=True)
|
|
@@ -244,6 +248,9 @@ def submit_protein_cofolding_workflow(
|
|
|
244
248
|
ligand_binding_affinity_index: int | None = None,
|
|
245
249
|
use_msa_server: bool = True,
|
|
246
250
|
use_potentials: bool = False,
|
|
251
|
+
contact_constraints: list[ContactConstraint] | None = None,
|
|
252
|
+
pocket_constraints: list[PocketConstraint] | None = None,
|
|
253
|
+
num_samples: int | None = None,
|
|
247
254
|
compute_strain: bool = False,
|
|
248
255
|
do_pose_refinement: bool = False,
|
|
249
256
|
name: str = "Protein-Ligand Co-Folding",
|
|
@@ -260,6 +267,10 @@ def submit_protein_cofolding_workflow(
|
|
|
260
267
|
Predicts the 3D structure of protein-protein, protein-ligand, protein-DNA,
|
|
261
268
|
protein-RNA, or other biomolecular complexes.
|
|
262
269
|
|
|
270
|
+
See `examples/protein_cofolding_with_constraints.py` for a worked example
|
|
271
|
+
of using `ConstraintTarget`, `ContactConstraint`, and `PocketConstraint`
|
|
272
|
+
(Boltz-2 only).
|
|
273
|
+
|
|
263
274
|
:param initial_protein_sequences: Protein sequences to be cofolded.
|
|
264
275
|
:param initial_dna_sequences: DNA sequences to be cofolded.
|
|
265
276
|
:param initial_rna_sequences: RNA sequences to be cofolded.
|
|
@@ -267,7 +278,10 @@ def submit_protein_cofolding_workflow(
|
|
|
267
278
|
:param ligand_binding_affinity_index: Index of the ligand for which to compute
|
|
268
279
|
the binding affinity.
|
|
269
280
|
:param use_msa_server: Whether to use the MSA server for the computation.
|
|
270
|
-
:param use_potentials: Whether to use potentials
|
|
281
|
+
:param use_potentials: Whether to use potentials (inference-time steering) with Boltz.
|
|
282
|
+
:param contact_constraints: Boltz contact constraints between two tokens.
|
|
283
|
+
:param pocket_constraints: Boltz pocket constraints between a binder and contact tokens.
|
|
284
|
+
:param num_samples: Number of diffusion samples to generate. If None, uses the model default.
|
|
271
285
|
:param compute_strain: Whether to compute the strain of the pose
|
|
272
286
|
(if `pose_refinement` is enabled).
|
|
273
287
|
:param do_pose_refinement: Whether to optimize non-rotatable bonds in output poses.
|
|
@@ -302,6 +316,9 @@ def submit_protein_cofolding_workflow(
|
|
|
302
316
|
workflow = stjames.ProteinCofoldingWorkflow(
|
|
303
317
|
use_msa_server=use_msa_server,
|
|
304
318
|
use_potentials=use_potentials,
|
|
319
|
+
contact_constraints=contact_constraints or [],
|
|
320
|
+
pocket_constraints=pocket_constraints or [],
|
|
321
|
+
num_samples=num_samples,
|
|
305
322
|
model=model_str,
|
|
306
323
|
ligand_binding_affinity_index=ligand_binding_affinity_index,
|
|
307
324
|
initial_smiles_list=initial_smiles_list,
|
|
@@ -122,11 +122,13 @@ def submit_redox_potential_workflow(
|
|
|
122
122
|
folder_uuid = folder.uuid
|
|
123
123
|
initial_molecule = molecule_to_dict(initial_molecule)
|
|
124
124
|
|
|
125
|
-
workflow = stjames.RedoxPotentialWorkflow(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
workflow = stjames.RedoxPotentialWorkflow.model_validate(
|
|
126
|
+
{
|
|
127
|
+
"initial_molecule": initial_molecule,
|
|
128
|
+
"oxidation": oxidation,
|
|
129
|
+
"reduction": reduction,
|
|
130
|
+
"mode": mode,
|
|
131
|
+
}
|
|
130
132
|
)
|
|
131
133
|
|
|
132
134
|
data = {
|
rowan/workflows/spin_states.py
CHANGED
|
@@ -7,11 +7,14 @@ import stjames
|
|
|
7
7
|
|
|
8
8
|
from ..calculation import Calculation, retrieve_calculation
|
|
9
9
|
from ..folder import Folder
|
|
10
|
-
from ..types import MoleculeInput
|
|
10
|
+
from ..types import MoleculeInput
|
|
11
11
|
from ..utils import api_client
|
|
12
12
|
from .base import (
|
|
13
13
|
Message,
|
|
14
|
-
|
|
14
|
+
Method,
|
|
15
|
+
MultiStageOptSettings,
|
|
16
|
+
Settings,
|
|
17
|
+
Task,
|
|
15
18
|
Workflow,
|
|
16
19
|
WorkflowResult,
|
|
17
20
|
molecule_to_dict,
|
|
@@ -129,10 +132,7 @@ class SpinStatesResult(WorkflowResult):
|
|
|
129
132
|
def submit_spin_states_workflow(
|
|
130
133
|
initial_molecule: MoleculeInput,
|
|
131
134
|
states: list[int],
|
|
132
|
-
|
|
133
|
-
solvent: SolventInput = None,
|
|
134
|
-
xtb_preopt: bool = True,
|
|
135
|
-
frequencies: bool = False,
|
|
135
|
+
multistage_opt_settings: MultiStageOptSettings | None = None,
|
|
136
136
|
name: str = "Spin States Workflow",
|
|
137
137
|
folder_uuid: str | None = None,
|
|
138
138
|
folder: Folder | None = None,
|
|
@@ -143,13 +143,14 @@ def submit_spin_states_workflow(
|
|
|
143
143
|
"""
|
|
144
144
|
Submits a spin-states workflow to the API.
|
|
145
145
|
|
|
146
|
+
Defaults to a `r2scan_3c//gfn2_xtb` stack. Pass an explicit
|
|
147
|
+
`MultiStageOptSettings(...)` to override.
|
|
148
|
+
|
|
146
149
|
:param initial_molecule: Molecule to calculate spin states for.
|
|
147
150
|
:param states: List of multiplicities to calculate
|
|
148
151
|
(e.g., [1, 3, 5] for singlet, triplet, quintet).
|
|
149
|
-
:param
|
|
150
|
-
|
|
151
|
-
:param xtb_preopt: Whether to pre-optimize with xTB.
|
|
152
|
-
:param frequencies: Whether to calculate frequencies.
|
|
152
|
+
:param multistage_opt_settings: Optimization stages and singlepoint settings
|
|
153
|
+
describing the method stack.
|
|
153
154
|
:param name: Name of the workflow.
|
|
154
155
|
:param folder_uuid: UUID of the folder to place the workflow in.
|
|
155
156
|
:param folder: Folder object to store the workflow in.
|
|
@@ -170,13 +171,18 @@ def submit_spin_states_workflow(
|
|
|
170
171
|
for mult in states:
|
|
171
172
|
_validate_multiplicity(mol_dict, mult)
|
|
172
173
|
|
|
174
|
+
if multistage_opt_settings is None:
|
|
175
|
+
multistage_opt_settings = MultiStageOptSettings(
|
|
176
|
+
optimization_settings=[
|
|
177
|
+
Settings(method=Method.GFN2_XTB, tasks=[Task.OPTIMIZE]),
|
|
178
|
+
],
|
|
179
|
+
singlepoint_settings=Settings(method=Method.R2SCAN3C, tasks=[Task.ENERGY]),
|
|
180
|
+
)
|
|
181
|
+
|
|
173
182
|
workflow = stjames.SpinStatesWorkflow(
|
|
174
183
|
initial_molecule=mol_dict,
|
|
175
184
|
states=states,
|
|
176
|
-
|
|
177
|
-
solvent=solvent,
|
|
178
|
-
xtb_preopt=xtb_preopt,
|
|
179
|
-
frequencies=frequencies,
|
|
185
|
+
multistage_opt_settings=multistage_opt_settings,
|
|
180
186
|
)
|
|
181
187
|
|
|
182
188
|
data = {
|
rowan/workflows/strain.py
CHANGED
|
@@ -129,10 +129,11 @@ def submit_strain_workflow(
|
|
|
129
129
|
:param harmonic_constraint_spring_constant: Spring constant for harmonic
|
|
130
130
|
constraints (kcal/mol/A). Default 5.0.
|
|
131
131
|
:param constrain_hydrogens: Whether to constrain hydrogen positions. Default False.
|
|
132
|
-
:param conf_gen_settings: Conformer generation settings. Defaults to
|
|
133
|
-
max 200 conformers.
|
|
132
|
+
:param conf_gen_settings: Conformer generation settings. Defaults to RDKit
|
|
133
|
+
ETKDG with max 200 conformers (no solvent).
|
|
134
134
|
:param multistage_opt_settings: Optimization settings for conformer ranking.
|
|
135
|
-
Defaults to
|
|
135
|
+
Defaults to GFN2-xTB optimization in water (ALPB) with a g-xTB singlepoint
|
|
136
|
+
in water (CPCMx).
|
|
136
137
|
:param name: Name of the workflow.
|
|
137
138
|
:param folder_uuid: UUID of the folder to store the workflow in.
|
|
138
139
|
:param folder: Folder object to store the workflow in.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rowan-python
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.9
|
|
4
4
|
Summary: Rowan Python Library
|
|
5
5
|
Project-URL: Homepage, https://github.com/rowansci/rowan-client
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/rowansci/rowan-client/issues
|
|
@@ -11,7 +11,7 @@ Requires-Dist: httpx
|
|
|
11
11
|
Requires-Dist: nest-asyncio
|
|
12
12
|
Requires-Dist: rdkit
|
|
13
13
|
Requires-Dist: setuptools
|
|
14
|
-
Requires-Dist: stjames>=0.0.
|
|
14
|
+
Requires-Dist: stjames>=0.0.183
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
|
|
17
17
|
# Rowan Python Library
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
rowan/__init__.py,sha256=
|
|
1
|
+
rowan/__init__.py,sha256=wiEroKH5I6VQ-tiseUcrNGJaS_0soFnYMX0EtpwyLIs,859
|
|
2
|
+
rowan/api_keys.py,sha256=TvG5l5MmQ3Qt8Z3Y7jCA_lcrwEHuI7xHy-KLbIdQ8_A,4793
|
|
2
3
|
rowan/calculation.py,sha256=lZZ52DxPsuJWCTzFZXjhauHK6dV0KCUwzoxtmoxSY48,3442
|
|
3
4
|
rowan/config.py,sha256=3cVKHUNzkIPnN2bvx7l5sia7Zc5poXS8lKOJlowXyLA,21088
|
|
4
5
|
rowan/constants.py,sha256=emCH4m9OL2Hm5E-6mJGM_FgzrK_JrZT-FiKJ6pMNQ4Y,84
|
|
@@ -12,19 +13,19 @@ rowan/user.py,sha256=Tnwz1-u_92ACt1xATQegtMj3FcosFsAG4m-4YuAkiyg,5955
|
|
|
12
13
|
rowan/utils.py,sha256=c1s6Ze-OqLtfvrD23OV60otskejmj-CD88nNf8_nFcw,3636
|
|
13
14
|
rowan/rowan_rdkit/__init__.py,sha256=EATX2VRzywzKxqkpCUMTf7RNQLkWsfi5VcCNDW6EIiw,503
|
|
14
15
|
rowan/rowan_rdkit/chem_utils.py,sha256=ZWdLziT59Qr5JzjvV789CAyRq0m5JIawsOP4RxUbQQA,35529
|
|
15
|
-
rowan/workflows/__init__.py,sha256=
|
|
16
|
+
rowan/workflows/__init__.py,sha256=CM3GKDTafp6vl79dWqSOvkVfwH1Ty8zuc8yzi65ABxM,4438
|
|
16
17
|
rowan/workflows/admet.py,sha256=0_wIwXXLfHF-3kgGx_1EM1ljjaYHLeEijJ-GbMYxpL8,2904
|
|
17
18
|
rowan/workflows/analogue_docking.py,sha256=LJpbbaug0tZ9Cg-m0b7EgGH5hJ5894fHOC16Wefx7mE,9206
|
|
18
|
-
rowan/workflows/base.py,sha256=
|
|
19
|
+
rowan/workflows/base.py,sha256=AyV4ZBta4vz0eiOCi9mcDPTbh-30x-11lfKKwcRJdQw,30330
|
|
19
20
|
rowan/workflows/basic_calculation.py,sha256=FKYczKpYaGE-koaHKi2VARmV9Nhqr0lTOx0Jv1RzC7k,10835
|
|
20
21
|
rowan/workflows/batch_docking.py,sha256=u_4hH7OeWkIbXqEm4uWTc3p0u9mpnR8EWqWCw7sVya4,3581
|
|
21
|
-
rowan/workflows/bde.py,sha256=
|
|
22
|
-
rowan/workflows/conformer_search.py,sha256=
|
|
22
|
+
rowan/workflows/bde.py,sha256=JJUx2wFJ8yZu0sqIn7Jkm6B6O84WrrpAstCck8c7FLI,5621
|
|
23
|
+
rowan/workflows/conformer_search.py,sha256=rzarx3PKRM2rf9x1F17Jg8ZCed7_3-yEBan4g0b2HK4,9868
|
|
23
24
|
rowan/workflows/constants.py,sha256=el8jWE9gnGTLNWn5_n_V0H362vIRneOqgy7BOQ8CScg,575
|
|
24
25
|
rowan/workflows/descriptors.py,sha256=rGrNca6kA4SzX5BAOjP6rE91MOLTvCWSYKF_LW2Z0y4,2963
|
|
25
26
|
rowan/workflows/docking.py,sha256=wmE7QJu1uDHBDynTT1XesXXAZtpB6xLjZUKsHOQyCcU,7386
|
|
26
27
|
rowan/workflows/double_ended_ts_search.py,sha256=abBblMkshhbzq5UTwIf-ovNFxY8Ltp2O-bGu_plkI58,7806
|
|
27
|
-
rowan/workflows/electronic_properties.py,sha256=
|
|
28
|
+
rowan/workflows/electronic_properties.py,sha256=ia4mlmgnioEuLDrcgDuxAyyI6VqRkdxBqshjb9uiEI8,8385
|
|
28
29
|
rowan/workflows/fukui.py,sha256=wLimH3QmorSpvkovRPlI91VuxHG4J91F2EcLYqg3eP0,5112
|
|
29
30
|
rowan/workflows/hydrogen_bond_donor_acceptor_strength.py,sha256=WWiEK_GlumIEgTTOaqw-Y5gPDkRkaePWcIjTdIocrPc,4916
|
|
30
31
|
rowan/workflows/interaction_energy_decomposition.py,sha256=Kjwkb-pviFSFIIZNjMb9i8nAkdKrbjFftmG_lkYtE40,6120
|
|
@@ -33,24 +34,24 @@ rowan/workflows/irc.py,sha256=BH6s0rJEQ3G5yN5mOOSGfiZCf-i6YZNUgtK2-m-gmdo,7491
|
|
|
33
34
|
rowan/workflows/macropka.py,sha256=YkXoPiyou6nAoBheES0endsqNdi_kclwlIscTljNuKI,5723
|
|
34
35
|
rowan/workflows/membrane_permeability.py,sha256=oIDmB8qF_K_Kesv7o_FiljAk4dpptEeOjoxtMvl1gSw,4612
|
|
35
36
|
rowan/workflows/msa.py,sha256=V3B1SyWPR8MT306hh9W-T9JTpi_E-XgAIeF9yRQZ7tI,5075
|
|
36
|
-
rowan/workflows/multistage_optimization.py,sha256=
|
|
37
|
+
rowan/workflows/multistage_optimization.py,sha256=9PbLHOXtM2TLCVl_ZY7JH6QCUudHWTn4R14_KsZF-v8,6840
|
|
37
38
|
rowan/workflows/nmr.py,sha256=hergJdsiawKj7iV-jHxDOS03n_EnZcaCIt_ZTl34-JY,5183
|
|
38
39
|
rowan/workflows/pka.py,sha256=TCFSE5HI5JLPslKdbUvJe4IxrVaLExrI_3PnDfXtxTw,8691
|
|
39
40
|
rowan/workflows/pocket_detection.py,sha256=aGHY0puxekp4c4nsNYHcvKCe1fsetygL04BcSvNFvE8,3864
|
|
40
41
|
rowan/workflows/pose_analysis_md.py,sha256=UvotLhWv0_VAkKteZboOutDry7l-Zt1K6_SBx3EXqgM,9530
|
|
41
42
|
rowan/workflows/protein_binder_design.py,sha256=J-9NSbRLdHb6JQRhY_vq43HlHCDCiQqrkOZUCAF-2dk,8604
|
|
42
|
-
rowan/workflows/protein_cofolding.py,sha256=
|
|
43
|
+
rowan/workflows/protein_cofolding.py,sha256=D2PVwL51H3traml1JDG-9jU3R0E29AdfR9Bk0tLX1Zw,14093
|
|
43
44
|
rowan/workflows/protein_md.py,sha256=_n0IdmTQsunbP1geF-wUjXNMKNYV-ngmAPEMJlj0dkI,7021
|
|
44
45
|
rowan/workflows/rbfe_graph.py,sha256=PLqzBRkxD7tPdBViYJZjgaCP8aA2UXKc9dD4odx5XUo,5788
|
|
45
|
-
rowan/workflows/redox_potential.py,sha256=
|
|
46
|
+
rowan/workflows/redox_potential.py,sha256=SBV1n6RXh4_vVVaEFpJx3iru_3UAOwDNgqOi8K6eHkU,5382
|
|
46
47
|
rowan/workflows/relative_binding_free_energy_perturbation.py,sha256=uxC3Rr63U6GjNa9u2Hurahu48l4rYEz5RQX4hV0D250,13456
|
|
47
48
|
rowan/workflows/scan.py,sha256=KQm58utOxs6qIpX1Jv3usoUpkVHeLw4mKCs8RTUkRhk,5696
|
|
48
49
|
rowan/workflows/solubility.py,sha256=9-zHEHkf4AgGNDCE3x1S-6wTgwxVm4ihRmh0kwLvPFs,8594
|
|
49
50
|
rowan/workflows/solvent_dependent_conformers.py,sha256=ovvnhCE4xlkpdhccLHEq7oBJRI2-rHmZ-7_ewGECerM,7020
|
|
50
|
-
rowan/workflows/spin_states.py,sha256=
|
|
51
|
-
rowan/workflows/strain.py,sha256=
|
|
51
|
+
rowan/workflows/spin_states.py,sha256=c0y2cwO9NE8DmxmQ9ZouA5QoBhxgZiTYFIqhC-geVAo,7382
|
|
52
|
+
rowan/workflows/strain.py,sha256=tb6PGng8B4wSDl4a_MWd0P-cdlSTRpT410VgOJAqXHQ,6393
|
|
52
53
|
rowan/workflows/tautomer_search.py,sha256=aqwXoj0ffWsb5gbvzfz_bpx5ifIfR_K07fbdWhU62Ko,5820
|
|
53
|
-
rowan_python-3.0.
|
|
54
|
-
rowan_python-3.0.
|
|
55
|
-
rowan_python-3.0.
|
|
56
|
-
rowan_python-3.0.
|
|
54
|
+
rowan_python-3.0.9.dist-info/METADATA,sha256=IdBYpQWGOhztIvdM5El7LpplQu9kzzF46ATGkgPIJMc,1600
|
|
55
|
+
rowan_python-3.0.9.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
56
|
+
rowan_python-3.0.9.dist-info/licenses/LICENSE,sha256=i05z7xEhyrg6f8j0lR3XYjShnF-MJGFQ-DnpsZ8yiVI,1084
|
|
57
|
+
rowan_python-3.0.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|