rc-foundry 0.1.5__py3-none-any.whl → 0.1.7__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.
Files changed (152) hide show
  1. foundry/inference_engines/checkpoint_registry.py +58 -11
  2. foundry/utils/alignment.py +10 -2
  3. foundry/version.py +2 -2
  4. foundry_cli/download_checkpoints.py +66 -66
  5. {rc_foundry-0.1.5.dist-info → rc_foundry-0.1.7.dist-info}/METADATA +25 -20
  6. rc_foundry-0.1.7.dist-info/RECORD +311 -0
  7. rf3/configs/callbacks/default.yaml +5 -0
  8. rf3/configs/callbacks/dump_validation_structures.yaml +6 -0
  9. rf3/configs/callbacks/metrics_logging.yaml +10 -0
  10. rf3/configs/callbacks/train_logging.yaml +16 -0
  11. rf3/configs/dataloader/default.yaml +15 -0
  12. rf3/configs/datasets/base.yaml +31 -0
  13. rf3/configs/datasets/pdb_and_distillation.yaml +58 -0
  14. rf3/configs/datasets/pdb_only.yaml +17 -0
  15. rf3/configs/datasets/train/disorder_distillation.yaml +48 -0
  16. rf3/configs/datasets/train/domain_distillation.yaml +50 -0
  17. rf3/configs/datasets/train/monomer_distillation.yaml +49 -0
  18. rf3/configs/datasets/train/na_complex_distillation.yaml +50 -0
  19. rf3/configs/datasets/train/pdb/af3_weighted_sampling.yaml +8 -0
  20. rf3/configs/datasets/train/pdb/base.yaml +32 -0
  21. rf3/configs/datasets/train/pdb/plinder.yaml +54 -0
  22. rf3/configs/datasets/train/pdb/train_interface.yaml +51 -0
  23. rf3/configs/datasets/train/pdb/train_pn_unit.yaml +46 -0
  24. rf3/configs/datasets/train/rna_monomer_distillation.yaml +56 -0
  25. rf3/configs/datasets/val/af3_ab_set.yaml +11 -0
  26. rf3/configs/datasets/val/af3_validation.yaml +11 -0
  27. rf3/configs/datasets/val/base.yaml +32 -0
  28. rf3/configs/datasets/val/runs_and_poses.yaml +12 -0
  29. rf3/configs/debug/default.yaml +66 -0
  30. rf3/configs/debug/train_specific_examples.yaml +21 -0
  31. rf3/configs/experiment/pretrained/rf3.yaml +50 -0
  32. rf3/configs/experiment/pretrained/rf3_with_confidence.yaml +13 -0
  33. rf3/configs/experiment/quick-rf3-with-confidence.yaml +15 -0
  34. rf3/configs/experiment/quick-rf3.yaml +61 -0
  35. rf3/configs/hydra/default.yaml +18 -0
  36. rf3/configs/hydra/no_logging.yaml +7 -0
  37. rf3/configs/inference.yaml +7 -0
  38. rf3/configs/inference_engine/base.yaml +23 -0
  39. rf3/configs/inference_engine/rf3.yaml +33 -0
  40. rf3/configs/logger/csv.yaml +6 -0
  41. rf3/configs/logger/default.yaml +3 -0
  42. rf3/configs/logger/wandb.yaml +15 -0
  43. rf3/configs/model/components/ema.yaml +1 -0
  44. rf3/configs/model/components/rf3_net.yaml +177 -0
  45. rf3/configs/model/components/rf3_net_with_confidence_head.yaml +45 -0
  46. rf3/configs/model/optimizers/adam.yaml +5 -0
  47. rf3/configs/model/rf3.yaml +43 -0
  48. rf3/configs/model/rf3_with_confidence.yaml +7 -0
  49. rf3/configs/model/schedulers/af3.yaml +6 -0
  50. rf3/configs/paths/data/default.yaml +43 -0
  51. rf3/configs/paths/default.yaml +21 -0
  52. rf3/configs/train.yaml +42 -0
  53. rf3/configs/trainer/cpu.yaml +6 -0
  54. rf3/configs/trainer/ddp.yaml +5 -0
  55. rf3/configs/trainer/loss/losses/confidence_loss.yaml +29 -0
  56. rf3/configs/trainer/loss/losses/diffusion_loss.yaml +9 -0
  57. rf3/configs/trainer/loss/losses/distogram_loss.yaml +2 -0
  58. rf3/configs/trainer/loss/structure_prediction.yaml +4 -0
  59. rf3/configs/trainer/loss/structure_prediction_with_confidence.yaml +2 -0
  60. rf3/configs/trainer/metrics/structure_prediction.yaml +14 -0
  61. rf3/configs/trainer/rf3.yaml +20 -0
  62. rf3/configs/trainer/rf3_with_confidence.yaml +13 -0
  63. rf3/configs/validate.yaml +45 -0
  64. rfd3/cli.py +10 -4
  65. rfd3/configs/__init__.py +0 -0
  66. rfd3/configs/callbacks/design_callbacks.yaml +10 -0
  67. rfd3/configs/callbacks/metrics_logging.yaml +20 -0
  68. rfd3/configs/callbacks/train_logging.yaml +24 -0
  69. rfd3/configs/dataloader/default.yaml +15 -0
  70. rfd3/configs/dataloader/fast.yaml +11 -0
  71. rfd3/configs/datasets/conditions/dna_condition.yaml +3 -0
  72. rfd3/configs/datasets/conditions/island.yaml +28 -0
  73. rfd3/configs/datasets/conditions/ppi.yaml +2 -0
  74. rfd3/configs/datasets/conditions/sequence_design.yaml +17 -0
  75. rfd3/configs/datasets/conditions/tipatom.yaml +28 -0
  76. rfd3/configs/datasets/conditions/unconditional.yaml +21 -0
  77. rfd3/configs/datasets/design_base.yaml +97 -0
  78. rfd3/configs/datasets/train/pdb/af3_train_interface.yaml +46 -0
  79. rfd3/configs/datasets/train/pdb/af3_train_pn_unit.yaml +42 -0
  80. rfd3/configs/datasets/train/pdb/base.yaml +14 -0
  81. rfd3/configs/datasets/train/pdb/base_no_weights.yaml +19 -0
  82. rfd3/configs/datasets/train/pdb/base_transform_args.yaml +59 -0
  83. rfd3/configs/datasets/train/pdb/na_complex_distillation.yaml +20 -0
  84. rfd3/configs/datasets/train/pdb/pdb_base.yaml +11 -0
  85. rfd3/configs/datasets/train/pdb/rfd3_train_interface.yaml +22 -0
  86. rfd3/configs/datasets/train/pdb/rfd3_train_pn_unit.yaml +23 -0
  87. rfd3/configs/datasets/train/rfd3_monomer_distillation.yaml +38 -0
  88. rfd3/configs/datasets/val/bcov_ppi_easy_medium.yaml +9 -0
  89. rfd3/configs/datasets/val/design_validation_base.yaml +40 -0
  90. rfd3/configs/datasets/val/dna_binder_design5.yaml +9 -0
  91. rfd3/configs/datasets/val/dna_binder_long.yaml +13 -0
  92. rfd3/configs/datasets/val/dna_binder_short.yaml +13 -0
  93. rfd3/configs/datasets/val/indexed.yaml +9 -0
  94. rfd3/configs/datasets/val/mcsa_41.yaml +9 -0
  95. rfd3/configs/datasets/val/mcsa_41_short_rigid.yaml +10 -0
  96. rfd3/configs/datasets/val/ppi_inference.yaml +7 -0
  97. rfd3/configs/datasets/val/sm_binder_hbonds.yaml +13 -0
  98. rfd3/configs/datasets/val/sm_binder_hbonds_short.yaml +15 -0
  99. rfd3/configs/datasets/val/unconditional.yaml +9 -0
  100. rfd3/configs/datasets/val/unconditional_deep.yaml +9 -0
  101. rfd3/configs/datasets/val/unindexed.yaml +8 -0
  102. rfd3/configs/datasets/val/val_examples/bcov_ppi_easy_medium_with_ori.yaml +151 -0
  103. rfd3/configs/datasets/val/val_examples/bcov_ppi_easy_medium_with_ori_spoof_helical_bundle.yaml +7 -0
  104. rfd3/configs/datasets/val/val_examples/bcov_ppi_easy_medium_with_ori_varying_lengths.yaml +28 -0
  105. rfd3/configs/datasets/val/val_examples/bpem_ori_hb.yaml +212 -0
  106. rfd3/configs/debug/default.yaml +64 -0
  107. rfd3/configs/debug/train_specific_examples.yaml +21 -0
  108. rfd3/configs/dev.yaml +9 -0
  109. rfd3/configs/experiment/debug.yaml +14 -0
  110. rfd3/configs/experiment/pretrain.yaml +31 -0
  111. rfd3/configs/experiment/test-uncond.yaml +10 -0
  112. rfd3/configs/experiment/test-unindexed.yaml +21 -0
  113. rfd3/configs/hydra/default.yaml +18 -0
  114. rfd3/configs/hydra/no_logging.yaml +7 -0
  115. rfd3/configs/inference.yaml +9 -0
  116. rfd3/configs/inference_engine/base.yaml +15 -0
  117. rfd3/configs/inference_engine/dev.yaml +20 -0
  118. rfd3/configs/inference_engine/rfdiffusion3.yaml +65 -0
  119. rfd3/configs/logger/csv.yaml +6 -0
  120. rfd3/configs/logger/default.yaml +2 -0
  121. rfd3/configs/logger/wandb.yaml +15 -0
  122. rfd3/configs/model/components/ema.yaml +1 -0
  123. rfd3/configs/model/components/rfd3_net.yaml +131 -0
  124. rfd3/configs/model/optimizers/adam.yaml +5 -0
  125. rfd3/configs/model/rfd3_base.yaml +8 -0
  126. rfd3/configs/model/samplers/edm.yaml +21 -0
  127. rfd3/configs/model/samplers/symmetry.yaml +10 -0
  128. rfd3/configs/model/schedulers/af3.yaml +6 -0
  129. rfd3/configs/paths/data/default.yaml +18 -0
  130. rfd3/configs/paths/default.yaml +22 -0
  131. rfd3/configs/train.yaml +28 -0
  132. rfd3/configs/trainer/cpu.yaml +6 -0
  133. rfd3/configs/trainer/ddp.yaml +5 -0
  134. rfd3/configs/trainer/loss/losses/diffusion_loss.yaml +12 -0
  135. rfd3/configs/trainer/loss/losses/sequence_loss.yaml +3 -0
  136. rfd3/configs/trainer/metrics/design_metrics.yaml +22 -0
  137. rfd3/configs/trainer/rfd3_base.yaml +35 -0
  138. rfd3/configs/validate.yaml +34 -0
  139. rfd3/engine.py +19 -11
  140. rfd3/inference/input_parsing.py +1 -1
  141. rfd3/inference/legacy_input_parsing.py +17 -1
  142. rfd3/inference/parsing.py +1 -0
  143. rfd3/inference/symmetry/atom_array.py +1 -5
  144. rfd3/inference/symmetry/checks.py +53 -28
  145. rfd3/inference/symmetry/frames.py +8 -5
  146. rfd3/inference/symmetry/symmetry_utils.py +38 -60
  147. rfd3/run_inference.py +3 -1
  148. rfd3/utils/inference.py +23 -0
  149. rc_foundry-0.1.5.dist-info/RECORD +0 -180
  150. {rc_foundry-0.1.5.dist-info → rc_foundry-0.1.7.dist-info}/WHEEL +0 -0
  151. {rc_foundry-0.1.5.dist-info → rc_foundry-0.1.7.dist-info}/entry_points.txt +0 -0
  152. {rc_foundry-0.1.5.dist-info → rc_foundry-0.1.7.dist-info}/licenses/LICENSE.md +0 -0
@@ -3,20 +3,62 @@
3
3
  import os
4
4
  from dataclasses import dataclass
5
5
  from pathlib import Path
6
+ from typing import Iterable, List
6
7
 
8
+ import dotenv
7
9
 
8
- def get_default_checkpoint_dir() -> Path:
9
- """Get the default checkpoint directory.
10
+ DEFAULT_CHECKPOINT_DIR = Path.home() / ".foundry" / "checkpoints"
11
+
12
+
13
+ def _normalize_paths(paths: Iterable[Path]) -> list[Path]:
14
+ """Return absolute, deduplicated paths in order."""
15
+ seen = set()
16
+ normalized: List[Path] = []
17
+ for path in paths:
18
+ resolved = path.expanduser().absolute()
19
+ if resolved not in seen:
20
+ normalized.append(resolved)
21
+ seen.add(resolved)
22
+ return normalized
10
23
 
11
- Priority:
12
- 1. FOUNDRY_CHECKPOINTS_DIR environment variable
13
- 2. ~/.foundry/checkpoints
24
+
25
+ def get_default_checkpoint_dirs() -> list[Path]:
26
+ """Return checkpoint search paths.
27
+
28
+ Always starts with the default ~/.foundry/checkpoints directory and then
29
+ appends any additional directories from the colon-separated
30
+ FOUNDRY_CHECKPOINT_DIRS environment variable.
14
31
  """
15
- if "FOUNDRY_CHECKPOINTS_DIR" in os.environ and os.environ.get(
16
- "FOUNDRY_CHECKPOINTS_DIR"
17
- ):
18
- return Path(os.environ["FOUNDRY_CHECKPOINTS_DIR"]).absolute()
19
- return Path.home() / ".foundry" / "checkpoints"
32
+ env_dirs = os.environ.get("FOUNDRY_CHECKPOINT_DIRS", "")
33
+
34
+ # For backward compatibility, also check FOUNDRY_CHECKPOINTS_DIR
35
+ if not env_dirs:
36
+ env_dirs = os.environ.get("FOUNDRY_CHECKPOINTS_DIR", "")
37
+
38
+ extra_dirs: list[Path] = []
39
+ if env_dirs:
40
+ extra_dirs = [Path(p.strip()) for p in env_dirs.split(":") if p.strip()]
41
+ return _normalize_paths([*extra_dirs, DEFAULT_CHECKPOINT_DIR])
42
+
43
+
44
+ def get_default_checkpoint_dir() -> Path:
45
+ """Backward-compatible helper returning the primary checkpoint directory."""
46
+ return get_default_checkpoint_dirs()[0]
47
+
48
+
49
+ def append_checkpoint_to_env(checkpoint_dirs: list[Path]) -> bool:
50
+ dotenv_path = dotenv.find_dotenv()
51
+ if dotenv_path:
52
+ checkpoint_dirs = _normalize_paths(checkpoint_dirs)
53
+ dotenv.set_key(
54
+ dotenv_path=dotenv_path,
55
+ key_to_set="FOUNDRY_CHECKPOINT_DIRS",
56
+ value_to_set=":".join(str(path) for path in checkpoint_dirs),
57
+ export=False,
58
+ )
59
+ return True
60
+ else:
61
+ return False
20
62
 
21
63
 
22
64
  @dataclass
@@ -27,7 +69,12 @@ class RegisteredCheckpoint:
27
69
  sha256: None = None # Optional: add checksum for verification
28
70
 
29
71
  def get_default_path(self):
30
- return get_default_checkpoint_dir() / self.filename
72
+ checkpoint_dirs = get_default_checkpoint_dirs()
73
+ for checkpoint_dir in checkpoint_dirs:
74
+ candidate = checkpoint_dir / self.filename
75
+ if candidate.exists():
76
+ return candidate
77
+ return checkpoint_dirs[0] / self.filename
31
78
 
32
79
 
33
80
  REGISTERED_CHECKPOINTS = {
@@ -18,14 +18,19 @@ def weighted_rigid_align(
18
18
  Returns:
19
19
  X_align_L: [B, L, 3]
20
20
  """
21
- assert X_L.shape == X_gt_L.shape
22
- assert X_L.shape[:-1] == w_L.shape
23
21
 
22
+ # Canonicalize dimensions
23
+ if X_L.ndim == 2:
24
+ X_L = X_L[None]
25
+ if X_gt_L.ndim == 2:
26
+ X_gt_L = X_gt_L[None]
24
27
  if X_exists_L is None:
25
28
  X_exists_L = torch.ones((X_L.shape[-2]), dtype=torch.bool)
26
29
  if w_L is None:
27
30
  w_L = torch.ones_like(X_L[..., 0])
28
31
  else:
32
+ if w_L.ndim == 1:
33
+ w_L = w_L[None]
29
34
  w_L = w_L.to(torch.float32)
30
35
 
31
36
  # Assert `X_exists_L` is a boolean mask
@@ -33,6 +38,9 @@ def weighted_rigid_align(
33
38
  X_exists_L.dtype == torch.bool
34
39
  ), "X_exists_L should be a boolean mask! Otherwise, the alignment will be incorrect (silent failure)!"
35
40
 
41
+ assert X_L.shape == X_gt_L.shape
42
+ assert X_L.shape[:-1] == w_L.shape
43
+
36
44
  X_resolved = X_L[:, X_exists_L]
37
45
  X_gt_resolved = X_gt_L[:, X_exists_L]
38
46
  w_resolved = w_L[:, X_exists_L]
foundry/version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.1.5'
32
- __version_tuple__ = version_tuple = (0, 1, 5)
31
+ __version__ = version = '0.1.7'
32
+ __version_tuple__ = version_tuple = (0, 1, 7)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -6,7 +6,7 @@ from typing import Optional
6
6
  from urllib.request import urlopen
7
7
 
8
8
  import typer
9
- from dotenv import find_dotenv, load_dotenv, set_key
9
+ from dotenv import load_dotenv
10
10
  from rich.console import Console
11
11
  from rich.progress import (
12
12
  BarColumn,
@@ -20,7 +20,8 @@ from rich.progress import (
20
20
 
21
21
  from foundry.inference_engines.checkpoint_registry import (
22
22
  REGISTERED_CHECKPOINTS,
23
- get_default_checkpoint_dir,
23
+ append_checkpoint_to_env,
24
+ get_default_checkpoint_dirs,
24
25
  )
25
26
 
26
27
  load_dotenv(override=True)
@@ -29,6 +30,27 @@ app = typer.Typer(help="Foundry model checkpoint installation utilities")
29
30
  console = Console()
30
31
 
31
32
 
33
+ def _resolve_checkpoint_dirs(checkpoint_dir: Optional[Path]) -> list[Path]:
34
+ """Return checkpoint search path with defaults first."""
35
+ checkpoint_dirs = get_default_checkpoint_dirs()
36
+ if checkpoint_dir is not None:
37
+ resolved = checkpoint_dir.expanduser().absolute()
38
+ if resolved not in checkpoint_dirs:
39
+ checkpoint_dirs.insert(0, resolved)
40
+ else:
41
+ # Move to front
42
+ checkpoint_dirs.remove(resolved)
43
+ checkpoint_dirs.insert(0, resolved)
44
+
45
+ # Try to persist checkpoint dir to .env (optional, may not exist in Colab etc.)
46
+ if append_checkpoint_to_env(checkpoint_dirs):
47
+ console.print(
48
+ f"Tracked checkpoint directories: {':'.join(str(path) for path in checkpoint_dirs)}"
49
+ )
50
+
51
+ return checkpoint_dirs
52
+
53
+
32
54
  def download_file(url: str, dest: Path, verify_hash: Optional[str] = None) -> None:
33
55
  """Download a file with progress bar and optional hash verification.
34
56
 
@@ -123,134 +145,112 @@ def install_model(model_name: str, checkpoint_dir: Path, force: bool = False) ->
123
145
  def install(
124
146
  models: list[str] = typer.Argument(
125
147
  ...,
126
- help="Models to install: 'all', 'rfd3', 'rf3', 'mpnn', or combination",
148
+ help="Models to install: 'all', 'rfd3', 'rf3', 'mpnn', or a combination thereof",
127
149
  ),
128
150
  checkpoint_dir: Optional[Path] = typer.Option(
129
151
  None,
130
152
  "--checkpoint-dir",
131
153
  "-d",
132
- help="Directory to save checkpoints (default: $FOUNDRY_CHECKPOINTS_DIR or ~/.foundry/checkpoints)",
154
+ help="Directory to save checkpoints (default search path: ~/.foundry/checkpoints plus any $FOUNDRY_CHECKPOINT_DIRS entries)",
133
155
  ),
134
156
  force: bool = typer.Option(
135
157
  False, "--force", "-f", help="Overwrite existing checkpoints"
136
158
  ),
137
159
  ):
138
160
  """Install model checkpoints for foundry.
139
-
140
161
  Examples:
141
-
142
162
  foundry install all
143
-
144
163
  foundry install rfd3 rf3
145
-
146
164
  foundry install proteinmpnn --checkpoint-dir ./checkpoints
147
165
  """
148
166
  # Determine checkpoint directory
149
- if checkpoint_dir is None:
150
- checkpoint_dir = get_default_checkpoint_dir()
167
+ checkpoint_dirs = _resolve_checkpoint_dirs(checkpoint_dir)
168
+ primary_checkpoint_dir = checkpoint_dirs[0]
151
169
 
152
- console.print(f"[bold]Checkpoint directory:[/bold] {checkpoint_dir}")
153
- console.print()
170
+ console.print(f"[bold]Install target:[/bold] {primary_checkpoint_dir}\n")
154
171
 
155
172
  # Expand 'all' to all available models
156
173
  if "all" in models:
174
+ models_to_install = list(REGISTERED_CHECKPOINTS.keys())
175
+ elif "base-models" in models:
157
176
  models_to_install = ["rfd3", "proteinmpnn", "ligandmpnn", "rf3"]
158
177
  else:
159
178
  models_to_install = models
160
179
 
161
180
  # Install each model
162
181
  for model_name in models_to_install:
163
- install_model(model_name, checkpoint_dir, force)
182
+ install_model(model_name, primary_checkpoint_dir, force)
164
183
  console.print()
165
184
 
166
- # Try to persist checkpoint dir to .env (optional, may not exist in Colab etc.)
167
- dotenv_path = find_dotenv()
168
- if dotenv_path:
169
- set_key(
170
- dotenv_path=dotenv_path,
171
- key_to_set="FOUNDRY_CHECKPOINTS_DIR",
172
- value_to_set=str(checkpoint_dir),
173
- export=False,
174
- )
175
- console.print(f"Saved FOUNDRY_CHECKPOINTS_DIR to {dotenv_path}")
176
-
177
185
  console.print("[bold green]Installation complete![/bold green]")
178
186
 
179
187
 
180
- @app.command(name="list")
181
- def list_models():
188
+ @app.command(name="list-available")
189
+ def list_available():
182
190
  """List available model checkpoints."""
183
191
  console.print("[bold]Available models:[/bold]\n")
184
192
  for name, info in REGISTERED_CHECKPOINTS.items():
185
193
  console.print(f" [cyan]{name:8}[/cyan] - {info.description}")
186
194
 
187
195
 
188
- @app.command()
189
- def show(
190
- checkpoint_dir: Optional[Path] = typer.Option(
191
- None,
192
- "--checkpoint-dir",
193
- "-d",
194
- help="Checkpoint directory to show",
195
- ),
196
- ):
197
- """Show installed checkpoints."""
198
- if checkpoint_dir is None:
199
- checkpoint_dir = get_default_checkpoint_dir()
196
+ @app.command(name="list-installed")
197
+ def list_installed():
198
+ """List installed checkpoints and their sizes."""
199
+ checkpoint_dirs = _resolve_checkpoint_dirs(None)
200
200
 
201
- if not checkpoint_dir.exists():
202
- console.print(
203
- f"[yellow]No checkpoints directory found at {checkpoint_dir}[/yellow]"
204
- )
205
- raise typer.Exit(0)
201
+ checkpoint_files: list[tuple[Path, float]] = []
202
+ for checkpoint_dir in checkpoint_dirs:
203
+ if not checkpoint_dir.exists():
204
+ continue
205
+ ckpts = list(checkpoint_dir.glob("*.ckpt")) + list(checkpoint_dir.glob("*.pt"))
206
+ for ckpt in ckpts:
207
+ size = ckpt.stat().st_size / (1024**3) # GB
208
+ checkpoint_files.append((ckpt, size))
206
209
 
207
- checkpoint_files = list(checkpoint_dir.glob("*.ckpt"))
208
210
  if not checkpoint_files:
209
- console.print(f"[yellow]No checkpoint files found in {checkpoint_dir}[/yellow]")
211
+ console.print(
212
+ "[yellow]No checkpoint files found in any checkpoint directory[/yellow]"
213
+ )
210
214
  raise typer.Exit(0)
211
215
 
212
- console.print(f"[bold]Installed checkpoints in {checkpoint_dir}:[/bold]\n")
216
+ console.print("[bold]Installed checkpoints:[/bold]\n")
213
217
  total_size = 0
214
- for ckpt in sorted(checkpoint_files):
215
- size = ckpt.stat().st_size / (1024**3) # GB
218
+ for ckpt, size in sorted(checkpoint_files, key=lambda item: str(item[0])):
216
219
  total_size += size
217
- console.print(f" {ckpt.name:30} {size:8.2f} GB")
220
+ console.print(f" {ckpt} {size:8.2f} GB")
218
221
 
219
222
  console.print(f"\n[bold]Total:[/bold] {total_size:.2f} GB")
220
223
 
221
224
 
222
- @app.command()
225
+ @app.command(name="clean")
223
226
  def clean(
224
- checkpoint_dir: Optional[Path] = typer.Option(
225
- None,
226
- "--checkpoint-dir",
227
- "-d",
228
- help="Checkpoint directory to clean",
229
- ),
230
227
  confirm: bool = typer.Option(
231
228
  True, "--confirm/--no-confirm", help="Ask for confirmation before deleting"
232
229
  ),
233
230
  ):
234
231
  """Remove all downloaded checkpoints."""
235
- if checkpoint_dir is None:
236
- checkpoint_dir = get_default_checkpoint_dir()
237
-
238
- if not checkpoint_dir.exists():
239
- console.print(f"[yellow]No checkpoints found at {checkpoint_dir}[/yellow]")
240
- raise typer.Exit(0)
232
+ checkpoint_dirs = _resolve_checkpoint_dirs(None)
241
233
 
242
234
  # List files to delete
243
- checkpoint_files = list(checkpoint_dir.glob("*.ckpt"))
235
+ checkpoint_files: list[Path] = []
236
+ for checkpoint_dir in checkpoint_dirs:
237
+ if not checkpoint_dir.exists():
238
+ continue
239
+ checkpoint_files.extend(checkpoint_dir.glob("*.ckpt"))
240
+ checkpoint_files.extend(checkpoint_dir.glob("*.pt"))
241
+
244
242
  if not checkpoint_files:
245
- console.print(f"[yellow]No checkpoint files found in {checkpoint_dir}[/yellow]")
243
+ console.print(
244
+ "[yellow]No checkpoint files found in any checkpoint directory[/yellow]"
245
+ )
246
246
  raise typer.Exit(0)
247
247
 
248
248
  console.print("[bold]Files to delete:[/bold]")
249
249
  total_size = 0
250
- for ckpt in checkpoint_files:
250
+ for ckpt in sorted(checkpoint_files, key=str):
251
251
  size = ckpt.stat().st_size / (1024**3) # GB
252
252
  total_size += size
253
- console.print(f" {ckpt.name} ({size:.2f} GB)")
253
+ console.print(f" {ckpt} ({size:.2f} GB)")
254
254
 
255
255
  console.print(f"\n[bold]Total:[/bold] {total_size:.2f} GB")
256
256
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rc-foundry
3
- Version: 0.1.5
3
+ Version: 0.1.7
4
4
  Summary: Shared utilities and training infrastructure for biomolecular structure prediction models.
5
5
  Author-email: Institute for Protein Design <contact@ipd.uw.edu>
6
6
  License: BSD 3-Clause License
@@ -104,33 +104,34 @@ All models within Foundry rely on [AtomWorks](https://github.com/RosettaCommons/
104
104
  pip install rc-foundry[all]
105
105
  ```
106
106
 
107
- **Downloading weights** All models can be downloaded to a target folder with:
108
-
107
+ **Downloading weights** Models can be downloaded to a target folder with:
108
+ ```
109
+ foundry install base-models --checkpoint-dir <path/to/ckpt/dir>
110
+ ```
111
+ where `checkpoint-dir` will be `~/.foundry/checkpoints` by default. Foundry always searches `~/.foundry/checkpoints` plus any colon-separated entries in `$FOUNDRY_CHECKPOINT_DIRS` during inference or subsequent commands to find checkpoints. `base-models` installs the latest RFD3, RF3 and MPNN variants - you can also download all of the models supported (including multiple checkpoints of RF3) with `all`, or by listing the models sequentially (e.g. `foundry install rfd3 rf3 ...`).
112
+ To list the registry of available checkpoints:
109
113
  ```
110
- foundry install all --checkpoint_dir <path/to/ckpt/dir>
114
+ foundry list-available
111
115
  ```
112
- This will download all the models supported (including multiple checkpoints of RF3) but as a beginner you can start with:
116
+ To check what you already have downloaded (searches `~/.foundry/checkpoints` plus `$FOUNDRY_CHECKPOINT_DIRS` if set):
113
117
  ```
114
- foundry install rfd3 ligandmpnn rf3 --checkpoint_dir <path/to/ckpt/dir>
118
+ foundry list-installed
115
119
  ```
116
120
 
117
- >*See `examples/all.ipynb` for how to run each model in a notebook.*
121
+ >*See `examples/all.ipynb` for how to run each model and design proteins end-to-end in a notebook.*
122
+
123
+ ### Google Colab
124
+ For an interactive Google Colab notebook walking through a basic design pipeline with RFD3, MPNN, and RF3, please see the [IPD Design Pipeline Tutorial](https://colab.research.google.com/drive/1ZwIMV3n9h0ZOnIXX0GyKUuoiahgifBxh?usp=sharing).
118
125
 
119
126
  ### RFdiffusion3 (RFD3)
120
127
 
121
128
  [RFdiffusion3](https://www.biorxiv.org/content/10.1101/2025.09.18.676967v2) is an all-atom generative model capable of designing protein structures under complex constraints.
122
129
 
123
- > *See [models/rfd3/README.md](models/rfd3/README.md) for complete documentation.*
124
-
125
130
  <div align="center">
126
- <img src="models/rfd3/docs/.assets/trajectory.png" alt="RFdiffusion3 generation trajectory." width="700">
131
+ <img src="docs/_static/cover.png" alt="RFdiffusion3 generation trajectory." width="700">
127
132
  </div>
128
133
 
129
- ### ProteinMPNN
130
- [ProteinMPNN](https://www.science.org/doi/10.1126/science.add2187) and [LigandMPNN](https://www.nature.com/articles/s41592-025-02626-1) are lightweight inverse-folding models which can be use to design diverse sequences for backbones under constrained conditions.
131
-
132
- > *See [models/mpnn/README.md](models/mpnn/README.md) for complete documentation.*
133
-
134
+ > *See [models/rfd3/README.md](models/rfd3/README.md) for complete documentation.*
134
135
 
135
136
  ### RosettaFold3 (RF3)
136
137
 
@@ -142,6 +143,11 @@ foundry install rfd3 ligandmpnn rf3 --checkpoint_dir <path/to/ckpt/dir>
142
143
 
143
144
  > *See [models/rf3/README.md](models/rf3/README.md) for complete documentation.*
144
145
 
146
+ ### ProteinMPNN
147
+ [ProteinMPNN](https://www.science.org/doi/10.1126/science.add2187) and [LigandMPNN](https://www.nature.com/articles/s41592-025-02626-1) are lightweight inverse-folding models which can be use to design diverse sequences for backbones under constrained conditions.
148
+
149
+ > *See [models/mpnn/README.md](models/mpnn/README.md) for complete documentation.*
150
+
145
151
  ---
146
152
 
147
153
  ## Development
@@ -159,11 +165,7 @@ foundry install rfd3 ligandmpnn rf3 --checkpoint_dir <path/to/ckpt/dir>
159
165
  Install both `foundry` and models in editable mode for development:
160
166
 
161
167
  ```bash
162
- # Install foundry and RF3 in editable mode
163
- uv pip install -e . -e ./models/rf3 -e ./models/rfd3 -e ./models/mpnn
164
-
165
- # Or install only foundry (no models)
166
- uv pip install -e .
168
+ uv pip install -e '.[all,dev]'
167
169
  ```
168
170
 
169
171
  This approach allows you to:
@@ -171,6 +173,9 @@ This approach allows you to:
171
173
  - Work on specific models without installing all models
172
174
  - Add new models as independent packages in `models/`
173
175
 
176
+ > [!NOTE]
177
+ > Running tests is not currently supported, test files may be missing.
178
+
174
179
  ### Adding New Models
175
180
 
176
181
  To add a new model: