rowan-python 2.1.11__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 +9 -0
- rowan/constants.py +3 -0
- rowan/folder.py +228 -0
- rowan/project.py +136 -0
- rowan/protein.py +245 -0
- rowan/py.typed +0 -0
- rowan/rowan_rdkit/__init__.py +29 -0
- rowan/rowan_rdkit/chem_utils.py +1012 -0
- rowan/user.py +137 -0
- rowan/utils.py +174 -0
- rowan/workflow.py +1608 -0
- rowan_python-2.1.11.dist-info/METADATA +41 -0
- rowan_python-2.1.11.dist-info/RECORD +15 -0
- rowan_python-2.1.11.dist-info/WHEEL +4 -0
- rowan_python-2.1.11.dist-info/licenses/LICENSE +21 -0
rowan/workflow.py
ADDED
|
@@ -0,0 +1,1608 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, Literal, Self, TypeAlias
|
|
6
|
+
|
|
7
|
+
import stjames
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
from rdkit import Chem
|
|
10
|
+
from stjames.optimization.freezing_string_method import FSMSettings
|
|
11
|
+
|
|
12
|
+
from .protein import Protein
|
|
13
|
+
from .utils import api_client
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
logger.setLevel(logging.INFO)
|
|
17
|
+
|
|
18
|
+
RdkitMol: TypeAlias = Chem.rdchem.Mol | Chem.rdchem.RWMol
|
|
19
|
+
StJamesMolecule: TypeAlias = stjames.Molecule
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Workflow(BaseModel):
|
|
23
|
+
"""A Rowan workflow.
|
|
24
|
+
|
|
25
|
+
Don’t instantiate this class directly. Instead use one of the submit workflow functions.
|
|
26
|
+
Workflow data is not loaded by default to avoid unnecessary downloads that could impact
|
|
27
|
+
performance. Call `load_data()` to fetch and attach the workflow data to this `Workflow` object.
|
|
28
|
+
|
|
29
|
+
:ivar name: The name of the workflow.
|
|
30
|
+
:var uuid: The UUID of the workflow.
|
|
31
|
+
:var created_at: The date and time the workflow was created.
|
|
32
|
+
:var updated_at: The date and time the workflow was last updated.
|
|
33
|
+
:var started_at: The date and time the workflow computation was started.
|
|
34
|
+
:var completed_at: The date and time the workflow was completed.
|
|
35
|
+
:var status: The status of the workflow.
|
|
36
|
+
:var parent_uuid: The UUID of the parent folder.
|
|
37
|
+
:var notes: Workflow notes.
|
|
38
|
+
:var starred: Whether the workflow is starred.
|
|
39
|
+
:var public: Whether the workflow is public.
|
|
40
|
+
:var workflow_type: The type of the workflow.
|
|
41
|
+
:var data: The data of the workflow.
|
|
42
|
+
:var email_when_complete: Whether the workflow should send an email when it is complete.
|
|
43
|
+
:var max_credits: The maximum number of credits to use for the workflow.
|
|
44
|
+
:var elapsed: The elapsed time of the workflow.
|
|
45
|
+
:var credits_charged: The number of credits charged for the workflow.
|
|
46
|
+
:var logfile: The workflow's logfile.
|
|
47
|
+
...
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
name: str
|
|
51
|
+
uuid: str
|
|
52
|
+
created_at: datetime
|
|
53
|
+
updated_at: datetime | None = None
|
|
54
|
+
started_at: datetime | None = None
|
|
55
|
+
completed_at: datetime | None = None
|
|
56
|
+
status: stjames.Status = Field(alias="object_status")
|
|
57
|
+
parent_uuid: str
|
|
58
|
+
notes: str
|
|
59
|
+
starred: bool
|
|
60
|
+
public: bool
|
|
61
|
+
workflow_type: str = Field(alias="object_type")
|
|
62
|
+
data: dict[str, Any] | None = Field(default=None, alias="object_data")
|
|
63
|
+
email_when_complete: bool
|
|
64
|
+
max_credits: int | None = None
|
|
65
|
+
elapsed: float | None = None
|
|
66
|
+
credits_charged: float
|
|
67
|
+
logfile: str = Field(alias="object_logfile")
|
|
68
|
+
|
|
69
|
+
class Config: # noqa: D106
|
|
70
|
+
validate_by_name = True
|
|
71
|
+
|
|
72
|
+
def __repr__(self) -> str:
|
|
73
|
+
return f"<Workflow name='{self.name}' created_at='{self.created_at}' uuid='{self.uuid}'>"
|
|
74
|
+
|
|
75
|
+
def fetch_latest(self, in_place: bool = False) -> Self:
|
|
76
|
+
"""
|
|
77
|
+
Loads workflow data from the database and updates the current instance.
|
|
78
|
+
|
|
79
|
+
:param in_place: Whether to update the current instance in-place.
|
|
80
|
+
:return: The updated instance (self).
|
|
81
|
+
:raises HTTPError: If the API request fails.
|
|
82
|
+
"""
|
|
83
|
+
with api_client() as client:
|
|
84
|
+
response = client.get(f"/workflow/{self.uuid}")
|
|
85
|
+
response.raise_for_status()
|
|
86
|
+
data = response.json()
|
|
87
|
+
|
|
88
|
+
if not in_place:
|
|
89
|
+
return self.__class__.model_validate(data)
|
|
90
|
+
|
|
91
|
+
# Create a new instance with proper field mapping
|
|
92
|
+
updated_workflow = self.model_validate(data)
|
|
93
|
+
|
|
94
|
+
# Update current instance with new data using class-level model_fields
|
|
95
|
+
for field_name in self.__class__.model_fields:
|
|
96
|
+
setattr(self, field_name, getattr(updated_workflow, field_name))
|
|
97
|
+
|
|
98
|
+
self.model_rebuild()
|
|
99
|
+
|
|
100
|
+
return self
|
|
101
|
+
|
|
102
|
+
def update(
|
|
103
|
+
self,
|
|
104
|
+
name: str | None = None,
|
|
105
|
+
parent_uuid: str | None = None,
|
|
106
|
+
notes: str | None = None,
|
|
107
|
+
starred: bool | None = None,
|
|
108
|
+
email_when_complete: bool | None = None,
|
|
109
|
+
public: bool | None = None,
|
|
110
|
+
in_place: bool = False,
|
|
111
|
+
) -> Self:
|
|
112
|
+
"""
|
|
113
|
+
Updates a workflow in the API with new data.
|
|
114
|
+
|
|
115
|
+
:param name: The new name of the workflow.
|
|
116
|
+
:param parent_uuid: The UUID of the parent folder.
|
|
117
|
+
:param notes: A description of the workflow.
|
|
118
|
+
:param starred: Whether the workflow is starred.
|
|
119
|
+
:param email_when_complete: Whether the workflow should send an email when it is complete.
|
|
120
|
+
:param public: Whether the workflow is public.
|
|
121
|
+
:raises HTTPError: If the API request fails.
|
|
122
|
+
"""
|
|
123
|
+
old_data = self.fetch_latest()
|
|
124
|
+
|
|
125
|
+
new_data = {
|
|
126
|
+
"name": name if name is not None else old_data.name,
|
|
127
|
+
"parent_uuid": parent_uuid if parent_uuid is not None else old_data.parent_uuid,
|
|
128
|
+
"notes": notes if notes is not None else old_data.notes,
|
|
129
|
+
"starred": starred if starred is not None else old_data.starred,
|
|
130
|
+
"email_when_complete": email_when_complete
|
|
131
|
+
if email_when_complete is not None
|
|
132
|
+
else old_data.email_when_complete,
|
|
133
|
+
"public": public if public is not None else old_data.public,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
with api_client() as client:
|
|
137
|
+
response = client.post(f"/workflow/{self.uuid}", json=new_data)
|
|
138
|
+
response.raise_for_status()
|
|
139
|
+
data = response.json()
|
|
140
|
+
|
|
141
|
+
if not in_place:
|
|
142
|
+
return self.__class__.model_validate(data)
|
|
143
|
+
|
|
144
|
+
updated_workflow = self.model_validate(data)
|
|
145
|
+
|
|
146
|
+
for field_name in self.__class__.model_fields:
|
|
147
|
+
setattr(self, field_name, getattr(updated_workflow, field_name))
|
|
148
|
+
|
|
149
|
+
self.model_rebuild()
|
|
150
|
+
|
|
151
|
+
return self
|
|
152
|
+
|
|
153
|
+
def wait_for_result(self, poll_interval: int = 5) -> Self:
|
|
154
|
+
"""
|
|
155
|
+
Wait for the workflow to finish.
|
|
156
|
+
|
|
157
|
+
This method will block until the workflow has finished computing. It
|
|
158
|
+
will periodically poll the API to check the status of the workflow.
|
|
159
|
+
|
|
160
|
+
:return: The current instance, with the workflow data loaded.
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
if poll_interval <= 0:
|
|
164
|
+
raise ValueError("poll_interval must be a positive integer")
|
|
165
|
+
|
|
166
|
+
while not self.is_finished():
|
|
167
|
+
time.sleep(poll_interval)
|
|
168
|
+
return self
|
|
169
|
+
|
|
170
|
+
def get_status(self) -> stjames.Status:
|
|
171
|
+
"""
|
|
172
|
+
Gets the status of the workflow.
|
|
173
|
+
|
|
174
|
+
:return: The status of the workflow, as an instance of stjames.Status.
|
|
175
|
+
"""
|
|
176
|
+
return self.fetch_latest().status or stjames.Status.QUEUED
|
|
177
|
+
|
|
178
|
+
def is_finished(self) -> bool:
|
|
179
|
+
"""
|
|
180
|
+
Check if the workflow is finished.
|
|
181
|
+
|
|
182
|
+
This method checks the current status of the workflow and determines if it has completed,
|
|
183
|
+
failed, or been stopped.
|
|
184
|
+
|
|
185
|
+
:return: True if the workflow status is COMPLETED_OK, FAILED, or STOPPED; False otherwise.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
status = self.get_status()
|
|
189
|
+
|
|
190
|
+
return status in {
|
|
191
|
+
stjames.Status.COMPLETED_OK,
|
|
192
|
+
stjames.Status.FAILED,
|
|
193
|
+
stjames.Status.STOPPED,
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
def stop(self) -> None:
|
|
197
|
+
"""
|
|
198
|
+
Stops a workflow.
|
|
199
|
+
|
|
200
|
+
:raises HTTPError: If the API request fails.
|
|
201
|
+
"""
|
|
202
|
+
with api_client() as client:
|
|
203
|
+
response = client.post(f"/workflow/{self.uuid}/stop")
|
|
204
|
+
response.raise_for_status()
|
|
205
|
+
|
|
206
|
+
def delete(self) -> None:
|
|
207
|
+
"""
|
|
208
|
+
Deletes the workflow.
|
|
209
|
+
|
|
210
|
+
:raises HTTPError: If the API request fails.
|
|
211
|
+
"""
|
|
212
|
+
with api_client() as client:
|
|
213
|
+
response = client.delete(f"/workflow/{self.uuid}")
|
|
214
|
+
response.raise_for_status()
|
|
215
|
+
|
|
216
|
+
def delete_data(self) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Deletes the workflow data from the API.
|
|
219
|
+
|
|
220
|
+
:raises HTTPError: If the API request fails.
|
|
221
|
+
"""
|
|
222
|
+
with api_client() as client:
|
|
223
|
+
response = client.delete(f"/workflow/{self.uuid}/delete_workflow_data")
|
|
224
|
+
response.raise_for_status()
|
|
225
|
+
|
|
226
|
+
def download_msa_files(self, msa_format: stjames.MSAFormat, path: Path | None = None) -> None:
|
|
227
|
+
if self.workflow_type != "msa":
|
|
228
|
+
raise ValueError("This workflow is not an MSA workflow.")
|
|
229
|
+
|
|
230
|
+
if path is None:
|
|
231
|
+
path = Path.cwd()
|
|
232
|
+
|
|
233
|
+
if not path.exists():
|
|
234
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
235
|
+
|
|
236
|
+
with api_client() as client:
|
|
237
|
+
response = client.get(
|
|
238
|
+
f"/workflow/{self.uuid}/get_msa_files", params={"msa_format": msa_format.value}
|
|
239
|
+
)
|
|
240
|
+
response.raise_for_status()
|
|
241
|
+
|
|
242
|
+
with open(path / f"{self.name}-msa.tar.gz", "wb") as f:
|
|
243
|
+
f.write(response.content)
|
|
244
|
+
|
|
245
|
+
def download_dcd_files(self, replicates: list[int],
|
|
246
|
+
name: str | None = None, path: Path | None = None) -> None:
|
|
247
|
+
"""
|
|
248
|
+
Downloads DCD trajectory files for specified replicates
|
|
249
|
+
|
|
250
|
+
:param replicates: List of replicate indices to download
|
|
251
|
+
:param name: Optional custom name for the tar.gz file (defaults to workflow name)
|
|
252
|
+
:param path: Directory to save the file to (defaults to current directory)
|
|
253
|
+
:raises ValueError: if workflow is not a pose analysis MD workflow
|
|
254
|
+
:raises requests.HTTPError: if the request to the API fails
|
|
255
|
+
"""
|
|
256
|
+
if self.workflow_type != "pose_analysis_md":
|
|
257
|
+
raise ValueError("This workflow is not a pose analysis molecular dynamics workflow.")
|
|
258
|
+
|
|
259
|
+
if path is None:
|
|
260
|
+
path = Path.cwd()
|
|
261
|
+
|
|
262
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
263
|
+
|
|
264
|
+
with api_client() as client:
|
|
265
|
+
response = client.post(
|
|
266
|
+
f"/trajectory/{self.uuid}/trajectory_dcds", json=replicates
|
|
267
|
+
)
|
|
268
|
+
response.raise_for_status()
|
|
269
|
+
|
|
270
|
+
file_path = path / f"{name or self.name}.tar.gz"
|
|
271
|
+
with open(file_path, "wb") as f:
|
|
272
|
+
f.write(response.content)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def submit_workflow(
|
|
276
|
+
workflow_type: stjames.WORKFLOW_NAME,
|
|
277
|
+
workflow_data: dict[str, Any] | None = None,
|
|
278
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol | None = None,
|
|
279
|
+
initial_smiles: str | None = None,
|
|
280
|
+
name: str | None = None,
|
|
281
|
+
folder_uuid: str | None = None,
|
|
282
|
+
max_credits: int | None = None,
|
|
283
|
+
) -> Workflow:
|
|
284
|
+
"""
|
|
285
|
+
Submits a workflow to the API.
|
|
286
|
+
|
|
287
|
+
:param workflow_type: The type of workflow to submit.
|
|
288
|
+
:param workflow_data: A dictionary containing the data required to run the workflow.
|
|
289
|
+
:param initial_molecule: A molecule object to use as the initial molecule in the workflow.
|
|
290
|
+
At least one of a molecule or SMILES must be provided.
|
|
291
|
+
:param initial_smiles: A SMILES string to use as the initial molecule in the workflow.
|
|
292
|
+
At least one of a molecule or SMILES must be provided.
|
|
293
|
+
:param name: A name to give to the workflow.
|
|
294
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
295
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
296
|
+
:return: A Workflow object representing the submitted workflow.
|
|
297
|
+
:raises ValueError: If neither `initial_smiles` nor a valid `initial_molecule` is provided.
|
|
298
|
+
:raises HTTPError: If the API request fails.
|
|
299
|
+
"""
|
|
300
|
+
if workflow_type not in stjames.WORKFLOW_MAPPING:
|
|
301
|
+
raise ValueError(
|
|
302
|
+
"Invalid workflow type. Must be one of:\n " + "\n ".join(stjames.WORKFLOW_MAPPING)
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
data = {
|
|
306
|
+
"name": name,
|
|
307
|
+
"folder_uuid": folder_uuid,
|
|
308
|
+
"workflow_type": workflow_type,
|
|
309
|
+
"workflow_data": workflow_data,
|
|
310
|
+
"max_credits": max_credits,
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if initial_smiles is not None:
|
|
314
|
+
data["initial_smiles"] = initial_smiles
|
|
315
|
+
elif isinstance(initial_molecule, StJamesMolecule):
|
|
316
|
+
data["initial_molecule"] = initial_molecule.model_dump()
|
|
317
|
+
elif isinstance(initial_molecule, dict):
|
|
318
|
+
data["initial_molecule"] = initial_molecule
|
|
319
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
320
|
+
data["initial_molecule"] = StJamesMolecule.from_rdkit(initial_molecule, cid=0).model_dump()
|
|
321
|
+
else:
|
|
322
|
+
raise ValueError("You must provide either `initial_smiles` or a valid `initial_molecule`.")
|
|
323
|
+
|
|
324
|
+
with api_client() as client:
|
|
325
|
+
response = client.post("/workflow", json=data)
|
|
326
|
+
response.raise_for_status()
|
|
327
|
+
return Workflow(**response.json())
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def batch_submit_workflow(
|
|
331
|
+
workflow_type: stjames.WORKFLOW_NAME,
|
|
332
|
+
workflow_data: dict[str, Any] | None = None,
|
|
333
|
+
initial_molecules: list[dict[str, Any] | StJamesMolecule | RdkitMol] | None = None,
|
|
334
|
+
initial_smileses: list[str] | None = None,
|
|
335
|
+
names: list[str] | None = None,
|
|
336
|
+
folder_uuid: str | None = None,
|
|
337
|
+
max_credits: int | None = None,
|
|
338
|
+
) -> list[Workflow]:
|
|
339
|
+
"""
|
|
340
|
+
Submits a batch of workflows to the API. Each workflow will be submitted with the
|
|
341
|
+
same workflow type, workflow data, and folder UUID, but with different initial molecules and/or
|
|
342
|
+
SMILES strings.
|
|
343
|
+
|
|
344
|
+
:param workflow_type: The type of workflow to submit.
|
|
345
|
+
:param workflow_data: A dictionary containing the data required to run the workflow.
|
|
346
|
+
:param initial_molecules: A list of molecule objects to use as the initial molecules in the
|
|
347
|
+
workflows.
|
|
348
|
+
At least one of a molecule or SMILES must be provided.
|
|
349
|
+
:param initial_smileses: A list of SMILES strings to use as the initial molecules in the
|
|
350
|
+
workflows.
|
|
351
|
+
At least one of a molecule or SMILES must be provided.
|
|
352
|
+
:param names: A list of names to give to the workflows.
|
|
353
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
354
|
+
:param max_credits: The maximum number of credits to use for the workflow. This applies per
|
|
355
|
+
workflow, not for the batch.
|
|
356
|
+
:return: A list of Workflow objects representing the submitted workflows.
|
|
357
|
+
:raises ValueError: If neither `initial_smiles` nor a valid `initial_molecule` is provided.
|
|
358
|
+
:raises HTTPError: If the API request fails.
|
|
359
|
+
"""
|
|
360
|
+
if workflow_type not in stjames.WORKFLOW_MAPPING:
|
|
361
|
+
raise ValueError(
|
|
362
|
+
"Invalid workflow type. Must be one of:\n " + "\n ".join(stjames.WORKFLOW_MAPPING)
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
if initial_molecules and initial_smileses:
|
|
366
|
+
raise ValueError(
|
|
367
|
+
"You must provide either `initial_molecules` or `initial_smileses`, but not both."
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
if names:
|
|
371
|
+
if initial_molecules and len(names) != len(initial_molecules):
|
|
372
|
+
logger.warning(
|
|
373
|
+
"The number of names is not the same as the number of initial "
|
|
374
|
+
"molecules. Generic names of the form 'Batch Workflow {i}' "
|
|
375
|
+
"will be used."
|
|
376
|
+
)
|
|
377
|
+
if initial_smileses and len(names) != len(initial_smileses):
|
|
378
|
+
logger.warning(
|
|
379
|
+
"The number of names is not the same as the number of initial SMILES."
|
|
380
|
+
"Generic names of the form 'Batch Workflow {i}' will be used."
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
data = {
|
|
384
|
+
"names": names,
|
|
385
|
+
"folder_uuid": folder_uuid,
|
|
386
|
+
"workflow_type": workflow_type,
|
|
387
|
+
"workflow_data": workflow_data,
|
|
388
|
+
"max_credits": max_credits,
|
|
389
|
+
"initial_molecules": initial_molecules,
|
|
390
|
+
"initial_smileses": initial_smileses,
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
with api_client() as client:
|
|
394
|
+
response = client.post("/workflow/batch_submit", json=data)
|
|
395
|
+
response.raise_for_status()
|
|
396
|
+
return [Workflow(**workflow_data) for workflow_data in response.json()]
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def retrieve_workflow(uuid: str) -> Workflow:
|
|
400
|
+
"""
|
|
401
|
+
Retrieves a workflow from the API.
|
|
402
|
+
|
|
403
|
+
:param uuid: The UUID of the workflow to retrieve.
|
|
404
|
+
:return: A Workflow object representing the retrieved workflow.
|
|
405
|
+
:raises HTTPError: If the API request fails.
|
|
406
|
+
"""
|
|
407
|
+
with api_client() as client:
|
|
408
|
+
response = client.get(f"/workflow/{uuid}")
|
|
409
|
+
response.raise_for_status()
|
|
410
|
+
return Workflow(**response.json())
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def retrieve_workflows(uuids: list[str]) -> list[Workflow]:
|
|
414
|
+
"""
|
|
415
|
+
Retrieves a list of workflows from the API.
|
|
416
|
+
|
|
417
|
+
:param uuids: The UUIDs of the workflows to retrieve.
|
|
418
|
+
:return: A list of Workflow objects representing the retrieved workflows.
|
|
419
|
+
:raises HTTPError: If the API request fails.
|
|
420
|
+
"""
|
|
421
|
+
with api_client() as client:
|
|
422
|
+
response = client.post("/workflow/batch_retrieve", json={"uuids": uuids})
|
|
423
|
+
response.raise_for_status()
|
|
424
|
+
return [Workflow(**workflow_data) for workflow_data in response.json()]
|
|
425
|
+
|
|
426
|
+
def batch_poll_status(uuids: list[str]) -> list[Workflow]:
|
|
427
|
+
"""
|
|
428
|
+
Polls the status of a list of workflows.
|
|
429
|
+
|
|
430
|
+
:param uuids: The UUIDs of the workflows to poll.
|
|
431
|
+
:return: A dictionary of statuses and the count of workflows in that status.
|
|
432
|
+
:raises HTTPError: If the API request fails.
|
|
433
|
+
"""
|
|
434
|
+
with api_client() as client:
|
|
435
|
+
response = client.post("/workflow/batch_status", json={"uuids": uuids})
|
|
436
|
+
response.raise_for_status()
|
|
437
|
+
return response.json()
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def retrieve_calculation_molecules(
|
|
441
|
+
uuid: str, return_frequencies: bool = False
|
|
442
|
+
) -> list[dict[str, Any]]:
|
|
443
|
+
"""
|
|
444
|
+
Retrieves a list of molecules from a calculation.
|
|
445
|
+
|
|
446
|
+
:param uuid: The UUID of the calculation to retrieve molecules from.
|
|
447
|
+
:param return_frequencies: Whether to return the frequencies of the molecules.
|
|
448
|
+
:return: A list of dictionaries representing the molecules in the calculation.
|
|
449
|
+
:raises HTTPError: If the API request fails.
|
|
450
|
+
"""
|
|
451
|
+
with api_client() as client:
|
|
452
|
+
response = client.get(
|
|
453
|
+
f"/calculation/{uuid}/molecules", params={"return_frequencies": return_frequencies}
|
|
454
|
+
)
|
|
455
|
+
response.raise_for_status()
|
|
456
|
+
return response.json()
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def list_workflows(
|
|
460
|
+
parent_uuid: str | None = None,
|
|
461
|
+
name_contains: str | None = None,
|
|
462
|
+
public: bool | None = None,
|
|
463
|
+
starred: bool | None = None,
|
|
464
|
+
status: int | None = None,
|
|
465
|
+
workflow_type: stjames.WORKFLOW_NAME | None = None,
|
|
466
|
+
page: int = 0,
|
|
467
|
+
size: int = 10,
|
|
468
|
+
) -> list[Workflow]:
|
|
469
|
+
"""
|
|
470
|
+
Lists workflows subject to the specified criteria.
|
|
471
|
+
|
|
472
|
+
:param parent_uuid: The UUID of the parent folder.
|
|
473
|
+
:param name_contains: Substring to search for in workflow names.
|
|
474
|
+
:param public: Filter workflows by their public status.
|
|
475
|
+
:param starred: Filter workflows by their starred status.
|
|
476
|
+
:param status: Filter workflows by their status.
|
|
477
|
+
:param workflow_type: Filter workflows by their type.
|
|
478
|
+
:param page: The page number to retrieve.
|
|
479
|
+
:param size: The number of items per page.
|
|
480
|
+
:return: A list of Workflow objects that match the search criteria.
|
|
481
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
482
|
+
"""
|
|
483
|
+
params: dict[str, Any] = {"page": page, "size": size}
|
|
484
|
+
|
|
485
|
+
if parent_uuid is not None:
|
|
486
|
+
params["parent_uuid"] = parent_uuid
|
|
487
|
+
|
|
488
|
+
if name_contains is not None:
|
|
489
|
+
params["name_contains"] = name_contains
|
|
490
|
+
|
|
491
|
+
if public is not None:
|
|
492
|
+
params["public"] = public
|
|
493
|
+
|
|
494
|
+
if starred is not None:
|
|
495
|
+
params["starred"] = starred
|
|
496
|
+
|
|
497
|
+
if status is not None:
|
|
498
|
+
params["object_status"] = status
|
|
499
|
+
|
|
500
|
+
if workflow_type is not None:
|
|
501
|
+
params["object_type"] = workflow_type
|
|
502
|
+
|
|
503
|
+
with api_client() as client:
|
|
504
|
+
response = client.get("/workflow", params=params)
|
|
505
|
+
response.raise_for_status()
|
|
506
|
+
return [Workflow(**item) for item in response.json()["workflows"]]
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def submit_basic_calculation_workflow(
|
|
510
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
511
|
+
method: stjames.Method | str = "uma_m_omol",
|
|
512
|
+
basis_set: stjames.BasisSet | str | None = None,
|
|
513
|
+
tasks: list[str] | None = None,
|
|
514
|
+
mode: str = "auto",
|
|
515
|
+
engine: str | None = None,
|
|
516
|
+
name: str = "Basic Calculation Workflow",
|
|
517
|
+
folder_uuid: str | None = None,
|
|
518
|
+
max_credits: int | None = None,
|
|
519
|
+
) -> Workflow:
|
|
520
|
+
"""
|
|
521
|
+
Submit a basic calculation workflow to the API.
|
|
522
|
+
|
|
523
|
+
:param initial_molecule: The molecule to perform the calculation on.
|
|
524
|
+
:param method: The method to use for the calculation.
|
|
525
|
+
:param basis_set: The basis_set to use (if any).
|
|
526
|
+
for options.
|
|
527
|
+
:param tasks: A list of tasks to perform for the calculation.
|
|
528
|
+
:param mode: The mode to run the calculation in. See [list of available modes](https://github.com/rowansci/stjames-public/blob/master/stjames/mode.py)
|
|
529
|
+
for options.
|
|
530
|
+
:param engine: The engine to use for the calculation. See [list of available engines](https://github.com/rowansci/stjames-public/blob/master/stjames/engine.py)
|
|
531
|
+
:param name: The name of the workflow.
|
|
532
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
533
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
534
|
+
:return: A Workflow object representing the submitted workflow.
|
|
535
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
536
|
+
"""
|
|
537
|
+
if not tasks:
|
|
538
|
+
tasks = ["optimize"]
|
|
539
|
+
|
|
540
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
541
|
+
initial_molecule = initial_molecule.model_dump()
|
|
542
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
543
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
544
|
+
|
|
545
|
+
if isinstance(method, str):
|
|
546
|
+
method = stjames.Method(method)
|
|
547
|
+
|
|
548
|
+
workflow = stjames.BasicCalculationWorkflow(
|
|
549
|
+
initial_molecule=initial_molecule,
|
|
550
|
+
settings=stjames.Settings(
|
|
551
|
+
method=method,
|
|
552
|
+
basis_set=basis_set,
|
|
553
|
+
tasks=tasks,
|
|
554
|
+
mode=mode,
|
|
555
|
+
),
|
|
556
|
+
engine=engine or method.default_engine(),
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
data = {
|
|
560
|
+
"name": name,
|
|
561
|
+
"folder_uuid": folder_uuid,
|
|
562
|
+
"workflow_type": "basic_calculation",
|
|
563
|
+
"workflow_data": workflow.model_dump(),
|
|
564
|
+
"initial_molecule": initial_molecule,
|
|
565
|
+
"max_credits": max_credits,
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
with api_client() as client:
|
|
569
|
+
response = client.post("/workflow", json=data)
|
|
570
|
+
response.raise_for_status()
|
|
571
|
+
return Workflow(**response.json())
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
def submit_conformer_search_workflow(
|
|
575
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
576
|
+
conf_gen_mode: str = "rapid",
|
|
577
|
+
final_method: stjames.Method | str = "aimnet2_wb97md3",
|
|
578
|
+
solvent: str | None = None,
|
|
579
|
+
transition_state: bool = False,
|
|
580
|
+
name: str = "Conformer Search Workflow",
|
|
581
|
+
folder_uuid: str | None = None,
|
|
582
|
+
max_credits: int | None = None,
|
|
583
|
+
) -> Workflow:
|
|
584
|
+
"""
|
|
585
|
+
Submits a conformer search workflow to the API.
|
|
586
|
+
|
|
587
|
+
:param initial_molecule: The molecule to perform the conformer search on.
|
|
588
|
+
:param conf_gen_mode: The mode to use for conformer generation. See
|
|
589
|
+
[list of available modes](https://github.com/rowansci/stjames-public/blob/master/stjames/mode.py)
|
|
590
|
+
for options.
|
|
591
|
+
:param final_method: The method to use for the final optimization.
|
|
592
|
+
See [list of available methods](https://github.com/rowansci/stjames-public/blob/master/stjames/method.py)
|
|
593
|
+
for options.
|
|
594
|
+
:param solvent: The solvent to use for the final optimization. See [the list of available solvents](https://github.com/rowansci/stjames-public/blob/master/stjames/solvent.py)
|
|
595
|
+
for valid values. Be aware that not all methods support solvents.
|
|
596
|
+
:param transition_state: Whether to optimize the transition state.
|
|
597
|
+
:param name: The name of the workflow.
|
|
598
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
599
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
600
|
+
:return: A Workflow object representing the submitted workflow.
|
|
601
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
602
|
+
"""
|
|
603
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
604
|
+
initial_molecule = initial_molecule.model_dump()
|
|
605
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
606
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
607
|
+
|
|
608
|
+
if isinstance(final_method, str):
|
|
609
|
+
final_method = stjames.Method(final_method)
|
|
610
|
+
|
|
611
|
+
solvent_model = None
|
|
612
|
+
if solvent:
|
|
613
|
+
solvent_model = "alpb" if final_method in stjames.XTB_METHODS else "cpcm"
|
|
614
|
+
|
|
615
|
+
opt_settings = stjames.Settings(
|
|
616
|
+
method=final_method,
|
|
617
|
+
tasks=["optimize"],
|
|
618
|
+
mode=stjames.Mode.AUTO,
|
|
619
|
+
solvent_settings={"solvent": solvent, "model": solvent_model} if solvent else None,
|
|
620
|
+
opt_settings={"transition_state": transition_state, "constraints": []},
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
msos = stjames.MultiStageOptSettings(
|
|
624
|
+
mode=stjames.Mode.MANUAL,
|
|
625
|
+
xtb_preopt=True,
|
|
626
|
+
optimization_settings=[opt_settings],
|
|
627
|
+
)
|
|
628
|
+
|
|
629
|
+
workflow = stjames.ConformerSearchWorkflow(
|
|
630
|
+
initial_molecule=initial_molecule,
|
|
631
|
+
multistage_opt_settings=msos,
|
|
632
|
+
conf_gen_mode=conf_gen_mode,
|
|
633
|
+
mso_mode="manual",
|
|
634
|
+
solvent=solvent,
|
|
635
|
+
transition_state=transition_state,
|
|
636
|
+
)
|
|
637
|
+
|
|
638
|
+
data = {
|
|
639
|
+
"name": name,
|
|
640
|
+
"folder_uuid": folder_uuid,
|
|
641
|
+
"workflow_type": "conformer_search",
|
|
642
|
+
"workflow_data": workflow.model_dump(),
|
|
643
|
+
"initial_molecule": initial_molecule,
|
|
644
|
+
"max_credits": max_credits,
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
with api_client() as client:
|
|
648
|
+
response = client.post("/workflow", json=data)
|
|
649
|
+
response.raise_for_status()
|
|
650
|
+
return Workflow(**response.json())
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def submit_solubility_workflow(
|
|
654
|
+
initial_smiles: str,
|
|
655
|
+
solubility_method: Literal["fastsolv", "kingfisher", "esol"] = "fastsolv",
|
|
656
|
+
solvents: list[str] | None = None,
|
|
657
|
+
temperatures: list[float] | None = None,
|
|
658
|
+
name: str = "Solubility Workflow",
|
|
659
|
+
folder_uuid: str | None = None,
|
|
660
|
+
max_credits: int | None = None,
|
|
661
|
+
) -> Workflow:
|
|
662
|
+
"""
|
|
663
|
+
Submits a solubility workflow to the API.
|
|
664
|
+
|
|
665
|
+
:param solubility_method: The name of the desired model for solubility prediction.
|
|
666
|
+
:param initial_smiles: The smiles of the molecule to calculate the solubility of.
|
|
667
|
+
:param solvents: The list of solvents to use for the calculation.
|
|
668
|
+
:param temperatures: The list of temperatures to use for the calculation.
|
|
669
|
+
:param name: The name of the workflow.
|
|
670
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
671
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
672
|
+
:return: A Workflow object representing the submitted workflow.
|
|
673
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
674
|
+
"""
|
|
675
|
+
|
|
676
|
+
if not solvents:
|
|
677
|
+
solvents = ["CCCCCC", "CC1=CC=CC=C1", "C1CCCO1", "CC(=O)OCC", "CCO", "CC#N"]
|
|
678
|
+
|
|
679
|
+
if not temperatures:
|
|
680
|
+
temperatures = [273.15, 298.15, 323.15, 348.15, 373.15]
|
|
681
|
+
|
|
682
|
+
workflow = stjames.SolubilityWorkflow(
|
|
683
|
+
initial_smiles=initial_smiles,
|
|
684
|
+
solubility_method=solubility_method,
|
|
685
|
+
solvents=solvents,
|
|
686
|
+
temperatures=temperatures,
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
data = {
|
|
690
|
+
"name": name,
|
|
691
|
+
"folder_uuid": folder_uuid,
|
|
692
|
+
"workflow_type": "solubility",
|
|
693
|
+
"workflow_data": workflow.model_dump(),
|
|
694
|
+
"initial_smiles": initial_smiles,
|
|
695
|
+
"max_credits": max_credits,
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
with api_client() as client:
|
|
699
|
+
response = client.post("/workflow", json=data)
|
|
700
|
+
response.raise_for_status()
|
|
701
|
+
return Workflow(**response.json())
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
def submit_pka_workflow(
|
|
705
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol | str,
|
|
706
|
+
pka_range: tuple[int, int] = (2, 12),
|
|
707
|
+
method: Literal["aimnet2_wagen2024", "chemprop_nevolianis2025"] = "aimnet2_wagen2024",
|
|
708
|
+
solvent: str = "water",
|
|
709
|
+
deprotonate_elements: list[int] | None = None,
|
|
710
|
+
protonate_elements: list[int] | None = None,
|
|
711
|
+
mode: str = "careful",
|
|
712
|
+
name: str = "pKa Workflow",
|
|
713
|
+
folder_uuid: str | None = None,
|
|
714
|
+
max_credits: int | None = None,
|
|
715
|
+
) -> Workflow:
|
|
716
|
+
"""
|
|
717
|
+
Submits a pKa workflow to the API.
|
|
718
|
+
|
|
719
|
+
:param initial_molecule: The molecule to calculate the pKa of.
|
|
720
|
+
Valid input types include `stjames.Molecule`, RDKit molecule, and SMILES.
|
|
721
|
+
:param pka_range: The range of pKa values to calculate.
|
|
722
|
+
:param method: The algorithm used to compute pKa values.
|
|
723
|
+
:param solvent: The solvent in which pKa values will be computed.
|
|
724
|
+
:param deprotonate_elements: The elements to deprotonate. Given by atomic number.
|
|
725
|
+
:param protonate_elements: The elements to protonate. Given by atomic number.
|
|
726
|
+
:param mode: The mode to run the calculation in. See
|
|
727
|
+
[list of available modes](https://github.com/rowansci/stjames-public/blob/master/stjames/mode.py)
|
|
728
|
+
for options.
|
|
729
|
+
:param name: The name of the workflow.
|
|
730
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
731
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
732
|
+
:return: A Workflow object representing the submitted workflow.
|
|
733
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
734
|
+
"""
|
|
735
|
+
initial_smiles: str = ""
|
|
736
|
+
initial_stjames_mol: StJamesMolecule | None = None
|
|
737
|
+
|
|
738
|
+
if isinstance(initial_molecule, dict):
|
|
739
|
+
initial_stjames_mol = StJamesMolecule.model_validate(initial_molecule)
|
|
740
|
+
elif isinstance(initial_molecule, StJamesMolecule):
|
|
741
|
+
initial_stjames_mol = initial_molecule
|
|
742
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
743
|
+
initial_stjames_mol = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
744
|
+
elif isinstance(initial_molecule, str):
|
|
745
|
+
initial_smiles = initial_molecule
|
|
746
|
+
|
|
747
|
+
protonate_elements = protonate_elements or [7]
|
|
748
|
+
deprotonate_elements = deprotonate_elements or [7, 8, 16]
|
|
749
|
+
|
|
750
|
+
workflow = stjames.pKaWorkflow(
|
|
751
|
+
initial_molecule=initial_stjames_mol,
|
|
752
|
+
initial_smiles=initial_smiles,
|
|
753
|
+
pka_range=pka_range,
|
|
754
|
+
deprotonate_elements=deprotonate_elements,
|
|
755
|
+
protonate_elements=protonate_elements,
|
|
756
|
+
mode=mode,
|
|
757
|
+
solvent=solvent,
|
|
758
|
+
microscopic_pka_method=method,
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
data = {
|
|
762
|
+
"name": name,
|
|
763
|
+
"folder_uuid": folder_uuid,
|
|
764
|
+
"workflow_type": "pka",
|
|
765
|
+
"workflow_data": workflow.model_dump(),
|
|
766
|
+
"initial_molecule": initial_stjames_mol.model_dump() if initial_stjames_mol else None,
|
|
767
|
+
"initial_smiles": initial_smiles,
|
|
768
|
+
"max_credits": max_credits,
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
with api_client() as client:
|
|
772
|
+
response = client.post("/workflow", json=data)
|
|
773
|
+
response.raise_for_status()
|
|
774
|
+
return Workflow(**response.json())
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
def submit_redox_potential_workflow(
|
|
778
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
779
|
+
reduction: bool = False,
|
|
780
|
+
oxidization: bool = True,
|
|
781
|
+
mode: str = "rapid",
|
|
782
|
+
name: str = "Redox Potential Workflow",
|
|
783
|
+
folder_uuid: str | None = None,
|
|
784
|
+
max_credits: int | None = None,
|
|
785
|
+
) -> Workflow:
|
|
786
|
+
"""
|
|
787
|
+
Submits a redox potential workflow to the API.
|
|
788
|
+
|
|
789
|
+
:param initial_molecule: The molecule to calculate the redox potential of.
|
|
790
|
+
:param reduction: Whether to calculate the reduction potential.
|
|
791
|
+
:param oxidization: Whether to calculate the oxidization potential.
|
|
792
|
+
:param mode: The mode to run the calculation in. See
|
|
793
|
+
[list of available modes](https://github.com/rowansci/stjames-public/blob/master/stjames/mode.py)
|
|
794
|
+
for options.
|
|
795
|
+
:param name: The name of the workflow.
|
|
796
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
797
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
798
|
+
:return: A Workflow object representing the submitted workflow.
|
|
799
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
800
|
+
"""
|
|
801
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
802
|
+
initial_molecule = initial_molecule.model_dump()
|
|
803
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
804
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
805
|
+
|
|
806
|
+
workflow = stjames.RedoxPotentialWorkflow(
|
|
807
|
+
initial_molecule=initial_molecule,
|
|
808
|
+
oxidation=oxidization,
|
|
809
|
+
reduction=reduction,
|
|
810
|
+
mode=mode,
|
|
811
|
+
)
|
|
812
|
+
|
|
813
|
+
data = {
|
|
814
|
+
"name": name,
|
|
815
|
+
"folder_uuid": folder_uuid,
|
|
816
|
+
"workflow_type": "redox_potential",
|
|
817
|
+
"workflow_data": workflow.model_dump(),
|
|
818
|
+
"initial_molecule": initial_molecule,
|
|
819
|
+
"max_credits": max_credits,
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
with api_client() as client:
|
|
823
|
+
response = client.post("/workflow", json=data)
|
|
824
|
+
response.raise_for_status()
|
|
825
|
+
return Workflow(**response.json())
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
def submit_fukui_workflow(
|
|
829
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
830
|
+
optimization_method: str = "gfn2_xtb",
|
|
831
|
+
fukui_method: str = "gfn1_xtb",
|
|
832
|
+
solvent_settings: dict[str, str] | None = None,
|
|
833
|
+
name: str = "Fukui Workflow",
|
|
834
|
+
folder_uuid: str | None = None,
|
|
835
|
+
max_credits: int | None = None,
|
|
836
|
+
) -> Workflow:
|
|
837
|
+
"""
|
|
838
|
+
Submits a fukui workflow to the API.
|
|
839
|
+
|
|
840
|
+
:param initial_molecule: The molecule to calculate the fukui indices of.
|
|
841
|
+
:param optimization_method: The method to use for the optimization.
|
|
842
|
+
:param fukui_method: The method to use for the fukui calculation.
|
|
843
|
+
:param solvent_settings: The solvent settings to use for the fukui calculation.
|
|
844
|
+
:param name: The name of the workflow.
|
|
845
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
846
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
847
|
+
:return: A Workflow object representing the submitted workflow.
|
|
848
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
849
|
+
"""
|
|
850
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
851
|
+
initial_molecule = initial_molecule.model_dump()
|
|
852
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
853
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
854
|
+
|
|
855
|
+
optimization_settings = stjames.Settings(method=optimization_method)
|
|
856
|
+
fukui_settings = stjames.Settings(method=fukui_method, solvent_settings=solvent_settings)
|
|
857
|
+
|
|
858
|
+
stjames.FukuiIndexWorkflow(
|
|
859
|
+
initial_molecule=initial_molecule,
|
|
860
|
+
optimization_settings=optimization_settings,
|
|
861
|
+
fukui_settings=fukui_settings,
|
|
862
|
+
)
|
|
863
|
+
|
|
864
|
+
workflow_data = {
|
|
865
|
+
"opt_settings": optimization_settings.model_dump(),
|
|
866
|
+
"opt_engine": stjames.Method(optimization_method).default_engine(),
|
|
867
|
+
"fukui_settings": fukui_settings.model_dump(),
|
|
868
|
+
"fukui_engine": stjames.Method(fukui_method).default_engine(),
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
data = {
|
|
872
|
+
"name": name,
|
|
873
|
+
"folder_uuid": folder_uuid,
|
|
874
|
+
"workflow_type": "fukui",
|
|
875
|
+
"workflow_data": workflow_data,
|
|
876
|
+
"initial_molecule": initial_molecule,
|
|
877
|
+
"max_credits": max_credits,
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
with api_client() as client:
|
|
881
|
+
response = client.post("/workflow", json=data)
|
|
882
|
+
response.raise_for_status()
|
|
883
|
+
return Workflow(**response.json())
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def submit_tautomer_search_workflow(
|
|
887
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
888
|
+
mode: str = "careful",
|
|
889
|
+
name: str = "Tautomer Search Workflow",
|
|
890
|
+
folder_uuid: str | None = None,
|
|
891
|
+
max_credits: int | None = None,
|
|
892
|
+
) -> Workflow:
|
|
893
|
+
"""
|
|
894
|
+
Submits a tautomer search workflow to the API.
|
|
895
|
+
|
|
896
|
+
:param initial_molecule: The molecule to calculate the tautomers of.
|
|
897
|
+
:param mode: The mode to run the calculation in. See
|
|
898
|
+
[list of available modes](https://github.com/rowansci/stjames-public/blob/master/stjames/mode.py)
|
|
899
|
+
for options.
|
|
900
|
+
:param name: The name of the workflow.
|
|
901
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
902
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
903
|
+
:return: A Workflow object representing the submitted workflow.
|
|
904
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
905
|
+
"""
|
|
906
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
907
|
+
initial_molecule = initial_molecule.model_dump()
|
|
908
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
909
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
910
|
+
|
|
911
|
+
workflow = stjames.TautomerWorkflow(
|
|
912
|
+
initial_molecule=initial_molecule,
|
|
913
|
+
mode=mode,
|
|
914
|
+
)
|
|
915
|
+
|
|
916
|
+
data = {
|
|
917
|
+
"name": name,
|
|
918
|
+
"folder_uuid": folder_uuid,
|
|
919
|
+
"workflow_type": "tautomers",
|
|
920
|
+
"workflow_data": workflow.model_dump(),
|
|
921
|
+
"initial_molecule": initial_molecule,
|
|
922
|
+
"max_credits": max_credits,
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
with api_client() as client:
|
|
926
|
+
response = client.post("/workflow", json=data)
|
|
927
|
+
response.raise_for_status()
|
|
928
|
+
return Workflow(**response.json())
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
def submit_descriptors_workflow(
|
|
932
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
933
|
+
name: str = "Descriptors Workflow",
|
|
934
|
+
folder_uuid: str | None = None,
|
|
935
|
+
max_credits: int | None = None,
|
|
936
|
+
) -> Workflow:
|
|
937
|
+
"""
|
|
938
|
+
Submits a descriptors workflow to the API.
|
|
939
|
+
|
|
940
|
+
:param initial_molecule: The molecule to calculate the descriptors of.
|
|
941
|
+
:param name: The name of the workflow.
|
|
942
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
943
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
944
|
+
:return: A Workflow object representing the submitted workflow.
|
|
945
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
946
|
+
"""
|
|
947
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
948
|
+
initial_molecule = initial_molecule.model_dump()
|
|
949
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
950
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
951
|
+
|
|
952
|
+
data = {
|
|
953
|
+
"name": name,
|
|
954
|
+
"folder_uuid": folder_uuid,
|
|
955
|
+
"workflow_type": "descriptors",
|
|
956
|
+
"workflow_data": {},
|
|
957
|
+
"initial_molecule": initial_molecule,
|
|
958
|
+
"max_credits": max_credits,
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
with api_client() as client:
|
|
962
|
+
response = client.post("/workflow", json=data)
|
|
963
|
+
response.raise_for_status()
|
|
964
|
+
return Workflow(**response.json())
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
def submit_scan_workflow(
|
|
968
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
969
|
+
scan_settings: stjames.ScanSettings | dict[str, Any] | None = None,
|
|
970
|
+
calculation_engine: str | None = None,
|
|
971
|
+
calculation_method: stjames.Method | str = "uma_m_omol",
|
|
972
|
+
wavefront_propagation: bool = True,
|
|
973
|
+
name: str = "Scan Workflow",
|
|
974
|
+
folder_uuid: str | None = None,
|
|
975
|
+
max_credits: int | None = None,
|
|
976
|
+
) -> Workflow:
|
|
977
|
+
"""
|
|
978
|
+
Submits a scan workflow to the API.
|
|
979
|
+
|
|
980
|
+
:param initial_molecule: The molecule used in the scan.
|
|
981
|
+
:param scan_settings: The scan settings.
|
|
982
|
+
:param calculation_engine: The engine to use for the calculation. See [list of available engines](https://github.com/rowansci/stjames-public/blob/master/stjames/engine.py)
|
|
983
|
+
:param calculation_method: The method to use for the calculation.
|
|
984
|
+
See [list of available methods](https://github.com/rowansci/stjames-public/blob/master/stjames/method.py)
|
|
985
|
+
for options.
|
|
986
|
+
:param wavefront_propagation: Whether to use wavefront propagation in the scan.
|
|
987
|
+
:param name: The name of the workflow.
|
|
988
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
989
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
990
|
+
:return: A Workflow object representing the submitted workflow.
|
|
991
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
992
|
+
"""
|
|
993
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
994
|
+
initial_molecule = initial_molecule.model_dump()
|
|
995
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
996
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
997
|
+
|
|
998
|
+
if isinstance(calculation_method, str):
|
|
999
|
+
calculation_method = stjames.Method(calculation_method)
|
|
1000
|
+
|
|
1001
|
+
calc_settings = stjames.Settings(
|
|
1002
|
+
method=calculation_method,
|
|
1003
|
+
tasks=["optimize"],
|
|
1004
|
+
corrections=[],
|
|
1005
|
+
mode="auto",
|
|
1006
|
+
opt_settings={"constraints": []},
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
workflow = stjames.ScanWorkflow(
|
|
1010
|
+
initial_molecule=initial_molecule,
|
|
1011
|
+
scan_settings=scan_settings,
|
|
1012
|
+
calc_settings=calc_settings,
|
|
1013
|
+
calc_engine=calculation_engine or calculation_method.default_engine(),
|
|
1014
|
+
wavefront_propagation=wavefront_propagation,
|
|
1015
|
+
)
|
|
1016
|
+
|
|
1017
|
+
data = {
|
|
1018
|
+
"name": name,
|
|
1019
|
+
"folder_uuid": folder_uuid,
|
|
1020
|
+
"workflow_type": "scan",
|
|
1021
|
+
"workflow_data": workflow.model_dump(),
|
|
1022
|
+
"initial_molecule": initial_molecule,
|
|
1023
|
+
"max_credits": max_credits,
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
with api_client() as client:
|
|
1027
|
+
response = client.post("/workflow", json=data)
|
|
1028
|
+
response.raise_for_status()
|
|
1029
|
+
return Workflow(**response.json())
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
def submit_macropka_workflow(
|
|
1033
|
+
initial_smiles: str,
|
|
1034
|
+
min_pH: int = 0,
|
|
1035
|
+
max_pH: int = 14,
|
|
1036
|
+
min_charge: int = -2,
|
|
1037
|
+
max_charge: int = 2,
|
|
1038
|
+
compute_solvation_energy: bool = False,
|
|
1039
|
+
compute_aqueous_solubility: bool = False,
|
|
1040
|
+
name: str = "Macropka Workflow",
|
|
1041
|
+
folder_uuid: str | None = None,
|
|
1042
|
+
max_credits: int | None = None,
|
|
1043
|
+
) -> Workflow:
|
|
1044
|
+
"""
|
|
1045
|
+
Submits a macropka workflow to the API.
|
|
1046
|
+
|
|
1047
|
+
:param initial_smiles: The molecule used in the macropka workflow.
|
|
1048
|
+
:param min_pH: The minimum pH to use in the macropka workflow.
|
|
1049
|
+
:param max_pH: The maximum pH to use in the macropka workflow.
|
|
1050
|
+
:param min_charge: The minimum charge to use in the macropka workflow.
|
|
1051
|
+
:param max_charge: The maximum charge to use in the macropka workflow.
|
|
1052
|
+
:param compute_aqueous_solubility: Whether to compute the aqueous solubility for each pH.
|
|
1053
|
+
:param compute_solvation_energy: Whether to compute the solvation energy.
|
|
1054
|
+
:param name: The name of the workflow.
|
|
1055
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
1056
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1057
|
+
:return: A Workflow object representing the submitted workflow.
|
|
1058
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1059
|
+
"""
|
|
1060
|
+
|
|
1061
|
+
workflow = stjames.MacropKaWorkflow(
|
|
1062
|
+
initial_smiles=initial_smiles,
|
|
1063
|
+
min_pH=min_pH,
|
|
1064
|
+
max_pH=max_pH,
|
|
1065
|
+
min_charge=min_charge,
|
|
1066
|
+
max_charge=max_charge,
|
|
1067
|
+
compute_solvation_energy=compute_solvation_energy,
|
|
1068
|
+
compute_aqueous_solubility=compute_aqueous_solubility,
|
|
1069
|
+
)
|
|
1070
|
+
|
|
1071
|
+
data = {
|
|
1072
|
+
"name": name,
|
|
1073
|
+
"folder_uuid": folder_uuid,
|
|
1074
|
+
"workflow_type": "macropka",
|
|
1075
|
+
"workflow_data": workflow.model_dump(),
|
|
1076
|
+
"initial_smiles": initial_smiles,
|
|
1077
|
+
"max_credits": max_credits,
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
with api_client() as client:
|
|
1081
|
+
response = client.post("/workflow", json=data)
|
|
1082
|
+
response.raise_for_status()
|
|
1083
|
+
return Workflow(**response.json())
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
def submit_irc_workflow(
|
|
1087
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol | None = None,
|
|
1088
|
+
method: stjames.Method | str = "uma_m_omol",
|
|
1089
|
+
preopt: bool = True,
|
|
1090
|
+
step_size: float = 0.05,
|
|
1091
|
+
max_irc_steps: int = 30,
|
|
1092
|
+
name: str = "IRC Workflow",
|
|
1093
|
+
folder_uuid: str | None = None,
|
|
1094
|
+
max_credits: int | None = None,
|
|
1095
|
+
) -> Workflow:
|
|
1096
|
+
"""
|
|
1097
|
+
Submits an Intrinsic Reaction Coordinate (IRC) workflow to the API.
|
|
1098
|
+
|
|
1099
|
+
:param initial_molecule: The initial molecule to perform the IRC calculation on.
|
|
1100
|
+
:param method: The computational method to use for the IRC calculation.
|
|
1101
|
+
See [list of available methods](https://github.com/rowansci/stjames-public/blob/master/stjames/method.py)
|
|
1102
|
+
for options.
|
|
1103
|
+
:param preopt: Whether to perform a pre-optimization of the molecule.
|
|
1104
|
+
:param step_size: The step size to use for the IRC calculation.
|
|
1105
|
+
:param max_irc_steps: The maximum number of IRC steps to perform.
|
|
1106
|
+
:param name: The name of the workflow.
|
|
1107
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
1108
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1109
|
+
:return: A Workflow object representing the submitted IRC workflow.
|
|
1110
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1111
|
+
"""
|
|
1112
|
+
|
|
1113
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
1114
|
+
initial_molecule = initial_molecule.model_dump()
|
|
1115
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
1116
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
1117
|
+
|
|
1118
|
+
if isinstance(method, str):
|
|
1119
|
+
method = stjames.Method(method)
|
|
1120
|
+
|
|
1121
|
+
workflow = stjames.IRCWorkflow(
|
|
1122
|
+
initial_molecule=initial_molecule,
|
|
1123
|
+
settings=stjames.Settings(
|
|
1124
|
+
method=method,
|
|
1125
|
+
tasks=[],
|
|
1126
|
+
corrections=[],
|
|
1127
|
+
mode="auto",
|
|
1128
|
+
),
|
|
1129
|
+
preopt=preopt,
|
|
1130
|
+
step_size=step_size,
|
|
1131
|
+
max_irc_steps=max_irc_steps,
|
|
1132
|
+
mode="manual",
|
|
1133
|
+
)
|
|
1134
|
+
|
|
1135
|
+
data = {
|
|
1136
|
+
"name": name,
|
|
1137
|
+
"folder_uuid": folder_uuid,
|
|
1138
|
+
"workflow_type": "irc",
|
|
1139
|
+
"workflow_data": workflow.model_dump(),
|
|
1140
|
+
"initial_molecule": initial_molecule,
|
|
1141
|
+
"max_credits": max_credits,
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
with api_client() as client:
|
|
1145
|
+
response = client.post("/workflow", json=data)
|
|
1146
|
+
response.raise_for_status()
|
|
1147
|
+
return Workflow(**response.json())
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
def submit_protein_cofolding_workflow(
|
|
1151
|
+
initial_protein_sequences: list[str],
|
|
1152
|
+
initial_smiles_list: list[str] | None = None,
|
|
1153
|
+
ligand_binding_affinity_index: int | None = None,
|
|
1154
|
+
use_msa_server: bool = True,
|
|
1155
|
+
use_potentials: bool = False,
|
|
1156
|
+
compute_strain: bool = False,
|
|
1157
|
+
do_pose_refinement: bool = False,
|
|
1158
|
+
name: str = "Cofolding Workflow",
|
|
1159
|
+
model: str = stjames.CofoldingModel.BOLTZ_2.value,
|
|
1160
|
+
folder_uuid: str | None = None,
|
|
1161
|
+
max_credits: int | None = None,
|
|
1162
|
+
) -> Workflow:
|
|
1163
|
+
"""
|
|
1164
|
+
Submits a protein cofolding workflow to the API.
|
|
1165
|
+
|
|
1166
|
+
:param initial_protein_sequences: The sequences of the proteins to be cofolded.
|
|
1167
|
+
:param initial_smiles_list: A list of SMILES strings for the ligands to be cofolded with.
|
|
1168
|
+
:param ligand_binding_affinity_index: The index of the ligand for which to compute the binding affinity.
|
|
1169
|
+
:param use_msa_server: Whether to use the MSA server for the computation.
|
|
1170
|
+
:param use_potentials: Whether to use potentials for the computation.
|
|
1171
|
+
:param do_pose_refinement: whether to optimize non-rotatable bonds in output poses
|
|
1172
|
+
:param compute_strain: whether to compute the strain of the pose (if `pose_refinement` is enabled)
|
|
1173
|
+
:param name: The name of the workflow.
|
|
1174
|
+
:param model: The model to use for the computation.
|
|
1175
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
1176
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1177
|
+
:return: A Workflow object representing the submitted workflow.
|
|
1178
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1179
|
+
""" # noqa: E501
|
|
1180
|
+
|
|
1181
|
+
workflow = stjames.ProteinCofoldingWorkflow(
|
|
1182
|
+
use_msa_server=use_msa_server,
|
|
1183
|
+
use_potentials=use_potentials,
|
|
1184
|
+
model=model,
|
|
1185
|
+
ligand_binding_affinity_index=ligand_binding_affinity_index,
|
|
1186
|
+
initial_smiles_list=initial_smiles_list,
|
|
1187
|
+
initial_protein_sequences=initial_protein_sequences,
|
|
1188
|
+
do_pose_refinement=do_pose_refinement,
|
|
1189
|
+
compute_strain=compute_strain,
|
|
1190
|
+
)
|
|
1191
|
+
|
|
1192
|
+
data = {
|
|
1193
|
+
"name": name,
|
|
1194
|
+
"folder_uuid": folder_uuid,
|
|
1195
|
+
"workflow_type": "protein_cofolding",
|
|
1196
|
+
"workflow_data": workflow.model_dump(),
|
|
1197
|
+
"max_credits": max_credits,
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
with api_client() as client:
|
|
1201
|
+
response = client.post("/workflow", json=data)
|
|
1202
|
+
response.raise_for_status()
|
|
1203
|
+
return Workflow(**response.json())
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
def submit_docking_workflow(
|
|
1207
|
+
protein: str | Protein,
|
|
1208
|
+
pocket: list[list[float]],
|
|
1209
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol | None = None,
|
|
1210
|
+
executable: str = "vina",
|
|
1211
|
+
scoring_function: str = "vinardo",
|
|
1212
|
+
exhaustiveness: float = 8,
|
|
1213
|
+
do_csearch: bool = False,
|
|
1214
|
+
do_optimization: bool = False,
|
|
1215
|
+
do_pose_refinement: bool = False,
|
|
1216
|
+
name: str = "Docking Workflow",
|
|
1217
|
+
folder_uuid: str | None = None,
|
|
1218
|
+
max_credits: int | None = None,
|
|
1219
|
+
) -> Workflow:
|
|
1220
|
+
"""
|
|
1221
|
+
Submits a Docking workflow to the API.
|
|
1222
|
+
|
|
1223
|
+
:param protein: The protein to dock. Can be input as a uuid or a Protein object.
|
|
1224
|
+
:param initial_molecule: The initial molecule to be docked
|
|
1225
|
+
:param executable: Which docking implementation to use.
|
|
1226
|
+
:param scoring_function: Which docking scoring function to use.
|
|
1227
|
+
:param exhaustiveness: Which exhaustiveness to employ.
|
|
1228
|
+
:param do_csearch: Whether to perform a conformational search on the ligand.
|
|
1229
|
+
:param do_optimization: Whether to perform an optimization on the ligand.
|
|
1230
|
+
:param do_pose_refinement: Whether or not to optimize output poses.
|
|
1231
|
+
:param name: The name of the workflow.
|
|
1232
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
1233
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1234
|
+
:return: A Workflow object representing the submitted docking workflow.
|
|
1235
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1236
|
+
"""
|
|
1237
|
+
|
|
1238
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
1239
|
+
initial_molecule = initial_molecule.model_dump()
|
|
1240
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
1241
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
1242
|
+
|
|
1243
|
+
if isinstance(protein, Protein):
|
|
1244
|
+
protein = protein.uuid
|
|
1245
|
+
|
|
1246
|
+
docking_settings = {
|
|
1247
|
+
"executable": executable,
|
|
1248
|
+
"exhaustiveness": exhaustiveness,
|
|
1249
|
+
"scoring_function": scoring_function,
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
workflow = stjames.DockingWorkflow(
|
|
1253
|
+
initial_molecule=initial_molecule,
|
|
1254
|
+
target_uuid=protein,
|
|
1255
|
+
pocket=pocket,
|
|
1256
|
+
do_csearch=do_csearch,
|
|
1257
|
+
do_optimization=do_optimization,
|
|
1258
|
+
do_pose_refinement=do_pose_refinement,
|
|
1259
|
+
docking_settings=docking_settings,
|
|
1260
|
+
)
|
|
1261
|
+
|
|
1262
|
+
data = {
|
|
1263
|
+
"name": name,
|
|
1264
|
+
"folder_uuid": folder_uuid,
|
|
1265
|
+
"workflow_type": "docking",
|
|
1266
|
+
"workflow_data": workflow.model_dump(),
|
|
1267
|
+
"initial_molecule": initial_molecule,
|
|
1268
|
+
"max_credits": max_credits,
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
with api_client() as client:
|
|
1272
|
+
response = client.post("/workflow", json=data)
|
|
1273
|
+
response.raise_for_status()
|
|
1274
|
+
return Workflow(**response.json())
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
def submit_ion_mobility_workflow(
|
|
1278
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
1279
|
+
temperature: float = 300,
|
|
1280
|
+
protonate: bool = False,
|
|
1281
|
+
do_csearch: bool = True,
|
|
1282
|
+
do_optimization: bool = True,
|
|
1283
|
+
name: str = "Ion-Mobility Workflow",
|
|
1284
|
+
folder_uuid: str | None = None,
|
|
1285
|
+
max_credits: int | None = None,
|
|
1286
|
+
) -> Workflow:
|
|
1287
|
+
"""
|
|
1288
|
+
Submits an ion-mobility workflow to the API.
|
|
1289
|
+
|
|
1290
|
+
:param initial_molecule: The molecule used in the scan.
|
|
1291
|
+
:param temperature: The temperature at which to predict CCS values.
|
|
1292
|
+
:param protonate: Whether or not to automatically detect protonation site.
|
|
1293
|
+
If `True`, every basic site will be protonated and values returned for the most stable.
|
|
1294
|
+
:param do_csearch: Whether to perform a conformational search on the molecule.
|
|
1295
|
+
:param do_optimization: Whether to perform an optimization on the molecule.
|
|
1296
|
+
:param name: The name of the workflow.
|
|
1297
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
1298
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1299
|
+
:return: A Workflow object representing the submitted workflow.
|
|
1300
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1301
|
+
"""
|
|
1302
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
1303
|
+
initial_molecule = initial_molecule.model_dump()
|
|
1304
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
1305
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
1306
|
+
|
|
1307
|
+
workflow = stjames.IonMobilityWorkflow(
|
|
1308
|
+
initial_molecule=initial_molecule,
|
|
1309
|
+
temperature=temperature,
|
|
1310
|
+
protonate=protonate,
|
|
1311
|
+
do_csearch=do_csearch,
|
|
1312
|
+
do_optimization=do_optimization,
|
|
1313
|
+
)
|
|
1314
|
+
|
|
1315
|
+
data = {
|
|
1316
|
+
"name": name,
|
|
1317
|
+
"folder_uuid": folder_uuid,
|
|
1318
|
+
"workflow_type": "ion_mobility",
|
|
1319
|
+
"workflow_data": workflow.model_dump(),
|
|
1320
|
+
"initial_molecule": initial_molecule,
|
|
1321
|
+
"max_credits": max_credits,
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
with api_client() as client:
|
|
1325
|
+
response = client.post("/workflow", json=data)
|
|
1326
|
+
response.raise_for_status()
|
|
1327
|
+
return Workflow(**response.json())
|
|
1328
|
+
|
|
1329
|
+
|
|
1330
|
+
def submit_nmr_workflow(
|
|
1331
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
1332
|
+
solvent: str | None = "chloroform",
|
|
1333
|
+
do_csearch: bool = True,
|
|
1334
|
+
do_optimization: bool = True,
|
|
1335
|
+
name: str = "NMR Workflow",
|
|
1336
|
+
folder_uuid: str | None = None,
|
|
1337
|
+
max_credits: int | None = None,
|
|
1338
|
+
) -> Workflow:
|
|
1339
|
+
"""
|
|
1340
|
+
Submits an NMR-prediction workflow to the API.
|
|
1341
|
+
|
|
1342
|
+
:param initial_molecule: The molecule used in the scan.
|
|
1343
|
+
:param solvent: The solvent in which to compute NMR spectra.
|
|
1344
|
+
:param do_csearch: Whether to perform a conformational search on the input structure.
|
|
1345
|
+
:param do_optimization: Whether to perform an optimization on the input structure.
|
|
1346
|
+
:param name: The name of the workflow.
|
|
1347
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
1348
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1349
|
+
:return: A Workflow object representing the submitted workflow.
|
|
1350
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1351
|
+
"""
|
|
1352
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
1353
|
+
initial_molecule = initial_molecule.model_dump()
|
|
1354
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
1355
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
1356
|
+
|
|
1357
|
+
workflow_data = {"initial_molecule": initial_molecule, "solvent": solvent}
|
|
1358
|
+
|
|
1359
|
+
if not do_csearch:
|
|
1360
|
+
workflow_data["conf_gen_settings"] = None
|
|
1361
|
+
|
|
1362
|
+
if not do_optimization:
|
|
1363
|
+
workflow_data["multistage_opt_settings"] = None
|
|
1364
|
+
|
|
1365
|
+
workflow = stjames.NMRSpectroscopyWorkflow.model_validate(workflow_data)
|
|
1366
|
+
|
|
1367
|
+
data = {
|
|
1368
|
+
"name": name,
|
|
1369
|
+
"folder_uuid": folder_uuid,
|
|
1370
|
+
"workflow_type": "nmr",
|
|
1371
|
+
"workflow_data": workflow.model_dump(serialize_as_any=True),
|
|
1372
|
+
"initial_molecule": initial_molecule,
|
|
1373
|
+
"max_credits": max_credits,
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
with api_client() as client:
|
|
1377
|
+
response = client.post("/workflow", json=data)
|
|
1378
|
+
response.raise_for_status()
|
|
1379
|
+
return Workflow(**response.json())
|
|
1380
|
+
|
|
1381
|
+
|
|
1382
|
+
def submit_strain_workflow(
|
|
1383
|
+
initial_molecule: dict[str, Any] | StJamesMolecule | RdkitMol,
|
|
1384
|
+
name: str = "Strain Workflow",
|
|
1385
|
+
folder_uuid: str | None = None,
|
|
1386
|
+
max_credits: int | None = None,
|
|
1387
|
+
) -> Workflow:
|
|
1388
|
+
"""
|
|
1389
|
+
Submits a strain workflow to the API.
|
|
1390
|
+
|
|
1391
|
+
:param initial_molecule: The molecule used in the scan.
|
|
1392
|
+
:param name: The name of the workflow.
|
|
1393
|
+
:param folder_uuid: The UUID of the folder to store the workflow in.
|
|
1394
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1395
|
+
:return: A Workflow object representing the submitted workflow.
|
|
1396
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1397
|
+
"""
|
|
1398
|
+
if isinstance(initial_molecule, StJamesMolecule):
|
|
1399
|
+
initial_molecule = initial_molecule.model_dump()
|
|
1400
|
+
elif isinstance(initial_molecule, RdkitMol):
|
|
1401
|
+
initial_molecule = StJamesMolecule.from_rdkit(initial_molecule, cid=0)
|
|
1402
|
+
|
|
1403
|
+
workflow = stjames.StrainWorkflow(initial_molecule=initial_molecule)
|
|
1404
|
+
|
|
1405
|
+
data = {
|
|
1406
|
+
"name": name,
|
|
1407
|
+
"folder_uuid": folder_uuid,
|
|
1408
|
+
"workflow_type": "strain",
|
|
1409
|
+
"workflow_data": workflow.model_dump(serialize_as_any=True),
|
|
1410
|
+
"initial_molecule": initial_molecule,
|
|
1411
|
+
"max_credits": max_credits,
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
with api_client() as client:
|
|
1415
|
+
response = client.post("/workflow", json=data)
|
|
1416
|
+
response.raise_for_status()
|
|
1417
|
+
return Workflow(**response.json())
|
|
1418
|
+
|
|
1419
|
+
|
|
1420
|
+
def submit_double_ended_ts_search_workflow(
|
|
1421
|
+
reactant: dict[str, Any] | StJamesMolecule,
|
|
1422
|
+
product: dict[str, Any] | StJamesMolecule,
|
|
1423
|
+
calculation_settings: stjames.Settings | dict[str, Any] | None = None,
|
|
1424
|
+
search_settings: FSMSettings | dict[str, Any] | None = None,
|
|
1425
|
+
optimize_inputs: bool = False,
|
|
1426
|
+
optimize_ts: bool = True,
|
|
1427
|
+
name: str = "Double-Ended TS Search Workflow",
|
|
1428
|
+
folder_uuid: str | None = None,
|
|
1429
|
+
max_credits: int | None = None,
|
|
1430
|
+
) -> Workflow:
|
|
1431
|
+
"""
|
|
1432
|
+
Submits a double-ended transition state search workflow to the API.
|
|
1433
|
+
|
|
1434
|
+
:param reactant: reactant Molecule.
|
|
1435
|
+
:param product: product Molecule.
|
|
1436
|
+
:param calculation_settings: Settings to use for calculations.
|
|
1437
|
+
:param search_settings: settings to use for the transition state search.
|
|
1438
|
+
:param optimize_inputs: Whether to optimize the reactant and product before the search.
|
|
1439
|
+
:param optimize_ts: Whether to optimize the found transition state.
|
|
1440
|
+
:param name: name of the workflow.
|
|
1441
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
1442
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1443
|
+
:return: Workflow object representing the submitted workflow.
|
|
1444
|
+
"""
|
|
1445
|
+
workflow = stjames.DoubleEndedTSSearchWorkflow(
|
|
1446
|
+
reactant=reactant,
|
|
1447
|
+
product=product,
|
|
1448
|
+
calculation_settings=calculation_settings,
|
|
1449
|
+
search_settings=search_settings,
|
|
1450
|
+
optimize_inputs=optimize_inputs,
|
|
1451
|
+
optimize_ts=optimize_ts,
|
|
1452
|
+
)
|
|
1453
|
+
data = {
|
|
1454
|
+
"name": name,
|
|
1455
|
+
"folder_uuid": folder_uuid,
|
|
1456
|
+
"workflow_type": "double_ended_ts_search",
|
|
1457
|
+
"workflow_data": workflow.model_dump(),
|
|
1458
|
+
"initial_molecule": reactant if isinstance(reactant, dict) else reactant.model_dump(),
|
|
1459
|
+
"max_credits": max_credits,
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
with api_client() as client:
|
|
1463
|
+
response = client.post("/workflow", json=data)
|
|
1464
|
+
response.raise_for_status()
|
|
1465
|
+
return Workflow(**response.json())
|
|
1466
|
+
|
|
1467
|
+
|
|
1468
|
+
def submit_pose_analysis_md_workflow(
|
|
1469
|
+
protein: str | Protein,
|
|
1470
|
+
initial_smiles: str,
|
|
1471
|
+
num_trajectories: int = 1,
|
|
1472
|
+
simulation_time_ns: int = 10,
|
|
1473
|
+
ligand_residue_name: str = "LIG",
|
|
1474
|
+
name: str = "Pose-Analysis MD Workflow",
|
|
1475
|
+
folder_uuid: str | None = None,
|
|
1476
|
+
max_credits: int | None = None,
|
|
1477
|
+
) -> Workflow:
|
|
1478
|
+
"""
|
|
1479
|
+
Submits a pose-analysis MD workflow to the API.
|
|
1480
|
+
|
|
1481
|
+
:param protein: The *holo* protein on which MD will be run.
|
|
1482
|
+
Can be input as a uuid or a Protein object.
|
|
1483
|
+
:param initial_smiles: The SMILES for the ligand.
|
|
1484
|
+
:param num_trajectories: The number of trajectories to run.
|
|
1485
|
+
:param simulation_time_ns: How long to run the simulation for, in nanoseconds.
|
|
1486
|
+
:param ligand_residue_name: The name of the residue corresponding to the ligand.
|
|
1487
|
+
:param name: The name of the workflow.
|
|
1488
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
1489
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1490
|
+
:return: A Workflow object representing the submitted workflow.
|
|
1491
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1492
|
+
"""
|
|
1493
|
+
|
|
1494
|
+
if isinstance(protein, Protein):
|
|
1495
|
+
protein = protein.uuid
|
|
1496
|
+
|
|
1497
|
+
workflow = stjames.PoseAnalysisMolecularDynamicsWorkflow(
|
|
1498
|
+
protein_uuid=protein,
|
|
1499
|
+
initial_smiles=initial_smiles,
|
|
1500
|
+
num_trajectories=num_trajectories,
|
|
1501
|
+
simulation_time_ns=simulation_time_ns,
|
|
1502
|
+
ligand_residue_name=ligand_residue_name,
|
|
1503
|
+
)
|
|
1504
|
+
|
|
1505
|
+
data = {
|
|
1506
|
+
"name": name,
|
|
1507
|
+
"folder_uuid": folder_uuid,
|
|
1508
|
+
"workflow_type": "pose_analysis_md",
|
|
1509
|
+
"workflow_data": workflow.model_dump(serialize_as_any=True),
|
|
1510
|
+
"initial_smiles": initial_smiles,
|
|
1511
|
+
"max_credits": max_credits,
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
with api_client() as client:
|
|
1515
|
+
response = client.post("/workflow", json=data)
|
|
1516
|
+
response.raise_for_status()
|
|
1517
|
+
return Workflow(**response.json())
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
def submit_batch_docking_workflow(
|
|
1521
|
+
smiles_list: list[str],
|
|
1522
|
+
protein: str | Protein,
|
|
1523
|
+
pocket: list[list[float]],
|
|
1524
|
+
executable: str = "qvina2",
|
|
1525
|
+
scoring_function: str = "vina",
|
|
1526
|
+
exhaustiveness: float = 8,
|
|
1527
|
+
name: str = "Batch Docking Workflow",
|
|
1528
|
+
folder_uuid: str | None = None,
|
|
1529
|
+
max_credits: int | None = None,
|
|
1530
|
+
) -> Workflow:
|
|
1531
|
+
"""
|
|
1532
|
+
Submits a batch docking workflow to the API.
|
|
1533
|
+
|
|
1534
|
+
:param smiles_list: The SMILES strings to dock.
|
|
1535
|
+
:param protein: The protein to dock. Can be input as a uuid or a Protein object.
|
|
1536
|
+
:param executable: Which docking implementation to use.
|
|
1537
|
+
:param scoring_function: Which docking scoring function to use.
|
|
1538
|
+
:param exhaustiveness: Which exhaustiveness to employ.
|
|
1539
|
+
:param name: The name of the workflow.
|
|
1540
|
+
:param folder_uuid: The UUID of the folder to place the workflow in.
|
|
1541
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1542
|
+
:return: A Workflow object representing the submitted batch docking workflow.
|
|
1543
|
+
:raises requests.HTTPError: if the request to the API fails.
|
|
1544
|
+
"""
|
|
1545
|
+
|
|
1546
|
+
docking_settings = {
|
|
1547
|
+
"executable": executable,
|
|
1548
|
+
"exhaustiveness": exhaustiveness,
|
|
1549
|
+
"scoring_function": scoring_function,
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
workflow = stjames.BatchDockingWorkflow(
|
|
1553
|
+
initial_smiles_list=smiles_list,
|
|
1554
|
+
target=protein,
|
|
1555
|
+
pocket=pocket,
|
|
1556
|
+
docking_settings=docking_settings,
|
|
1557
|
+
)
|
|
1558
|
+
|
|
1559
|
+
data = {
|
|
1560
|
+
"name": name,
|
|
1561
|
+
"folder_uuid": folder_uuid,
|
|
1562
|
+
"workflow_type": "batch_docking",
|
|
1563
|
+
"workflow_data": workflow.model_dump(serialize_as_any=True),
|
|
1564
|
+
"max_credits": max_credits,
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
with api_client() as client:
|
|
1568
|
+
response = client.post("/workflow", json=data)
|
|
1569
|
+
response.raise_for_status()
|
|
1570
|
+
return Workflow(**response.json())
|
|
1571
|
+
|
|
1572
|
+
|
|
1573
|
+
def submit_msa_workflow(
|
|
1574
|
+
initial_protein_sequences: list[stjames.ProteinSequence | str],
|
|
1575
|
+
output_formats: list[stjames.MSAFormat],
|
|
1576
|
+
name: str = "MSA Workflow",
|
|
1577
|
+
folder_uuid: str | None = None,
|
|
1578
|
+
max_credits: int | None = None,
|
|
1579
|
+
) -> Workflow:
|
|
1580
|
+
"""
|
|
1581
|
+
Submits a multiple sequence alignment (MSA) workflow to the API.
|
|
1582
|
+
|
|
1583
|
+
:param initial_protein_sequences: List of protein sequences to align, as ProteinSequence objects
|
|
1584
|
+
sor strings.
|
|
1585
|
+
:param output_formats: List of output formats for the resulting MSA files.
|
|
1586
|
+
:param name: The name to assign to the workflow.
|
|
1587
|
+
:param folder_uuid: UUID of the folder where the workflow will be stored.
|
|
1588
|
+
:param max_credits: The maximum number of credits to use for the workflow.
|
|
1589
|
+
:return: A Workflow object representing the submitted MSA workflow.
|
|
1590
|
+
:raises HTTPError: If the API request fails.
|
|
1591
|
+
"""
|
|
1592
|
+
workflow = stjames.MSAWorkflow(
|
|
1593
|
+
initial_protein_sequences=initial_protein_sequences,
|
|
1594
|
+
output_formats=output_formats,
|
|
1595
|
+
)
|
|
1596
|
+
|
|
1597
|
+
data = {
|
|
1598
|
+
"name": name,
|
|
1599
|
+
"folder_uuid": folder_uuid,
|
|
1600
|
+
"workflow_type": "msa",
|
|
1601
|
+
"workflow_data": workflow.model_dump(serialize_as_any=True),
|
|
1602
|
+
"max_credits": max_credits,
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
with api_client() as client:
|
|
1606
|
+
response = client.post("/workflow", json=data)
|
|
1607
|
+
response.raise_for_status()
|
|
1608
|
+
return Workflow(**response.json())
|