Spaces:
Sleeping
Sleeping
Upload refine.py
Browse files- scripts/refine.py +36 -66
scripts/refine.py
CHANGED
|
@@ -1,78 +1,48 @@
|
|
| 1 |
import os
|
| 2 |
-
from Bio.PDB import PDBParser, Superimposer
|
| 3 |
-
from
|
| 4 |
-
from openmm
|
| 5 |
-
from openmm import
|
| 6 |
-
from openmm.unit import kelvin, picosecond # type: ignore
|
| 7 |
|
| 8 |
-
def polish_design(target_pdb_id,
|
| 9 |
-
|
| 10 |
-
|
| 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 (
|
|
|
|
| 21 |
target_struct = parser.get_structure("target", target_path)
|
| 22 |
-
design_struct = parser.get_structure("design",
|
| 23 |
|
| 24 |
sup = Superimposer()
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
design_atoms = [a for a in design_struct.get_atoms() if a.get_name() == 'CA']
|
| 28 |
|
| 29 |
-
|
| 30 |
-
sup.set_atoms(target_atoms[:len(design_atoms)], design_atoms)
|
| 31 |
sup.apply(design_struct.get_atoms())
|
| 32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
|
| 34 |
-
#
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
fixer.addMissingAtoms()
|
| 40 |
-
fixer.addMissingHydrogens(7.4)
|
| 41 |
|
| 42 |
-
|
| 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 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 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
|
|
|
|
| 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
|