42Cummer commited on
Commit
af2fbfa
·
verified ·
1 Parent(s): a49e856

Upload refine.py

Browse files
Files changed (1) hide show
  1. scripts/refine.py +36 -66
scripts/refine.py CHANGED
@@ -1,78 +1,48 @@
1
  import os
2
- from Bio.PDB import PDBParser, Superimposer, PDBIO # type: ignore
3
- from pdbfixer import PDBFixer # type: ignore
4
- from openmm.app import PDBFile, ForceField, Simulation, Modeller # type: ignore
5
- from openmm import LangevinIntegrator # type: ignore
6
- from openmm.unit import kelvin, picosecond # type: ignore
7
 
8
- def polish_design(target_pdb_id, uploaded_file_obj):
9
- """
10
- Refines the uploaded ESM-folded PDB against the target template.
11
- uploaded_file_obj: This is the temp file path provided by Gradio.
12
- """
13
- # 1. Get the local template path
14
- target_path = f"data/{target_pdb_id.lower()}.pdb"
15
- # Gradio passes a 'temp' file object; we get the string path
16
- design_path = uploaded_file_obj.name
17
-
18
- parser = PDBParser(QUIET=True)
19
 
20
- # 2. ALIGNMENT (The Matchmaker)
 
21
  target_struct = parser.get_structure("target", target_path)
22
- design_struct = parser.get_structure("design", design_path)
23
 
24
  sup = Superimposer()
25
- # Grabbing Alpha Carbons for the alignment
26
- target_atoms = [a for a in target_struct.get_atoms() if a.get_name() == 'CA']
27
- design_atoms = [a for a in design_struct.get_atoms() if a.get_name() == 'CA']
28
 
29
- # Snap the design onto the template and calculate RMSD
30
- sup.set_atoms(target_atoms[:len(design_atoms)], design_atoms)
31
  sup.apply(design_struct.get_atoms())
32
- current_rmsd = sup.rms
 
 
 
 
 
 
 
 
 
 
33
 
34
- # 3. PHYSICS CLEANUP (Resolving Clashes)
35
- # PDBFixer solves the 'Nitrogen' error by standardizing atom types
36
- fixer = PDBFixer(design_path)
37
- fixer.findMissingResidues()
38
- fixer.findMissingAtoms()
39
- fixer.addMissingAtoms()
40
- fixer.addMissingHydrogens(7.4)
41
 
42
- # Try to do energy minimization, but fall back to just using fixed structure if it fails
43
- output_dir = "generated/shuttle"
44
- os.makedirs(output_dir, exist_ok=True)
45
- output_filename = os.path.join(output_dir, "refined.pdb")
46
 
47
- try:
48
- # Use Modeller to properly handle terminal residues
49
- modeller = Modeller(fixer.topology, fixer.positions)
50
-
51
- # Setup the Forcefield (AMBER14)
52
- forcefield = ForceField('amber14-all.xml', 'amber14/tip3p.xml')
53
- # Add hydrogens with forcefield to get proper terminal capping
54
- modeller.addHydrogens(forcefield=forcefield)
55
-
56
- # Create system - now with properly capped terminals
57
- system = forcefield.createSystem(modeller.topology)
58
- integrator = LangevinIntegrator(300*kelvin, 1/picosecond, 0.002*picosecond)
59
- simulation = Simulation(modeller.topology, system, integrator)
60
- simulation.context.setPositions(modeller.positions)
61
-
62
- # Energy Minimization: The 'Wiggle' that removes clashes
63
- simulation.minimizeEnergy(maxIterations=100)
64
-
65
- # Export minimized structure
66
- with open(output_filename, "w") as f:
67
- PDBFile.writeFile(
68
- simulation.topology,
69
- simulation.context.getState(getPositions=True).getPositions(),
70
- f # type: ignore
71
- )
72
- except Exception as e:
73
- # Fallback: if OpenMM fails (e.g., due to incomplete terminal residues),
74
- # just save the PDBFixer-processed structure without energy minimization
75
- print(f"Warning: Energy minimization failed ({str(e)}), using PDBFixer output only")
76
- PDBFile.writeFile(fixer.topology, fixer.positions, output_filename)
77
 
78
- return output_filename, current_rmsd
 
1
  import os
2
+ from Bio.PDB import PDBParser, Superimposer
3
+ from openmm.app import PDBFile, ForceField, Simulation, Modeller
4
+ from openmm import LangevinIntegrator
5
+ from openmm.unit import kelvin, picosecond
 
6
 
7
+ def polish_design(target_pdb_id, uploaded_file_path):
8
+ # 1. Setup paths
9
+ target_path = os.path.join("data", f"{target_pdb_id.lower()}.pdb")
 
 
 
 
 
 
 
 
10
 
11
+ # 2. ALIGNMENT (Biopython)
12
+ parser = PDBParser(QUIET=True)
13
  target_struct = parser.get_structure("target", target_path)
14
+ design_struct = parser.get_structure("design", uploaded_file_path)
15
 
16
  sup = Superimposer()
17
+ t_atoms = [a for a in target_struct.get_atoms() if a.get_name() == 'CA']
18
+ d_atoms = [a for a in design_struct.get_atoms() if a.get_name() == 'CA']
 
19
 
20
+ sup.set_atoms(t_atoms[:len(d_atoms)], d_atoms)
 
21
  sup.apply(design_struct.get_atoms())
22
+ rmsd = sup.rms
23
+
24
+ # 3. PHYSICS (OpenMM Modeller replaces PDBFixer)
25
+ pdb = PDBFile(uploaded_file_path)
26
+ modeller = Modeller(pdb.topology, pdb.positions)
27
+
28
+ # Standardize Forcefield
29
+ forcefield = ForceField('amber14-all.xml', 'amber14/tip3p.xml')
30
+
31
+ # Add Hydrogens (Standardizes the Nitrogen typenames)
32
+ modeller.addHydrogens(forcefield, pH=7.4)
33
 
34
+ # Run the wiggle to kill the 8 clashes
35
+ system = forcefield.createSystem(modeller.topology)
36
+ integrator = LangevinIntegrator(300*kelvin, 1/picosecond, 0.002*picosecond)
37
+ simulation = Simulation(modeller.topology, system, integrator)
38
+ simulation.context.setPositions(modeller.positions)
 
 
39
 
40
+ simulation.minimizeEnergy(maxIterations=100)
 
 
 
41
 
42
+ # 4. EXPORT
43
+ output_name = "Broteinshake_Lead_Refined.pdb"
44
+ with open(output_name, "w") as f:
45
+ PDBFile.writeFile(simulation.topology,
46
+ simulation.context.getState(getPositions=True).getPositions(), f)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ return output_name, rmsd