Spaces:
Sleeping
Sleeping
File size: 13,125 Bytes
427fd9c 2fe706b 0ade04a 73fc96d c2be249 4ed9de7 73fc96d 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b 4a6a364 73fc96d e72bc1b 0a04e5a 73fc96d 4ed9de7 73fc96d 4ed9de7 73fc96d 4ed9de7 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b 2f6c8f7 73fc96d e72bc1b 73fc96d 2fe706b 73fc96d 2fe706b e72bc1b 73fc96d 0ade04a e72bc1b 72ea7e1 0ade04a 72ea7e1 2fe706b 72ea7e1 b786476 820c44b 73fc96d 0ade04a 820c44b c2be249 73fc96d d6059b9 c2be249 820c44b c2be249 4ed9de7 e72bc1b 0ade04a 4ed9de7 73fc96d e72bc1b 0ade04a c2be249 73fc96d 0ade04a 73fc96d 820c44b 73fc96d 3494b39 820c44b 2fe706b d6059b9 2fe706b d6059b9 2fe706b 3494b39 0ade04a d6059b9 0ade04a 7441807 0ade04a 73fc96d 0ade04a 7441807 73fc96d c2be249 2fe706b 820c44b 73fc96d 0ade04a 820c44b 2fe706b d6059b9 2fe706b d6059b9 2fe706b 3494b39 0ade04a d6059b9 0ade04a 73fc96d 0ade04a 7441807 73fc96d 0ade04a 2fe706b 73fc96d 0fc2a04 e72bc1b 73fc96d e72bc1b 73fc96d 820c44b 73fc96d 820c44b d6059b9 2fe706b 820c44b 0ade04a 4ed9de7 73fc96d 0ade04a 2fe706b 73fc96d 0ade04a 3494b39 0fc2a04 73fc96d e72bc1b 820c44b 73fc96d 820c44b d6059b9 2fe706b 820c44b 0ade04a 4ed9de7 73fc96d 0ade04a 73fc96d 0ade04a 4ed9de7 73fc96d c926c74 e72bc1b 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b 73fc96d 2fe706b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
import os
import re
import numpy as np
import gradio as gr
from ase.io import read
from ase.io.trajectory import Trajectory
# ========= 3Dmol.js (para ver trayectorias MD/Relax) =========
THREE_D_MOL_SOURCES = [
"https://3dmol.org/build/3Dmol-min.js",
"https://cdn.jsdelivr.net/npm/3dmol/build/3Dmol-min.js",
"https://unpkg.com/3dmol/build/3Dmol-min.js",
]
def _loader_js():
srcs = "[" + ",".join([f"'{u}'" for u in THREE_D_MOL_SOURCES]) + "]"
return f"""
function _ensure3Dmol(cb){{
if(typeof window.$3Dmol!=='undefined') return cb();
const srcs={srcs}; let i=0;
function tryNext(){{
if(i>=srcs.length) return;
const s=document.createElement('script'); s.src=srcs[i++]; s.onload=cb; s.onerror=tryNext; document.head.appendChild(s);
}}
tryNext();
}}
"""
def _atoms_to_xyz_block(atoms):
syms = atoms.get_chemical_symbols()
pos = atoms.get_positions()
out = [str(len(syms)), "frame"]
for s,(x,y,z) in zip(syms,pos):
out.append(f"{s} {x:.6f} {y:.6f} {z:.6f}")
return "\n".join(out)
def traj_to_html(traj_path, width=520, height=520, interval_ms=200):
if not traj_path or not os.path.exists(traj_path):
return "<div style='color:#b00;padding:20px;'>No trajectory file found</div>"
try:
traj = Trajectory(traj_path)
if len(traj)==0:
return "<div style='color:#555;padding:20px;'>Empty trajectory</div>"
except Exception as e:
return f"<div style='color:#b00;padding:20px;'>Error reading trajectory: {e}</div>"
frames = [_atoms_to_xyz_block(at) for at in traj]
frames_json = str(frames).replace("'", '"')
viewer_id = f"viewer_{abs(hash(traj_path))%100000}"
loader = _loader_js()
return f"""
<div style="margin-bottom:10px;padding:10px;background:#f5f5f5;border-radius:5px;">
<strong>🧬 3D Molecular Viewer</strong> — {len(frames)} frames
</div>
<div id="{viewer_id}" style="width:{width}px;height:{height}px;border:2px solid #ddd;border-radius:8px;background:#fafafa;"></div>
<script>
{loader}
_ensure3Dmol(function(){{
var el=document.getElementById("{viewer_id}"); if(!el||typeof $3Dmol==='undefined') return;
var v=$3Dmol.createViewer(el, {{backgroundColor:'white'}});
var frames={frames_json}; var i=0;
function draw(k){{ v.clear(); v.addModel(frames[k], "xyz"); v.setStyle({{}}, {{stick:{{}}, sphere:{{}}}}); v.zoomTo(); v.render(); }}
draw(0);
if(frames.length>1) setInterval(function(){{ i=(i+1)%frames.length; draw(i); }}, {interval_ms});
}});
</script>
"""
# ================= OrbMol (SPE) =================
from orb_models.forcefield import pretrained
from orb_models.forcefield.calculator import ORBCalculator
_MODEL_CALC = None
def _load_orbmol_calc():
global _MODEL_CALC
if _MODEL_CALC is None:
orbff = pretrained.orb_v3_conservative_inf_omat(device="cpu", precision="float32-high")
_MODEL_CALC = ORBCalculator(orbff, device="cpu")
return _MODEL_CALC
def predict_molecule(structure_file, charge=0, spin_multiplicity=1):
"""
Single Point Energy + fuerzas (OrbMol). Solo se ejecuta al pulsar el botón.
"""
try:
calc = _load_orbmol_calc()
if not structure_file:
return "Error: Please upload a structure file", "Error"
file_path = structure_file # gr.File(type='filepath') -> str
if not os.path.exists(file_path):
return f"Error: File not found: {file_path}", "Error"
if os.path.getsize(file_path) == 0:
return f"Error: Empty file: {file_path}", "Error"
atoms = read(file_path)
atoms.info = {"charge": int(charge), "spin": int(spin_multiplicity)}
atoms.calc = calc
energy = atoms.get_potential_energy() # eV
forces = atoms.get_forces() # eV/Å
lines = [f"Total Energy: {energy:.6f} eV", "", "Atomic Forces:"]
for i, fc in enumerate(forces):
lines.append(f"Atom {i+1}: [{fc[0]:.4f}, {fc[1]:.4f}, {fc[2]:.4f}] eV/Å")
max_force = float(np.max(np.linalg.norm(forces, axis=1)))
lines += ["", f"Max Force: {max_force:.4f} eV/Å"]
return "\n".join(lines), "Calculation completed with OrbMol"
except Exception as e:
return f"Error during calculation: {e}", "Error"
# ================= Simulaciones (tus helpers) =================
from simulation_scripts_orbmol import (
run_md_simulation,
run_relaxation_simulation,
)
# ========== Wrappers MD / Relax (con firma correcta) ==========
def md_wrapper(structure_file, charge, spin, steps, tempK, timestep_fs, ensemble):
"""
Llama a tu run_md_simulation con el ORDEN correcto usando keywords:
(structure_file, num_steps, num_prerelax_steps, md_timestep, temperature_k, md_ensemble,
task_name='OMol', total_charge=..., spin_multiplicity=...)
"""
try:
if not structure_file:
return ("Error: Please upload a structure file", None, "", "", "", "", None)
file_path = structure_file
if not os.path.exists(file_path):
return ("Error: File not found: " + str(file_path), None, "", "", "", "", None)
if os.path.getsize(file_path) == 0:
return ("Error: Empty file: " + str(file_path), None, "", "", "", "", None)
traj_path, log_text, script_text, explanation = run_md_simulation(
file_path,
int(steps),
20,
float(timestep_fs),
float(tempK),
"NVT" if ensemble == "NVT" else "NVE",
total_charge=int(charge),
spin_multiplicity=int(spin),
)
status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
html_value = traj_to_html(traj_path)
return (status, traj_path, log_text, script_text, explanation, html_value, None)
except Exception as e:
return (f"Error: {e}", None, "", "", "", "", None)
def relax_wrapper(structure_file, steps, fmax, charge, spin, relax_cell):
"""
Firma correcta usando keywords:
(structure_file, num_steps, fmax, task_name='OMol', total_charge=..., spin_multiplicity=..., relax_unit_cell=...)
"""
try:
if not structure_file:
return ("Error: Please upload a structure file", None, "", "", "", "", None)
file_path = structure_file
if not os.path.exists(file_path):
return ("Error: File not found: " + str(file_path), None, "", "", "", "", None)
if os.path.getsize(file_path) == 0:
return ("Error: Empty file: " + str(file_path), None, "", "", "", "", None)
traj_path, log_text, script_text, explanation = run_relaxation_simulation(
file_path,
int(steps),
float(fmax),
total_charge=int(charge),
spin_multiplicity=int(spin),
relax_unit_cell=bool(relax_cell),
)
status = f"Relaxation finished (≤ {int(steps)} steps, fmax={float(fmax)} eV/Å)"
html_value = traj_to_html(traj_path)
return (status, traj_path, log_text, script_text, explanation, html_value, None)
except Exception as e:
return (f"Error: {e}", None, "", "", "", "", None)
# ===================== UI (solo calcula al pulsar botón) =====================
with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
with gr.Tabs():
# ===== SPE =====
with gr.Tab("Single Point Energy"):
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("## OrbMol — Single Point Energy")
xyz_input = gr.File(
label="Upload Structure File (.xyz/.pdb/.cif/.traj/.mol/.sdf)",
file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"],
file_count="single",
type="filepath",
)
with gr.Row():
charge_input = gr.Slider(minimum=-10, maximum=10, value=0, step=1, label="Charge")
spin_input = gr.Slider(minimum=1, maximum=11, value=1, step=1, label="Spin Multiplicity")
run_spe = gr.Button("Run OrbMol Prediction", variant="primary")
with gr.Column(variant="panel", min_width=520):
spe_out = gr.Textbox(label="Energy & Forces", lines=18, interactive=False)
spe_status = gr.Textbox(label="Status", interactive=False, max_lines=1)
run_spe.click(predict_molecule, [xyz_input, charge_input, spin_input], [spe_out, spe_status])
# ===== MD =====
with gr.Tab("Molecular Dynamics"):
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("## Molecular Dynamics Simulation")
xyz_md = gr.File(
label="Upload Structure File (.xyz/.pdb/.cif/.traj/.mol/.sdf)",
file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"],
file_count="single",
type="filepath",
)
with gr.Row():
charge_md = gr.Slider(minimum=-10, maximum=10, value=0, step=1, label="Charge")
spin_md = gr.Slider(minimum=1, maximum=11, value=1, step=1, label="Spin Multiplicity")
with gr.Row():
steps_md = gr.Slider(minimum=10, maximum=2000, value=100, step=10, label="Steps")
temp_md = gr.Slider(minimum=10, maximum=1500, value=300, step=10, label="Temperature (K)")
with gr.Row():
timestep_md = gr.Slider(minimum=0.1, maximum=5.0, value=1.0, step=0.1, label="Timestep (fs)")
ensemble_md = gr.Radio(["NVE","NVT"], value="NVE", label="Ensemble")
run_md_btn = gr.Button("Run MD Simulation", variant="primary")
with gr.Column(variant="panel", min_width=520):
md_status = gr.Textbox(label="MD Status", interactive=False)
md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
md_html = gr.HTML(label="Trajectory Viewer", sanitize=False)
md_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=18, max_lines=28)
md_explain= gr.Markdown()
md_plot = gr.Plot(label="(optional)")
run_md_btn.click(
md_wrapper,
inputs=[xyz_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
outputs=[md_status, md_traj, md_log, md_script, md_explain, md_html, md_plot],
)
# ===== Relax =====
with gr.Tab("Relaxation / Optimization"):
with gr.Row():
with gr.Column(scale=2):
gr.Markdown("## Structure Relaxation/Optimization")
xyz_rlx = gr.File(
label="Upload Structure File (.xyz/.pdb/.cif/.traj/.mol/.sdf)",
file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"],
file_count="single",
type="filepath",
)
steps_rlx = gr.Slider(minimum=1, maximum=2000, value=300, step=1, label="Max Steps")
fmax_rlx = gr.Slider(minimum=0.001, maximum=0.5, value=0.05, step=0.001, label="Fmax (eV/Å)")
with gr.Row():
charge_rlx = gr.Slider(minimum=-10, maximum=10, value=0, step=1, label="Charge")
spin_rlx = gr.Slider(minimum=1, maximum=11, value=1, step=1, label="Spin")
relax_cell = gr.Checkbox(False, label="Relax Unit Cell")
run_rlx_btn= gr.Button("Run Optimization", variant="primary")
with gr.Column(variant="panel", min_width=520):
rlx_status = gr.Textbox(label="Status", interactive=False)
rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
rlx_html = gr.HTML(label="Final Structure / Trajectory", sanitize=False)
rlx_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=18, max_lines=28)
rlx_explain= gr.Markdown()
rlx_plot = gr.Plot(label="(optional)")
run_rlx_btn.click(
relax_wrapper,
inputs=[xyz_rlx, steps_rlx, fmax_rlx, charge_rlx, spin_rlx, relax_cell],
outputs=[rlx_status, rlx_traj, rlx_log, rlx_script, rlx_explain, rlx_html, rlx_plot],
)
print("Starting OrbMol model loading…")
_ = _load_orbmol_calc()
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)
|