annabossler commited on
Commit
b786476
·
verified ·
1 Parent(s): f67747c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -426
app.py CHANGED
@@ -1,52 +1,13 @@
1
  import gradio as gr
2
  import torch
3
  import numpy as np
 
 
4
  import tempfile
5
  import os
6
- from ase import Atoms
7
- from ase.io import read, write
8
- from ase.optimize import LBFGS
9
- from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
10
- from ase.md.verlet import VelocityVerlet
11
- from ase.io.trajectory import Trajectory
12
- from ase.md import MDLogger
13
- from ase import units
14
  from orb_models.forcefield import pretrained
15
  from orb_models.forcefield.calculator import ORBCalculator
16
 
17
- # Install and import gradio_molecule3d
18
- try:
19
- from gradio_molecule3d import Molecule3D
20
- HAS_3D = True
21
- except ImportError:
22
- HAS_3D = False
23
-
24
- # Default molecular representations for 3D visualization
25
- DEFAULT_MOLECULAR_REPRESENTATIONS = [
26
- {
27
- "model": 0,
28
- "chain": "",
29
- "resname": "",
30
- "style": "sphere",
31
- "color": "Jmol",
32
- "scale": 0.3,
33
- },
34
- {
35
- "model": 0,
36
- "chain": "",
37
- "resname": "",
38
- "style": "stick",
39
- "color": "Jmol",
40
- "scale": 0.2,
41
- },
42
- ]
43
-
44
- DEFAULT_MOLECULAR_SETTINGS = {
45
- "backgroundColor": "white",
46
- "orthographic": False,
47
- "disableFog": False,
48
- }
49
-
50
  # Global variable for the model
51
  model_calc = None
52
 
@@ -57,8 +18,8 @@ def load_orbmol_model():
57
  try:
58
  print("Loading OrbMol model...")
59
  orbff = pretrained.orb_v3_conservative_inf_omat(
60
- device="cpu",
61
- precision="float32-high"
62
  )
63
  model_calc = ORBCalculator(orbff, device="cpu")
64
  print("✅ OrbMol model loaded successfully")
@@ -67,230 +28,76 @@ def load_orbmol_model():
67
  model_calc = None
68
  return model_calc
69
 
70
- def run_md_simulation(input_file, md_steps, prerelax_steps, md_timestep, temperature_k, md_ensemble, charge, spin_multiplicity, explanation_buffer=""):
71
- """Run molecular dynamics simulation similar to FAIR Chem UMA"""
72
- try:
73
- calc = load_orbmol_model()
74
- if calc is None:
75
- return None, "❌ Error: Could not load OrbMol model", "", explanation_buffer
76
-
77
- # Parse input file content
78
- if isinstance(input_file, str):
79
- # Handle XYZ string input
80
- with tempfile.NamedTemporaryFile(mode='w', suffix='.xyz', delete=False) as f:
81
- f.write(input_file)
82
- xyz_file = f.name
83
- atoms = read(xyz_file)
84
- os.unlink(xyz_file)
85
- else:
86
- # Handle uploaded file
87
- atoms = read(input_file)
88
-
89
- # Set charge and spin
90
- atoms.info = {"charge": int(charge), "spin": int(spin_multiplicity)}
91
- atoms.calc = calc
92
-
93
- # Pre-relaxation
94
- if prerelax_steps > 0:
95
- opt = LBFGS(atoms)
96
- opt.run(fmax=0.05, steps=prerelax_steps)
97
-
98
- # Create trajectory file
99
- traj_path = tempfile.NamedTemporaryFile(suffix='.traj', delete=False).name
100
-
101
- # Initialize velocity distribution
102
- MaxwellBoltzmannDistribution(atoms, temperature_K=temperature_k)
103
-
104
- # Set up MD
105
- if md_ensemble == "NVE":
106
- dyn = VelocityVerlet(atoms, timestep=md_timestep * units.fs)
107
- else: # NVT
108
- from ase.md.langevin import Langevin
109
- dyn = Langevin(atoms, md_timestep * units.fs, temperature_K=temperature_k, friction=0.001/units.fs)
110
-
111
- # Attach trajectory
112
- traj = Trajectory(traj_path, "w", atoms)
113
- dyn.attach(traj.write, interval=1)
114
-
115
- # Run simulation
116
- dyn.run(md_steps)
117
- traj.close()
118
-
119
- # Generate log
120
- log_content = f"""OrbMol Molecular Dynamics Simulation
121
- =====================================
122
- System: {len(atoms)} atoms
123
- MD Steps: {md_steps}
124
- Temperature: {temperature_k} K
125
- Ensemble: {md_ensemble}
126
- Timestep: {md_timestep} fs
127
- Charge: {charge}
128
- Spin Multiplicity: {spin_multiplicity}
129
-
130
- Final Energy: {atoms.get_potential_energy():.6f} eV
131
- Simulation completed successfully!
132
- """
133
-
134
- # Generate reproduction script
135
- script_content = f"""# OrbMol MD Simulation Script
136
- import ase.io
137
- from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
138
- from ase.md.verlet import VelocityVerlet
139
- from ase.optimize import LBFGS
140
- from ase.io.trajectory import Trajectory
141
- from ase import units
142
- from orb_models.forcefield import pretrained
143
- from orb_models.forcefield.calculator import ORBCalculator
144
-
145
- # Load structure
146
- atoms = ase.io.read('input_structure.xyz') # Your input file
147
- atoms.info = {{"charge": {charge}, "spin": {spin_multiplicity}}}
148
-
149
- # Set up OrbMol calculator
150
- orbff = pretrained.orb_v3_conservative_inf_omat(device="cpu")
151
- atoms.calc = ORBCalculator(orbff, device="cpu")
152
-
153
- # Pre-relaxation
154
- opt = LBFGS(atoms)
155
- opt.run(fmax=0.05, steps={prerelax_steps})
156
-
157
- # Initialize velocities
158
- MaxwellBoltzmannDistribution(atoms, temperature_K={temperature_k})
159
-
160
- # Set up MD
161
- dyn = VelocityVerlet(atoms, timestep={md_timestep} * units.fs)
162
- traj = Trajectory("md_output.traj", "w", atoms)
163
- dyn.attach(traj.write, interval=1)
164
-
165
- # Run simulation
166
- dyn.run({md_steps})
167
- """
168
-
169
- explanation = explanation_buffer if explanation_buffer else f"Molecular dynamics simulation completed! This shows {len(atoms)} atoms moving over {md_steps} steps at {temperature_k} K. The atoms are vibrating due to thermal motion, and you can see the molecular structure evolving over time."
170
-
171
- return traj_path, log_content, script_content, explanation
172
-
173
- except Exception as e:
174
- return None, f"❌ Error during MD simulation: {str(e)}", "", "Error occurred"
175
-
176
- def run_optimization(input_file, optimization_steps, fmax, charge, spin_multiplicity):
177
- """Run geometry optimization"""
178
- try:
179
- calc = load_orbmol_model()
180
- if calc is None:
181
- return None, "❌ Error: Could not load OrbMol model", ""
182
-
183
- # Parse input
184
- if isinstance(input_file, str):
185
- with tempfile.NamedTemporaryFile(mode='w', suffix='.xyz', delete=False) as f:
186
- f.write(input_file)
187
- xyz_file = f.name
188
- atoms = read(xyz_file)
189
- os.unlink(xyz_file)
190
- else:
191
- atoms = read(input_file)
192
-
193
- atoms.info = {"charge": int(charge), "spin": int(spin_multiplicity)}
194
- atoms.calc = calc
195
-
196
- # Create trajectory file
197
- traj_path = tempfile.NamedTemporaryFile(suffix='.traj', delete=False).name
198
-
199
- # Optimize
200
- opt = LBFGS(atoms, trajectory=traj_path)
201
- opt.run(fmax=fmax, steps=optimization_steps)
202
-
203
- # Generate log
204
- log_content = f"""OrbMol Geometry Optimization
205
- ===========================
206
- System: {len(atoms)} atoms
207
- Max Steps: {optimization_steps}
208
- Force Convergence: {fmax} eV/Å
209
- Charge: {charge}
210
- Spin Multiplicity: {spin_multiplicity}
211
-
212
- Final Energy: {atoms.get_potential_energy():.6f} eV
213
- Max Force: {np.max(np.linalg.norm(atoms.get_forces(), axis=1)):.6f} eV/Å
214
- Optimization completed!
215
- """
216
-
217
- script_content = f"""# OrbMol Geometry Optimization Script
218
- import ase.io
219
- from ase.optimize import LBFGS
220
- from orb_models.forcefield import pretrained
221
- from orb_models.forcefield.calculator import ORBCalculator
222
-
223
- atoms = ase.io.read('input_structure.xyz')
224
- atoms.info = {{"charge": {charge}, "spin": {spin_multiplicity}}}
225
-
226
- orbff = pretrained.orb_v3_conservative_inf_omat(device="cpu")
227
- atoms.calc = ORBCalculator(orbff, device="cpu")
228
-
229
- opt = LBFGS(atoms, trajectory="optimization.traj")
230
- opt.run(fmax={fmax}, steps={optimization_steps})
231
- """
232
-
233
- return traj_path, log_content, script_content
234
-
235
- except Exception as e:
236
- return None, f"❌ Error during optimization: {str(e)}", ""
237
-
238
- def predict_single_point(xyz_content, charge=0, spin_multiplicity=1):
239
- """Single point energy and forces calculation"""
240
  try:
 
241
  calc = load_orbmol_model()
242
  if calc is None:
243
  return "❌ Error: Could not load OrbMol model", ""
244
-
245
  if not xyz_content.strip():
246
  return "❌ Error: Please enter XYZ coordinates", ""
247
-
 
248
  with tempfile.NamedTemporaryFile(mode='w', suffix='.xyz', delete=False) as f:
249
  f.write(xyz_content)
250
  xyz_file = f.name
251
-
 
252
  atoms = read(xyz_file)
253
- atoms.info = {"charge": int(charge), "spin": int(spin_multiplicity)}
 
 
 
 
 
 
 
254
  atoms.calc = calc
255
-
256
- energy = atoms.get_potential_energy()
257
- forces = atoms.get_forces()
258
-
259
- result = f"""🔋 **Total Energy**: {energy:.6f} eV
 
 
 
260
 
261
  ⚡ **Atomic Forces**:
262
  """
 
263
  for i, force in enumerate(forces):
264
  result += f"Atom {i+1}: [{force[0]:.4f}, {force[1]:.4f}, {force[2]:.4f}] eV/Å\n"
265
-
 
266
  max_force = np.max(np.linalg.norm(forces, axis=1))
267
  result += f"\n📊 **Max Force**: {max_force:.4f} eV/Å"
268
-
 
269
  os.unlink(xyz_file)
 
270
  return result, "✅ Calculation completed with OrbMol"
271
-
272
  except Exception as e:
273
  return f"❌ Error during calculation: {str(e)}", "Error"
274
 
275
  # Predefined examples
276
- examples_md = [
277
- ["2\nHydrogen molecule\nH 0.0 0.0 0.0\nH 0.0 0.0 0.74", 100, 20, 1.0, 300.0, "NVE", 0, 1, "Simple H2 molecule dynamics showing thermal vibrations"],
278
- ["3\nWater molecule\nO 0.0 0.0 0.0\nH 0.7571 0.0 0.5864\nH -0.7571 0.0 0.5864", 200, 20, 1.0, 300.0, "NVE", 0, 1, "Water molecule thermal motion and vibrations"],
279
- ]
280
-
281
- examples_sp = [
282
  ["""2
283
  Hydrogen molecule
284
  H 0.0 0.0 0.0
285
  H 0.0 0.0 0.74""", 0, 1],
286
-
287
  ["""3
288
- Water molecule
289
  O 0.0000 0.0000 0.0000
290
  H 0.7571 0.0000 0.5864
291
  H -0.7571 0.0000 0.5864""", 0, 1],
292
-
293
- ["""5
294
  Methane
295
  C 0.0000 0.0000 0.0000
296
  H 1.0890 0.0000 0.0000
@@ -299,223 +106,113 @@ H -0.3630 -0.5133 0.8887
299
  H -0.3630 -0.5133 -0.8887""", 0, 1]
300
  ]
301
 
302
- # Main Gradio interface
303
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
304
-
305
  with gr.Row():
306
  with gr.Column(scale=2):
307
  with gr.Column(variant="panel"):
308
  gr.Markdown("# OrbMol Demo - Quantum-Accurate Molecular Predictions")
309
-
310
- with gr.Tab("1. OrbMol Intro"):
311
- gr.Markdown("""
312
- **OrbMol** is a neural network potential trained on the **OMol25** dataset (100M+ high-accuracy DFT calculations).
313
-
314
- Predicts **energies** and **forces** with quantum accuracy, optimized for:
315
- * 🧬 Biomolecules
316
- * ⚗️ Metal complexes
317
- * 🔋 Electrolytes
318
-
319
- Try the examples below to see OrbMol in action!
320
- """)
321
-
322
- # Quick examples for MD
323
- gr.Examples(
324
- examples=examples_md,
325
- inputs=[
326
- gr.Textbox(visible=False, value=""), # Will be set by interface
327
- gr.Slider(visible=False),
328
- gr.Slider(visible=False),
329
- gr.Slider(visible=False),
330
- gr.Slider(visible=False),
331
- gr.Radio(visible=False),
332
- gr.Slider(visible=False),
333
- gr.Slider(visible=False),
334
- gr.Textbox(visible=False)
335
- ],
336
- outputs=[
337
- gr.File(visible=False),
338
- gr.Code(visible=False),
339
- gr.Code(visible=False),
340
- gr.Markdown(visible=False)
341
- ],
342
- fn=run_md_simulation,
343
- cache_examples=True,
344
- label="Try molecular dynamics examples!"
345
- )
346
-
347
- with gr.Tab("2. Single Point Calculations"):
348
- gr.Markdown("Calculate energy and forces for a single molecular geometry:")
349
-
350
- # Single point interface
351
- with gr.Row():
352
- with gr.Column():
353
- xyz_input_sp = gr.Textbox(
354
- label="XYZ Coordinates",
355
- placeholder="""3
356
- Water molecule
357
- O 0.0 0.0 0.0
358
- H 0.76 0.0 0.59
359
- H -0.76 0.0 0.59""",
360
- lines=8
361
- )
362
-
363
- with gr.Row():
364
- charge_sp = gr.Slider(value=0, label="Total Charge", minimum=-10, maximum=10, step=1)
365
- spin_sp = gr.Slider(value=1, label="Spin Multiplicity", minimum=1, maximum=11, step=1)
366
-
367
- predict_btn_sp = gr.Button("Calculate Energy & Forces", variant="primary")
368
-
369
- with gr.Column():
370
- results_sp = gr.Textbox(label="Results", lines=12, interactive=False)
371
- status_sp = gr.Textbox(label="Status", max_lines=1, interactive=False)
372
-
373
- gr.Examples(
374
- examples=examples_sp,
375
- inputs=[xyz_input_sp, charge_sp, spin_sp],
376
- label="Single point examples"
377
- )
378
-
379
- with gr.Tab("3. Molecular Dynamics"):
380
- gr.Markdown("Run molecular dynamics simulations with OrbMol:")
381
-
382
- xyz_input_md = gr.Textbox(
383
- label="XYZ Coordinates",
384
- placeholder="""3
385
- Water molecule
386
- O 0.0 0.0 0.0
387
- H 0.76 0.0 0.59
388
- H -0.76 0.0 0.59""",
389
- lines=8
390
- )
391
-
392
- with gr.Row():
393
- md_steps = gr.Slider(minimum=10, maximum=500, value=100, label="MD Steps")
394
- prerelax_steps = gr.Slider(minimum=0, maximum=100, value=20, label="Pre-Relaxation Steps")
395
-
396
- with gr.Row():
397
- temperature_k = gr.Slider(minimum=0, maximum=1500, value=300, label="Temperature [K]")
398
- md_timestep = gr.Slider(minimum=0.1, maximum=5.0, value=1.0, label="Timestep [fs]")
399
-
400
- md_ensemble = gr.Radio(choices=["NVE", "NVT"], value="NVE", label="Ensemble")
401
-
402
- with gr.Row():
403
- charge_md = gr.Slider(value=0, label="Total Charge", minimum=-10, maximum=10, step=1)
404
- spin_md = gr.Slider(value=1, label="Spin Multiplicity", minimum=1, maximum=11, step=1)
405
-
406
- md_button = gr.Button("Run MD Simulation", variant="primary")
407
-
408
- with gr.Tab("4. Geometry Optimization"):
409
- gr.Markdown("Optimize molecular geometries with OrbMol:")
410
-
411
- xyz_input_opt = gr.Textbox(
412
  label="XYZ Coordinates",
413
  placeholder="""3
414
  Water molecule
415
- O 0.0 0.0 0.0
416
- H 0.76 0.0 0.59
417
- H -0.76 0.0 0.59""",
418
- lines=8
 
419
  )
420
-
421
- with gr.Row():
422
- opt_steps = gr.Slider(minimum=1, maximum=500, value=300, label="Max Steps")
423
- fmax = gr.Slider(minimum=0.001, maximum=0.5, value=0.05, label="Force Tolerance [eV/Å]")
424
-
425
  with gr.Row():
426
- charge_opt = gr.Slider(value=0, label="Total Charge", minimum=-10, maximum=10, step=1)
427
- spin_opt = gr.Slider(value=1, label="Spin Multiplicity", minimum=1, maximum=11, step=1)
428
-
429
- opt_button = gr.Button("Run Optimization", variant="primary")
430
-
431
- # Results panel
 
 
 
432
  with gr.Column(variant="panel", elem_id="results", min_width=500):
433
- gr.Markdown("## OrbMol Simulation Results")
434
-
435
- with gr.Tab("Visualization"):
436
- if HAS_3D:
437
- output_structure = Molecule3D(
438
- label="Simulation Visualization",
439
- reps=DEFAULT_MOLECULAR_REPRESENTATIONS,
440
- config=DEFAULT_MOLECULAR_SETTINGS,
441
- height=500,
442
- interactive=False,
443
- )
444
- else:
445
- gr.Markdown("3D visualization not available. Install gradio-molecule3d for 3D viewing.")
446
-
447
- output_traj = gr.File(label="Trajectory File", interactive=False)
448
-
449
- explanation = gr.Markdown("Run a simulation to see results here!")
450
-
451
- with gr.Tab("Log"):
452
- output_text = gr.Code(lines=20, max_lines=30, label="Simulation Log", interactive=False)
453
-
454
- with gr.Tab("Script"):
455
- reproduction_script = gr.Code(
456
- interactive=False,
457
- max_lines=30,
458
- language="python",
459
- label="Reproduction Script",
460
- )
461
-
462
- # Sidebar
 
 
 
 
 
463
  with gr.Sidebar(open=True):
464
  gr.Markdown("## Learn more about OrbMol")
465
-
466
  with gr.Accordion("What is OrbMol?", open=False):
467
  gr.Markdown("""
468
- * OrbMol is a neural network potential for molecular property prediction
469
- * Built on Orb-v3 architecture, trained on OMol25 dataset (100M+ DFT calculations)
470
- * Supports charge and spin multiplicity for accurate molecular modeling
471
  * Optimized for biomolecules, metal complexes, and electrolytes
472
-
 
473
  [Read more about OrbMol](https://orbitalmaterials.com/posts/orbmol-extending-orb-to-molecular-systems)
474
  """)
475
-
476
  with gr.Accordion("Model Disclaimers", open=False):
477
  gr.Markdown("""
478
- * OrbMol has limitations and may not work perfectly for all systems
479
  * Always validate results for your specific use case
480
- * Consider the limitations of the training data and methodology
481
  """)
482
-
483
  with gr.Accordion("Open source packages", open=False):
484
  gr.Markdown("""
485
- * Model: [orbital-materials/orb-models](https://github.com/orbital-materials/orb-models)
486
- * Uses ASE, Gradio, and other open source packages
487
- * Licensed under Apache 2.0
488
  """)
489
-
490
- # Connect buttons to functions
491
- predict_btn_sp.click(
492
- predict_single_point,
493
- inputs=[xyz_input_sp, charge_sp, spin_sp],
494
- outputs=[results_sp, status_sp]
495
- )
496
-
497
- md_button.click(
498
- run_md_simulation,
499
- inputs=[xyz_input_md, md_steps, prerelax_steps, md_timestep, temperature_k, md_ensemble, charge_md, spin_md],
500
- outputs=[output_traj, output_text, reproduction_script, explanation]
501
- )
502
-
503
- opt_button.click(
504
- run_optimization,
505
- inputs=[xyz_input_opt, opt_steps, fmax, charge_opt, spin_opt],
506
- outputs=[output_traj, output_text, reproduction_script]
507
- )
508
-
509
- # Update 3D visualization when trajectory changes
510
- if HAS_3D:
511
- output_traj.change(
512
- lambda x: x,
513
- inputs=[output_traj],
514
- outputs=[output_structure]
515
- )
516
 
517
  # Load model on startup
518
- print("🚀 Loading OrbMol model...")
519
  load_orbmol_model()
520
 
521
  if __name__ == "__main__":
@@ -523,4 +220,4 @@ if __name__ == "__main__":
523
  server_name="0.0.0.0",
524
  server_port=7860,
525
  show_error=True
526
- )
 
1
  import gradio as gr
2
  import torch
3
  import numpy as np
4
+ from ase import Atoms
5
+ from ase.io import read
6
  import tempfile
7
  import os
 
 
 
 
 
 
 
 
8
  from orb_models.forcefield import pretrained
9
  from orb_models.forcefield.calculator import ORBCalculator
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  # Global variable for the model
12
  model_calc = None
13
 
 
18
  try:
19
  print("Loading OrbMol model...")
20
  orbff = pretrained.orb_v3_conservative_inf_omat(
21
+ device="cpu",
22
+ precision="float32" # más seguro que "float32-high" según la versión
23
  )
24
  model_calc = ORBCalculator(orbff, device="cpu")
25
  print("✅ OrbMol model loaded successfully")
 
28
  model_calc = None
29
  return model_calc
30
 
31
+ def predict_molecule(xyz_content, charge=0, spin_multiplicity=1):
32
+ """
33
+ Main function: XYZ → OrbMol → Results
34
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  try:
36
+ # Load model
37
  calc = load_orbmol_model()
38
  if calc is None:
39
  return "❌ Error: Could not load OrbMol model", ""
40
+
41
  if not xyz_content.strip():
42
  return "❌ Error: Please enter XYZ coordinates", ""
43
+
44
+ # Create temporary file with XYZ
45
  with tempfile.NamedTemporaryFile(mode='w', suffix='.xyz', delete=False) as f:
46
  f.write(xyz_content)
47
  xyz_file = f.name
48
+
49
+ # Read molecular structure
50
  atoms = read(xyz_file)
51
+
52
+ # Configure charge and spin (IMPORTANT for OrbMol!)
53
+ atoms.info = {
54
+ "charge": int(charge),
55
+ "spin": int(spin_multiplicity)
56
+ }
57
+
58
+ # Assign OrbMol calculator
59
  atoms.calc = calc
60
+
61
+ # Make the prediction!
62
+ energy = atoms.get_potential_energy() # In eV
63
+ forces = atoms.get_forces() # In eV/Å
64
+
65
+ # Format results nicely
66
+ result = f"""
67
+ 🔋 **Total Energy**: {energy:.6f} eV
68
 
69
  ⚡ **Atomic Forces**:
70
  """
71
+
72
  for i, force in enumerate(forces):
73
  result += f"Atom {i+1}: [{force[0]:.4f}, {force[1]:.4f}, {force[2]:.4f}] eV/Å\n"
74
+
75
+ # Additional statistics
76
  max_force = np.max(np.linalg.norm(forces, axis=1))
77
  result += f"\n📊 **Max Force**: {max_force:.4f} eV/Å"
78
+
79
+ # Clean up temporary file
80
  os.unlink(xyz_file)
81
+
82
  return result, "✅ Calculation completed with OrbMol"
83
+
84
  except Exception as e:
85
  return f"❌ Error during calculation: {str(e)}", "Error"
86
 
87
  # Predefined examples
88
+ examples = [
 
 
 
 
 
89
  ["""2
90
  Hydrogen molecule
91
  H 0.0 0.0 0.0
92
  H 0.0 0.0 0.74""", 0, 1],
93
+
94
  ["""3
95
+ Water molecule
96
  O 0.0000 0.0000 0.0000
97
  H 0.7571 0.0000 0.5864
98
  H -0.7571 0.0000 0.5864""", 0, 1],
99
+
100
+ ["""4
101
  Methane
102
  C 0.0000 0.0000 0.0000
103
  H 1.0890 0.0000 0.0000
 
106
  H -0.3630 -0.5133 -0.8887""", 0, 1]
107
  ]
108
 
109
+ # Gradio interface - using FAIR Chem UMA style
110
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
111
+
112
  with gr.Row():
113
  with gr.Column(scale=2):
114
  with gr.Column(variant="panel"):
115
  gr.Markdown("# OrbMol Demo - Quantum-Accurate Molecular Predictions")
116
+
117
+ gr.Markdown("""
118
+ **OrbMol** is a neural network potential trained on the **OMol25** dataset (100M+ high-accuracy DFT calculations).
119
+
120
+ Predicts **energies** and **forces** with quantum accuracy, optimized for:
121
+ * 🧬 Biomolecules
122
+ * ⚗️ Metal complexes
123
+ * 🔋 Electrolytes
124
+ """)
125
+
126
+ gr.Markdown("## Simulation inputs")
127
+
128
+ with gr.Column(variant="panel"):
129
+ gr.Markdown("### Input molecular structure")
130
+
131
+ xyz_input = gr.Textbox(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  label="XYZ Coordinates",
133
  placeholder="""3
134
  Water molecule
135
+ O 0.0000 0.0000 0.0000
136
+ H 0.7571 0.0000 0.5864
137
+ H -0.7571 0.0000 0.5864""",
138
+ lines=12,
139
+ info="Paste XYZ coordinates of your molecule here"
140
  )
141
+
142
+ gr.Markdown("OMol-specific settings for total charge and spin multiplicity")
 
 
 
143
  with gr.Row():
144
+ charge_input = gr.Slider(
145
+ value=0, label="Total Charge", minimum=-10, maximum=10, step=1
146
+ )
147
+ spin_input = gr.Slider(
148
+ value=1, maximum=11, minimum=1, step=1, label="Spin Multiplicity"
149
+ )
150
+
151
+ predict_btn = gr.Button("Run OrbMol Prediction", variant="primary", size="lg")
152
+
153
  with gr.Column(variant="panel", elem_id="results", min_width=500):
154
+ gr.Markdown("## OrbMol Prediction Results")
155
+
156
+ results_output = gr.Textbox(
157
+ label="Energy & Forces",
158
+ lines=15,
159
+ interactive=False,
160
+ info="OrbMol energy and force predictions"
161
+ )
162
+
163
+ status_output = gr.Textbox(
164
+ label="Status",
165
+ interactive=False,
166
+ max_lines=1
167
+ )
168
+
169
+ # Examples section
170
+ gr.Markdown("### 🧪 Try These Examples")
171
+ gr.Examples(
172
+ examples=examples,
173
+ inputs=[
174
+ xyz_input,
175
+ gr.Slider(visible=False, minimum=-10, maximum=10), # charge
176
+ gr.Slider(visible=False, minimum=1, maximum=11) # spin
177
+ ],
178
+ label="Click any example to load it"
179
+ )
180
+
181
+ # Connect button to function
182
+ predict_btn.click(
183
+ predict_molecule,
184
+ inputs=[xyz_input, charge_input, spin_input],
185
+ outputs=[results_output, status_output]
186
+ )
187
+
188
+ # Footer info - matching FAIR Chem UMA style
189
  with gr.Sidebar(open=True):
190
  gr.Markdown("## Learn more about OrbMol")
 
191
  with gr.Accordion("What is OrbMol?", open=False):
192
  gr.Markdown("""
193
+ * OrbMol is a neural network potential for molecular property prediction with quantum-level accuracy
194
+ * Built on the Orb-v3 architecture and trained on OMol25 dataset (100M+ DFT calculations)
 
195
  * Optimized for biomolecules, metal complexes, and electrolytes
196
+ * Supports configurable charge and spin multiplicity
197
+
198
  [Read more about OrbMol](https://orbitalmaterials.com/posts/orbmol-extending-orb-to-molecular-systems)
199
  """)
200
+
201
  with gr.Accordion("Model Disclaimers", open=False):
202
  gr.Markdown("""
203
+ * While OrbMol represents significant progress in molecular ML potentials, the model has limitations
204
  * Always validate results for your specific use case
205
+ * Consider the limitations of the ωB97M-V/def2-TZVPD level of theory used in training
206
  """)
207
+
208
  with gr.Accordion("Open source packages", open=False):
209
  gr.Markdown("""
210
+ * Model code available at [orbital-materials/orb-models](https://github.com/orbital-materials/orb-models)
211
+ * This demo uses ASE, Gradio, and other open source packages
 
212
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
  # Load model on startup
215
+ print("🚀 Starting OrbMol model loading...")
216
  load_orbmol_model()
217
 
218
  if __name__ == "__main__":
 
220
  server_name="0.0.0.0",
221
  server_port=7860,
222
  show_error=True
223
+ )