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 CHANGED
@@ -29,6 +29,7 @@ from stjames.optimization.freezing_string_method import (
29
29
  api_key: str | None = None
30
30
  project_uuid: str | None = None
31
31
 
32
+ from .api_keys import *
32
33
  from .calculation import *
33
34
  from .folder import *
34
35
  from .molecule import *
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())
@@ -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
- initial_molecule=initial_molecule,
95
- mode=mode,
96
- atoms=atoms or [],
97
- all_CH=all_CH,
98
- all_CX=all_CX,
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: stjames.ConformerGenSettings | None = None,
120
- final_method: stjames.Method | str = "aimnet2_wb97md3",
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
- :param solvent: Solvent to use for the final optimization.
143
- :param transition_state: Whether to optimize the transition state.
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 = stjames.ETKDGSettings()
228
+ conf_gen_settings = ETKDGSettings()
159
229
 
160
230
  mol_dict = molecule_to_dict(initial_molecule)
161
231
 
162
- if isinstance(final_method, str):
163
- final_method = stjames.Method(final_method)
164
-
165
- solvent_model = None
166
- if solvent:
167
- solvent_model = "alpb" if final_method in stjames.XTB_METHODS else "cpcm"
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=msos,
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, SolventInput
10
+ from ..types import MoleculeInput
9
11
  from ..utils import api_client
10
12
  from .base import (
11
- Mode,
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
- mode: Mode = Mode.RAPID,
120
- solvent: SolventInput = None,
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 mode: Mode to run the calculation in.
136
- :param solvent: Solvent for the final single-point calculation.
137
- :param xtb_preopt: Whether to pre-optimize with xTB.
138
- :param transition_state: Whether this is a transition state optimization.
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
- mode=mode,
158
- solvent=solvent,
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 for the computation.
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
- initial_molecule=initial_molecule,
127
- oxidation=oxidation,
128
- reduction=reduction,
129
- mode=mode,
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 = {
@@ -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, SolventInput
10
+ from ..types import MoleculeInput
11
11
  from ..utils import api_client
12
12
  from .base import (
13
13
  Message,
14
- Mode,
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
- mode: Mode = Mode.RAPID,
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 mode: Mode to run the calculation in.
150
- :param solvent: Solvent to use for the calculation.
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
- mode=mode,
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 ETKDG with
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 AIMNet2/wB97M-D3 optimization with CPCMx singlepoint.
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.7
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.174
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=HvGc27Y6l1_E_mcvabDhmDOOtMrJ6ME7Cx8LfVKqyVs,835
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=UTkqcsqtANh9TtaYXwOSYmTOvzR9ucQ_xhDupAFHROI,4351
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=eLGyzTc9NpXBGC-FRjsaUwKP6RluWrz0ipDZ4jDY_jc,30103
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=cM8UNBYycwLE5yJeh8DEtX6mW6hghsM6XKEFkbd7Q8g,5551
22
- rowan/workflows/conformer_search.py,sha256=_uCfGFsUTDyxDc55XTsvMSjs800LyfzBRa4_-9Pjp4g,7690
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=2L0BUvhx0iT0k4gQf7hbceCpatznT2xui7rs6lpME7k,7564
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=HFVx8mnHxG97pDYyL6eOhNGmESqTxaKNgUdwrFpFUJ0,6456
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=1R29XjAVjWHyelGG-mylP2GIamZbLCQKaaaFsCAnYgI,13012
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=lg2Djev58oOmBmI4l3eIaGKafkNXMhwo17K2G7kQvjY,5319
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=GZgBJPO6_ds9el4b7wbigIZ5213Z9DwXhokczJ5NDhs,7122
51
- rowan/workflows/strain.py,sha256=r0tlZoUlAslAiF7dPTpa9WlQFUAKyVjZ19zASjSS8Hs,6339
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.7.dist-info/METADATA,sha256=-sirW_Q74BeqsjNRR4wAWYoV8ebpuNLzc6-8FrgOKRs,1600
54
- rowan_python-3.0.7.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
55
- rowan_python-3.0.7.dist-info/licenses/LICENSE,sha256=i05z7xEhyrg6f8j0lR3XYjShnF-MJGFQ-DnpsZ8yiVI,1084
56
- rowan_python-3.0.7.dist-info/RECORD,,
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,,