boltz2-python-client 0.2__tar.gz
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.
- boltz2_python_client-0.2/ASYNC_GUIDE.md +470 -0
- boltz2_python_client-0.2/COVALENT_COMPLEX_GUIDE.md +207 -0
- boltz2_python_client-0.2/INSTALL_TESTPYPI.md +122 -0
- boltz2_python_client-0.2/LICENSE +21 -0
- boltz2_python_client-0.2/MANIFEST.in +17 -0
- boltz2_python_client-0.2/PARAMETERS.md +554 -0
- boltz2_python_client-0.2/PKG-INFO +533 -0
- boltz2_python_client-0.2/README.md +497 -0
- boltz2_python_client-0.2/YAML_GUIDE.md +395 -0
- boltz2_python_client-0.2/boltz2_client/__init__.py +153 -0
- boltz2_python_client-0.2/boltz2_client/cli.py +1213 -0
- boltz2_python_client-0.2/boltz2_client/client.py +986 -0
- boltz2_python_client-0.2/boltz2_client/exceptions.py +213 -0
- boltz2_python_client-0.2/boltz2_client/models.py +466 -0
- boltz2_python_client-0.2/boltz2_client/models_affinity.py +46 -0
- boltz2_python_client-0.2/boltz2_client/utils.py +455 -0
- boltz2_python_client-0.2/boltz2_client/virtual_screening.py +608 -0
- boltz2_python_client-0.2/boltz2_python_client.egg-info/PKG-INFO +533 -0
- boltz2_python_client-0.2/boltz2_python_client.egg-info/SOURCES.txt +50 -0
- boltz2_python_client-0.2/boltz2_python_client.egg-info/dependency_links.txt +1 -0
- boltz2_python_client-0.2/boltz2_python_client.egg-info/entry_points.txt +2 -0
- boltz2_python_client-0.2/boltz2_python_client.egg-info/requires.txt +8 -0
- boltz2_python_client-0.2/boltz2_python_client.egg-info/top_level.txt +1 -0
- boltz2_python_client-0.2/examples/.ipynb_checkpoints/08_affinity_prediction-checkpoint.py +199 -0
- boltz2_python_client-0.2/examples/.ipynb_checkpoints/multi_endpoint_screening-checkpoint.py +204 -0
- boltz2_python_client-0.2/examples/01_basic_protein_folding.py +49 -0
- boltz2_python_client-0.2/examples/02_protein_structure_prediction_with_msa.py +186 -0
- boltz2_python_client-0.2/examples/03_protein_ligand_complex.py +237 -0
- boltz2_python_client-0.2/examples/04_covalent_bonding.py +199 -0
- boltz2_python_client-0.2/examples/05_dna_protein_complex.py +211 -0
- boltz2_python_client-0.2/examples/06_yaml_configurations.py +273 -0
- boltz2_python_client-0.2/examples/07_advanced_parameters.py +344 -0
- boltz2_python_client-0.2/examples/08_affinity_prediction_simple.py +106 -0
- boltz2_python_client-0.2/examples/09_virtual_screening.py +227 -0
- boltz2_python_client-0.2/examples/msa-kras-g12c_combined.a3m +1178 -0
- boltz2_python_client-0.2/examples/multi_protein_complex.yaml +10 -0
- boltz2_python_client-0.2/examples/protein_ligand.yaml +8 -0
- boltz2_python_client-0.2/examples/sars_cov2_mpro_nirmatrelvir.yaml +8 -0
- boltz2_python_client-0.2/licenses/PyYAML-LICENSE +22 -0
- boltz2_python_client-0.2/licenses/README.md +24 -0
- boltz2_python_client-0.2/licenses/aiofiles-LICENSE +17 -0
- boltz2_python_client-0.2/licenses/click-LICENSE +30 -0
- boltz2_python_client-0.2/licenses/httpx-LICENSE +29 -0
- boltz2_python_client-0.2/licenses/py3Dmol-LICENSE +21 -0
- boltz2_python_client-0.2/licenses/pydantic-LICENSE +21 -0
- boltz2_python_client-0.2/licenses/rich-LICENSE +21 -0
- boltz2_python_client-0.2/licenses/typing-extensions-LICENSE +109 -0
- boltz2_python_client-0.2/pyproject.toml +61 -0
- boltz2_python_client-0.2/setup.cfg +4 -0
- boltz2_python_client-0.2/tests/__init__.py +1 -0
- boltz2_python_client-0.2/tests/test_basic.py +167 -0
- boltz2_python_client-0.2/tests/test_examples_syntax.py +148 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
# Async Programming Guide for Boltz-2 Python Client
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This guide demonstrates how to efficiently perform asynchronous protein structure predictions using the Boltz-2 Python client. Async programming allows you to process multiple protein sequences concurrently, dramatically improving throughput for batch operations.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
1. [Basic Async Concepts](#basic-async-concepts)
|
|
10
|
+
2. [Simple Async Example](#simple-async-example)
|
|
11
|
+
3. [Batch Processing with Rate Limiting](#batch-processing-with-rate-limiting)
|
|
12
|
+
4. [Advanced Patterns](#advanced-patterns)
|
|
13
|
+
5. [Performance Optimization](#performance-optimization)
|
|
14
|
+
6. [Error Handling](#error-handling)
|
|
15
|
+
7. [Best Practices](#best-practices)
|
|
16
|
+
|
|
17
|
+
## Basic Async Concepts
|
|
18
|
+
|
|
19
|
+
### Why Use Async?
|
|
20
|
+
|
|
21
|
+
- **Concurrency**: Process multiple proteins simultaneously
|
|
22
|
+
- **Efficiency**: Better resource utilization during I/O operations
|
|
23
|
+
- **Scalability**: Handle large batches without blocking
|
|
24
|
+
- **Throughput**: Significantly faster than sequential processing
|
|
25
|
+
|
|
26
|
+
### Key Components
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import asyncio
|
|
30
|
+
from boltz2_client import Boltz2Client, EndpointType
|
|
31
|
+
|
|
32
|
+
# Create async client
|
|
33
|
+
client = Boltz2Client(
|
|
34
|
+
base_url="http://localhost:8000",
|
|
35
|
+
endpoint_type=EndpointType.LOCAL
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Async function
|
|
39
|
+
async def fold_protein(sequence: str):
|
|
40
|
+
response = await client.predict_protein_structure(
|
|
41
|
+
sequence=sequence,
|
|
42
|
+
recycling_steps=1,
|
|
43
|
+
sampling_steps=20,
|
|
44
|
+
save_structures=False
|
|
45
|
+
)
|
|
46
|
+
return response
|
|
47
|
+
|
|
48
|
+
# Run async function
|
|
49
|
+
result = asyncio.run(fold_protein("MKTVRQERLK..."))
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Simple Async Example
|
|
53
|
+
|
|
54
|
+
### Single Protein (Async)
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import asyncio
|
|
58
|
+
from boltz2_client import Boltz2Client
|
|
59
|
+
|
|
60
|
+
async def predict_single():
|
|
61
|
+
client = Boltz2Client("http://localhost:8000")
|
|
62
|
+
|
|
63
|
+
response = await client.predict_protein_structure(
|
|
64
|
+
sequence="MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG",
|
|
65
|
+
recycling_steps=3,
|
|
66
|
+
sampling_steps=50
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
print(f"Confidence: {response.confidence_scores[0]:.3f}")
|
|
70
|
+
return response
|
|
71
|
+
|
|
72
|
+
# Run it
|
|
73
|
+
result = asyncio.run(predict_single())
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Multiple Proteins (Concurrent)
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
import asyncio
|
|
80
|
+
from boltz2_client import Boltz2Client
|
|
81
|
+
|
|
82
|
+
async def predict_multiple():
|
|
83
|
+
client = Boltz2Client("http://localhost:8000")
|
|
84
|
+
|
|
85
|
+
sequences = [
|
|
86
|
+
"MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG",
|
|
87
|
+
"MKLLVVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLV",
|
|
88
|
+
"ACDEFGHIKLMNPQRSTVWYACDEFGHIKLMNPQRSTVWYACDEFGHIKLMNPQRSTVWY"
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
# Create tasks for concurrent execution
|
|
92
|
+
tasks = [
|
|
93
|
+
client.predict_protein_structure(
|
|
94
|
+
sequence=seq,
|
|
95
|
+
recycling_steps=1,
|
|
96
|
+
sampling_steps=20,
|
|
97
|
+
save_structures=False
|
|
98
|
+
)
|
|
99
|
+
for seq in sequences
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
# Wait for all to complete
|
|
103
|
+
results = await asyncio.gather(*tasks)
|
|
104
|
+
|
|
105
|
+
for i, result in enumerate(results):
|
|
106
|
+
confidence = result.confidence_scores[0] if result.confidence_scores else 0
|
|
107
|
+
print(f"Protein {i+1}: confidence={confidence:.3f}")
|
|
108
|
+
|
|
109
|
+
return results
|
|
110
|
+
|
|
111
|
+
# Run it
|
|
112
|
+
results = asyncio.run(predict_multiple())
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Batch Processing with Rate Limiting
|
|
116
|
+
|
|
117
|
+
### Using Semaphore for Rate Limiting
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
import asyncio
|
|
121
|
+
from boltz2_client import Boltz2Client
|
|
122
|
+
|
|
123
|
+
class RateLimitedFolder:
|
|
124
|
+
def __init__(self, max_concurrent=5):
|
|
125
|
+
self.client = Boltz2Client("http://localhost:8000")
|
|
126
|
+
self.semaphore = asyncio.Semaphore(max_concurrent)
|
|
127
|
+
|
|
128
|
+
async def fold_with_limit(self, sequence: str, protein_id: str):
|
|
129
|
+
async with self.semaphore: # Rate limiting
|
|
130
|
+
try:
|
|
131
|
+
response = await self.client.predict_protein_structure(
|
|
132
|
+
sequence=sequence,
|
|
133
|
+
recycling_steps=1,
|
|
134
|
+
sampling_steps=20,
|
|
135
|
+
save_structures=False
|
|
136
|
+
)
|
|
137
|
+
confidence = response.confidence_scores[0] if response.confidence_scores else 0
|
|
138
|
+
print(f"โ
{protein_id}: confidence={confidence:.3f}")
|
|
139
|
+
return {"id": protein_id, "success": True, "confidence": confidence}
|
|
140
|
+
except Exception as e:
|
|
141
|
+
print(f"โ {protein_id}: {e}")
|
|
142
|
+
return {"id": protein_id, "success": False, "error": str(e)}
|
|
143
|
+
|
|
144
|
+
async def batch_fold():
|
|
145
|
+
folder = RateLimitedFolder(max_concurrent=3)
|
|
146
|
+
|
|
147
|
+
# Your protein sequences
|
|
148
|
+
proteins = [
|
|
149
|
+
("protein_1", "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"),
|
|
150
|
+
("protein_2", "MKLLVVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLVLV"),
|
|
151
|
+
# ... more proteins
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
tasks = [
|
|
155
|
+
folder.fold_with_limit(sequence, protein_id)
|
|
156
|
+
for protein_id, sequence in proteins
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
results = await asyncio.gather(*tasks)
|
|
160
|
+
return results
|
|
161
|
+
|
|
162
|
+
# Run batch folding
|
|
163
|
+
results = asyncio.run(batch_fold())
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Advanced Patterns
|
|
167
|
+
|
|
168
|
+
### Progress Tracking with asyncio.as_completed
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
import asyncio
|
|
172
|
+
import time
|
|
173
|
+
from boltz2_client import Boltz2Client
|
|
174
|
+
|
|
175
|
+
async def fold_with_progress(sequences):
|
|
176
|
+
client = Boltz2Client("http://localhost:8000")
|
|
177
|
+
|
|
178
|
+
# Create tasks
|
|
179
|
+
tasks = [
|
|
180
|
+
client.predict_protein_structure(
|
|
181
|
+
sequence=seq,
|
|
182
|
+
recycling_steps=1,
|
|
183
|
+
sampling_steps=20,
|
|
184
|
+
save_structures=False
|
|
185
|
+
)
|
|
186
|
+
for seq in sequences
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
results = []
|
|
190
|
+
completed = 0
|
|
191
|
+
total = len(tasks)
|
|
192
|
+
|
|
193
|
+
# Process as they complete
|
|
194
|
+
for coro in asyncio.as_completed(tasks):
|
|
195
|
+
try:
|
|
196
|
+
result = await coro
|
|
197
|
+
confidence = result.confidence_scores[0] if result.confidence_scores else 0
|
|
198
|
+
results.append(result)
|
|
199
|
+
completed += 1
|
|
200
|
+
|
|
201
|
+
print(f"Progress: {completed}/{total} ({completed/total*100:.1f}%) - Latest confidence: {confidence:.3f}")
|
|
202
|
+
|
|
203
|
+
except Exception as e:
|
|
204
|
+
print(f"Error: {e}")
|
|
205
|
+
completed += 1
|
|
206
|
+
|
|
207
|
+
return results
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Retry Logic with Exponential Backoff
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
import asyncio
|
|
214
|
+
import random
|
|
215
|
+
from boltz2_client import Boltz2Client
|
|
216
|
+
|
|
217
|
+
async def fold_with_retry(client, sequence, max_retries=3):
|
|
218
|
+
for attempt in range(max_retries):
|
|
219
|
+
try:
|
|
220
|
+
response = await client.predict_protein_structure(
|
|
221
|
+
sequence=sequence,
|
|
222
|
+
recycling_steps=1,
|
|
223
|
+
sampling_steps=20,
|
|
224
|
+
save_structures=False
|
|
225
|
+
)
|
|
226
|
+
return response
|
|
227
|
+
except Exception as e:
|
|
228
|
+
if attempt < max_retries - 1:
|
|
229
|
+
delay = (2 ** attempt) + random.uniform(0, 1) # Exponential backoff
|
|
230
|
+
print(f"Attempt {attempt + 1} failed, retrying in {delay:.1f}s: {e}")
|
|
231
|
+
await asyncio.sleep(delay)
|
|
232
|
+
else:
|
|
233
|
+
print(f"All {max_retries} attempts failed: {e}")
|
|
234
|
+
raise
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Chunked Processing for Large Batches
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
import asyncio
|
|
241
|
+
from boltz2_client import Boltz2Client
|
|
242
|
+
|
|
243
|
+
async def process_in_chunks(sequences, chunk_size=10):
|
|
244
|
+
client = Boltz2Client("http://localhost:8000")
|
|
245
|
+
all_results = []
|
|
246
|
+
|
|
247
|
+
# Process sequences in chunks
|
|
248
|
+
for i in range(0, len(sequences), chunk_size):
|
|
249
|
+
chunk = sequences[i:i + chunk_size]
|
|
250
|
+
print(f"Processing chunk {i//chunk_size + 1}/{(len(sequences)-1)//chunk_size + 1}")
|
|
251
|
+
|
|
252
|
+
# Process chunk concurrently
|
|
253
|
+
tasks = [
|
|
254
|
+
client.predict_protein_structure(
|
|
255
|
+
sequence=seq,
|
|
256
|
+
recycling_steps=1,
|
|
257
|
+
sampling_steps=20,
|
|
258
|
+
save_structures=False
|
|
259
|
+
)
|
|
260
|
+
for seq in chunk
|
|
261
|
+
]
|
|
262
|
+
|
|
263
|
+
chunk_results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
264
|
+
all_results.extend(chunk_results)
|
|
265
|
+
|
|
266
|
+
# Brief pause between chunks
|
|
267
|
+
await asyncio.sleep(1)
|
|
268
|
+
|
|
269
|
+
return all_results
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Performance Optimization
|
|
273
|
+
|
|
274
|
+
### Optimal Concurrency Settings
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
# Local endpoint - adjust based on GPU memory
|
|
278
|
+
MAX_CONCURRENT_LOCAL = 3-5
|
|
279
|
+
|
|
280
|
+
# NVIDIA hosted endpoint - respect rate limits
|
|
281
|
+
MAX_CONCURRENT_HOSTED = 10-20
|
|
282
|
+
|
|
283
|
+
# Fast settings for batch processing
|
|
284
|
+
FAST_SETTINGS = {
|
|
285
|
+
"recycling_steps": 1,
|
|
286
|
+
"sampling_steps": 20,
|
|
287
|
+
"save_structures": False
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
# High-quality settings for important predictions
|
|
291
|
+
QUALITY_SETTINGS = {
|
|
292
|
+
"recycling_steps": 3,
|
|
293
|
+
"sampling_steps": 50,
|
|
294
|
+
"save_structures": True
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Memory Management
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
import asyncio
|
|
302
|
+
import gc
|
|
303
|
+
from boltz2_client import Boltz2Client
|
|
304
|
+
|
|
305
|
+
async def memory_efficient_batch(sequences, batch_size=50):
|
|
306
|
+
client = Boltz2Client("http://localhost:8000")
|
|
307
|
+
|
|
308
|
+
for i in range(0, len(sequences), batch_size):
|
|
309
|
+
batch = sequences[i:i + batch_size]
|
|
310
|
+
|
|
311
|
+
# Process batch
|
|
312
|
+
results = await asyncio.gather(*[
|
|
313
|
+
client.predict_protein_structure(
|
|
314
|
+
sequence=seq,
|
|
315
|
+
recycling_steps=1,
|
|
316
|
+
sampling_steps=20,
|
|
317
|
+
save_structures=False
|
|
318
|
+
)
|
|
319
|
+
for seq in batch
|
|
320
|
+
])
|
|
321
|
+
|
|
322
|
+
# Process results immediately
|
|
323
|
+
for result in results:
|
|
324
|
+
# Save or process result
|
|
325
|
+
pass
|
|
326
|
+
|
|
327
|
+
# Clean up memory
|
|
328
|
+
del results
|
|
329
|
+
gc.collect()
|
|
330
|
+
|
|
331
|
+
print(f"Completed batch {i//batch_size + 1}")
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Error Handling
|
|
335
|
+
|
|
336
|
+
### Comprehensive Error Handling
|
|
337
|
+
|
|
338
|
+
```python
|
|
339
|
+
import asyncio
|
|
340
|
+
from boltz2_client import Boltz2Client
|
|
341
|
+
from boltz2_client.exceptions import (
|
|
342
|
+
Boltz2APIError,
|
|
343
|
+
Boltz2TimeoutError,
|
|
344
|
+
Boltz2ConnectionError,
|
|
345
|
+
Boltz2ValidationError
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
async def robust_fold(client, sequence, protein_id):
|
|
349
|
+
try:
|
|
350
|
+
response = await client.predict_protein_structure(
|
|
351
|
+
sequence=sequence,
|
|
352
|
+
recycling_steps=1,
|
|
353
|
+
sampling_steps=20,
|
|
354
|
+
save_structures=False
|
|
355
|
+
)
|
|
356
|
+
return {"id": protein_id, "success": True, "result": response}
|
|
357
|
+
|
|
358
|
+
except Boltz2ValidationError as e:
|
|
359
|
+
return {"id": protein_id, "success": False, "error": "validation", "message": str(e)}
|
|
360
|
+
except Boltz2TimeoutError as e:
|
|
361
|
+
return {"id": protein_id, "success": False, "error": "timeout", "message": str(e)}
|
|
362
|
+
except Boltz2ConnectionError as e:
|
|
363
|
+
return {"id": protein_id, "success": False, "error": "connection", "message": str(e)}
|
|
364
|
+
except Boltz2APIError as e:
|
|
365
|
+
return {"id": protein_id, "success": False, "error": "api", "message": str(e)}
|
|
366
|
+
except Exception as e:
|
|
367
|
+
return {"id": protein_id, "success": False, "error": "unknown", "message": str(e)}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Best Practices
|
|
371
|
+
|
|
372
|
+
### 1. Choose Appropriate Concurrency
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
# Local endpoint: Limited by GPU memory
|
|
376
|
+
local_concurrent = 3-5
|
|
377
|
+
|
|
378
|
+
# NVIDIA hosted: Limited by rate limits
|
|
379
|
+
hosted_concurrent = 10-20
|
|
380
|
+
|
|
381
|
+
# Start conservative and increase gradually
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### 2. Use Fast Settings for Batch Processing
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
# For batch processing, use minimal settings
|
|
388
|
+
batch_settings = {
|
|
389
|
+
"recycling_steps": 1,
|
|
390
|
+
"sampling_steps": 20,
|
|
391
|
+
"save_structures": False
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
# For important predictions, use quality settings
|
|
395
|
+
quality_settings = {
|
|
396
|
+
"recycling_steps": 3,
|
|
397
|
+
"sampling_steps": 50,
|
|
398
|
+
"save_structures": True
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### 3. Implement Proper Error Handling
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
# Always handle exceptions gracefully
|
|
406
|
+
# Use retry logic for transient errors
|
|
407
|
+
# Log errors for debugging
|
|
408
|
+
# Continue processing other sequences on individual failures
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### 4. Monitor Resource Usage
|
|
412
|
+
|
|
413
|
+
```python
|
|
414
|
+
import psutil
|
|
415
|
+
import time
|
|
416
|
+
|
|
417
|
+
async def monitor_resources():
|
|
418
|
+
while True:
|
|
419
|
+
cpu = psutil.cpu_percent()
|
|
420
|
+
memory = psutil.virtual_memory().percent
|
|
421
|
+
print(f"CPU: {cpu}%, Memory: {memory}%")
|
|
422
|
+
await asyncio.sleep(10)
|
|
423
|
+
|
|
424
|
+
# Run monitoring in background
|
|
425
|
+
asyncio.create_task(monitor_resources())
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### 5. Save Results Incrementally
|
|
429
|
+
|
|
430
|
+
```python
|
|
431
|
+
import json
|
|
432
|
+
from datetime import datetime
|
|
433
|
+
|
|
434
|
+
async def save_results_incrementally(results, filename=None):
|
|
435
|
+
if not filename:
|
|
436
|
+
filename = f"results_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
|
|
437
|
+
|
|
438
|
+
with open(filename, 'w') as f:
|
|
439
|
+
json.dump(results, f, indent=2)
|
|
440
|
+
|
|
441
|
+
print(f"Results saved to {filename}")
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
## Troubleshooting
|
|
446
|
+
|
|
447
|
+
### Common Issues
|
|
448
|
+
|
|
449
|
+
1. **Too many concurrent requests**: Reduce `max_concurrent`
|
|
450
|
+
2. **Memory issues**: Use chunked processing
|
|
451
|
+
3. **Timeout errors**: Increase timeout or reduce complexity
|
|
452
|
+
4. **Rate limiting**: Add delays between requests
|
|
453
|
+
5. **Connection errors**: Implement retry logic
|
|
454
|
+
|
|
455
|
+
### Debugging Tips
|
|
456
|
+
|
|
457
|
+
```python
|
|
458
|
+
import logging
|
|
459
|
+
|
|
460
|
+
# Enable debug logging
|
|
461
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
462
|
+
|
|
463
|
+
# Add timing information
|
|
464
|
+
import time
|
|
465
|
+
start = time.time()
|
|
466
|
+
# ... your async code ...
|
|
467
|
+
print(f"Total time: {time.time() - start:.2f}s")
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
This guide provides a comprehensive foundation for async protein folding with the Boltz-2 Python client. Start with the simple examples and gradually implement more advanced patterns as needed.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Covalent Protein-Ligand Complex Prediction Guide
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This guide demonstrates how to test and use the `boltz2-python-client` package for covalent protein-ligand complex prediction.
|
|
6
|
+
|
|
7
|
+
## ๐งช Package Status
|
|
8
|
+
|
|
9
|
+
โ
**WORKING FEATURES:**
|
|
10
|
+
- โ
Health checks and service monitoring
|
|
11
|
+
- โ
Basic protein structure prediction (async & sync)
|
|
12
|
+
- โ
**Covalent protein-ligand complex prediction** ๐
|
|
13
|
+
- โ
Service metadata retrieval
|
|
14
|
+
- โ
File I/O and result saving (JSON + mmCIF)
|
|
15
|
+
- โ
CLI interface for basic operations
|
|
16
|
+
- โ
Type-safe Pydantic models with CCD support
|
|
17
|
+
- โ
Comprehensive error handling
|
|
18
|
+
- โ
Progress indicators and rich output
|
|
19
|
+
|
|
20
|
+
โ ๏ธ **COVALENT COMPLEX CONSTRAINTS:**
|
|
21
|
+
- The covalent bond constraint format is working but requires:
|
|
22
|
+
- Correct residue indexing (0-based)
|
|
23
|
+
- Valid cysteine positions in the sequence
|
|
24
|
+
- Proper atom naming conventions
|
|
25
|
+
|
|
26
|
+
## ๐ Quick Start
|
|
27
|
+
|
|
28
|
+
### 1. Basic Health Check
|
|
29
|
+
```bash
|
|
30
|
+
boltz2 health
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Simple Protein Prediction
|
|
34
|
+
```bash
|
|
35
|
+
boltz2 protein "MKTVRQERLKSIVRILERSKEPVSGAQLAEELSVSRQVIVQDIAYLRSLGYNIVATPRGYVLAGG"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3. **Covalent Complex Prediction** โญ
|
|
39
|
+
```python
|
|
40
|
+
from boltz2_client import Boltz2Client
|
|
41
|
+
from boltz2_client.models import PredictionRequest, Polymer, Ligand
|
|
42
|
+
|
|
43
|
+
# Updated protein sequence with Cys at position 12
|
|
44
|
+
PROTEIN_SEQUENCE = (
|
|
45
|
+
"MTEYKLVVVGACGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQVVIDGETCLLDILDTAGQEEY"
|
|
46
|
+
"SAMRDQYMRTGEGFLCVFAINNTKSFEDIHHYREQIKRVKDSEDVPMVLVGNKCDLPSRTVDTK"
|
|
47
|
+
"QAQDLARSYGIPFIETSAKTRQGVDDAFYTLVREIRKHKE"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
async def predict_covalent_complex():
|
|
51
|
+
client = Boltz2Client()
|
|
52
|
+
|
|
53
|
+
# Define protein
|
|
54
|
+
protein = Polymer(
|
|
55
|
+
id="A",
|
|
56
|
+
molecule_type="protein",
|
|
57
|
+
sequence=PROTEIN_SEQUENCE
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Define U4U ligand using CCD code
|
|
61
|
+
ligand = Ligand(
|
|
62
|
+
id="LIG",
|
|
63
|
+
ccd="U4U" # Chemical Component Dictionary code
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Define covalent bond constraint
|
|
67
|
+
bond_constraint = {
|
|
68
|
+
"constraint_type": "bond",
|
|
69
|
+
"atoms": [
|
|
70
|
+
{
|
|
71
|
+
"id": "A",
|
|
72
|
+
"residue_index": 12, # Cys12 (1-based indexing)
|
|
73
|
+
"atom_name": "SG"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "LIG",
|
|
77
|
+
"residue_index": 1, # First ligand residue
|
|
78
|
+
"atom_name": "C22"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# Create prediction request
|
|
84
|
+
request = PredictionRequest(
|
|
85
|
+
polymers=[protein],
|
|
86
|
+
ligands=[ligand],
|
|
87
|
+
constraints=[bond_constraint],
|
|
88
|
+
recycling_steps=3,
|
|
89
|
+
sampling_steps=50
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Run prediction
|
|
93
|
+
response = await client.predict(request, show_progress=True)
|
|
94
|
+
|
|
95
|
+
# Save results
|
|
96
|
+
saved_files = await client.save_prediction(
|
|
97
|
+
response,
|
|
98
|
+
"covalent_results",
|
|
99
|
+
prefix="kras_u4u"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
return response, saved_files
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## ๐งฌ **Successful Test Results**
|
|
106
|
+
|
|
107
|
+
### โ
**Working Example: KRAS G12C + U4U Covalent Complex**
|
|
108
|
+
|
|
109
|
+
**Test Configuration:**
|
|
110
|
+
- **Protein**: 168 residues with Cys at position 12
|
|
111
|
+
- **Ligand**: U4U (CCD code)
|
|
112
|
+
- **Covalent Bond**: Cys12 SG โ LIG C22
|
|
113
|
+
- **Prediction Time**: ~6.4 seconds
|
|
114
|
+
- **Confidence**: 0.904 (excellent!)
|
|
115
|
+
|
|
116
|
+
**Output Files:**
|
|
117
|
+
- `kras_u4u_covalent_20250609_104356.json` - Prediction metadata
|
|
118
|
+
- `kras_u4u_covalent_structure_1_20250609_104356.cif` - mmCIF structure
|
|
119
|
+
|
|
120
|
+
## ๐ **Key Implementation Details**
|
|
121
|
+
|
|
122
|
+
### 1. **Ligand Specification**
|
|
123
|
+
The package now supports both SMILES and CCD codes:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
# Option 1: CCD code (recommended for known compounds)
|
|
127
|
+
ligand = Ligand(id="LIG", ccd="U4U")
|
|
128
|
+
|
|
129
|
+
# Option 2: SMILES string
|
|
130
|
+
ligand = Ligand(id="LIG", smiles="CC1=C(C=C(C=C1)C(=O)NC2=CC(=C(C=C2)CN3CCN(CC3)C)F)C(F)(F)F")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 2. **Constraint Format**
|
|
134
|
+
Covalent bond constraints use this exact format:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
bond_constraint = {
|
|
138
|
+
"constraint_type": "bond",
|
|
139
|
+
"atoms": [
|
|
140
|
+
{
|
|
141
|
+
"id": "A", # Polymer ID
|
|
142
|
+
"residue_index": 12, # 1-based residue number
|
|
143
|
+
"atom_name": "SG" # Atom name (e.g., SG for cysteine sulfur)
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"id": "LIG", # Ligand ID
|
|
147
|
+
"residue_index": 1, # Ligand residue (usually 1)
|
|
148
|
+
"atom_name": "C22" # Ligand atom name
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 3. **Indexing Convention**
|
|
155
|
+
- **Residue indexing**: 1-based (Cys12 = residue_index: 12)
|
|
156
|
+
- **Sequence indexing**: 0-based for validation (sequence[11] = 'C')
|
|
157
|
+
|
|
158
|
+
## ๐ง **Testing Commands**
|
|
159
|
+
|
|
160
|
+
### Run Example Script
|
|
161
|
+
```bash
|
|
162
|
+
python examples/04_covalent_bonding.py
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## ๐ **Expected Results**
|
|
166
|
+
|
|
167
|
+
A successful covalent complex prediction should produce:
|
|
168
|
+
|
|
169
|
+
1. **High confidence scores** (>0.8 is excellent)
|
|
170
|
+
2. **mmCIF structure file** with both protein and ligand
|
|
171
|
+
3. **JSON metadata** with prediction details
|
|
172
|
+
4. **Reasonable prediction time** (5-15 seconds for this example)
|
|
173
|
+
|
|
174
|
+
## ๐ฏ **Best Practices**
|
|
175
|
+
|
|
176
|
+
1. **Verify cysteine position**: Ensure your sequence has 'C' at the specified position
|
|
177
|
+
2. **Use CCD codes**: When available, CCD codes are more reliable than SMILES
|
|
178
|
+
3. **Check confidence**: High confidence (>0.7) indicates reliable predictions
|
|
179
|
+
4. **Save results**: Always save both JSON metadata and mmCIF structures
|
|
180
|
+
5. **Monitor progress**: Use `show_progress=True` for long predictions
|
|
181
|
+
|
|
182
|
+
## ๐จ **Common Issues & Solutions**
|
|
183
|
+
|
|
184
|
+
### Issue: "Field required" error for constraints
|
|
185
|
+
**Solution**: Use the exact constraint format shown above
|
|
186
|
+
|
|
187
|
+
### Issue: "String should match pattern" for ligand ID
|
|
188
|
+
**Solution**: Use simple IDs like "LIG" instead of complex codes like "U4U"
|
|
189
|
+
|
|
190
|
+
### Issue: Low confidence at covalent site
|
|
191
|
+
**Solution**: Verify the atom names and residue indices are correct
|
|
192
|
+
|
|
193
|
+
### Issue: Prediction timeout
|
|
194
|
+
**Solution**: Increase timeout parameter: `client.predict(request, timeout=900)`
|
|
195
|
+
|
|
196
|
+
## ๐ **Success!**
|
|
197
|
+
|
|
198
|
+
The `boltz2-python-client` package is now fully functional for covalent protein-ligand complex prediction!
|
|
199
|
+
|
|
200
|
+
**Key achievements:**
|
|
201
|
+
- โ
Successful covalent bond constraint implementation
|
|
202
|
+
- โ
Support for both SMILES and CCD ligand specifications
|
|
203
|
+
- โ
High-quality predictions with excellent confidence scores
|
|
204
|
+
- โ
Comprehensive error handling and validation
|
|
205
|
+
- โ
Professional file output and result management
|
|
206
|
+
|
|
207
|
+
You can now use this package for production covalent complex predictions! ๐งชโจ
|