annabossler commited on
Commit
76079ef
·
verified ·
1 Parent(s): 1fedfc5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +30 -78
app.py CHANGED
@@ -4,77 +4,27 @@ import numpy as np
4
  import gradio as gr
5
  from ase.io import read, write
6
  from ase.io.trajectory import Trajectory
 
7
  import hashlib
8
 
9
- # ==== Forzar visor HTML con 3Dmol.js ====
10
- HAVE_MOL3D = False
11
-
12
- # ==== Fallback HTML con 3Dmol.js ====
13
- def traj_to_html(traj_path, width=520, height=520, interval_ms=200):
14
- """
15
- Lee una .traj de ASE y genera un visor HTML (3Dmol.js) con animación.
16
- """
17
  if not traj_path or not os.path.exists(traj_path):
18
- return "<div style='color:#b00; padding:20px;'>No trajectory file found</div>"
19
-
20
- viewer_id = f"viewer_{abs(hash(traj_path)) % 100000}"
21
-
22
  try:
23
  traj = Trajectory(traj_path)
24
  if len(traj) == 0:
25
- return "<div style='color:#555; padding:20px;'>Empty trajectory</div>"
 
 
 
 
 
26
  except Exception as e:
27
- return f"<div style='color:#b00; padding:20px;'>Error: {e}</div>"
28
-
29
- xyz_frames = []
30
- for atoms in traj:
31
- symbols = atoms.get_chemical_symbols()
32
- coords = atoms.get_positions()
33
- parts = [str(len(symbols)), "frame"]
34
- for s, (x, y, z) in zip(symbols, coords):
35
- parts.append(f"{s} {x:.6f} {y:.6f} {z:.6f}")
36
- xyz_frames.append("\n".join(parts))
37
-
38
- frames_json = str(xyz_frames).replace("'", '"')
39
-
40
- html = f"""
41
- <div style="margin-bottom:10px; padding:10px; background:#f5f5f5; border-radius:5px;">
42
- <strong>🧬 3D Molecular Viewer</strong> — {len(xyz_frames)} frames
43
- </div>
44
- <div id="{viewer_id}" style="width:{width}px; height:{height}px; position:relative; border:2px solid #ddd; border-radius:8px; background:#fafafa;"></div>
45
- <script>
46
- if (typeof window.$3Dmol === 'undefined') {{
47
- var script = document.createElement('script');
48
- script.src = 'https://3dmol.org/build/3Dmol-min.js';
49
- script.onload = function() {{ setTimeout(function() {{ initViewer_{viewer_id}(); }}, 100); }};
50
- document.head.appendChild(script);
51
- }} else {{
52
- initViewer_{viewer_id}();
53
- }}
54
- function initViewer_{viewer_id}() {{
55
- var el = document.getElementById("{viewer_id}");
56
- if (!el || typeof $3Dmol === "undefined") return;
57
- var viewer = $3Dmol.createViewer(el, {{backgroundColor: 'white'}});
58
- var frames = {frames_json};
59
- var currentFrame = 0;
60
- function showFrame(i) {{
61
- viewer.clear();
62
- viewer.addModel(frames[i], "xyz");
63
- viewer.setStyle({{}}, {{stick: {{}}, sphere: {{}}}});
64
- viewer.zoomTo();
65
- viewer.render();
66
- }}
67
- showFrame(0);
68
- if (frames.length > 1) {{
69
- setInterval(function() {{
70
- currentFrame = (currentFrame + 1) % frames.length;
71
- showFrame(currentFrame);
72
- }}, {interval_ms});
73
- }}
74
- }}
75
- </script>
76
- """
77
- return html
78
 
79
  # ==== OrbMol SPE ====
80
  from orb_models.forcefield import pretrained
@@ -136,7 +86,7 @@ from simulation_scripts_orbmol import (
136
  def md_wrapper(structure_file, charge, spin, steps, tempK, timestep_fs, ensemble):
137
  try:
138
  if not structure_file:
139
- return ("Error: Please upload a structure file", None, "", "", "", None, "")
140
 
141
  # structure_file es directamente el path del archivo
142
  file_path = structure_file
@@ -153,16 +103,18 @@ def md_wrapper(structure_file, charge, spin, steps, tempK, timestep_fs, ensemble
153
  )
154
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
155
 
156
- html_value = traj_to_html(traj_path)
157
- return (status, traj_path, log_text, script_text, explanation, None, html_value)
 
 
158
 
159
  except Exception as e:
160
- return (f"Error: {e}", None, "", "", "", None, "")
161
 
162
  def relax_wrapper(structure_file, steps, fmax, charge, spin, relax_cell):
163
  try:
164
  if not structure_file:
165
- return ("Error: Please upload a structure file", None, "", "", "", None, "")
166
 
167
  # structure_file es directamente el path del archivo
168
  file_path = structure_file
@@ -177,11 +129,13 @@ def relax_wrapper(structure_file, steps, fmax, charge, spin, relax_cell):
177
  )
178
  status = f"Relaxation finished (≤ {int(steps)} steps, fmax={float(fmax)} eV/Å)"
179
 
180
- html_value = traj_to_html(traj_path)
181
- return (status, traj_path, log_text, script_text, explanation, None, html_value)
 
 
182
 
183
  except Exception as e:
184
- return (f"Error: {e}", None, "", "", "", None, "")
185
 
186
  # ==== UI ====
187
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
@@ -237,8 +191,7 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
237
  with gr.Column(variant="panel", min_width=520):
238
  md_status = gr.Textbox(label="MD Status", interactive=False)
239
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
240
- md_viewer_placeholder = gr.HTML(visible=False)
241
- md_html = gr.HTML(label="Trajectory Viewer")
242
  md_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
243
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
244
  md_explain = gr.Markdown()
@@ -246,7 +199,7 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
246
  run_md_btn.click(
247
  md_wrapper,
248
  inputs=[xyz_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
249
- outputs=[md_status, md_traj, md_log, md_script, md_explain, md_viewer_placeholder, md_html],
250
  )
251
 
252
  # -------- Relax --------
@@ -273,8 +226,7 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
273
  with gr.Column(variant="panel", min_width=520):
274
  rlx_status = gr.Textbox(label="Status", interactive=False)
275
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
276
- rlx_viewer_placeholder = gr.HTML(visible=False)
277
- rlx_html = gr.HTML(label="Final Structure")
278
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
279
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
280
  rlx_explain = gr.Markdown()
@@ -282,7 +234,7 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
282
  run_rlx_btn.click(
283
  relax_wrapper,
284
  inputs=[xyz_rlx, steps_rlx, fmax_rlx, charge_rlx, spin_rlx, relax_cell],
285
- outputs=[rlx_status, rlx_traj, rlx_log, rlx_script, rlx_explain, rlx_viewer_placeholder, rlx_html],
286
  )
287
 
288
  print("Starting OrbMol model loading…")
 
4
  import gradio as gr
5
  from ase.io import read, write
6
  from ase.io.trajectory import Trajectory
7
+ from gradio_molecule3d import Molecule3D
8
  import hashlib
9
 
10
+ # ==== Molecule3D viewer preparation ====
11
+ def prepare_molecule_for_viewer(traj_path):
12
+ """Convert trajectory to format compatible with Molecule3D viewer"""
 
 
 
 
 
13
  if not traj_path or not os.path.exists(traj_path):
14
+ return None
15
+
 
 
16
  try:
17
  traj = Trajectory(traj_path)
18
  if len(traj) == 0:
19
+ return None
20
+
21
+ # Save last frame as PDB for Molecule3D
22
+ temp_pdb = tempfile.NamedTemporaryFile(suffix='.pdb', delete=False)
23
+ write(temp_pdb.name, traj[-1], format='pdb')
24
+ return temp_pdb.name
25
  except Exception as e:
26
+ print(f"Error preparing molecule: {e}")
27
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  # ==== OrbMol SPE ====
30
  from orb_models.forcefield import pretrained
 
86
  def md_wrapper(structure_file, charge, spin, steps, tempK, timestep_fs, ensemble):
87
  try:
88
  if not structure_file:
89
+ return ("Error: Please upload a structure file", None, "", "", "", None)
90
 
91
  # structure_file es directamente el path del archivo
92
  file_path = structure_file
 
103
  )
104
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
105
 
106
+ # Preparar archivo PDB para el visor 3D
107
+ pdb_file = prepare_molecule_for_viewer(traj_path)
108
+
109
+ return (status, traj_path, log_text, script_text, explanation, pdb_file)
110
 
111
  except Exception as e:
112
+ return (f"Error: {e}", None, "", "", "", None)
113
 
114
  def relax_wrapper(structure_file, steps, fmax, charge, spin, relax_cell):
115
  try:
116
  if not structure_file:
117
+ return ("Error: Please upload a structure file", None, "", "", "", None)
118
 
119
  # structure_file es directamente el path del archivo
120
  file_path = structure_file
 
129
  )
130
  status = f"Relaxation finished (≤ {int(steps)} steps, fmax={float(fmax)} eV/Å)"
131
 
132
+ # Preparar archivo PDB para el visor 3D
133
+ pdb_file = prepare_molecule_for_viewer(traj_path)
134
+
135
+ return (status, traj_path, log_text, script_text, explanation, pdb_file)
136
 
137
  except Exception as e:
138
+ return (f"Error: {e}", None, "", "", "", None)
139
 
140
  # ==== UI ====
141
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
 
191
  with gr.Column(variant="panel", min_width=520):
192
  md_status = gr.Textbox(label="MD Status", interactive=False)
193
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
194
+ md_viewer = Molecule3D(label="3D Structure Viewer")
 
195
  md_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
196
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
197
  md_explain = gr.Markdown()
 
199
  run_md_btn.click(
200
  md_wrapper,
201
  inputs=[xyz_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
202
+ outputs=[md_status, md_traj, md_log, md_script, md_explain, md_viewer],
203
  )
204
 
205
  # -------- Relax --------
 
226
  with gr.Column(variant="panel", min_width=520):
227
  rlx_status = gr.Textbox(label="Status", interactive=False)
228
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
229
+ rlx_viewer = Molecule3D(label="3D Structure Viewer")
 
230
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
231
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
232
  rlx_explain = gr.Markdown()
 
234
  run_rlx_btn.click(
235
  relax_wrapper,
236
  inputs=[xyz_rlx, steps_rlx, fmax_rlx, charge_rlx, spin_rlx, relax_cell],
237
+ outputs=[rlx_status, rlx_traj, rlx_log, rlx_script, rlx_explain, rlx_viewer],
238
  )
239
 
240
  print("Starting OrbMol model loading…")