From a18f99614aee57101707240c282b0f4409dcc78c Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 10 Oct 2025 09:35:57 -0500 Subject: [PATCH 01/22] Address 'command' referenced before assignment error in tests --- tests/test_diffusion.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index f3eaeccd..993e38f3 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -118,15 +118,25 @@ def _write_command(self, bash_file, test_f) -> None: inference.final_step=48 """ out_lines=[] + command_lines = [] + in_command = False with open(bash_file, "r") as f: - lines = f.readlines() - for line in lines: - if not (line.startswith("python") or line.startswith("../")): + for line in f: + stripped = line.strip() + if stripped.startswith("python") or stripped.startswith("../"): + in_command = True + if in_command: + # Remove trailing line continuation slashes + if stripped.endswith("\\"): + command_lines.append(stripped[:-1].strip()) + else: + command_lines.append(stripped) + in_command = False # End of command + else: out_lines.append(line) - else: - command = line.strip() - if not command.startswith("python"): - command = f'python {command}' + if not command_lines: + raise ValueError(f"No valid python command found in {bash_file}") + command = " ".join(command_lines) # get the partial_T if "partial_T" in command: final_step = int(command.split("partial_T=")[1].split(" ")[0]) - 2 From 2d157302d341c3d8b8d8ef2e02a955d419f51e55 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 10 Oct 2025 09:36:45 -0500 Subject: [PATCH 02/22] Adjusting command format for design_macrocyclic_binder.sh and design_macrocyclic_monomer.sh --- examples/design_macrocyclic_binder.sh | 19 ++++++++----------- examples/design_macrocyclic_monomer.sh | 18 ++++++++---------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/examples/design_macrocyclic_binder.sh b/examples/design_macrocyclic_binder.sh index c0c69f0b..1fe5a851 100755 --- a/examples/design_macrocyclic_binder.sh +++ b/examples/design_macrocyclic_binder.sh @@ -1,18 +1,15 @@ #!/bin/bash -prefix=./outputs/diffused_binder_cyclic2 +# Note that in the example below the indices in the +# input_pdbs/7zkr_GABARAP.pdb file have been shifted +# by +2 in chain A relative to pdbID 7zkr. -# Note that the indices in this pdb file have been -# shifted by +2 in chain A relative to pdbID 7zkr. -pdb='./input_pdbs/7zkr_GABARAP.pdb' - -num_designs=10 -script="../scripts/run_inference.py" -$script --config-name base \ -inference.output_prefix=$prefix \ -inference.num_designs=$num_designs \ +../scripts/run_inference.py \ +--config-name base \ +inference.output_prefix=example_outputs/diffused_binder_cyclic2 \ +inference.num_designs=10 \ 'contigmap.contigs=[12-18 A3-117/0]' \ -inference.input_pdb=$pdb \ +inference.input_pdb=/input_pdbs/7zkr_GABARAP.pdb \ inference.cyclic=True \ diffuser.T=50 \ inference.cyc_chains='a' \ diff --git a/examples/design_macrocyclic_monomer.sh b/examples/design_macrocyclic_monomer.sh index 96eda600..3aa1ac3d 100755 --- a/examples/design_macrocyclic_monomer.sh +++ b/examples/design_macrocyclic_monomer.sh @@ -1,17 +1,15 @@ #!/bin/bash -prefix=./outputs/uncond_cycpep -# Note that the indices in this pdb file have been -# shifted by +2 in chain A relative to pdbID 7zkr. -pdb='./input_pdbs/7zkr_GABARAP.pdb' +# Note that in the example below the indices in the +# input_pdbs/7zkr_GABARAP.pdb file have been shifted +# by +2 in chain A relative to pdbID 7zkr. -num_designs=10 -script="../scripts/run_inference.py" -$script --config-name base \ -inference.output_prefix=$prefix \ -inference.num_designs=$num_designs \ +../scripts/run_inference.py \ +--config-name base \ +inference.output_prefix=example_outputs/uncond_cycpep \ +inference.num_designs=10 \ 'contigmap.contigs=[12-18]' \ -inference.input_pdb=$pdb \ +inference.input_pdb=input_pdbs/7zkr_GABARAP.pdb \ inference.cyclic=True \ diffuser.T=50 \ inference.cyc_chains='a' From a45c3f9da7cfd5d3733d33d142ed8e980a7cf6b3 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 10 Oct 2025 13:41:05 -0500 Subject: [PATCH 03/22] Fail tests when example scripts exit non-zero --- tests/test_diffusion.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index 993e38f3..f84af956 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -48,10 +48,12 @@ def setUp(self): print(f"Running commands in {self.out_f}, two steps of diffusion, deterministic=True") self.results = {} + self.exec_status = {} for bash_file in sorted( glob.glob(f"{self.out_f}/*.sh"), reverse=False): test_name = os.path.basename(bash_file)[:-len('.sh')] res, output = execute(f"Running {test_name}", f'bash {bash_file}', return_='tuple', add_message_and_command_line_to_output=True) + self.exec_status[test_name] = (exit_code, output) self.results[test_name] = dict( state = 'failed' if res else 'passed', @@ -61,6 +63,13 @@ def setUp(self): #subprocess.run(["bash", bash_file], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) #subprocess.run(["bash", bash_file]) + def test_examples_run_without_errors(self): + for name, (exit_code, output) in sorted(self.exec_status.items()): + with self.subTest(example=name): + self.assertEqual(exit_code, 0, + msg=f"Example '{name}' exited with {exit_code}\n{output}") + + def test_commands(self): """ From f43a81d59d6999759667db97269d0fea3693c277 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 10 Oct 2025 13:53:59 -0500 Subject: [PATCH 04/22] Changing number of designs for examples from 10 to 2 to speed up tests --- examples/design_cyclic_oligos.sh | 2 +- examples/design_dihedral_oligos.sh | 2 +- examples/design_macrocyclic_binder.sh | 2 +- examples/design_macrocyclic_monomer.sh | 2 +- examples/design_motifscaffolding.sh | 2 +- examples/design_motifscaffolding_inpaintseq.sh | 2 +- examples/design_motifscaffolding_with_target.sh | 2 +- examples/design_nickel.sh | 2 +- examples/design_partialdiffusion.sh | 2 +- examples/design_partialdiffusion_multipleseq.sh | 2 +- examples/design_partialdiffusion_withseq.sh | 2 +- examples/design_ppi.sh | 2 +- examples/design_ppi_flexible_peptide.sh | 2 +- ...pi_flexible_peptide_with_secondarystructure_specification.sh | 2 +- examples/design_ppi_scaffolded.sh | 2 +- examples/design_tetrahedral_oligos.sh | 2 +- examples/design_timbarrel.sh | 2 +- examples/design_unconditional.sh | 2 +- examples/design_unconditional_w_contact_potential.sh | 2 +- examples/design_unconditional_w_monomer_ROG.sh | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/design_cyclic_oligos.sh b/examples/design_cyclic_oligos.sh index db9a0896..0f620816 100755 --- a/examples/design_cyclic_oligos.sh +++ b/examples/design_cyclic_oligos.sh @@ -7,4 +7,4 @@ # We decay this potential with quadratic form, so that it is applied more strongly initially # We specify a total length of 480aa, so each chain is 80 residues long -python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="C6" inference.num_designs=10 inference.output_prefix="example_outputs/C6_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[480-480]' +python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="C6" inference.num_designs=2 inference.output_prefix="example_outputs/C6_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[480-480]' diff --git a/examples/design_dihedral_oligos.sh b/examples/design_dihedral_oligos.sh index 0d64a6fe..ac2f6a6f 100755 --- a/examples/design_dihedral_oligos.sh +++ b/examples/design_dihedral_oligos.sh @@ -7,4 +7,4 @@ # We decay this potential with quadratic form, so that it is applied more strongly initially # We specify a total length of 320aa, so each chain is 80 residues long -python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="D2" inference.num_designs=10 inference.output_prefix="example_outputs/D2_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[320-320]' +python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="D2" inference.num_designs=2 inference.output_prefix="example_outputs/D2_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[320-320]' diff --git a/examples/design_macrocyclic_binder.sh b/examples/design_macrocyclic_binder.sh index 1fe5a851..7db500db 100755 --- a/examples/design_macrocyclic_binder.sh +++ b/examples/design_macrocyclic_binder.sh @@ -7,7 +7,7 @@ ../scripts/run_inference.py \ --config-name base \ inference.output_prefix=example_outputs/diffused_binder_cyclic2 \ -inference.num_designs=10 \ +inference.num_designs=2 \ 'contigmap.contigs=[12-18 A3-117/0]' \ inference.input_pdb=/input_pdbs/7zkr_GABARAP.pdb \ inference.cyclic=True \ diff --git a/examples/design_macrocyclic_monomer.sh b/examples/design_macrocyclic_monomer.sh index 3aa1ac3d..d0cc3188 100755 --- a/examples/design_macrocyclic_monomer.sh +++ b/examples/design_macrocyclic_monomer.sh @@ -7,7 +7,7 @@ ../scripts/run_inference.py \ --config-name base \ inference.output_prefix=example_outputs/uncond_cycpep \ -inference.num_designs=10 \ +inference.num_designs=2 \ 'contigmap.contigs=[12-18]' \ inference.input_pdb=input_pdbs/7zkr_GABARAP.pdb \ inference.cyclic=True \ diff --git a/examples/design_motifscaffolding.sh b/examples/design_motifscaffolding.sh index f5a80ddf..2c9088e8 100755 --- a/examples/design_motifscaffolding.sh +++ b/examples/design_motifscaffolding.sh @@ -8,4 +8,4 @@ # - 10-40 residues (randomly sampled) # We generate 10 designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=10 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=2 diff --git a/examples/design_motifscaffolding_inpaintseq.sh b/examples/design_motifscaffolding_inpaintseq.sh index 8a06444b..08a1c61d 100755 --- a/examples/design_motifscaffolding_inpaintseq.sh +++ b/examples/design_motifscaffolding_inpaintseq.sh @@ -12,4 +12,4 @@ # We generate 10 designs # We then specify that residues 163-168 (inclusive), 170-171 (inclusive) and 179 (inclusive) on the A chain of the input, should be masked in the input -../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_inpaintseq inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=10 'contigmap.inpaint_seq=[A163-168/A170-171/A179]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_inpaintseq inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=2 'contigmap.inpaint_seq=[A163-168/A170-171/A179]' diff --git a/examples/design_motifscaffolding_with_target.sh b/examples/design_motifscaffolding_with_target.sh index b52d7402..fcb32c5d 100755 --- a/examples/design_motifscaffolding_with_target.sh +++ b/examples/design_motifscaffolding_with_target.sh @@ -11,4 +11,4 @@ # We generate 10 designs # As in the paper (at least for some of the designs we tested), we use the complex-finetuned model -python ../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_with_target inference.input_pdb=input_pdbs/1YCR.pdb 'contigmap.contigs=[A25-109/0 0-70/B17-29/0-70]' contigmap.length=70-120 inference.num_designs=10 inference.ckpt_override_path=../models/Complex_base_ckpt.pt +python ../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_with_target inference.input_pdb=input_pdbs/1YCR.pdb 'contigmap.contigs=[A25-109/0 0-70/B17-29/0-70]' contigmap.length=70-120 inference.num_designs=2 inference.ckpt_override_path=../models/Complex_base_ckpt.pt diff --git a/examples/design_nickel.sh b/examples/design_nickel.sh index 8239680f..560951ec 100755 --- a/examples/design_nickel.sh +++ b/examples/design_nickel.sh @@ -17,4 +17,4 @@ ckpt='../models/Base_epoch8_ckpt.pt' -python ../scripts/run_inference.py inference.symmetry="C4" inference.num_designs=15 inference.output_prefix=example_outputs/design_nickel 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.06"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2 potentials.guide_decay="quadratic" inference.input_pdb=input_pdbs/nickel_symmetric_motif.pdb 'contigmap.contigs=[50/A2-4/50/0 50/A7-9/50/0 50/A12-14/50/0 50/A17-19/50/0]' inference.ckpt_override_path=$ckpt +python ../scripts/run_inference.py inference.symmetry="C4" inference.num_designs=2 inference.output_prefix=example_outputs/design_nickel 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.06"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2 potentials.guide_decay="quadratic" inference.input_pdb=input_pdbs/nickel_symmetric_motif.pdb 'contigmap.contigs=[50/A2-4/50/0 50/A7-9/50/0 50/A12-14/50/0 50/A17-19/50/0]' inference.ckpt_override_path=$ckpt diff --git a/examples/design_partialdiffusion.sh b/examples/design_partialdiffusion.sh index 1e1fdc24..3330ad9a 100755 --- a/examples/design_partialdiffusion.sh +++ b/examples/design_partialdiffusion.sh @@ -7,4 +7,4 @@ # But, in either case, the contig length must sum to the length of the input pdb file # We generate 10 designs, and noise and denoise 10 steps (20% of the full trajectory) -../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion inference.input_pdb=input_pdbs/2KL8.pdb 'contigmap.contigs=[79-79]' inference.num_designs=10 diffuser.partial_T=10 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion inference.input_pdb=input_pdbs/2KL8.pdb 'contigmap.contigs=[79-79]' inference.num_designs=2 diffuser.partial_T=10 diff --git a/examples/design_partialdiffusion_multipleseq.sh b/examples/design_partialdiffusion_multipleseq.sh index 1962ff03..36fe03fd 100755 --- a/examples/design_partialdiffusion_multipleseq.sh +++ b/examples/design_partialdiffusion_multipleseq.sh @@ -6,4 +6,4 @@ # Note the ranges do not necessarily need to lie on the same chain as in this example. # However, positions are 0-indexed over the whole sequence--not per-chain-- so care must be taken when providing ranges to provide_seq. -../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithmultiplesequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=10 'contigmap.provide_seq=[172-177,200-205]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithmultiplesequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=2 'contigmap.provide_seq=[172-177,200-205]' diff --git a/examples/design_partialdiffusion_withseq.sh b/examples/design_partialdiffusion_withseq.sh index ab585c74..95c5d73d 100755 --- a/examples/design_partialdiffusion_withseq.sh +++ b/examples/design_partialdiffusion_withseq.sh @@ -11,4 +11,4 @@ # This contig will lead to the whole input pdb being noise by 10 steps (partial_T=10) # However, we provide the sequence of the peptide (the last 20 residues in the contig), with provide_seq=[172-205]. This is 0-indexed -../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithsequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=10 'contigmap.provide_seq=[172-205]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithsequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=2 'contigmap.provide_seq=[172-205]' diff --git a/examples/design_ppi.sh b/examples/design_ppi.sh index 5e217b21..8354ef7b 100755 --- a/examples/design_ppi.sh +++ b/examples/design_ppi.sh @@ -8,4 +8,4 @@ # We tell diffusion to target three specific residues on the target, specifically residues 59, 83 and 91 of the A chain # We make 10 designs, and reduce the noise added during inference to 0, to improve the quality of the designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi inference.input_pdb=input_pdbs/insulin_target.pdb 'contigmap.contigs=[A1-150/0 70-100]' 'ppi.hotspot_res=[A59,A83,A91]' inference.num_designs=10 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi inference.input_pdb=input_pdbs/insulin_target.pdb 'contigmap.contigs=[A1-150/0 70-100]' 'ppi.hotspot_res=[A59,A83,A91]' inference.num_designs=2 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 diff --git a/examples/design_ppi_flexible_peptide.sh b/examples/design_ppi_flexible_peptide.sh index 1af54c71..5960f6b3 100755 --- a/examples/design_ppi_flexible_peptide.sh +++ b/examples/design_ppi_flexible_peptide.sh @@ -9,4 +9,4 @@ # We make 10 designs # We mask (diffuse) the structure of the peptide using the inpaint_str flag. This has the effect of having RFdiffusion simultaneously design a binder and predict the structure of the peptide within the complex. -../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide inference.input_pdb=input_pdbs/3IOL.pdb 'contigmap.contigs=[B10-35/0 70-100]' 'ppi.hotspot_res=[B28,B29]' inference.num_designs=10 'contigmap.inpaint_str=[B10-35]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide inference.input_pdb=input_pdbs/3IOL.pdb 'contigmap.contigs=[B10-35/0 70-100]' 'ppi.hotspot_res=[B28,B29]' inference.num_designs=2 'contigmap.inpaint_str=[B10-35]' diff --git a/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh b/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh index 6e0dfc88..96015db4 100755 --- a/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh +++ b/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh @@ -10,4 +10,4 @@ # We then specify that we want this to adopt a helical conformation # If you wanted to specify that it should adopt a strand conformation, you would specify `contigmap.inpaint_str_strand` -../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide_with_secondarystructure inference.input_pdb=input_pdbs/tau_peptide.pdb 'contigmap.contigs=[70-100/0 B165-178]' inference.num_designs=10 'contigmap.inpaint_str=[B165-178]' scaffoldguided.scaffoldguided=True 'contigmap.inpaint_str_helix=[B165-178]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide_with_secondarystructure inference.input_pdb=input_pdbs/tau_peptide.pdb 'contigmap.contigs=[70-100/0 B165-178]' inference.num_designs=2 'contigmap.inpaint_str=[B165-178]' scaffoldguided.scaffoldguided=True 'contigmap.inpaint_str_helix=[B165-178]' diff --git a/examples/design_ppi_scaffolded.sh b/examples/design_ppi_scaffolded.sh index 63ca165e..96e1ecf0 100755 --- a/examples/design_ppi_scaffolded.sh +++ b/examples/design_ppi_scaffolded.sh @@ -7,4 +7,4 @@ # We then provide a path to a directory of different scaffolds (we've provided some for you to use, from Cao et al., 2022) # We generate 10 designs, and reduce the noise added during inference to 0 (which improves the quality of designs) -../scripts/run_inference.py scaffoldguided.target_path=input_pdbs/insulin_target.pdb inference.output_prefix=example_outputs/design_ppi_scaffolded scaffoldguided.scaffoldguided=True 'ppi.hotspot_res=[A59,A83,A91]' scaffoldguided.target_pdb=True scaffoldguided.target_ss=target_folds/insulin_target_ss.pt scaffoldguided.target_adj=target_folds/insulin_target_adj.pt scaffoldguided.scaffold_dir=./ppi_scaffolds/ inference.num_designs=10 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 +../scripts/run_inference.py scaffoldguided.target_path=input_pdbs/insulin_target.pdb inference.output_prefix=example_outputs/design_ppi_scaffolded scaffoldguided.scaffoldguided=True 'ppi.hotspot_res=[A59,A83,A91]' scaffoldguided.target_pdb=True scaffoldguided.target_ss=target_folds/insulin_target_ss.pt scaffoldguided.target_adj=target_folds/insulin_target_adj.pt scaffoldguided.scaffold_dir=./ppi_scaffolds/ inference.num_designs=2 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 diff --git a/examples/design_tetrahedral_oligos.sh b/examples/design_tetrahedral_oligos.sh index 231e14a9..4d9fcfd0 100755 --- a/examples/design_tetrahedral_oligos.sh +++ b/examples/design_tetrahedral_oligos.sh @@ -7,4 +7,4 @@ # We decay this potential with quadratic form, so that it is applied more strongly initially # We specify a total length of 1200aa, so each chain is 100 residues long -python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="tetrahedral" inference.num_designs=10 inference.output_prefix="example_outputs/tetrahedral_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[1200-1200]' +python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="tetrahedral" inference.num_designs=2 inference.output_prefix="example_outputs/tetrahedral_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[1200-1200]' diff --git a/examples/design_timbarrel.sh b/examples/design_timbarrel.sh index 410254ed..dc679908 100755 --- a/examples/design_timbarrel.sh +++ b/examples/design_timbarrel.sh @@ -8,4 +8,4 @@ # We add 0-5 residues (randomly sampled) to the N and the C-terminus # This will allow the generation of diverse TIM barrels with slightly different length helices and strands -../scripts/run_inference.py inference.output_prefix=example_outputs/design_tim_barrel scaffoldguided.scaffoldguided=True scaffoldguided.target_pdb=False scaffoldguided.scaffold_dir=tim_barrel_scaffold/ inference.num_designs=10 denoiser.noise_scale_ca=0.5 denoiser.noise_scale_frame=0.5 scaffoldguided.sampled_insertion=0-5 scaffoldguided.sampled_N=0-5 scaffoldguided.sampled_C=0-5 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_tim_barrel scaffoldguided.scaffoldguided=True scaffoldguided.target_pdb=False scaffoldguided.scaffold_dir=tim_barrel_scaffold/ inference.num_designs=2 denoiser.noise_scale_ca=0.5 denoiser.noise_scale_frame=0.5 scaffoldguided.sampled_insertion=0-5 scaffoldguided.sampled_N=0-5 scaffoldguided.sampled_C=0-5 diff --git a/examples/design_unconditional.sh b/examples/design_unconditional.sh index 3ece16f7..78887776 100755 --- a/examples/design_unconditional.sh +++ b/examples/design_unconditional.sh @@ -4,4 +4,4 @@ # We tell RFdiffusion that designs should be 100-200 residues in length (randomly sampled each design) # We generate 10 such designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=10 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=2 diff --git a/examples/design_unconditional_w_contact_potential.sh b/examples/design_unconditional_w_contact_potential.sh index 999a9c04..b2743723 100755 --- a/examples/design_unconditional_w_contact_potential.sh +++ b/examples/design_unconditional_w_contact_potential.sh @@ -4,4 +4,4 @@ # We tell RFdiffusion that designs should be 100-200 residues in length (randomly sampled each design) # We generate 10 such designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional_w_contact_potential 'contigmap.contigs=[100-200]' inference.num_designs=10 'potentials.guiding_potentials=["type:monomer_contacts,weight:0.05"]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional_w_contact_potential 'contigmap.contigs=[100-200]' inference.num_designs=2 'potentials.guiding_potentials=["type:monomer_contacts,weight:0.05"]' diff --git a/examples/design_unconditional_w_monomer_ROG.sh b/examples/design_unconditional_w_monomer_ROG.sh index b34a0a72..079caa6b 100755 --- a/examples/design_unconditional_w_monomer_ROG.sh +++ b/examples/design_unconditional_w_monomer_ROG.sh @@ -7,4 +7,4 @@ # We use the monomer_ROG potential, with guide scale 2 and quadratic decay # Note that this potential is probably not necessary in this kind of case, but is provided as an example -../scripts/run_inference.py inference.output_prefix=example_outputs/design_monomer_ROG_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=10 'potentials.guiding_potentials=["type:monomer_ROG,weight:1,min_dist:5"]' potentials.guide_scale=2 potentials.guide_decay="quadratic" +../scripts/run_inference.py inference.output_prefix=example_outputs/design_monomer_ROG_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=2 'potentials.guiding_potentials=["type:monomer_ROG,weight:1,min_dist:5"]' potentials.guide_scale=2 potentials.guide_decay="quadratic" From 778f8d4b28f7cfd6e54c61c76ffd47de6d38bd2a Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 10 Oct 2025 15:21:04 -0500 Subject: [PATCH 05/22] Fix input_pdb path in design_macrocyclic_binder and fix incorrect call to res in test_diffusion.py --- examples/design_macrocyclic_binder.sh | 2 +- tests/test_diffusion.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/design_macrocyclic_binder.sh b/examples/design_macrocyclic_binder.sh index 7db500db..99170417 100755 --- a/examples/design_macrocyclic_binder.sh +++ b/examples/design_macrocyclic_binder.sh @@ -9,7 +9,7 @@ inference.output_prefix=example_outputs/diffused_binder_cyclic2 \ inference.num_designs=2 \ 'contigmap.contigs=[12-18 A3-117/0]' \ -inference.input_pdb=/input_pdbs/7zkr_GABARAP.pdb \ +inference.input_pdb=./input_pdbs/7zkr_GABARAP.pdb \ inference.cyclic=True \ diffuser.T=50 \ inference.cyc_chains='a' \ diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index f84af956..2e8ba44d 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -53,7 +53,7 @@ def setUp(self): for bash_file in sorted( glob.glob(f"{self.out_f}/*.sh"), reverse=False): test_name = os.path.basename(bash_file)[:-len('.sh')] res, output = execute(f"Running {test_name}", f'bash {bash_file}', return_='tuple', add_message_and_command_line_to_output=True) - self.exec_status[test_name] = (exit_code, output) + self.exec_status[test_name] = (res, output) self.results[test_name] = dict( state = 'failed' if res else 'passed', From a9b748be37b34792043b195e955dec5270da8b77 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Tue, 14 Oct 2025 11:44:50 -0500 Subject: [PATCH 06/22] Add print statement to list failed examples --- tests/test_diffusion.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index 2e8ba44d..32ea9bea 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -25,6 +25,8 @@ class TestSubmissionCommands(unittest.TestCase): outputs are the same as the reference outputs. """ + failed_tests = [] + def setUp(self): """ Grabs files from the examples folder @@ -66,9 +68,16 @@ def setUp(self): def test_examples_run_without_errors(self): for name, (exit_code, output) in sorted(self.exec_status.items()): with self.subTest(example=name): + if exit_code != 0: + self.__class__.failed_tests.append(f"{name}") self.assertEqual(exit_code, 0, msg=f"Example '{name}' exited with {exit_code}\n{output}") + sys.stderr.write("\n==== EXAMPLE FAILURE SUMMARY ====\n") + for line in self.__class__.failed_tests: + sys.stderr.write(f" - {line}\n") + sys.stderr.write("=========================\n\n") + sys.stderr.flush() def test_commands(self): @@ -169,7 +178,6 @@ def _write_command(self, bash_file, test_f) -> None: f.write(output_command) - def execute_through_pty(command_line): import pty, select From 5dff3eb188675093229d50a9f854a9d253df70d3 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 17 Oct 2025 10:39:26 -0500 Subject: [PATCH 07/22] These changes split the examples up in chunks and runs the different chunks to speed up the workflow. --- .github/workflows/main.yml | 10 +- tests/test_diffusion.py | 244 +++++++++++++++++++++++++++---------- 2 files changed, 188 insertions(+), 66 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6b23c5dc..89a694ff 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -87,7 +87,15 @@ jobs: - name: Setup and Run ppi_scaffolds tests run: | tar -xvf examples/ppi_scaffolds_subset.tar.gz -C examples - cd tests && uv run python test_diffusion.py + total_chunks=$(nproc) + for chunk_index in $(seq 1 $total_chunks); do + echo "Running chunk $chunk_index of $total_chunks" + uv run python tests/test_diffusion.py --total-chunks $total_chunks --chunk-index $chunk_index & + done + + wait + echo "All chunks completed." + #cd tests && uv run python test_diffusion.py # - name: Test with pytest diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index 32ea9bea..71829775 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -11,6 +11,7 @@ script_dir = os.path.dirname(os.path.abspath(__file__)) + class TestSubmissionCommands(unittest.TestCase): """ Test harness for checking that commands in the examples folder, @@ -27,12 +28,37 @@ class TestSubmissionCommands(unittest.TestCase): failed_tests = [] + # number of chunks to split examples into + total_chunks = 1 + # which chunk to run + chunk_index = 1 + def setUp(self): """ Grabs files from the examples folder """ submissions = glob.glob(f"{script_dir}/../examples/*.sh") # get datetime for output folder, in YYYY_MM_DD_HH_MM_SS format + chunks = self.__class__.total_chunks + idx = self.__class__.chunk_index + if chunks < 1: + raise ValueError("total_chunks must be at least 1") + if idx < 1 or idx > chunks: + raise ValueError( + "chunk_index must be between 1 and total_chunks (inclusive)" + ) + if chunks > 1: + submissions = [ + submissions[i] + for i in range(len(submissions)) + if i % chunks == (idx - 1) + ] + print( + f"Running chunk {idx}/{chunks}, {len(submissions)} submissions to run" + ) + if not submissions: + raise ValueError("No submissions selected for chunk {idx} of {chunks}") + now = datetime.datetime.now() now = now.strftime("%Y_%m_%d_%H_%M_%S") self.out_f = f"{script_dir}/tests_{now}" @@ -41,37 +67,54 @@ def setUp(self): # Make sure we have access to all the relevant files exclude_dirs = ["outputs", "example_outputs"] for filename in os.listdir(f"{script_dir}/../examples"): - if filename not in exclude_dirs and not os.path.islink(os.path.join(script_dir, filename)) and os.path.isdir(os.path.join(f'{script_dir}/../examples', filename)): - os.symlink(os.path.join(f'{script_dir}/../examples', filename), os.path.join(script_dir, filename)) + if ( + filename not in exclude_dirs + and not os.path.islink(os.path.join(script_dir, filename)) + and os.path.isdir(os.path.join(f"{script_dir}/../examples", filename)) + ): + os.symlink( + os.path.join(f"{script_dir}/../examples", filename), + os.path.join(script_dir, filename), + ) for submission in submissions: self._write_command(submission, self.out_f) - print(f"Running commands in {self.out_f}, two steps of diffusion, deterministic=True") + print( + f"Running commands in {self.out_f}, two steps of diffusion, deterministic=True" + ) self.results = {} self.exec_status = {} - for bash_file in sorted( glob.glob(f"{self.out_f}/*.sh"), reverse=False): - test_name = os.path.basename(bash_file)[:-len('.sh')] - res, output = execute(f"Running {test_name}", f'bash {bash_file}', return_='tuple', add_message_and_command_line_to_output=True) + for bash_file in sorted(glob.glob(f"{self.out_f}/*.sh"), reverse=False): + test_name = os.path.basename(bash_file)[: -len(".sh")] + res, output = execute( + f"Running {test_name}", + f"bash {bash_file}", + return_="tuple", + add_message_and_command_line_to_output=True, + ) self.exec_status[test_name] = (res, output) self.results[test_name] = dict( - state = 'failed' if res else 'passed', - log = output, + state="failed" if res else "passed", + log=output, ) - #subprocess.run(["bash", bash_file], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - #subprocess.run(["bash", bash_file]) + # subprocess.run(["bash", bash_file], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + # subprocess.run(["bash", bash_file]) def test_examples_run_without_errors(self): for name, (exit_code, output) in sorted(self.exec_status.items()): with self.subTest(example=name): if exit_code != 0: self.__class__.failed_tests.append(f"{name}") - self.assertEqual(exit_code, 0, - msg=f"Example '{name}' exited with {exit_code}\n{output}") + self.assertEqual( + exit_code, + 0, + msg=f"Example '{name}' exited with {exit_code}\n{output}", + ) sys.stderr.write("\n==== EXAMPLE FAILURE SUMMARY ====\n") for line in self.__class__.failed_tests: @@ -79,51 +122,57 @@ def test_examples_run_without_errors(self): sys.stderr.write("=========================\n\n") sys.stderr.flush() - def test_commands(self): """ Runs all the commands in the test_f folder """ - reference=f'{script_dir}/reference_outputs' + reference = f"{script_dir}/reference_outputs" os.makedirs(reference, exist_ok=True) - test_files=glob.glob(f"{self.out_f}/example_outputs/*pdb") - print(f'{self.out_f=} {test_files=}') + test_files = glob.glob(f"{self.out_f}/example_outputs/*pdb") + print(f"{self.out_f=} {test_files=}") # first check that we have the right number of outputs - #self.assertEqual(len(test_files), len(glob.glob(f"{self.out_f}/*.sh"))), "One or more of the example commands didn't produce an output (check the example command is formatted correctly)" + # self.assertEqual(len(test_files), len(glob.glob(f"{self.out_f}/*.sh"))), "One or more of the example commands didn't produce an output (check the example command is formatted correctly)" result = self.defaultTestResult() for test_file in test_files: with self.subTest(test_file=test_file): - test_pdb=iu.parse_pdb(test_file) + test_pdb = iu.parse_pdb(test_file) if not os.path.exists(f"{reference}/{os.path.basename(test_file)}"): copyfile(test_file, f"{reference}/{os.path.basename(test_file)}") - print(f"Created reference file {reference}/{os.path.basename(test_file)}") + print( + f"Created reference file {reference}/{os.path.basename(test_file)}" + ) else: - ref_pdb=iu.parse_pdb(f"{reference}/{os.path.basename(test_file)}") - rmsd=calc_rmsd(test_pdb['xyz'][:,:3].reshape(-1,3), ref_pdb['xyz'][:,:3].reshape(-1,3))[0] + ref_pdb = iu.parse_pdb(f"{reference}/{os.path.basename(test_file)}") + rmsd = calc_rmsd( + test_pdb["xyz"][:, :3].reshape(-1, 3), + ref_pdb["xyz"][:, :3].reshape(-1, 3), + )[0] try: self.assertAlmostEqual(rmsd, 0, 2) result.addSuccess(self) print(f"Subtest {test_file} passed") - state = 'passed' - log = f'Subtest {test_file} passed' + state = "passed" + log = f"Subtest {test_file} passed" except AssertionError as e: result.addFailure(self, e) print(f"Subtest {test_file} failed") - state = 'failed' - log = f'Subtest {test_file} failed:\n{e!r}' + state = "failed" + log = f"Subtest {test_file} failed:\n{e!r}" - self.results[ 'pdb-diff.' + test_file.rpartition('/')[-1] ] = dict(state = state, log = log) + self.results["pdb-diff." + test_file.rpartition("/")[-1]] = dict( + state=state, log=log + ) - with open('.results.json', 'w') as f: json.dump(self.results, f, sort_keys=True, indent=2) + with open(".results.json", "w") as f: + json.dump(self.results, f, sort_keys=True, indent=2) self.assertTrue(result.wasSuccessful(), "One or more subtests failed") - def _write_command(self, bash_file, test_f) -> None: """ Takes a bash file from the examples folder, and writes @@ -135,7 +184,7 @@ def _write_command(self, bash_file, test_f) -> None: else: inference.final_step=48 """ - out_lines=[] + out_lines = [] command_lines = [] in_command = False with open(bash_file, "r") as f: @@ -149,8 +198,8 @@ def _write_command(self, bash_file, test_f) -> None: command_lines.append(stripped[:-1].strip()) else: command_lines.append(stripped) - in_command = False # End of command - else: + in_command = False # End of command + else: out_lines.append(line) if not command_lines: raise ValueError(f"No valid python command found in {bash_file}") @@ -161,16 +210,17 @@ def _write_command(self, bash_file, test_f) -> None: else: final_step = 48 - output_command = f"{command} inference.deterministic=True inference.final_step={final_step}" + output_command = ( + f"{command} inference.deterministic=True inference.final_step={final_step}" + ) # replace inference.num_designs with 1 if "inference.num_designs=" in output_command: output_command = f'{output_command.split("inference.num_designs=")[0]}inference.num_designs=1 {" ".join(output_command.split("inference.num_designs=")[1].split(" ")[1:])}' else: - output_command = f'{output_command} inference.num_designs=1' + output_command = f"{output_command} inference.num_designs=1" # replace 'example_outputs' with f'{self.out_f}/example_outputs' output_command = f'{output_command.split("example_outputs")[0]}{self.out_f}/example_outputs{output_command.split("example_outputs")[1]}' - # write the new command with open(f"{test_f}/{os.path.basename(bash_file)}", "w") as f: for line in out_lines: @@ -184,21 +234,32 @@ def execute_through_pty(command_line): if sys.platform == "darwin": master, slave = pty.openpty() - p = subprocess.Popen(command_line, shell=True, stdout=slave, stdin=slave, - stderr=subprocess.STDOUT, close_fds=True) + p = subprocess.Popen( + command_line, + shell=True, + stdout=slave, + stdin=slave, + stderr=subprocess.STDOUT, + close_fds=True, + ) buffer = [] while True: try: if select.select([master], [], [], 0.2)[0]: # has something to read data = os.read(master, 1 << 22) - if data: buffer.append(data) + if data: + buffer.append(data) - elif (p.poll() is not None) and (not select.select([master], [], [], 0.2)[0] ): break # process is finished and output buffer if fully read + elif (p.poll() is not None) and ( + not select.select([master], [], [], 0.2)[0] + ): + break # process is finished and output buffer if fully read - except OSError: break # OSError will be raised when child process close PTY descriptior + except OSError: + break # OSError will be raised when child process close PTY descriptior - output = b''.join(buffer).decode(encoding='utf-8', errors='backslashreplace') + output = b"".join(buffer).decode(encoding="utf-8", errors="backslashreplace") os.close(master) os.close(slave) @@ -206,7 +267,7 @@ def execute_through_pty(command_line): p.wait() exit_code = p.returncode - ''' + """ buffer = [] while True: if select.select([master], [], [], 0.2)[0]: # has something to read @@ -227,13 +288,19 @@ def execute_through_pty(command_line): output = b''.join(buffer).decode(encoding='utf-8', errors='backslashreplace') exit_code = p.returncode - ''' + """ else: master, slave = pty.openpty() - p = subprocess.Popen(command_line, shell=True, stdout=slave, stdin=slave, - stderr=subprocess.STDOUT, close_fds=True) + p = subprocess.Popen( + command_line, + shell=True, + stdout=slave, + stdin=slave, + stderr=subprocess.STDOUT, + close_fds=True, + ) os.close(slave) @@ -241,10 +308,12 @@ def execute_through_pty(command_line): while True: try: data = os.read(master, 1 << 22) - if data: buffer.append(data) - except OSError: break # OSError will be raised when child process close PTY descriptior + if data: + buffer.append(data) + except OSError: + break # OSError will be raised when child process close PTY descriptior - output = b''.join(buffer).decode(encoding='utf-8', errors='backslashreplace') + output = b"".join(buffer).decode(encoding="utf-8", errors="backslashreplace") os.close(master) @@ -254,39 +323,84 @@ def execute_through_pty(command_line): return exit_code, output - -def execute(message, command_line, return_='status', until_successes=False, terminate_on_failure=True, silent=False, silence_output=False, silence_output_on_errors=False, add_message_and_command_line_to_output=False): - if not silent: print(message); print(command_line); sys.stdout.flush(); +def execute( + message, + command_line, + return_="status", + until_successes=False, + terminate_on_failure=True, + silent=False, + silence_output=False, + silence_output_on_errors=False, + add_message_and_command_line_to_output=False, +): + if not silent: + print(message) + print(command_line) + sys.stdout.flush() while True: - #exit_code, output = execute_through_subprocess(command_line) - #exit_code, output = execute_through_pexpect(command_line) + # exit_code, output = execute_through_subprocess(command_line) + # exit_code, output = execute_through_pexpect(command_line) exit_code, output = execute_through_pty(command_line) - if (exit_code and not silence_output_on_errors) or not (silent or silence_output): print(output); sys.stdout.flush(); + if (exit_code and not silence_output_on_errors) or not ( + silent or silence_output + ): + print(output) + sys.stdout.flush() - if exit_code and until_successes: pass # Thats right - redability COUNT! - else: break + if exit_code and until_successes: + pass # Thats right - redability COUNT! + else: + break - print( "Error while executing {}: {}\n".format(message, output) ) + print("Error while executing {}: {}\n".format(message, output)) print("Sleeping 60s... then I will retry...") - sys.stdout.flush(); + sys.stdout.flush() time.sleep(60) - if add_message_and_command_line_to_output: output = message + '\nCommand line: ' + command_line + '\n' + output + if add_message_and_command_line_to_output: + output = message + "\nCommand line: " + command_line + "\n" + output - if return_ == 'tuple' or return_ == tuple: return(exit_code, output) + if return_ == "tuple" or return_ == tuple: + return (exit_code, output) if exit_code and terminate_on_failure: print("\nEncounter error while executing: " + command_line) - if return_==True: return True + if return_ == True: + return True else: - print('\nEncounter error while executing: ' + command_line + '\n' + output); - raise BenchmarkError('\nEncounter error while executing: ' + command_line + '\n' + output) + print("\nEncounter error while executing: " + command_line + "\n" + output) + raise BenchmarkError( + "\nEncounter error while executing: " + command_line + "\n" + output + ) - if return_ == 'output': return output - else: return exit_code + if return_ == "output": + return output + else: + return exit_code if __name__ == "__main__": - unittest.main() + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument( + "--total_chunks", + type=int, + default=1, + help="total number of chunks to split the examples into (default: 1)", + ) + parser.add_argument( + "--chunk_index", + type=int, + default=1, + help="Which chunk to run (1-based index, default:1)", + ) + args, remaining = parser.parse_known_args() + + TestSubmissionCommands.total_chunks = args.total_chunks + TestSubmissionCommands.chunk_index = args.chunk_index + + unittest.main(argv=[sys.argv[0]] + remaining) From e2378c73581772e64ef866affe2a62d43409a470 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 17 Oct 2025 10:51:44 -0500 Subject: [PATCH 08/22] Change num_designs in examples back to 10, since this is reset in test_diffusion.py --- examples/design_cyclic_oligos.sh | 2 +- examples/design_dihedral_oligos.sh | 2 +- examples/design_macrocyclic_binder.sh | 2 +- examples/design_macrocyclic_monomer.sh | 2 +- examples/design_motifscaffolding.sh | 2 +- examples/design_motifscaffolding_inpaintseq.sh | 2 +- examples/design_motifscaffolding_with_target.sh | 2 +- examples/design_nickel.sh | 2 +- examples/design_partialdiffusion.sh | 2 +- examples/design_partialdiffusion_multipleseq.sh | 2 +- examples/design_partialdiffusion_withseq.sh | 2 +- examples/design_ppi.sh | 2 +- examples/design_ppi_flexible_peptide.sh | 2 +- ...pi_flexible_peptide_with_secondarystructure_specification.sh | 2 +- examples/design_ppi_scaffolded.sh | 2 +- examples/design_tetrahedral_oligos.sh | 2 +- examples/design_timbarrel.sh | 2 +- examples/design_unconditional.sh | 2 +- examples/design_unconditional_w_contact_potential.sh | 2 +- examples/design_unconditional_w_monomer_ROG.sh | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/design_cyclic_oligos.sh b/examples/design_cyclic_oligos.sh index 0f620816..db9a0896 100755 --- a/examples/design_cyclic_oligos.sh +++ b/examples/design_cyclic_oligos.sh @@ -7,4 +7,4 @@ # We decay this potential with quadratic form, so that it is applied more strongly initially # We specify a total length of 480aa, so each chain is 80 residues long -python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="C6" inference.num_designs=2 inference.output_prefix="example_outputs/C6_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[480-480]' +python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="C6" inference.num_designs=10 inference.output_prefix="example_outputs/C6_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[480-480]' diff --git a/examples/design_dihedral_oligos.sh b/examples/design_dihedral_oligos.sh index ac2f6a6f..0d64a6fe 100755 --- a/examples/design_dihedral_oligos.sh +++ b/examples/design_dihedral_oligos.sh @@ -7,4 +7,4 @@ # We decay this potential with quadratic form, so that it is applied more strongly initially # We specify a total length of 320aa, so each chain is 80 residues long -python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="D2" inference.num_designs=2 inference.output_prefix="example_outputs/D2_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[320-320]' +python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="D2" inference.num_designs=10 inference.output_prefix="example_outputs/D2_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[320-320]' diff --git a/examples/design_macrocyclic_binder.sh b/examples/design_macrocyclic_binder.sh index 99170417..1067a01e 100755 --- a/examples/design_macrocyclic_binder.sh +++ b/examples/design_macrocyclic_binder.sh @@ -7,7 +7,7 @@ ../scripts/run_inference.py \ --config-name base \ inference.output_prefix=example_outputs/diffused_binder_cyclic2 \ -inference.num_designs=2 \ +inference.num_designs=10 \ 'contigmap.contigs=[12-18 A3-117/0]' \ inference.input_pdb=./input_pdbs/7zkr_GABARAP.pdb \ inference.cyclic=True \ diff --git a/examples/design_macrocyclic_monomer.sh b/examples/design_macrocyclic_monomer.sh index d0cc3188..3aa1ac3d 100755 --- a/examples/design_macrocyclic_monomer.sh +++ b/examples/design_macrocyclic_monomer.sh @@ -7,7 +7,7 @@ ../scripts/run_inference.py \ --config-name base \ inference.output_prefix=example_outputs/uncond_cycpep \ -inference.num_designs=2 \ +inference.num_designs=10 \ 'contigmap.contigs=[12-18]' \ inference.input_pdb=input_pdbs/7zkr_GABARAP.pdb \ inference.cyclic=True \ diff --git a/examples/design_motifscaffolding.sh b/examples/design_motifscaffolding.sh index 2c9088e8..f5a80ddf 100755 --- a/examples/design_motifscaffolding.sh +++ b/examples/design_motifscaffolding.sh @@ -8,4 +8,4 @@ # - 10-40 residues (randomly sampled) # We generate 10 designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=2 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=10 diff --git a/examples/design_motifscaffolding_inpaintseq.sh b/examples/design_motifscaffolding_inpaintseq.sh index 08a1c61d..8a06444b 100755 --- a/examples/design_motifscaffolding_inpaintseq.sh +++ b/examples/design_motifscaffolding_inpaintseq.sh @@ -12,4 +12,4 @@ # We generate 10 designs # We then specify that residues 163-168 (inclusive), 170-171 (inclusive) and 179 (inclusive) on the A chain of the input, should be masked in the input -../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_inpaintseq inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=2 'contigmap.inpaint_seq=[A163-168/A170-171/A179]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_inpaintseq inference.input_pdb=input_pdbs/5TPN.pdb 'contigmap.contigs=[10-40/A163-181/10-40]' inference.num_designs=10 'contigmap.inpaint_seq=[A163-168/A170-171/A179]' diff --git a/examples/design_motifscaffolding_with_target.sh b/examples/design_motifscaffolding_with_target.sh index fcb32c5d..b52d7402 100755 --- a/examples/design_motifscaffolding_with_target.sh +++ b/examples/design_motifscaffolding_with_target.sh @@ -11,4 +11,4 @@ # We generate 10 designs # As in the paper (at least for some of the designs we tested), we use the complex-finetuned model -python ../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_with_target inference.input_pdb=input_pdbs/1YCR.pdb 'contigmap.contigs=[A25-109/0 0-70/B17-29/0-70]' contigmap.length=70-120 inference.num_designs=2 inference.ckpt_override_path=../models/Complex_base_ckpt.pt +python ../scripts/run_inference.py inference.output_prefix=example_outputs/design_motifscaffolding_with_target inference.input_pdb=input_pdbs/1YCR.pdb 'contigmap.contigs=[A25-109/0 0-70/B17-29/0-70]' contigmap.length=70-120 inference.num_designs=10 inference.ckpt_override_path=../models/Complex_base_ckpt.pt diff --git a/examples/design_nickel.sh b/examples/design_nickel.sh index 560951ec..fe303068 100755 --- a/examples/design_nickel.sh +++ b/examples/design_nickel.sh @@ -17,4 +17,4 @@ ckpt='../models/Base_epoch8_ckpt.pt' -python ../scripts/run_inference.py inference.symmetry="C4" inference.num_designs=2 inference.output_prefix=example_outputs/design_nickel 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.06"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2 potentials.guide_decay="quadratic" inference.input_pdb=input_pdbs/nickel_symmetric_motif.pdb 'contigmap.contigs=[50/A2-4/50/0 50/A7-9/50/0 50/A12-14/50/0 50/A17-19/50/0]' inference.ckpt_override_path=$ckpt +python ../scripts/run_inference.py inference.symmetry="C4" inference.num_designs=10 inference.output_prefix=example_outputs/design_nickel 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.06"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2 potentials.guide_decay="quadratic" inference.input_pdb=input_pdbs/nickel_symmetric_motif.pdb 'contigmap.contigs=[50/A2-4/50/0 50/A7-9/50/0 50/A12-14/50/0 50/A17-19/50/0]' inference.ckpt_override_path=$ckpt diff --git a/examples/design_partialdiffusion.sh b/examples/design_partialdiffusion.sh index 3330ad9a..1e1fdc24 100755 --- a/examples/design_partialdiffusion.sh +++ b/examples/design_partialdiffusion.sh @@ -7,4 +7,4 @@ # But, in either case, the contig length must sum to the length of the input pdb file # We generate 10 designs, and noise and denoise 10 steps (20% of the full trajectory) -../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion inference.input_pdb=input_pdbs/2KL8.pdb 'contigmap.contigs=[79-79]' inference.num_designs=2 diffuser.partial_T=10 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion inference.input_pdb=input_pdbs/2KL8.pdb 'contigmap.contigs=[79-79]' inference.num_designs=10 diffuser.partial_T=10 diff --git a/examples/design_partialdiffusion_multipleseq.sh b/examples/design_partialdiffusion_multipleseq.sh index 36fe03fd..1962ff03 100755 --- a/examples/design_partialdiffusion_multipleseq.sh +++ b/examples/design_partialdiffusion_multipleseq.sh @@ -6,4 +6,4 @@ # Note the ranges do not necessarily need to lie on the same chain as in this example. # However, positions are 0-indexed over the whole sequence--not per-chain-- so care must be taken when providing ranges to provide_seq. -../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithmultiplesequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=2 'contigmap.provide_seq=[172-177,200-205]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithmultiplesequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=10 'contigmap.provide_seq=[172-177,200-205]' diff --git a/examples/design_partialdiffusion_withseq.sh b/examples/design_partialdiffusion_withseq.sh index 95c5d73d..ab585c74 100755 --- a/examples/design_partialdiffusion_withseq.sh +++ b/examples/design_partialdiffusion_withseq.sh @@ -11,4 +11,4 @@ # This contig will lead to the whole input pdb being noise by 10 steps (partial_T=10) # However, we provide the sequence of the peptide (the last 20 residues in the contig), with provide_seq=[172-205]. This is 0-indexed -../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithsequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=2 'contigmap.provide_seq=[172-205]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_partialdiffusion_peptidewithsequence inference.input_pdb=input_pdbs/peptide_complex_ideal_helix.pdb 'contigmap.contigs=["172-172/0 34-34"]' diffuser.partial_T=10 inference.num_designs=10 'contigmap.provide_seq=[172-205]' diff --git a/examples/design_ppi.sh b/examples/design_ppi.sh index 8354ef7b..5e217b21 100755 --- a/examples/design_ppi.sh +++ b/examples/design_ppi.sh @@ -8,4 +8,4 @@ # We tell diffusion to target three specific residues on the target, specifically residues 59, 83 and 91 of the A chain # We make 10 designs, and reduce the noise added during inference to 0, to improve the quality of the designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi inference.input_pdb=input_pdbs/insulin_target.pdb 'contigmap.contigs=[A1-150/0 70-100]' 'ppi.hotspot_res=[A59,A83,A91]' inference.num_designs=2 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi inference.input_pdb=input_pdbs/insulin_target.pdb 'contigmap.contigs=[A1-150/0 70-100]' 'ppi.hotspot_res=[A59,A83,A91]' inference.num_designs=10 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 diff --git a/examples/design_ppi_flexible_peptide.sh b/examples/design_ppi_flexible_peptide.sh index 5960f6b3..1af54c71 100755 --- a/examples/design_ppi_flexible_peptide.sh +++ b/examples/design_ppi_flexible_peptide.sh @@ -9,4 +9,4 @@ # We make 10 designs # We mask (diffuse) the structure of the peptide using the inpaint_str flag. This has the effect of having RFdiffusion simultaneously design a binder and predict the structure of the peptide within the complex. -../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide inference.input_pdb=input_pdbs/3IOL.pdb 'contigmap.contigs=[B10-35/0 70-100]' 'ppi.hotspot_res=[B28,B29]' inference.num_designs=2 'contigmap.inpaint_str=[B10-35]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide inference.input_pdb=input_pdbs/3IOL.pdb 'contigmap.contigs=[B10-35/0 70-100]' 'ppi.hotspot_res=[B28,B29]' inference.num_designs=10 'contigmap.inpaint_str=[B10-35]' diff --git a/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh b/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh index 96015db4..6e0dfc88 100755 --- a/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh +++ b/examples/design_ppi_flexible_peptide_with_secondarystructure_specification.sh @@ -10,4 +10,4 @@ # We then specify that we want this to adopt a helical conformation # If you wanted to specify that it should adopt a strand conformation, you would specify `contigmap.inpaint_str_strand` -../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide_with_secondarystructure inference.input_pdb=input_pdbs/tau_peptide.pdb 'contigmap.contigs=[70-100/0 B165-178]' inference.num_designs=2 'contigmap.inpaint_str=[B165-178]' scaffoldguided.scaffoldguided=True 'contigmap.inpaint_str_helix=[B165-178]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_ppi_flexible_peptide_with_secondarystructure inference.input_pdb=input_pdbs/tau_peptide.pdb 'contigmap.contigs=[70-100/0 B165-178]' inference.num_designs=10 'contigmap.inpaint_str=[B165-178]' scaffoldguided.scaffoldguided=True 'contigmap.inpaint_str_helix=[B165-178]' diff --git a/examples/design_ppi_scaffolded.sh b/examples/design_ppi_scaffolded.sh index 96e1ecf0..63ca165e 100755 --- a/examples/design_ppi_scaffolded.sh +++ b/examples/design_ppi_scaffolded.sh @@ -7,4 +7,4 @@ # We then provide a path to a directory of different scaffolds (we've provided some for you to use, from Cao et al., 2022) # We generate 10 designs, and reduce the noise added during inference to 0 (which improves the quality of designs) -../scripts/run_inference.py scaffoldguided.target_path=input_pdbs/insulin_target.pdb inference.output_prefix=example_outputs/design_ppi_scaffolded scaffoldguided.scaffoldguided=True 'ppi.hotspot_res=[A59,A83,A91]' scaffoldguided.target_pdb=True scaffoldguided.target_ss=target_folds/insulin_target_ss.pt scaffoldguided.target_adj=target_folds/insulin_target_adj.pt scaffoldguided.scaffold_dir=./ppi_scaffolds/ inference.num_designs=2 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 +../scripts/run_inference.py scaffoldguided.target_path=input_pdbs/insulin_target.pdb inference.output_prefix=example_outputs/design_ppi_scaffolded scaffoldguided.scaffoldguided=True 'ppi.hotspot_res=[A59,A83,A91]' scaffoldguided.target_pdb=True scaffoldguided.target_ss=target_folds/insulin_target_ss.pt scaffoldguided.target_adj=target_folds/insulin_target_adj.pt scaffoldguided.scaffold_dir=./ppi_scaffolds/ inference.num_designs=10 denoiser.noise_scale_ca=0 denoiser.noise_scale_frame=0 diff --git a/examples/design_tetrahedral_oligos.sh b/examples/design_tetrahedral_oligos.sh index 4d9fcfd0..231e14a9 100755 --- a/examples/design_tetrahedral_oligos.sh +++ b/examples/design_tetrahedral_oligos.sh @@ -7,4 +7,4 @@ # We decay this potential with quadratic form, so that it is applied more strongly initially # We specify a total length of 1200aa, so each chain is 100 residues long -python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="tetrahedral" inference.num_designs=2 inference.output_prefix="example_outputs/tetrahedral_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[1200-1200]' +python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="tetrahedral" inference.num_designs=10 inference.output_prefix="example_outputs/tetrahedral_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[1200-1200]' diff --git a/examples/design_timbarrel.sh b/examples/design_timbarrel.sh index dc679908..410254ed 100755 --- a/examples/design_timbarrel.sh +++ b/examples/design_timbarrel.sh @@ -8,4 +8,4 @@ # We add 0-5 residues (randomly sampled) to the N and the C-terminus # This will allow the generation of diverse TIM barrels with slightly different length helices and strands -../scripts/run_inference.py inference.output_prefix=example_outputs/design_tim_barrel scaffoldguided.scaffoldguided=True scaffoldguided.target_pdb=False scaffoldguided.scaffold_dir=tim_barrel_scaffold/ inference.num_designs=2 denoiser.noise_scale_ca=0.5 denoiser.noise_scale_frame=0.5 scaffoldguided.sampled_insertion=0-5 scaffoldguided.sampled_N=0-5 scaffoldguided.sampled_C=0-5 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_tim_barrel scaffoldguided.scaffoldguided=True scaffoldguided.target_pdb=False scaffoldguided.scaffold_dir=tim_barrel_scaffold/ inference.num_designs=10 denoiser.noise_scale_ca=0.5 denoiser.noise_scale_frame=0.5 scaffoldguided.sampled_insertion=0-5 scaffoldguided.sampled_N=0-5 scaffoldguided.sampled_C=0-5 diff --git a/examples/design_unconditional.sh b/examples/design_unconditional.sh index 78887776..3ece16f7 100755 --- a/examples/design_unconditional.sh +++ b/examples/design_unconditional.sh @@ -4,4 +4,4 @@ # We tell RFdiffusion that designs should be 100-200 residues in length (randomly sampled each design) # We generate 10 such designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=2 +../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=10 diff --git a/examples/design_unconditional_w_contact_potential.sh b/examples/design_unconditional_w_contact_potential.sh index b2743723..999a9c04 100755 --- a/examples/design_unconditional_w_contact_potential.sh +++ b/examples/design_unconditional_w_contact_potential.sh @@ -4,4 +4,4 @@ # We tell RFdiffusion that designs should be 100-200 residues in length (randomly sampled each design) # We generate 10 such designs -../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional_w_contact_potential 'contigmap.contigs=[100-200]' inference.num_designs=2 'potentials.guiding_potentials=["type:monomer_contacts,weight:0.05"]' +../scripts/run_inference.py inference.output_prefix=example_outputs/design_unconditional_w_contact_potential 'contigmap.contigs=[100-200]' inference.num_designs=10 'potentials.guiding_potentials=["type:monomer_contacts,weight:0.05"]' diff --git a/examples/design_unconditional_w_monomer_ROG.sh b/examples/design_unconditional_w_monomer_ROG.sh index 079caa6b..b34a0a72 100755 --- a/examples/design_unconditional_w_monomer_ROG.sh +++ b/examples/design_unconditional_w_monomer_ROG.sh @@ -7,4 +7,4 @@ # We use the monomer_ROG potential, with guide scale 2 and quadratic decay # Note that this potential is probably not necessary in this kind of case, but is provided as an example -../scripts/run_inference.py inference.output_prefix=example_outputs/design_monomer_ROG_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=2 'potentials.guiding_potentials=["type:monomer_ROG,weight:1,min_dist:5"]' potentials.guide_scale=2 potentials.guide_decay="quadratic" +../scripts/run_inference.py inference.output_prefix=example_outputs/design_monomer_ROG_unconditional 'contigmap.contigs=[100-200]' inference.num_designs=10 'potentials.guiding_potentials=["type:monomer_ROG,weight:1,min_dist:5"]' potentials.guide_scale=2 potentials.guide_decay="quadratic" From 6d0036b4809704b412012c194db8c694432da810 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 17 Oct 2025 10:57:53 -0500 Subject: [PATCH 09/22] Fix typo in main.yml in test_diffusion options --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 89a694ff..c41bc94a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -90,7 +90,7 @@ jobs: total_chunks=$(nproc) for chunk_index in $(seq 1 $total_chunks); do echo "Running chunk $chunk_index of $total_chunks" - uv run python tests/test_diffusion.py --total-chunks $total_chunks --chunk-index $chunk_index & + uv run python tests/test_diffusion.py --total_chunks $total_chunks --chunk_index $chunk_index & done wait From a629d43e928409c1e27f5396b376f1bcaca9a3be Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 17 Oct 2025 11:04:32 -0500 Subject: [PATCH 10/22] Add step to cd into tests directory in main.yml --- .github/workflows/main.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c41bc94a..56743674 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -87,10 +87,11 @@ jobs: - name: Setup and Run ppi_scaffolds tests run: | tar -xvf examples/ppi_scaffolds_subset.tar.gz -C examples - total_chunks=$(nproc) + total_chunks=$(nproc) + cd tests for chunk_index in $(seq 1 $total_chunks); do echo "Running chunk $chunk_index of $total_chunks" - uv run python tests/test_diffusion.py --total_chunks $total_chunks --chunk_index $chunk_index & + uv run python test_diffusion.py --total_chunks $total_chunks --chunk_index $chunk_index & done wait From 17f315b2de6d84c0ac189164b2c8d5c52fe8ac46 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 17 Oct 2025 12:45:28 -0500 Subject: [PATCH 11/22] Add index of chunk to test directory name --- tests/test_diffusion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index 71829775..e73c9cd8 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -61,7 +61,7 @@ def setUp(self): now = datetime.datetime.now() now = now.strftime("%Y_%m_%d_%H_%M_%S") - self.out_f = f"{script_dir}/tests_{now}" + self.out_f = f"{script_dir}/tests_{now}_{idx}" os.mkdir(self.out_f) # Make sure we have access to all the relevant files From 260692d6c2ce4a565fd60cf636c825c3317cc123 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Mon, 20 Oct 2025 08:48:02 -0500 Subject: [PATCH 12/22] Edits to test_diffusion to make change setUp to setUpClass to make this a class method so examples run only once --- tests/test_diffusion.py | 42 +++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index e73c9cd8..10231d11 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -33,14 +33,19 @@ class TestSubmissionCommands(unittest.TestCase): # which chunk to run chunk_index = 1 - def setUp(self): + out_f = None + results = {} + exec_status = {} + + @classmethod + def setUpClass(cls): """ - Grabs files from the examples folder + Class-level setup: Grabs files from the examples folder, discover & rewrite example commands, then execute them once. """ submissions = glob.glob(f"{script_dir}/../examples/*.sh") # get datetime for output folder, in YYYY_MM_DD_HH_MM_SS format - chunks = self.__class__.total_chunks - idx = self.__class__.chunk_index + chunks = cls.total_chunks + idx = cls.chunk_index if chunks < 1: raise ValueError("total_chunks must be at least 1") if idx < 1 or idx > chunks: @@ -61,8 +66,8 @@ def setUp(self): now = datetime.datetime.now() now = now.strftime("%Y_%m_%d_%H_%M_%S") - self.out_f = f"{script_dir}/tests_{now}_{idx}" - os.mkdir(self.out_f) + cls.out_f = f"{script_dir}/tests_{now}_{idx}" + os.mkdir(cls.out_f) # Make sure we have access to all the relevant files exclude_dirs = ["outputs", "example_outputs"] @@ -78,16 +83,16 @@ def setUp(self): ) for submission in submissions: - self._write_command(submission, self.out_f) + cls._write_command(submission, cls.out_f) print( - f"Running commands in {self.out_f}, two steps of diffusion, deterministic=True" + f"Running commands in {cls.out_f}, two steps of diffusion, deterministic=True" ) - self.results = {} - self.exec_status = {} + cls.results = {} + cls.exec_status = {} - for bash_file in sorted(glob.glob(f"{self.out_f}/*.sh"), reverse=False): + for bash_file in sorted(glob.glob(f"{cls.out_f}/*.sh"), reverse=False): test_name = os.path.basename(bash_file)[: -len(".sh")] res, output = execute( f"Running {test_name}", @@ -95,9 +100,9 @@ def setUp(self): return_="tuple", add_message_and_command_line_to_output=True, ) - self.exec_status[test_name] = (res, output) + cls.exec_status[test_name] = (res, output) - self.results[test_name] = dict( + cls.results[test_name] = dict( state="failed" if res else "passed", log=output, ) @@ -106,7 +111,7 @@ def setUp(self): # subprocess.run(["bash", bash_file]) def test_examples_run_without_errors(self): - for name, (exit_code, output) in sorted(self.exec_status.items()): + for name, (exit_code, output) in sorted(self.__class__.exec_status.items()): with self.subTest(example=name): if exit_code != 0: self.__class__.failed_tests.append(f"{name}") @@ -128,8 +133,8 @@ def test_commands(self): """ reference = f"{script_dir}/reference_outputs" os.makedirs(reference, exist_ok=True) - test_files = glob.glob(f"{self.out_f}/example_outputs/*pdb") - print(f"{self.out_f=} {test_files=}") + test_files = glob.glob(f"{self.__class__.out_f}/example_outputs/*pdb") + print(f"{self.__class__.out_f=} {test_files=}") # first check that we have the right number of outputs # self.assertEqual(len(test_files), len(glob.glob(f"{self.out_f}/*.sh"))), "One or more of the example commands didn't produce an output (check the example command is formatted correctly)" @@ -173,7 +178,8 @@ def test_commands(self): self.assertTrue(result.wasSuccessful(), "One or more subtests failed") - def _write_command(self, bash_file, test_f) -> None: + @classmethod + def _write_command(cls, bash_file, test_f) -> None: """ Takes a bash file from the examples folder, and writes a version of it to the test_f folder. @@ -219,7 +225,7 @@ def _write_command(self, bash_file, test_f) -> None: else: output_command = f"{output_command} inference.num_designs=1" # replace 'example_outputs' with f'{self.out_f}/example_outputs' - output_command = f'{output_command.split("example_outputs")[0]}{self.out_f}/example_outputs{output_command.split("example_outputs")[1]}' + output_command = f'{output_command.split("example_outputs")[0]}{cls.out_f}/example_outputs{output_command.split("example_outputs")[1]}' # write the new command with open(f"{test_f}/{os.path.basename(bash_file)}", "w") as f: From a570b2b8bdce98e979d875cde81d5f9ed0f3d225 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Tue, 21 Oct 2025 09:57:15 -0500 Subject: [PATCH 13/22] Edit main.yml workflow so if an example fails, the test doesn't pass --- .github/workflows/main.yml | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 56743674..6b79b1c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -86,17 +86,40 @@ jobs: - name: Setup and Run ppi_scaffolds tests run: | + set -euo pipefail tar -xvf examples/ppi_scaffolds_subset.tar.gz -C examples total_chunks=$(nproc) cd tests + + #launch all chunks in background and record PIDs + labels + decalre -a pics + declare -a label_by_pid + for chunk_index in $(seq 1 $total_chunks); do echo "Running chunk $chunk_index of $total_chunks" uv run python test_diffusion.py --total_chunks $total_chunks --chunk_index $chunk_index & + pid=$! + pids+=("$pid") + label_by_pid["$pid"]="chunk_$chunk_index" + done + + # wait for each and track failures + fail=0 + for pid in "${pids[@]}"; do + if ! wait "$pid"; do + echo "${label_by_pid[$pid]} failed (PID $pid)" + fail=1 + else + echo "✅ ${label_by_pid[$pid]} passed (PID $pid)" + fi done - wait + # make step fail if any chunk failed + if [ "$fail" -ne 0 ]; then + echo "One or more chunks failed." + exit 1 + fi echo "All chunks completed." - #cd tests && uv run python test_diffusion.py # - name: Test with pytest From 4dd3a5f8c05e3fe06fd231f5299b0e47da093348 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Tue, 21 Oct 2025 10:02:56 -0500 Subject: [PATCH 14/22] Remove -o option from pipefail --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6b79b1c1..822d7d7f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -86,7 +86,7 @@ jobs: - name: Setup and Run ppi_scaffolds tests run: | - set -euo pipefail + set -eu pipefail tar -xvf examples/ppi_scaffolds_subset.tar.gz -C examples total_chunks=$(nproc) cd tests From 56feb3bb4ab497e656ba185579aed06e5c32647a Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Tue, 21 Oct 2025 10:09:12 -0500 Subject: [PATCH 15/22] Remove set pipefail --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 822d7d7f..baf7afa6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -86,7 +86,6 @@ jobs: - name: Setup and Run ppi_scaffolds tests run: | - set -eu pipefail tar -xvf examples/ppi_scaffolds_subset.tar.gz -C examples total_chunks=$(nproc) cd tests @@ -110,7 +109,7 @@ jobs: echo "${label_by_pid[$pid]} failed (PID $pid)" fail=1 else - echo "✅ ${label_by_pid[$pid]} passed (PID $pid)" + echo "${label_by_pid[$pid]} passed (PID $pid)" fi done From dc1867dadf5f9ac6cb8b97e647eee67f0b6f8d23 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Tue, 21 Oct 2025 16:29:06 -0500 Subject: [PATCH 16/22] Edit main.yml so workflow runs --- .github/workflows/main.yml | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index baf7afa6..a19916ef 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -91,35 +91,25 @@ jobs: cd tests #launch all chunks in background and record PIDs + labels - decalre -a pics - declare -a label_by_pid - + pids="" for chunk_index in $(seq 1 $total_chunks); do echo "Running chunk $chunk_index of $total_chunks" uv run python test_diffusion.py --total_chunks $total_chunks --chunk_index $chunk_index & - pid=$! - pids+=("$pid") - label_by_pid["$pid"]="chunk_$chunk_index" + pids="$pids $!" done # wait for each and track failures fail=0 - for pid in "${pids[@]}"; do - if ! wait "$pid"; do - echo "${label_by_pid[$pid]} failed (PID $pid)" + for pid in $pids; do + if ! wait "$pid"; then + echo "A chunk (PID $pid) failed" fail=1 else - echo "${label_by_pid[$pid]} passed (PID $pid)" + echo "A chunk (PID $pid) passed" fi done - # make step fail if any chunk failed - if [ "$fail" -ne 0 ]; then - echo "One or more chunks failed." - exit 1 - fi - echo "All chunks completed." - + exit "$fail" # - name: Test with pytest # run: | From 4d870c07da5e645393ee85a557b41e799d8b6371 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Wed, 22 Oct 2025 10:03:07 -0500 Subject: [PATCH 17/22] In setUpClass check that directory doesn't already exists, so tests do not fail before running examples --- tests/test_diffusion.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index 10231d11..8de5c03e 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -74,13 +74,16 @@ def setUpClass(cls): for filename in os.listdir(f"{script_dir}/../examples"): if ( filename not in exclude_dirs - and not os.path.islink(os.path.join(script_dir, filename)) + and not os.path.exists(os.path.join(script_dir, filename)) and os.path.isdir(os.path.join(f"{script_dir}/../examples", filename)) ): - os.symlink( - os.path.join(f"{script_dir}/../examples", filename), - os.path.join(script_dir, filename), - ) + try: + os.symlink( + os.path.join(f"{script_dir}/../examples", filename), + os.path.join(script_dir, filename), + ) + except FileExistsError: + pass for submission in submissions: cls._write_command(submission, cls.out_f) From be5b7b6b89dbba576e2001087879a140bc532f44 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Wed, 22 Oct 2025 15:13:35 -0500 Subject: [PATCH 18/22] Preseed DGL so avoid examples that are ran at the same time failing --- .github/workflows/main.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a19916ef..b2dd2e3d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -69,6 +69,13 @@ jobs: uv pip install --no-cache-dir -e . --no-deps rm -rf ~/.cache # /app/RFdiffusion/tests + - name: Preseed DGL backend + shell: bash + run: | + mkdir -p "$HOME/.dgl" + printf '{"backend": "pytorch"}' > "$HOME/.dgl/config.conf" + echo "DGLBACKEND=pytorch" >> "$GITHUB_ENV" + - name: Download weights run: | mkdir models From 681874e6ea19e763a5ccb35d1a434c9b3f6d8179 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Wed, 22 Oct 2025 15:16:41 -0500 Subject: [PATCH 19/22] Reduce length for design_tetrahedral_oligos to 600 to reduce run time --- examples/design_tetrahedral_oligos.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/design_tetrahedral_oligos.sh b/examples/design_tetrahedral_oligos.sh index 231e14a9..5aab7887 100755 --- a/examples/design_tetrahedral_oligos.sh +++ b/examples/design_tetrahedral_oligos.sh @@ -5,6 +5,6 @@ # This external potential promotes contacts both within (with a relative weight of 1) and between chains (relative weight 0.1) # We specify that we want to apply these potentials to all chains, with a guide scale of 2.0 (a sensible starting point) # We decay this potential with quadratic form, so that it is applied more strongly initially -# We specify a total length of 1200aa, so each chain is 100 residues long +# We specify a total length of 1200aa, so each chain is 100 residues long - length updated to 600aa, so each chain is 50 residues long for testing to run faster -python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="tetrahedral" inference.num_designs=10 inference.output_prefix="example_outputs/tetrahedral_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[1200-1200]' +python ../scripts/run_inference.py --config-name=symmetry inference.symmetry="tetrahedral" inference.num_designs=10 inference.output_prefix="example_outputs/tetrahedral_oligo" 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.1"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2.0 potentials.guide_decay="quadratic" 'contigmap.contigs=[600-600]' From 4aea4fd65a8cbdbb5c6fff13dba36927a48b738c Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Thu, 23 Oct 2025 12:26:00 -0500 Subject: [PATCH 20/22] Change design_nickel.sh num_designs back to 15 --- examples/design_nickel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/design_nickel.sh b/examples/design_nickel.sh index fe303068..8239680f 100755 --- a/examples/design_nickel.sh +++ b/examples/design_nickel.sh @@ -17,4 +17,4 @@ ckpt='../models/Base_epoch8_ckpt.pt' -python ../scripts/run_inference.py inference.symmetry="C4" inference.num_designs=10 inference.output_prefix=example_outputs/design_nickel 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.06"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2 potentials.guide_decay="quadratic" inference.input_pdb=input_pdbs/nickel_symmetric_motif.pdb 'contigmap.contigs=[50/A2-4/50/0 50/A7-9/50/0 50/A12-14/50/0 50/A17-19/50/0]' inference.ckpt_override_path=$ckpt +python ../scripts/run_inference.py inference.symmetry="C4" inference.num_designs=15 inference.output_prefix=example_outputs/design_nickel 'potentials.guiding_potentials=["type:olig_contacts,weight_intra:1,weight_inter:0.06"]' potentials.olig_intra_all=True potentials.olig_inter_all=True potentials.guide_scale=2 potentials.guide_decay="quadratic" inference.input_pdb=input_pdbs/nickel_symmetric_motif.pdb 'contigmap.contigs=[50/A2-4/50/0 50/A7-9/50/0 50/A12-14/50/0 50/A17-19/50/0]' inference.ckpt_override_path=$ckpt From ead721f32670eae379612d9e545690c3f288d251 Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Fri, 24 Oct 2025 09:48:03 -0500 Subject: [PATCH 21/22] Remove try block with except FileExistsError that isn't needed --- tests/test_diffusion.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index 8de5c03e..2bc6bfd6 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -77,13 +77,10 @@ def setUpClass(cls): and not os.path.exists(os.path.join(script_dir, filename)) and os.path.isdir(os.path.join(f"{script_dir}/../examples", filename)) ): - try: - os.symlink( - os.path.join(f"{script_dir}/../examples", filename), - os.path.join(script_dir, filename), - ) - except FileExistsError: - pass + os.symlink( + os.path.join(f"{script_dir}/../examples", filename), + os.path.join(script_dir, filename), + ) for submission in submissions: cls._write_command(submission, cls.out_f) From dd7643d6406cfbb1332eccaa36e6c0fc786251de Mon Sep 17 00:00:00 2001 From: woodsh17 Date: Wed, 12 Nov 2025 13:45:07 -0600 Subject: [PATCH 22/22] Revert "Remove try block with except FileExistsError that isn't needed" After running the test, I found that this was needed This reverts commit ead721f32670eae379612d9e545690c3f288d251. --- tests/test_diffusion.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/test_diffusion.py b/tests/test_diffusion.py index 2bc6bfd6..8de5c03e 100644 --- a/tests/test_diffusion.py +++ b/tests/test_diffusion.py @@ -77,10 +77,13 @@ def setUpClass(cls): and not os.path.exists(os.path.join(script_dir, filename)) and os.path.isdir(os.path.join(f"{script_dir}/../examples", filename)) ): - os.symlink( - os.path.join(f"{script_dir}/../examples", filename), - os.path.join(script_dir, filename), - ) + try: + os.symlink( + os.path.join(f"{script_dir}/../examples", filename), + os.path.join(script_dir, filename), + ) + except FileExistsError: + pass for submission in submissions: cls._write_command(submission, cls.out_f)