annabossler commited on
Commit
7441807
·
verified ·
1 Parent(s): cc11f7f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +56 -124
app.py CHANGED
@@ -6,58 +6,19 @@ from ase.io import read, write
6
  from ase.io.trajectory import Trajectory
7
  import hashlib
8
 
9
- # ==== Usar componente nativo Molecule3D ====
10
- try:
11
- from gradio_molecule3d import Molecule3D
12
- HAVE_MOL3D = True
13
- print("✅ gradio_molecule3d loaded successfully")
14
- except Exception as e:
15
- HAVE_MOL3D = False
16
- print(f"❌ gradio_molecule3d not available: {e}")
17
-
18
- # ==== Convierte .traj -> contenido PDB (string) para Molecule3D ====
19
- def traj_to_molecule3d_file(traj_path):
20
- """
21
- Lee el último frame de una .traj y devuelve el CONTENIDO PDB (string)
22
- para pasarlo directamente a Molecule3D. No devuelve una ruta.
23
- """
24
- if not traj_path or not os.path.exists(traj_path):
25
- return None
26
- try:
27
- traj = Trajectory(traj_path)
28
- if len(traj) == 0:
29
- return None
30
-
31
- atoms = traj[-1]
32
 
33
- # Escribir a PDB temporal y devolver su contenido como string
34
- with tempfile.NamedTemporaryFile(suffix=".pdb", delete=False) as f:
35
- pdb_path = f.name
36
- write(pdb_path, atoms)
37
-
38
- try:
39
- with open(pdb_path, "r", encoding="utf-8", errors="ignore") as fh:
40
- pdb_text = fh.read()
41
- finally:
42
- try:
43
- os.remove(pdb_path)
44
- except Exception:
45
- pass
46
-
47
- return pdb_text
48
- except Exception as e:
49
- print(f"Error converting trajectory: {e}")
50
- return None
51
-
52
- # ==== Fallback HTML con 3Dmol.js (por si acaso) ====
53
  def traj_to_html(traj_path, width=520, height=520, interval_ms=200):
54
  """
55
- Fallback HTML viewer (solo si Molecule3D no está disponible).
56
  """
57
  if not traj_path or not os.path.exists(traj_path):
58
  return "<div style='color:#b00; padding:20px;'>No trajectory file found</div>"
59
 
60
- viewer_id = f"viewer_{abs(hash(traj_path)) % 10000}"
61
 
62
  try:
63
  traj = Trajectory(traj_path)
@@ -79,50 +40,47 @@ def traj_to_html(traj_path, width=520, height=520, interval_ms=200):
79
 
80
  html = f"""
81
  <div style="margin-bottom:10px; padding:10px; background:#f5f5f5; border-radius:5px;">
82
- <strong>🧬 3D Molecular Viewer</strong> - {len(xyz_frames)} frames
83
  </div>
84
  <div id="{viewer_id}" style="width:{width}px; height:{height}px; position:relative; border:2px solid #ddd; border-radius:8px; background:#fafafa;"></div>
85
  <script>
86
  if (typeof window.$3Dmol === 'undefined') {{
87
- var script = document.createElement('script');
88
- script.src = 'https://3dmol.org/build/3Dmol-min.js';
89
- script.onload = function() {{
90
- setTimeout(function() {{ initViewer_{viewer_id}(); }}, 100);
91
- }};
92
- document.head.appendChild(script);
93
  }} else {{
94
- initViewer_{viewer_id}();
95
  }}
96
  function initViewer_{viewer_id}() {{
97
- var el = document.getElementById("{viewer_id}");
98
- if (!el || typeof $3Dmol === "undefined") return;
99
-
100
- var viewer = $3Dmol.createViewer(el, {{backgroundColor: 'white'}});
101
- var frames = {frames_json};
102
- var currentFrame = 0;
103
-
104
- function showFrame(frameIndex) {{
105
- viewer.clear();
106
- viewer.addModel(frames[frameIndex], "xyz");
107
- viewer.setStyle({{}}, {{stick: {{radius: 0.1}}, sphere: {{radius: 0.3}}}});
108
- viewer.zoomTo();
109
- viewer.render();
110
- }}
111
-
112
- showFrame(0);
113
-
114
- if (frames.length > 1) {{
115
- setInterval(function() {{
116
- currentFrame = (currentFrame + 1) % frames.length;
117
- showFrame(currentFrame);
118
- }}, {interval_ms});
119
- }}
120
  }}
121
  </script>
122
  """
123
  return html
124
 
125
- # ==== OrbMol SPE directo (sin cambios) ====
126
  from orb_models.forcefield import pretrained
127
  from orb_models.forcefield.calculator import ORBCalculator
128
 
@@ -138,7 +96,7 @@ def _load_orbmol_calc():
138
 
139
  def predict_molecule(xyz_content, charge=0, spin_multiplicity=1):
140
  """
141
- Single Point Energy + fuerzas. No escribe nada salvo un .xyz temporal.
142
  """
143
  try:
144
  calc = _load_orbmol_calc()
@@ -171,7 +129,7 @@ def predict_molecule(xyz_content, charge=0, spin_multiplicity=1):
171
  except Exception as e:
172
  return f"Error during calculation: {e}", "Error"
173
 
174
- # ==== Simulaciones (sin cambios) ====
175
  from simulation_scripts_orbmol import (
176
  run_md_simulation,
177
  run_relaxation_simulation,
@@ -193,7 +151,7 @@ def _to_file_if_xyz(input_or_path: str):
193
  return tf.name, True
194
  return input_or_path, False
195
 
196
- # Wrappers actualizados para devolver PDB (string) a Molecule3D
197
  def md_wrapper(xyz_content, charge, spin, steps, tempK, timestep_fs, ensemble):
198
  tmp_created = False
199
  path_or_str = xyz_content
@@ -203,7 +161,7 @@ def md_wrapper(xyz_content, charge, spin, steps, tempK, timestep_fs, ensemble):
203
  traj_path, log_text, script_text, explanation = run_md_simulation(
204
  path_or_str,
205
  int(steps),
206
- 20, # pre-relax fija
207
  float(timestep_fs),
208
  float(tempK),
209
  "NVT" if ensemble == "NVT" else "NVE",
@@ -212,13 +170,8 @@ def md_wrapper(xyz_content, charge, spin, steps, tempK, timestep_fs, ensemble):
212
  )
213
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
214
 
215
- # Usar Molecule3D si está disponible, sino HTML
216
- if HAVE_MOL3D:
217
- pdb_text = traj_to_molecule3d_file(traj_path)
218
- return (status, traj_path, log_text, script_text, explanation, pdb_text, "")
219
- else:
220
- html_value = traj_to_html(traj_path)
221
- return (status, traj_path, log_text, script_text, explanation, None, html_value)
222
 
223
  except Exception as e:
224
  return (f"Error: {e}", None, "", "", "", None, "")
@@ -243,24 +196,17 @@ def relax_wrapper(xyz_content, steps, fmax, charge, spin, relax_cell):
243
  )
244
  status = f"Relaxation finished (≤ {int(steps)} steps, fmax={float(fmax)} eV/Å)"
245
 
246
- # Usar Molecule3D si está disponible, sino HTML
247
- if HAVE_MOL3D:
248
- pdb_text = traj_to_molecule3d_file(traj_path)
249
- return (status, traj_path, log_text, script_text, explanation, pdb_text, "")
250
- else:
251
- html_value = traj_to_html(traj_path)
252
- return (status, traj_path, log_text, script_text, explanation, None, html_value)
253
 
254
  except Exception as e:
255
  return (f"Error: {e}", None, "", "", "", None, "")
256
  finally:
257
  if tmp_created and isinstance(path_or_str, str) and os.path.exists(path_or_str):
258
- try:
259
- os.remove(path_or_str)
260
- except Exception:
261
- pass
262
 
263
- # ==== Ejemplos (sin cambios) ====
264
  examples = [
265
  ["""2
266
  Hydrogen molecule
@@ -280,10 +226,10 @@ H -0.3630 -0.5133 0.8887
280
  H -0.3630 -0.5133 -0.8887""", 0, 1],
281
  ]
282
 
283
- # ==== UI actualizada ====
284
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
285
  with gr.Tabs():
286
- # -------- SPE (sin cambios) --------
287
  with gr.Tab("Single Point Energy"):
288
  with gr.Row():
289
  with gr.Column(scale=2):
@@ -301,7 +247,7 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
301
  gr.Examples(examples=examples, inputs=[xyz_input, charge_input, spin_input])
302
  run_spe.click(predict_molecule, [xyz_input, charge_input, spin_input], [spe_out, spe_status])
303
 
304
- # -------- MD (actualizada con Molecule3D) --------
305
  with gr.Tab("Molecular Dynamics"):
306
  with gr.Row():
307
  with gr.Column(scale=2):
@@ -320,15 +266,8 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
320
  with gr.Column(variant="panel", min_width=520):
321
  md_status = gr.Textbox(label="MD Status", interactive=False)
322
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
323
-
324
- # Usar Molecule3D si está disponible
325
- if HAVE_MOL3D:
326
- md_viewer = Molecule3D(label="3D Molecular Viewer")
327
- md_html = gr.HTML(visible=False) # Oculto cuando usamos Molecule3D
328
- else:
329
- md_viewer = gr.HTML(visible=False) # Placeholder
330
- md_html = gr.HTML(label="Trajectory Viewer")
331
-
332
  md_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
333
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
334
  md_explain = gr.Markdown()
@@ -336,10 +275,10 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
336
  run_md_btn.click(
337
  md_wrapper,
338
  inputs=[xyz_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
339
- outputs=[md_status, md_traj, md_log, md_script, md_explain, md_viewer, md_html],
340
  )
341
 
342
- # -------- Relax (actualizada con Molecule3D) --------
343
  with gr.Tab("Relaxation / Optimization"):
344
  with gr.Row():
345
  with gr.Column(scale=2):
@@ -355,15 +294,8 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
355
  with gr.Column(variant="panel", min_width=520):
356
  rlx_status = gr.Textbox(label="Status", interactive=False)
357
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
358
-
359
- # Usar Molecule3D si está disponible
360
- if HAVE_MOL3D:
361
- rlx_viewer = Molecule3D(label="Final Structure")
362
- rlx_html = gr.HTML(visible=False) # Oculto cuando usamos Molecule3D
363
- else:
364
- rlx_viewer = gr.HTML(visible=False) # Placeholder
365
- rlx_html = gr.HTML(label="Final Structure")
366
-
367
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
368
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
369
  rlx_explain = gr.Markdown()
@@ -371,7 +303,7 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
371
  run_rlx_btn.click(
372
  relax_wrapper,
373
  inputs=[xyz_rlx, steps_rlx, fmax_rlx, charge_rlx, spin_rlx, relax_cell],
374
- outputs=[rlx_status, rlx_traj, rlx_log, rlx_script, rlx_explain, rlx_viewer, rlx_html],
375
  )
376
 
377
  print("Starting OrbMol model loading…")
 
6
  from ase.io.trajectory import Trajectory
7
  import hashlib
8
 
9
+ # ==== Forzar visor HTML con 3Dmol.js ====
10
+ # (desactiva Molecule3D porque requiere formatos con conectividad)
11
+ HAVE_MOL3D = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ # ==== Fallback HTML con 3Dmol.js ====
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  def traj_to_html(traj_path, width=520, height=520, interval_ms=200):
15
  """
16
+ Lee una .traj de ASE y genera un visor HTML (3Dmol.js) con animación.
17
  """
18
  if not traj_path or not os.path.exists(traj_path):
19
  return "<div style='color:#b00; padding:20px;'>No trajectory file found</div>"
20
 
21
+ viewer_id = f"viewer_{abs(hash(traj_path)) % 100000}"
22
 
23
  try:
24
  traj = Trajectory(traj_path)
 
40
 
41
  html = f"""
42
  <div style="margin-bottom:10px; padding:10px; background:#f5f5f5; border-radius:5px;">
43
+ <strong>🧬 3D Molecular Viewer</strong> {len(xyz_frames)} frames
44
  </div>
45
  <div id="{viewer_id}" style="width:{width}px; height:{height}px; position:relative; border:2px solid #ddd; border-radius:8px; background:#fafafa;"></div>
46
  <script>
47
  if (typeof window.$3Dmol === 'undefined') {{
48
+ var script = document.createElement('script');
49
+ script.src = 'https://3dmol.org/build/3Dmol-min.js';
50
+ script.onload = function() {{ setTimeout(function() {{ initViewer_{viewer_id}(); }}, 100); }};
51
+ document.head.appendChild(script);
 
 
52
  }} else {{
53
+ initViewer_{viewer_id}();
54
  }}
55
  function initViewer_{viewer_id}() {{
56
+ var el = document.getElementById("{viewer_id}");
57
+ if (!el || typeof $3Dmol === "undefined") return;
58
+
59
+ var viewer = $3Dmol.createViewer(el, {{backgroundColor: 'white'}});
60
+ var frames = {frames_json};
61
+ var currentFrame = 0;
62
+
63
+ function showFrame(i) {{
64
+ viewer.clear();
65
+ viewer.addModel(frames[i], "xyz");
66
+ viewer.setStyle({{}}, {{stick: {{}}, sphere: {{}}}});
67
+ viewer.zoomTo();
68
+ viewer.render();
69
+ }}
70
+
71
+ showFrame(0);
72
+ if (frames.length > 1) {{
73
+ setInterval(function() {{
74
+ currentFrame = (currentFrame + 1) % frames.length;
75
+ showFrame(currentFrame);
76
+ }}, {interval_ms});
77
+ }}
 
78
  }}
79
  </script>
80
  """
81
  return html
82
 
83
+ # ==== OrbMol SPE ====
84
  from orb_models.forcefield import pretrained
85
  from orb_models.forcefield.calculator import ORBCalculator
86
 
 
96
 
97
  def predict_molecule(xyz_content, charge=0, spin_multiplicity=1):
98
  """
99
+ Single Point Energy + fuerzas (OrbMol). Toma XYZ en texto.
100
  """
101
  try:
102
  calc = _load_orbmol_calc()
 
129
  except Exception as e:
130
  return f"Error during calculation: {e}", "Error"
131
 
132
+ # ==== Simulaciones (helpers) ====
133
  from simulation_scripts_orbmol import (
134
  run_md_simulation,
135
  run_relaxation_simulation,
 
151
  return tf.name, True
152
  return input_or_path, False
153
 
154
+ # ==== Wrappers: devuelven HTML (3Dmol.js) ====
155
  def md_wrapper(xyz_content, charge, spin, steps, tempK, timestep_fs, ensemble):
156
  tmp_created = False
157
  path_or_str = xyz_content
 
161
  traj_path, log_text, script_text, explanation = run_md_simulation(
162
  path_or_str,
163
  int(steps),
164
+ 20,
165
  float(timestep_fs),
166
  float(tempK),
167
  "NVT" if ensemble == "NVT" else "NVE",
 
170
  )
171
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
172
 
173
+ html_value = traj_to_html(traj_path)
174
+ return (status, traj_path, log_text, script_text, explanation, None, html_value)
 
 
 
 
 
175
 
176
  except Exception as e:
177
  return (f"Error: {e}", None, "", "", "", None, "")
 
196
  )
197
  status = f"Relaxation finished (≤ {int(steps)} steps, fmax={float(fmax)} eV/Å)"
198
 
199
+ html_value = traj_to_html(traj_path)
200
+ return (status, traj_path, log_text, script_text, explanation, None, html_value)
 
 
 
 
 
201
 
202
  except Exception as e:
203
  return (f"Error: {e}", None, "", "", "", None, "")
204
  finally:
205
  if tmp_created and isinstance(path_or_str, str) and os.path.exists(path_or_str):
206
+ try: os.remove(path_or_str)
207
+ except Exception: pass
 
 
208
 
209
+ # ==== Ejemplos ====
210
  examples = [
211
  ["""2
212
  Hydrogen molecule
 
226
  H -0.3630 -0.5133 -0.8887""", 0, 1],
227
  ]
228
 
229
+ # ==== UI ====
230
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
231
  with gr.Tabs():
232
+ # -------- SPE --------
233
  with gr.Tab("Single Point Energy"):
234
  with gr.Row():
235
  with gr.Column(scale=2):
 
247
  gr.Examples(examples=examples, inputs=[xyz_input, charge_input, spin_input])
248
  run_spe.click(predict_molecule, [xyz_input, charge_input, spin_input], [spe_out, spe_status])
249
 
250
+ # -------- MD --------
251
  with gr.Tab("Molecular Dynamics"):
252
  with gr.Row():
253
  with gr.Column(scale=2):
 
266
  with gr.Column(variant="panel", min_width=520):
267
  md_status = gr.Textbox(label="MD Status", interactive=False)
268
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
269
+ md_viewer_placeholder = gr.HTML(visible=False) # no usamos Molecule3D
270
+ md_html = gr.HTML(label="Trajectory Viewer")
 
 
 
 
 
 
 
271
  md_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
272
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
273
  md_explain = gr.Markdown()
 
275
  run_md_btn.click(
276
  md_wrapper,
277
  inputs=[xyz_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
278
+ outputs=[md_status, md_traj, md_log, md_script, md_explain, md_viewer_placeholder, md_html],
279
  )
280
 
281
+ # -------- Relax --------
282
  with gr.Tab("Relaxation / Optimization"):
283
  with gr.Row():
284
  with gr.Column(scale=2):
 
294
  with gr.Column(variant="panel", min_width=520):
295
  rlx_status = gr.Textbox(label="Status", interactive=False)
296
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
297
+ rlx_viewer_placeholder = gr.HTML(visible=False)
298
+ rlx_html = gr.HTML(label="Final Structure")
 
 
 
 
 
 
 
299
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
300
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
301
  rlx_explain = gr.Markdown()
 
303
  run_rlx_btn.click(
304
  relax_wrapper,
305
  inputs=[xyz_rlx, steps_rlx, fmax_rlx, charge_rlx, spin_rlx, relax_cell],
306
+ outputs=[rlx_status, rlx_traj, rlx_log, rlx_script, rlx_explain, rlx_viewer_placeholder, rlx_html],
307
  )
308
 
309
  print("Starting OrbMol model loading…")