rowan-mcp 0.1.0__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.
Potentially problematic release.
This version of rowan-mcp might be problematic. Click here for more details.
- rowan_mcp/__init__.py +14 -0
- rowan_mcp/__main__.py +14 -0
- rowan_mcp/functions/admet.py +94 -0
- rowan_mcp/functions/bde.py +113 -0
- rowan_mcp/functions/calculation_retrieve.py +89 -0
- rowan_mcp/functions/conformers.py +135 -0
- rowan_mcp/functions/descriptors.py +92 -0
- rowan_mcp/functions/docking.py +340 -0
- rowan_mcp/functions/docking_enhanced.py +174 -0
- rowan_mcp/functions/electronic_properties.py +263 -0
- rowan_mcp/functions/folder_management.py +137 -0
- rowan_mcp/functions/fukui.py +355 -0
- rowan_mcp/functions/hydrogen_bond_basicity.py +94 -0
- rowan_mcp/functions/irc.py +125 -0
- rowan_mcp/functions/macropka.py +195 -0
- rowan_mcp/functions/molecular_converter.py +423 -0
- rowan_mcp/functions/molecular_dynamics.py +191 -0
- rowan_mcp/functions/molecule_cache.db +0 -0
- rowan_mcp/functions/molecule_lookup.py +446 -0
- rowan_mcp/functions/multistage_opt.py +171 -0
- rowan_mcp/functions/pdb_handler.py +200 -0
- rowan_mcp/functions/pka.py +137 -0
- rowan_mcp/functions/redox_potential.py +352 -0
- rowan_mcp/functions/scan.py +536 -0
- rowan_mcp/functions/scan_analyzer.py +347 -0
- rowan_mcp/functions/solubility.py +277 -0
- rowan_mcp/functions/spin_states.py +747 -0
- rowan_mcp/functions/system_management.py +368 -0
- rowan_mcp/functions/tautomers.py +91 -0
- rowan_mcp/functions/workflow_management.py +422 -0
- rowan_mcp/server.py +169 -0
- rowan_mcp-0.1.0.dist-info/METADATA +216 -0
- rowan_mcp-0.1.0.dist-info/RECORD +35 -0
- rowan_mcp-0.1.0.dist-info/WHEEL +4 -0
- rowan_mcp-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Rowan docking function for MCP tool integration.
|
|
3
|
+
Implements protein-ligand docking following the stjames-public workflow pattern.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Optional, Union, List, Tuple, Dict, Any
|
|
7
|
+
import rowan
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
import requests
|
|
11
|
+
|
|
12
|
+
# Set up logging
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
# Get API key from environment
|
|
16
|
+
api_key = os.environ.get("ROWAN_API_KEY")
|
|
17
|
+
if api_key:
|
|
18
|
+
rowan.api_key = api_key
|
|
19
|
+
else:
|
|
20
|
+
logger.warning("ROWAN_API_KEY not found in environment")
|
|
21
|
+
|
|
22
|
+
def fetch_pdb_content(pdb_id: str) -> Optional[str]:
|
|
23
|
+
"""Fetch PDB content from RCSB PDB database.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
pdb_id: 4-character PDB ID (e.g., "1COX")
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
PDB file content as string, or None if fetch fails
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
url = f"https://files.rcsb.org/download/{pdb_id.upper()}.pdb"
|
|
33
|
+
response = requests.get(url, timeout=30)
|
|
34
|
+
response.raise_for_status()
|
|
35
|
+
return response.text
|
|
36
|
+
except Exception as e:
|
|
37
|
+
logger.error(f"Failed to fetch PDB {pdb_id}: {str(e)}")
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
def rowan_docking(
|
|
41
|
+
name: str,
|
|
42
|
+
# Ligand specification (following stjames priority)
|
|
43
|
+
molecules: Optional[List[str]] = None,
|
|
44
|
+
smiles: Optional[Union[str, List[str]]] = None,
|
|
45
|
+
# Protein specification
|
|
46
|
+
target: Optional[str] = None,
|
|
47
|
+
target_uuid: Optional[str] = None,
|
|
48
|
+
# Pocket specification
|
|
49
|
+
pocket: Optional[Tuple[Tuple[float, float, float], Tuple[float, float, float]]] = None,
|
|
50
|
+
# Workflow parameters
|
|
51
|
+
do_csearch: bool = True,
|
|
52
|
+
do_optimization: bool = True,
|
|
53
|
+
do_pose_refinement: bool = True,
|
|
54
|
+
conformers: Optional[List[str]] = None,
|
|
55
|
+
# MCP workflow parameters
|
|
56
|
+
folder_uuid: Optional[str] = None,
|
|
57
|
+
blocking: bool = True,
|
|
58
|
+
ping_interval: int = 5
|
|
59
|
+
) -> str:
|
|
60
|
+
"""Perform protein-ligand docking using Rowan's ML workflow.
|
|
61
|
+
|
|
62
|
+
Performs comprehensive protein-ligand docking with conformer generation,
|
|
63
|
+
strain filtering, AutoDock Vina docking, and pose refinement.
|
|
64
|
+
|
|
65
|
+
IMPORTANT: For docking, you need to provide the protein target in one of two ways:
|
|
66
|
+
1. target_uuid: UUID of a pre-uploaded protein in your Rowan account
|
|
67
|
+
2. target: Reserved for future use (currently not supported via API)
|
|
68
|
+
|
|
69
|
+
To dock against a known protein like 1COX, you should:
|
|
70
|
+
1. Upload the PDB file to your Rowan account via the web interface
|
|
71
|
+
2. Get the protein UUID from your account
|
|
72
|
+
3. Use that UUID with the target_uuid parameter
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
name: Name for the docking calculation
|
|
76
|
+
molecules: List of molecules to dock (SMILES strings)
|
|
77
|
+
smiles: SMILES string(s) of ligands (can be string or list)
|
|
78
|
+
target: Not currently supported - use target_uuid instead
|
|
79
|
+
target_uuid: UUID of pre-uploaded protein target from your Rowan account
|
|
80
|
+
pocket: Tuple of (center, size) where each is (x, y, z) coordinates
|
|
81
|
+
Example: ((10.0, 15.0, 20.0), (20.0, 20.0, 20.0))
|
|
82
|
+
do_csearch: Whether to perform conformer search (default: True)
|
|
83
|
+
do_optimization: Whether to optimize starting structures (default: True)
|
|
84
|
+
do_pose_refinement: Whether to optimize non-rotatable bonds in output poses (default: True)
|
|
85
|
+
conformers: List of pre-optimized conformer UUIDs (optional)
|
|
86
|
+
folder_uuid: Optional folder UUID to organize the calculation
|
|
87
|
+
blocking: Whether to wait for completion (default: True)
|
|
88
|
+
ping_interval: Interval in seconds to check calculation status
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Formatted string with workflow results or submission confirmation
|
|
92
|
+
|
|
93
|
+
Examples:
|
|
94
|
+
# Using pre-uploaded protein
|
|
95
|
+
rowan_docking(
|
|
96
|
+
name="aspirin_docking",
|
|
97
|
+
smiles="CC(=O)Oc1ccccc1C(=O)O",
|
|
98
|
+
target_uuid="your-protein-uuid-here",
|
|
99
|
+
pocket=((10.0, 15.0, 20.0), (20.0, 20.0, 20.0))
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Multiple molecules
|
|
103
|
+
rowan_docking(
|
|
104
|
+
name="multi_ligand_docking",
|
|
105
|
+
molecules=["CCO", "CC(C)O", "CCCO"],
|
|
106
|
+
target_uuid="your-protein-uuid-here",
|
|
107
|
+
pocket=((0.0, 0.0, 0.0), (25.0, 25.0, 25.0))
|
|
108
|
+
)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
# Validate that we have ligand input
|
|
112
|
+
if molecules is None and smiles is None:
|
|
113
|
+
return "Error: Either 'molecules' or 'smiles' parameter must be provided"
|
|
114
|
+
|
|
115
|
+
# Validate that we have protein input
|
|
116
|
+
if target is None and target_uuid is None:
|
|
117
|
+
return "Error: Either 'target' or 'target_uuid' parameter must be provided"
|
|
118
|
+
|
|
119
|
+
# If target is provided, inform user it's not currently supported
|
|
120
|
+
if target is not None:
|
|
121
|
+
return ("Error: Direct PDB content upload is not currently supported through this API. "
|
|
122
|
+
"Please use one of these alternatives:\n"
|
|
123
|
+
"1. Upload your PDB file through the Rowan web interface at https://labs.rowansci.com\n"
|
|
124
|
+
"2. Get the protein UUID from your account\n"
|
|
125
|
+
"3. Use the 'target_uuid' parameter with that UUID\n\n"
|
|
126
|
+
"For known proteins like 1COX, 2COX, etc., they may already be available "
|
|
127
|
+
"in the Rowan protein library.")
|
|
128
|
+
|
|
129
|
+
# Validate pocket if provided
|
|
130
|
+
if pocket is not None:
|
|
131
|
+
try:
|
|
132
|
+
center, size = pocket
|
|
133
|
+
if len(center) != 3 or len(size) != 3:
|
|
134
|
+
return "Error: Pocket must be ((x,y,z), (x,y,z)) format"
|
|
135
|
+
|
|
136
|
+
# Validate that size dimensions are positive
|
|
137
|
+
if any(s <= 0 for s in size):
|
|
138
|
+
return "Error: Pocket size dimensions must be positive"
|
|
139
|
+
|
|
140
|
+
except (TypeError, ValueError) as e:
|
|
141
|
+
return f"Error: Invalid pocket format. Expected ((x,y,z), (x,y,z)). Got: {pocket}"
|
|
142
|
+
else:
|
|
143
|
+
# Default pocket if not provided
|
|
144
|
+
pocket = ((0.0, 0.0, 0.0), (20.0, 20.0, 20.0))
|
|
145
|
+
logger.info("Using default pocket: center=(0,0,0), size=(20,20,20)")
|
|
146
|
+
|
|
147
|
+
# Determine initial_molecule for rowan.compute()
|
|
148
|
+
# For docking, the 'molecule' parameter is the ligand to dock
|
|
149
|
+
initial_molecule = None
|
|
150
|
+
ligands_list = None
|
|
151
|
+
|
|
152
|
+
if molecules and len(molecules) > 0:
|
|
153
|
+
initial_molecule = molecules[0]
|
|
154
|
+
ligands_list = molecules
|
|
155
|
+
elif isinstance(smiles, str):
|
|
156
|
+
initial_molecule = smiles
|
|
157
|
+
ligands_list = [smiles]
|
|
158
|
+
elif isinstance(smiles, list) and len(smiles) > 0:
|
|
159
|
+
initial_molecule = smiles[0]
|
|
160
|
+
ligands_list = smiles
|
|
161
|
+
else:
|
|
162
|
+
return "Error: Could not determine initial molecule from inputs"
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
# Build parameters following stjames DockingWorkflow structure
|
|
166
|
+
compute_params = {
|
|
167
|
+
"name": name,
|
|
168
|
+
"molecule": initial_molecule, # Required by rowan.compute() - this is the ligand
|
|
169
|
+
"workflow_type": "docking",
|
|
170
|
+
"folder_uuid": folder_uuid,
|
|
171
|
+
"blocking": blocking,
|
|
172
|
+
"ping_interval": ping_interval,
|
|
173
|
+
# DockingWorkflow specific parameters
|
|
174
|
+
"do_csearch": do_csearch,
|
|
175
|
+
"do_optimization": do_optimization,
|
|
176
|
+
"do_pose_refinement": do_pose_refinement,
|
|
177
|
+
"pocket": pocket,
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# For multiple ligands, pass them as 'molecules' parameter
|
|
181
|
+
# This allows docking multiple ligands in one workflow
|
|
182
|
+
if ligands_list and len(ligands_list) > 1:
|
|
183
|
+
compute_params["molecules"] = ligands_list
|
|
184
|
+
|
|
185
|
+
# Add protein specification (only one of these should be present)
|
|
186
|
+
if target_uuid is not None:
|
|
187
|
+
compute_params["target_uuid"] = target_uuid
|
|
188
|
+
# Note: Direct PDB upload is not supported in current implementation
|
|
189
|
+
# Users must pre-upload proteins through the Rowan web interface
|
|
190
|
+
|
|
191
|
+
# Add conformers if provided
|
|
192
|
+
if conformers is not None:
|
|
193
|
+
compute_params["conformers"] = conformers
|
|
194
|
+
|
|
195
|
+
# Submit docking calculation
|
|
196
|
+
result = rowan.compute(**compute_params)
|
|
197
|
+
|
|
198
|
+
# Format results
|
|
199
|
+
uuid = result.get('uuid', 'N/A')
|
|
200
|
+
status = result.get('status', 'unknown')
|
|
201
|
+
|
|
202
|
+
if blocking:
|
|
203
|
+
# Blocking mode - check if successful
|
|
204
|
+
if status == "success":
|
|
205
|
+
formatted = f"✅ Docking calculation '{name}' completed successfully!\n"
|
|
206
|
+
formatted += f"🔖 Workflow UUID: {uuid}\n"
|
|
207
|
+
formatted += f"📊 Status: {status}\n\n"
|
|
208
|
+
|
|
209
|
+
# Extract docking results if available
|
|
210
|
+
object_data = result.get("object_data", {})
|
|
211
|
+
scores = object_data.get("scores", [])
|
|
212
|
+
|
|
213
|
+
if scores:
|
|
214
|
+
formatted += f"🎯 Docking Results: {len(scores)} poses generated\n"
|
|
215
|
+
formatted += f"📈 Best docking score: {scores[0] if scores else 'N/A'}\n"
|
|
216
|
+
|
|
217
|
+
# Show top poses
|
|
218
|
+
formatted += "\nTop poses:\n"
|
|
219
|
+
for i, score in enumerate(scores[:5]):
|
|
220
|
+
formatted += f" {i+1}. Score: {score}\n"
|
|
221
|
+
|
|
222
|
+
if len(scores) > 5:
|
|
223
|
+
formatted += f" ... and {len(scores) - 5} more poses\n"
|
|
224
|
+
else:
|
|
225
|
+
formatted += "📈 Results: Check workflow details for docking data\n"
|
|
226
|
+
|
|
227
|
+
return formatted
|
|
228
|
+
else:
|
|
229
|
+
# Failed calculation
|
|
230
|
+
return f"❌ Docking calculation failed\n🔖 UUID: {uuid}\n📋 Status: {status}\n💬 Check workflow details for more information"
|
|
231
|
+
else:
|
|
232
|
+
# Non-blocking mode
|
|
233
|
+
formatted = f"📋 Docking calculation '{name}' submitted!\n"
|
|
234
|
+
formatted += f"🔖 Workflow UUID: {uuid}\n"
|
|
235
|
+
formatted += f"⏳ Status: Running...\n"
|
|
236
|
+
formatted += f"💡 Use rowan_workflow_management to check status\n\n"
|
|
237
|
+
|
|
238
|
+
formatted += f"Docking Details:\n"
|
|
239
|
+
formatted += f"🧬 Ligand: {initial_molecule}\n"
|
|
240
|
+
formatted += f"🎯 Target: {target_uuid or target[:50] + '...' if target and len(target) > 50 else target}\n"
|
|
241
|
+
formatted += f"📍 Pocket: center={pocket[0]}, size={pocket[1]}\n"
|
|
242
|
+
formatted += f"⚙️ Settings: csearch={do_csearch}, optimize={do_optimization}, refine={do_pose_refinement}\n"
|
|
243
|
+
|
|
244
|
+
if conformers:
|
|
245
|
+
formatted += f"🔬 Pre-optimized conformers: {len(conformers)}\n"
|
|
246
|
+
|
|
247
|
+
return formatted
|
|
248
|
+
|
|
249
|
+
except Exception as e:
|
|
250
|
+
logger.error(f"Error in rowan_docking: {str(e)}")
|
|
251
|
+
return f"❌ Docking calculation failed: {str(e)}"
|
|
252
|
+
|
|
253
|
+
def rowan_docking_pdb_id(
|
|
254
|
+
name: str,
|
|
255
|
+
pdb_id: str,
|
|
256
|
+
# Ligand specification
|
|
257
|
+
molecules: Optional[List[str]] = None,
|
|
258
|
+
smiles: Optional[Union[str, List[str]]] = None,
|
|
259
|
+
# Other parameters same as rowan_docking
|
|
260
|
+
pocket: Optional[Tuple[Tuple[float, float, float], Tuple[float, float, float]]] = None,
|
|
261
|
+
do_csearch: bool = True,
|
|
262
|
+
do_optimization: bool = True,
|
|
263
|
+
do_pose_refinement: bool = True,
|
|
264
|
+
conformers: Optional[List[str]] = None,
|
|
265
|
+
folder_uuid: Optional[str] = None,
|
|
266
|
+
blocking: bool = True,
|
|
267
|
+
ping_interval: int = 5
|
|
268
|
+
) -> str:
|
|
269
|
+
"""Helper function that explains how to dock with a PDB ID.
|
|
270
|
+
|
|
271
|
+
NOTE: Direct PDB upload is not currently supported through the API.
|
|
272
|
+
This function provides guidance on how to dock against known proteins.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
name: Name for the docking calculation
|
|
276
|
+
pdb_id: 4-character PDB ID (e.g., "1COX", "2COX", "6COX")
|
|
277
|
+
(other parameters same as rowan_docking)
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
Instructions on how to perform docking with the given PDB
|
|
281
|
+
"""
|
|
282
|
+
# Check if we can fetch the PDB to verify it exists
|
|
283
|
+
logger.info(f"Checking if PDB {pdb_id} exists...")
|
|
284
|
+
pdb_content = fetch_pdb_content(pdb_id)
|
|
285
|
+
|
|
286
|
+
if pdb_content is None:
|
|
287
|
+
return (f"Error: PDB ID '{pdb_id}' not found in RCSB database. "
|
|
288
|
+
f"Please check that the PDB ID is valid.")
|
|
289
|
+
|
|
290
|
+
# Provide instructions for the user
|
|
291
|
+
ligand_param = ""
|
|
292
|
+
if molecules:
|
|
293
|
+
ligand_param = f" molecules={molecules},\n"
|
|
294
|
+
elif smiles:
|
|
295
|
+
if isinstance(smiles, str):
|
|
296
|
+
ligand_param = f' smiles="{smiles}",\n'
|
|
297
|
+
else:
|
|
298
|
+
ligand_param = f" smiles={smiles},\n"
|
|
299
|
+
|
|
300
|
+
return (f"✅ PDB {pdb_id} found in RCSB database!\n\n"
|
|
301
|
+
f"To perform docking with this protein:\n\n"
|
|
302
|
+
f"1. Go to https://labs.rowansci.com\n"
|
|
303
|
+
f"2. Upload the PDB file for {pdb_id}\n"
|
|
304
|
+
f" - You can download it from: https://files.rcsb.org/download/{pdb_id.upper()}.pdb\n"
|
|
305
|
+
f"3. Once uploaded, find the protein UUID in your account\n"
|
|
306
|
+
f"4. Use the docking function with target_uuid:\n\n"
|
|
307
|
+
f"```python\n"
|
|
308
|
+
f"rowan_docking(\n"
|
|
309
|
+
f" name=\"{name}\",\n"
|
|
310
|
+
f"{ligand_param}"
|
|
311
|
+
f" target_uuid=\"your-protein-uuid-here\",\n"
|
|
312
|
+
f" pocket={pocket},\n"
|
|
313
|
+
f" do_csearch={do_csearch},\n"
|
|
314
|
+
f" do_optimization={do_optimization},\n"
|
|
315
|
+
f" do_pose_refinement={do_pose_refinement}\n"
|
|
316
|
+
f")\n"
|
|
317
|
+
f"```\n\n"
|
|
318
|
+
f"Note: Some common proteins may already be available in the Rowan protein library.\n"
|
|
319
|
+
f"Check your account for pre-uploaded structures.")
|
|
320
|
+
|
|
321
|
+
def test_rowan_docking():
|
|
322
|
+
"""Test the rowan_docking function."""
|
|
323
|
+
try:
|
|
324
|
+
# Test with minimal parameters
|
|
325
|
+
result = rowan_docking(
|
|
326
|
+
name="test_docking",
|
|
327
|
+
smiles="CCO", # Ethanol
|
|
328
|
+
target_uuid="test-protein-uuid", # Would need real UUID
|
|
329
|
+
pocket=((0.0, 0.0, 0.0), (20.0, 20.0, 20.0)),
|
|
330
|
+
blocking=False
|
|
331
|
+
)
|
|
332
|
+
print("✅ Docking test result:")
|
|
333
|
+
print(result)
|
|
334
|
+
return True
|
|
335
|
+
except Exception as e:
|
|
336
|
+
print(f"❌ Docking test failed: {e}")
|
|
337
|
+
return False
|
|
338
|
+
|
|
339
|
+
if __name__ == "__main__":
|
|
340
|
+
test_rowan_docking()
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Enhanced docking function that accepts PDB IDs directly
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional, Union, List, Tuple
|
|
6
|
+
import logging
|
|
7
|
+
from .docking import rowan_docking
|
|
8
|
+
from .pdb_handler import handle_pdb_input
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
def rowan_docking_enhanced(
|
|
13
|
+
name: str,
|
|
14
|
+
# Ligand specification
|
|
15
|
+
smiles: Optional[Union[str, List[str]]] = None,
|
|
16
|
+
molecules: Optional[List[str]] = None,
|
|
17
|
+
# Protein specification - NEW: accepts PDB ID or UUID
|
|
18
|
+
target: Optional[str] = None, # Can be PDB ID (e.g., "4Z18") or UUID
|
|
19
|
+
# Pocket specification
|
|
20
|
+
pocket: Optional[Tuple[Tuple[float, float, float], Tuple[float, float, float]]] = None,
|
|
21
|
+
# Workflow parameters
|
|
22
|
+
do_csearch: bool = True,
|
|
23
|
+
do_optimization: bool = True,
|
|
24
|
+
do_pose_refinement: bool = True,
|
|
25
|
+
conformers: Optional[List[str]] = None,
|
|
26
|
+
# MCP workflow parameters
|
|
27
|
+
folder_uuid: Optional[str] = None,
|
|
28
|
+
blocking: bool = True,
|
|
29
|
+
ping_interval: int = 5
|
|
30
|
+
) -> str:
|
|
31
|
+
"""
|
|
32
|
+
Enhanced docking function that accepts PDB IDs directly.
|
|
33
|
+
|
|
34
|
+
This function intelligently handles protein input:
|
|
35
|
+
- If target looks like a UUID (36 chars with dashes), uses it directly
|
|
36
|
+
- If target looks like a PDB ID (e.g., "4Z18"), attempts to fetch and use it
|
|
37
|
+
- Provides clear instructions when manual upload is needed
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
name: Name for the docking calculation
|
|
41
|
+
smiles: SMILES string(s) of ligands
|
|
42
|
+
molecules: Alternative to smiles - list of molecules
|
|
43
|
+
target: PDB ID (e.g., "4Z18") or protein UUID
|
|
44
|
+
pocket: Pocket specification ((center), (size))
|
|
45
|
+
(other parameters same as rowan_docking)
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Docking results or clear instructions on what to do
|
|
49
|
+
|
|
50
|
+
Examples:
|
|
51
|
+
# Using PDB ID directly
|
|
52
|
+
rowan_docking_enhanced(
|
|
53
|
+
name="my_docking",
|
|
54
|
+
smiles="CC(=O)Oc1ccccc1C(=O)O", # Aspirin
|
|
55
|
+
target="4Z18", # PDB ID
|
|
56
|
+
pocket=((10.0, 15.0, 20.0), (20.0, 20.0, 20.0))
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Using UUID (if you already have one)
|
|
60
|
+
rowan_docking_enhanced(
|
|
61
|
+
name="my_docking",
|
|
62
|
+
smiles="CC(=O)Oc1ccccc1C(=O)O",
|
|
63
|
+
target="abc123de-f456-7890-ghij-klmnopqrstuv", # UUID
|
|
64
|
+
pocket=((10.0, 15.0, 20.0), (20.0, 20.0, 20.0))
|
|
65
|
+
)
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
# Validate ligand input
|
|
69
|
+
if smiles is None and molecules is None:
|
|
70
|
+
return "Error: Either 'smiles' or 'molecules' must be provided"
|
|
71
|
+
|
|
72
|
+
# Validate protein input
|
|
73
|
+
if target is None:
|
|
74
|
+
return "Error: 'target' parameter is required (PDB ID or protein UUID)"
|
|
75
|
+
|
|
76
|
+
# Handle the target input
|
|
77
|
+
logger.info(f"Processing target input: {target}")
|
|
78
|
+
pdb_result = handle_pdb_input(target, folder_uuid)
|
|
79
|
+
|
|
80
|
+
# If we successfully got a UUID, proceed with docking
|
|
81
|
+
if pdb_result['success'] and pdb_result['uuid']:
|
|
82
|
+
logger.info(f"Successfully resolved target to UUID: {pdb_result['uuid']}")
|
|
83
|
+
|
|
84
|
+
# Call the main docking function with the UUID
|
|
85
|
+
result = rowan_docking(
|
|
86
|
+
name=name,
|
|
87
|
+
smiles=smiles,
|
|
88
|
+
molecules=molecules,
|
|
89
|
+
target_uuid=pdb_result['uuid'],
|
|
90
|
+
pocket=pocket,
|
|
91
|
+
do_csearch=do_csearch,
|
|
92
|
+
do_optimization=do_optimization,
|
|
93
|
+
do_pose_refinement=do_pose_refinement,
|
|
94
|
+
conformers=conformers,
|
|
95
|
+
folder_uuid=folder_uuid,
|
|
96
|
+
blocking=blocking,
|
|
97
|
+
ping_interval=ping_interval
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Add context about PDB if it was used
|
|
101
|
+
if 'pdb_id' in pdb_result:
|
|
102
|
+
result = f"🧬 Using PDB {pdb_result['pdb_id']}:\n\n{result}"
|
|
103
|
+
|
|
104
|
+
return result
|
|
105
|
+
|
|
106
|
+
# If we couldn't get a UUID, provide helpful information
|
|
107
|
+
else:
|
|
108
|
+
pdb_id = pdb_result.get('pdb_id', target)
|
|
109
|
+
|
|
110
|
+
# Format a helpful response
|
|
111
|
+
response = f"🔍 PDB Input Detected: {pdb_id}\n\n"
|
|
112
|
+
response += f"❌ {pdb_result['message']}\n\n"
|
|
113
|
+
|
|
114
|
+
if pdb_result.get('instructions'):
|
|
115
|
+
response += pdb_result['instructions']
|
|
116
|
+
else:
|
|
117
|
+
response += f"""
|
|
118
|
+
📋 To dock with PDB {pdb_id}:
|
|
119
|
+
|
|
120
|
+
1. **Download the PDB file**:
|
|
121
|
+
https://files.rcsb.org/download/{pdb_id}.pdb
|
|
122
|
+
|
|
123
|
+
2. **Upload to Rowan**:
|
|
124
|
+
https://labs.rowansci.com
|
|
125
|
+
|
|
126
|
+
3. **Get the protein UUID** from your account
|
|
127
|
+
|
|
128
|
+
4. **Run docking with the UUID**:
|
|
129
|
+
```python
|
|
130
|
+
rowan_docking_enhanced(
|
|
131
|
+
name="{name}",
|
|
132
|
+
smiles={f'"{smiles}"' if isinstance(smiles, str) else smiles},
|
|
133
|
+
target="your-protein-uuid-here",
|
|
134
|
+
pocket={pocket}
|
|
135
|
+
)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Note: Direct PDB upload through the API is not currently supported.
|
|
139
|
+
Proteins must be uploaded through the web interface.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
return response
|
|
143
|
+
|
|
144
|
+
def test_enhanced_docking():
|
|
145
|
+
"""Test the enhanced docking function"""
|
|
146
|
+
|
|
147
|
+
print("Testing enhanced docking with PDB ID...")
|
|
148
|
+
|
|
149
|
+
# Test with PDB ID
|
|
150
|
+
result = rowan_docking_enhanced(
|
|
151
|
+
name="test_4z18_docking",
|
|
152
|
+
smiles="CC(=O)Oc1ccccc1C(=O)O", # Aspirin
|
|
153
|
+
target="4Z18", # PDB ID
|
|
154
|
+
pocket=((10.0, 15.0, 20.0), (20.0, 20.0, 20.0)),
|
|
155
|
+
blocking=False
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
print(result)
|
|
159
|
+
|
|
160
|
+
# Test with UUID
|
|
161
|
+
print("\n" + "="*60 + "\n")
|
|
162
|
+
print("Testing with UUID...")
|
|
163
|
+
|
|
164
|
+
result = rowan_docking_enhanced(
|
|
165
|
+
name="test_uuid_docking",
|
|
166
|
+
smiles="CC(=O)Oc1ccccc1C(=O)O",
|
|
167
|
+
target="12345678-1234-5678-1234-567812345678", # Fake UUID format
|
|
168
|
+
blocking=False
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
print(result)
|
|
172
|
+
|
|
173
|
+
if __name__ == "__main__":
|
|
174
|
+
test_enhanced_docking()
|