boltz-vsynthes 1.0.35__tar.gz → 1.0.37__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.
Files changed (123) hide show
  1. {boltz_vsynthes-1.0.35/src/boltz_vsynthes.egg-info → boltz_vsynthes-1.0.37}/PKG-INFO +1 -1
  2. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/pyproject.toml +1 -1
  3. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/schema.py +91 -91
  4. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/yaml.py +23 -13
  5. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/write/writer.py +29 -66
  6. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37/src/boltz_vsynthes.egg-info}/PKG-INFO +1 -1
  7. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/LICENSE +0 -0
  8. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/README.md +0 -0
  9. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/setup.cfg +0 -0
  10. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/__init__.py +0 -0
  11. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/__init__.py +0 -0
  12. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/const.py +0 -0
  13. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/crop/__init__.py +0 -0
  14. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/crop/affinity.py +0 -0
  15. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/crop/boltz.py +0 -0
  16. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/crop/cropper.py +0 -0
  17. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/feature/__init__.py +0 -0
  18. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/feature/featurizer.py +0 -0
  19. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/feature/featurizerv2.py +0 -0
  20. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/feature/symmetry.py +0 -0
  21. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/__init__.py +0 -0
  22. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/dynamic/__init__.py +0 -0
  23. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/dynamic/date.py +0 -0
  24. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/dynamic/filter.py +0 -0
  25. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/dynamic/max_residues.py +0 -0
  26. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/dynamic/resolution.py +0 -0
  27. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/dynamic/size.py +0 -0
  28. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/dynamic/subset.py +0 -0
  29. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/static/__init__.py +0 -0
  30. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/static/filter.py +0 -0
  31. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/static/ligand.py +0 -0
  32. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/filter/static/polymer.py +0 -0
  33. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/module/__init__.py +0 -0
  34. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/module/inference.py +0 -0
  35. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/module/inferencev2.py +0 -0
  36. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/module/training.py +0 -0
  37. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/module/trainingv2.py +0 -0
  38. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/mol.py +0 -0
  39. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/msa/__init__.py +0 -0
  40. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/msa/mmseqs2.py +0 -0
  41. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/pad.py +0 -0
  42. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/__init__.py +0 -0
  43. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/a3m.py +0 -0
  44. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/csv.py +0 -0
  45. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/fasta.py +0 -0
  46. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/mmcif.py +0 -0
  47. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/mmcif_with_constraints.py +0 -0
  48. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/pdb.py +0 -0
  49. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/pdb_download.py +0 -0
  50. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/parse/sdf.py +0 -0
  51. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/sample/__init__.py +0 -0
  52. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/sample/cluster.py +0 -0
  53. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/sample/distillation.py +0 -0
  54. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/sample/random.py +0 -0
  55. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/sample/sampler.py +0 -0
  56. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/tokenize/__init__.py +0 -0
  57. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/tokenize/boltz.py +0 -0
  58. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/tokenize/boltz2.py +0 -0
  59. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/tokenize/tokenizer.py +0 -0
  60. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/types.py +0 -0
  61. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/write/__init__.py +0 -0
  62. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/write/mmcif.py +0 -0
  63. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/write/pdb.py +0 -0
  64. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/data/write/utils.py +0 -0
  65. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/main.py +0 -0
  66. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/__init__.py +0 -0
  67. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/__init__.py +0 -0
  68. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/attention.py +0 -0
  69. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/attentionv2.py +0 -0
  70. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/confidence_utils.py +0 -0
  71. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/dropout.py +0 -0
  72. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/initialize.py +0 -0
  73. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/outer_product_mean.py +0 -0
  74. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/pair_averaging.py +0 -0
  75. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/pairformer.py +0 -0
  76. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/relative.py +0 -0
  77. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/transition.py +0 -0
  78. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/triangular_attention/__init__.py +0 -0
  79. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/triangular_attention/attention.py +0 -0
  80. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/triangular_attention/primitives.py +0 -0
  81. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/triangular_attention/utils.py +0 -0
  82. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/layers/triangular_mult.py +0 -0
  83. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/__init__.py +0 -0
  84. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/bfactor.py +0 -0
  85. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/confidence.py +0 -0
  86. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/confidencev2.py +0 -0
  87. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/diffusion.py +0 -0
  88. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/diffusionv2.py +0 -0
  89. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/distogram.py +0 -0
  90. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/distogramv2.py +0 -0
  91. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/loss/validation.py +0 -0
  92. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/models/__init__.py +0 -0
  93. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/models/boltz1.py +0 -0
  94. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/models/boltz2.py +0 -0
  95. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/__init__.py +0 -0
  96. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/affinity.py +0 -0
  97. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/confidence.py +0 -0
  98. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/confidence_utils.py +0 -0
  99. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/confidencev2.py +0 -0
  100. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/diffusion.py +0 -0
  101. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/diffusion_conditioning.py +0 -0
  102. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/diffusionv2.py +0 -0
  103. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/encoders.py +0 -0
  104. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/encodersv2.py +0 -0
  105. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/transformers.py +0 -0
  106. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/transformersv2.py +0 -0
  107. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/trunk.py +0 -0
  108. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/trunkv2.py +0 -0
  109. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/modules/utils.py +0 -0
  110. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/optim/__init__.py +0 -0
  111. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/optim/ema.py +0 -0
  112. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/optim/scheduler.py +0 -0
  113. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/potentials/__init__.py +0 -0
  114. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/potentials/potentials.py +0 -0
  115. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz/model/potentials/schedules.py +0 -0
  116. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz_vsynthes.egg-info/SOURCES.txt +0 -0
  117. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz_vsynthes.egg-info/dependency_links.txt +0 -0
  118. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz_vsynthes.egg-info/entry_points.txt +0 -0
  119. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz_vsynthes.egg-info/requires.txt +0 -0
  120. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/src/boltz_vsynthes.egg-info/top_level.txt +0 -0
  121. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/tests/test_kernels.py +0 -0
  122. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/tests/test_regression.py +0 -0
  123. {boltz_vsynthes-1.0.35 → boltz_vsynthes-1.0.37}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boltz-vsynthes
3
- Version: 1.0.35
3
+ Version: 1.0.37
4
4
  Summary: Boltz for VSYNTHES
5
5
  Requires-Python: <3.13,>=3.10
6
6
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "boltz-vsynthes"
7
- version = "1.0.35"
7
+ version = "1.0.37"
8
8
  requires-python = ">=3.10,<3.13"
9
9
  description = "Boltz for VSYNTHES"
10
10
  readme = "README.md"
@@ -3,6 +3,7 @@ from dataclasses import dataclass
3
3
  from pathlib import Path
4
4
  from typing import Optional
5
5
  import json
6
+ import yaml
6
7
 
7
8
  import click
8
9
  import numpy as np
@@ -936,6 +937,7 @@ def parse_boltz_schema( # noqa: C901, PLR0915, PLR0912
936
937
  ccd: Mapping[str, Mol],
937
938
  mol_dir: Optional[Path] = None,
938
939
  boltz_2: bool = False,
940
+ output_dir: Optional[Path] = None,
939
941
  ) -> Target:
940
942
  """Parse a Boltz input yaml / json.
941
943
 
@@ -987,6 +989,8 @@ def parse_boltz_schema( # noqa: C901, PLR0915, PLR0912
987
989
  Path to the directory containing the molecules.
988
990
  boltz2: bool
989
991
  Whether to parse the input for Boltz2.
992
+ output_dir: Path, optional
993
+ Path to the output directory. If provided, results will be saved in a subfolder named after the input file.
990
994
 
991
995
  Returns
992
996
  -------
@@ -994,6 +998,14 @@ def parse_boltz_schema( # noqa: C901, PLR0915, PLR0912
994
998
  The parsed target.
995
999
 
996
1000
  """
1001
+ # Create output directory if specified
1002
+ if output_dir is not None:
1003
+ output_dir = Path(output_dir)
1004
+ output_dir.mkdir(parents=True, exist_ok=True)
1005
+ # Create subfolder based on input name
1006
+ subfolder = output_dir / name
1007
+ subfolder.mkdir(parents=True, exist_ok=True)
1008
+
997
1009
  # Assert version 1
998
1010
  version = schema.get("version", 1)
999
1011
  if version != 1:
@@ -1222,7 +1234,7 @@ def parse_boltz_schema( # noqa: C901, PLR0915, PLR0912
1222
1234
  )
1223
1235
 
1224
1236
  # Parse a non-polymer
1225
- elif (entity_type == "ligand") and ("ccd" in items[0][entity_type]):
1237
+ elif (entity_type == "ligand") and "ccd" in (items[0][entity_type]):
1226
1238
  seq = items[0][entity_type]["ccd"]
1227
1239
 
1228
1240
  if isinstance(seq, str):
@@ -1314,60 +1326,6 @@ def parse_boltz_schema( # noqa: C901, PLR0915, PLR0912
1314
1326
  "cyclic", False
1315
1327
  ), "Cyclic flag is not supported for ligands"
1316
1328
 
1317
- elif (entity_type == "ligand") and ("sdf" in items[0][entity_type]):
1318
- # Handle SDF file
1319
- sdf_path = Path(items[0][entity_type]["sdf"])
1320
- from boltz.data.parse.sdf import parse_sdf
1321
- target = parse_sdf(sdf_path, ccd, mol_dir)
1322
- mol = target["sequences"][0]["ligand"]["smiles"]
1323
-
1324
- if affinity:
1325
- mol = standardize(mol)
1326
-
1327
- mol = AllChem.MolFromSmiles(mol)
1328
- mol = AllChem.AddHs(mol)
1329
-
1330
- # Set atom names
1331
- canonical_order = AllChem.CanonicalRankAtoms(mol)
1332
- for atom, can_idx in zip(mol.GetAtoms(), canonical_order):
1333
- atom_name = atom.GetSymbol().upper() + str(can_idx + 1)
1334
- if len(atom_name) > 4:
1335
- msg = (
1336
- f"{mol} has an atom with a name longer than "
1337
- f"4 characters: {atom_name}."
1338
- )
1339
- raise ValueError(msg)
1340
- atom.SetProp("name", atom_name)
1341
-
1342
- success = compute_3d_conformer(mol)
1343
- if not success:
1344
- msg = f"Failed to compute 3D conformer for {mol}"
1345
- raise ValueError(msg)
1346
-
1347
- mol_no_h = AllChem.RemoveHs(mol, sanitize=False)
1348
- affinity_mw = AllChem.Descriptors.MolWt(mol_no_h) if affinity else None
1349
- extra_mols[f"LIG{ligand_id}"] = mol_no_h
1350
- residue = parse_ccd_residue(
1351
- name=f"LIG{ligand_id}",
1352
- ref_mol=mol,
1353
- res_idx=0,
1354
- )
1355
-
1356
- ligand_id += 1
1357
- parsed_chain = ParsedChain(
1358
- entity=entity_id,
1359
- residues=[residue],
1360
- type=const.chain_type_ids["NONPOLYMER"],
1361
- cyclic_period=0,
1362
- sequence=None,
1363
- affinity=affinity,
1364
- affinity_mw=affinity_mw,
1365
- )
1366
-
1367
- assert not items[0][entity_type].get(
1368
- "cyclic", False
1369
- ), "Cyclic flag is not supported for ligands"
1370
-
1371
1329
  else:
1372
1330
  msg = f"Invalid entity type: {entity_type}"
1373
1331
  raise ValueError(msg)
@@ -1426,43 +1384,24 @@ def parse_boltz_schema( # noqa: C901, PLR0915, PLR0912
1426
1384
  protein_chains.add(chain_name)
1427
1385
 
1428
1386
  # Add affinity info
1387
+ if chain.affinity and affinity_info is not None:
1388
+ msg = "Cannot compute affinity for multiple ligands!"
1389
+ raise ValueError(msg)
1390
+
1429
1391
  if chain.affinity:
1430
- # If this is a protein binder, we need to create affinity info for each ligand
1431
- if chain_name in affinity_proteins:
1432
- # Find all ligand chains
1433
- ligand_chains = [
1434
- (name, c) for name, c in chains.items()
1435
- if c.type == const.chain_type_ids["NONPOLYMER"]
1436
- ]
1437
- if not ligand_chains:
1438
- msg = "No ligand chains found for protein binder!"
1439
- raise ValueError(msg)
1440
-
1441
- # Create affinity info for each ligand
1442
- for ligand_name, ligand_chain in ligand_chains:
1443
- affinity_info = AffinityInfo(
1444
- chain_id=asym_id,
1445
- mw=chain.affinity_mw,
1446
- )
1447
- # Save the affinity info in a subfolder named after the ligand
1448
- output_dir = Path(f"output/{ligand_name}")
1449
- output_dir.mkdir(parents=True, exist_ok=True)
1450
- # Save the affinity info
1451
- with open(output_dir / "affinity_info.json", "w") as f:
1452
- json.dump({
1453
- "chain_id": asym_id,
1454
- "mw": chain.affinity_mw,
1455
- "ligand_name": ligand_name
1456
- }, f)
1457
- else:
1458
- # This is a ligand binder
1459
- if affinity_info is not None:
1460
- msg = "Cannot compute affinity for multiple ligands!"
1461
- raise ValueError(msg)
1462
- affinity_info = AffinityInfo(
1463
- chain_id=asym_id,
1464
- mw=chain.affinity_mw,
1465
- )
1392
+ affinity_info = AffinityInfo(
1393
+ chain_id=asym_id,
1394
+ mw=chain.affinity_mw,
1395
+ )
1396
+ # Save affinity info if output directory is specified
1397
+ if output_dir is not None:
1398
+ affinity_path = subfolder / "affinity_info.json"
1399
+ with open(affinity_path, "w") as f:
1400
+ json.dump({
1401
+ "chain_id": asym_id,
1402
+ "mw": chain.affinity_mw,
1403
+ "chain_name": chain_name
1404
+ }, f)
1466
1405
 
1467
1406
  # Find all copies of this chain in the assembly
1468
1407
  entity_id = int(chain.entity)
@@ -1925,3 +1864,64 @@ def standardize(smiles: str) -> Optional[str]:
1925
1864
  raise ValueError("Molecule is broken")
1926
1865
 
1927
1866
  return smiles
1867
+
1868
+
1869
+ def parse_boltz_directory(
1870
+ input_dir: Path,
1871
+ output_dir: Path,
1872
+ ccd: Mapping[str, Mol],
1873
+ mol_dir: Optional[Path] = None,
1874
+ boltz_2: bool = False,
1875
+ ) -> list[Target]:
1876
+ """Parse all YAML files in a directory.
1877
+
1878
+ Parameters
1879
+ ----------
1880
+ input_dir : Path
1881
+ Path to the directory containing YAML files.
1882
+ output_dir : Path
1883
+ Path to the output directory where results will be saved.
1884
+ ccd : Mapping[str, Mol]
1885
+ Dictionary of CCD components.
1886
+ mol_dir : Path, optional
1887
+ Path to the directory containing the molecules.
1888
+ boltz_2 : bool, optional
1889
+ Whether to parse the input for Boltz2.
1890
+
1891
+ Returns
1892
+ -------
1893
+ list[Target]
1894
+ List of parsed targets.
1895
+
1896
+ """
1897
+ input_dir = Path(input_dir)
1898
+ output_dir = Path(output_dir)
1899
+ output_dir.mkdir(parents=True, exist_ok=True)
1900
+
1901
+ targets = []
1902
+ for yaml_file in input_dir.glob("*.yaml"):
1903
+ # Skip hidden files and directories
1904
+ if yaml_file.name.startswith('.') or any(part.startswith('.') for part in yaml_file.parts):
1905
+ continue
1906
+
1907
+ try:
1908
+ # Load YAML file
1909
+ with open(yaml_file, "r") as f:
1910
+ schema = yaml.safe_load(f)
1911
+
1912
+ # Parse schema
1913
+ target = parse_boltz_schema(
1914
+ name=yaml_file.stem,
1915
+ schema=schema,
1916
+ ccd=ccd,
1917
+ mol_dir=mol_dir,
1918
+ boltz_2=boltz_2,
1919
+ output_dir=output_dir,
1920
+ )
1921
+ targets.append(target)
1922
+
1923
+ except Exception as e:
1924
+ print(f"Error processing {yaml_file}: {str(e)}")
1925
+ continue
1926
+
1927
+ return targets
@@ -1,9 +1,10 @@
1
1
  from pathlib import Path
2
+ from typing import Union, List, Optional
2
3
 
3
4
  import yaml
4
5
  from rdkit.Chem.rdchem import Mol
5
6
 
6
- from boltz.data.parse.schema import parse_boltz_schema
7
+ from boltz.data.parse.schema import parse_boltz_schema, parse_boltz_directory
7
8
  from boltz.data.types import Target
8
9
 
9
10
 
@@ -12,8 +13,9 @@ def parse_yaml(
12
13
  ccd: dict[str, Mol],
13
14
  mol_dir: Path,
14
15
  boltz2: bool = False,
15
- ) -> Target:
16
- """Parse a Boltz input yaml / json.
16
+ output_dir: Optional[Path] = None,
17
+ ) -> Union[Target, List[Target]]:
18
+ """Parse a Boltz input yaml / json file or directory.
17
19
 
18
20
  The input file should be a yaml file with the following format:
19
21
 
@@ -49,20 +51,28 @@ def parse_yaml(
49
51
  Parameters
50
52
  ----------
51
53
  path : Path
52
- Path to the YAML input format.
53
- components : Dict
54
+ Path to the YAML input file or directory containing YAML files.
55
+ ccd : Dict
54
56
  Dictionary of CCD components.
55
- boltz2 : bool
57
+ mol_dir : Path
58
+ Path to the directory containing molecules.
59
+ boltz2 : bool, optional
56
60
  Whether to parse the input for Boltz2.
61
+ output_dir : Path, optional
62
+ Path to the output directory where results will be saved.
57
63
 
58
64
  Returns
59
65
  -------
60
- Target
61
- The parsed target.
66
+ Union[Target, List[Target]]
67
+ The parsed target(s).
62
68
 
63
69
  """
64
- with path.open("r") as file:
65
- data = yaml.safe_load(file)
66
-
67
- name = path.stem
68
- return parse_boltz_schema(name, data, ccd, mol_dir, boltz2)
70
+ path = Path(path)
71
+
72
+ if path.is_dir():
73
+ return parse_boltz_directory(path, output_dir or path, ccd, mol_dir, boltz2)
74
+ else:
75
+ with path.open("r") as file:
76
+ data = yaml.safe_load(file)
77
+ name = path.stem
78
+ return parse_boltz_schema(name, data, ccd, mol_dir, boltz2, output_dir)
@@ -290,72 +290,35 @@ class BoltzAffinityWriter(BasePredictionWriter):
290
290
  if prediction["exception"]:
291
291
  self.failed += 1
292
292
  return
293
-
294
- # Get the record and check if it has multiple ligands
295
- record = batch["record"][0]
296
- record_dir = self.output_dir / record.id
297
-
298
- # Check if we have ligand-specific directories
299
- ligand_dirs = [d for d in record_dir.iterdir() if d.is_dir() and d.name.startswith("LIG")]
300
-
301
- if ligand_dirs:
302
- # We have multiple ligands, save predictions in each ligand's directory
303
- for ligand_dir in ligand_dirs:
304
- # Dump affinity summary
305
- affinity_summary = {}
306
- pred_affinity_value = prediction["affinity_pred_value"]
307
- pred_affinity_probability = prediction["affinity_probability_binary"]
308
- affinity_summary = {
309
- "affinity_pred_value": pred_affinity_value.item(),
310
- "affinity_probability_binary": pred_affinity_probability.item(),
311
- }
312
- if "affinity_pred_value1" in prediction:
313
- pred_affinity_value1 = prediction["affinity_pred_value1"]
314
- pred_affinity_probability1 = prediction["affinity_probability_binary1"]
315
- pred_affinity_value2 = prediction["affinity_pred_value2"]
316
- pred_affinity_probability2 = prediction["affinity_probability_binary2"]
317
- affinity_summary["affinity_pred_value1"] = pred_affinity_value1.item()
318
- affinity_summary["affinity_probability_binary1"] = (
319
- pred_affinity_probability1.item()
320
- )
321
- affinity_summary["affinity_pred_value2"] = pred_affinity_value2.item()
322
- affinity_summary["affinity_probability_binary2"] = (
323
- pred_affinity_probability2.item()
324
- )
325
-
326
- # Save the affinity summary in the ligand's directory
327
- path = ligand_dir / f"affinity_{record.id}.json"
328
- with path.open("w") as f:
329
- f.write(json.dumps(affinity_summary, indent=4))
330
- else:
331
- # Single ligand case, save in record directory
332
- # Dump affinity summary
333
- affinity_summary = {}
334
- pred_affinity_value = prediction["affinity_pred_value"]
335
- pred_affinity_probability = prediction["affinity_probability_binary"]
336
- affinity_summary = {
337
- "affinity_pred_value": pred_affinity_value.item(),
338
- "affinity_probability_binary": pred_affinity_probability.item(),
339
- }
340
- if "affinity_pred_value1" in prediction:
341
- pred_affinity_value1 = prediction["affinity_pred_value1"]
342
- pred_affinity_probability1 = prediction["affinity_probability_binary1"]
343
- pred_affinity_value2 = prediction["affinity_pred_value2"]
344
- pred_affinity_probability2 = prediction["affinity_probability_binary2"]
345
- affinity_summary["affinity_pred_value1"] = pred_affinity_value1.item()
346
- affinity_summary["affinity_probability_binary1"] = (
347
- pred_affinity_probability1.item()
348
- )
349
- affinity_summary["affinity_pred_value2"] = pred_affinity_value2.item()
350
- affinity_summary["affinity_probability_binary2"] = (
351
- pred_affinity_probability2.item()
352
- )
353
-
354
- # Save the affinity summary
355
- record_dir.mkdir(exist_ok=True)
356
- path = record_dir / f"affinity_{record.id}.json"
357
- with path.open("w") as f:
358
- f.write(json.dumps(affinity_summary, indent=4))
293
+ # Dump affinity summary
294
+ affinity_summary = {}
295
+ pred_affinity_value = prediction["affinity_pred_value"]
296
+ pred_affinity_probability = prediction["affinity_probability_binary"]
297
+ affinity_summary = {
298
+ "affinity_pred_value": pred_affinity_value.item(),
299
+ "affinity_probability_binary": pred_affinity_probability.item(),
300
+ }
301
+ if "affinity_pred_value1" in prediction:
302
+ pred_affinity_value1 = prediction["affinity_pred_value1"]
303
+ pred_affinity_probability1 = prediction["affinity_probability_binary1"]
304
+ pred_affinity_value2 = prediction["affinity_pred_value2"]
305
+ pred_affinity_probability2 = prediction["affinity_probability_binary2"]
306
+ affinity_summary["affinity_pred_value1"] = pred_affinity_value1.item()
307
+ affinity_summary["affinity_probability_binary1"] = (
308
+ pred_affinity_probability1.item()
309
+ )
310
+ affinity_summary["affinity_pred_value2"] = pred_affinity_value2.item()
311
+ affinity_summary["affinity_probability_binary2"] = (
312
+ pred_affinity_probability2.item()
313
+ )
314
+
315
+ # Save the affinity summary
316
+ struct_dir = self.output_dir / batch["record"][0].id
317
+ struct_dir.mkdir(exist_ok=True)
318
+ path = struct_dir / f"affinity_{batch['record'][0].id}.json"
319
+
320
+ with path.open("w") as f:
321
+ f.write(json.dumps(affinity_summary, indent=4))
359
322
 
360
323
  def on_predict_epoch_end(
361
324
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boltz-vsynthes
3
- Version: 1.0.35
3
+ Version: 1.0.37
4
4
  Summary: Boltz for VSYNTHES
5
5
  Requires-Python: <3.13,>=3.10
6
6
  Description-Content-Type: text/markdown
File without changes