annabossler commited on
Commit
6d4df16
·
verified ·
1 Parent(s): 956ff48

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +234 -40
app.py CHANGED
@@ -9,6 +9,7 @@ from gradio_molecule3d import Molecule3D
9
  from simulation_scripts_orbmol import load_orbmol_model, run_md_simulation, run_relaxation_simulation
10
  import hashlib
11
 
 
12
  DEFAULT_MOLECULAR_REPRESENTATIONS = [
13
  {
14
  "model": 0,
@@ -38,36 +39,50 @@ DEFAULT_MOLECULAR_SETTINGS = {
38
  "disableFog": False,
39
  }
40
 
 
41
  def convert_to_pdb_for_viewer(file_path):
 
42
  if not file_path or not os.path.exists(file_path):
43
  return None
 
44
  try:
45
  atoms = read(file_path)
 
46
  cache_dir = os.path.join(tempfile.gettempdir(), "gradio")
47
  os.makedirs(cache_dir, exist_ok=True)
 
48
  pdb_path = os.path.join(cache_dir, f"mol_{hashlib.md5(file_path.encode()).hexdigest()[:12]}.pdb")
 
49
  write(pdb_path, atoms, format="proteindatabank")
 
50
  return pdb_path
51
  except Exception as e:
52
  print(f"Error converting to PDB: {e}")
53
  return None
54
 
 
55
  def predict_molecule(structure_file, task_name, charge=0, spin_multiplicity=1):
 
56
  try:
57
  calc = load_orbmol_model(task_name)
58
  if not structure_file:
59
  return "Error: Please upload a structure file", "Error", None
 
60
  file_path = structure_file
61
  if not os.path.exists(file_path):
62
  return f"Error: File not found: {file_path}", "Error", None
63
  if os.path.getsize(file_path) == 0:
64
  return f"Error: Empty file: {file_path}", "Error", None
 
65
  atoms = read(file_path)
 
66
  if task_name in ["OMol", "OMol-Direct"]:
67
  atoms.info = {"charge": int(charge), "spin": int(spin_multiplicity)}
 
68
  atoms.calc = calc
69
  energy = atoms.get_potential_energy()
70
  forces = atoms.get_forces()
 
71
  lines = [
72
  f"Model: {task_name}",
73
  f"Total Energy: {energy:.6f} eV",
@@ -78,17 +93,22 @@ def predict_molecule(structure_file, task_name, charge=0, spin_multiplicity=1):
78
  lines.append(f"Atom {i+1}: [{fc[0]:.4f}, {fc[1]:.4f}, {fc[2]:.4f}] eV/Å")
79
  max_force = float(np.max(np.linalg.norm(forces, axis=1)))
80
  lines += ["", f"Max Force: {max_force:.4f} eV/Å"]
 
81
  pdb_file = convert_to_pdb_for_viewer(file_path)
 
82
  return "\n".join(lines), f"Calculation completed with {task_name}", pdb_file
 
83
  except Exception as e:
84
  import traceback
85
  traceback.print_exc()
86
  return f"Error during calculation: {e}", "Error", None
87
 
 
88
  def md_wrapper(structure_file, task_name, charge, spin, steps, tempK, timestep_fs, ensemble):
89
  try:
90
  if not structure_file:
91
  return ("Error: Please upload a structure file", None, "", "", "", None)
 
92
  traj_path, log_text, script_text, explanation = run_md_simulation(
93
  structure_file,
94
  int(steps),
@@ -101,8 +121,11 @@ def md_wrapper(structure_file, task_name, charge, spin, steps, tempK, timestep_f
101
  int(spin),
102
  )
103
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
 
104
  pdb_file = convert_to_pdb_for_viewer(traj_path)
 
105
  return (status, traj_path, log_text, script_text, explanation, pdb_file)
 
106
  except Exception as e:
107
  import traceback
108
  traceback.print_exc()
@@ -112,6 +135,7 @@ def relax_wrapper(structure_file, task_name, steps, fmax, charge, spin, relax_ce
112
  try:
113
  if not structure_file:
114
  return ("Error: Please upload a structure file", None, "", "", "", None)
 
115
  traj_path, log_text, script_text, explanation = run_relaxation_simulation(
116
  structure_file,
117
  int(steps),
@@ -122,59 +146,178 @@ def relax_wrapper(structure_file, task_name, steps, fmax, charge, spin, relax_ce
122
  bool(relax_cell),
123
  )
124
  status = f"Relaxation finished (<={int(steps)} steps, fmax={float(fmax)} eV/Å)"
 
125
  pdb_file = convert_to_pdb_for_viewer(traj_path)
 
126
  return (status, traj_path, log_text, script_text, explanation, pdb_file)
 
127
  except Exception as e:
128
  import traceback
129
  traceback.print_exc()
130
  return (f"Error: {e}", None, "", "", "", None)
131
 
 
132
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
133
  with gr.Tabs():
 
134
  with gr.Tab("Home"):
135
- gr.Image("logo_color_text.png", show_share_button=False, show_download_button=False, show_label=False, show_fullscreen_button=False)
136
- gr.Markdown("# OrbMol Quantum-Accurate Molecular Predictions")
137
- gr.Markdown("Welcome to the OrbMol demo! Use the tabs above to access different functionalities:")
138
- gr.Markdown("1. **Single Point Energy**: Calculate energies and forces for a given molecular structure.")
139
- gr.Markdown("2. **Molecular Dynamics**: Run MD simulations using OrbMol-trained potentials.")
140
- gr.Markdown("3. **Relaxation / Optimization**: Optimize molecular structures to their minimum-energy configurations.")
141
- gr.Markdown("Supported file formats: `.xyz`, `.pdb`, `.cif`, `.traj`, `.mol`, `.sdf`.")
142
- gr.Markdown("## Pretrained Models")
143
- gr.Markdown("**OMol** and **OMol-Direct**")
144
- gr.Markdown("- **Training dataset**: OMol25 (>100M calculations on small molecules, biomolecules, metal complexes, and electrolytes).")
145
- gr.Markdown("- **Level of theory**: wB97M-V/def2-TZVPD with non-local dispersion; solvation treated explicitly.")
146
- gr.Markdown("- **Inputs**: total charge & spin multiplicity.")
147
- gr.Markdown("- **Applications**: biology, organic chemistry, protein folding, small-molecule drugs, organic liquids, homogeneous catalysis.")
148
- gr.Markdown("- **Caveats**: trained only on aperiodic systems → periodic/inorganic cases may not work well.")
149
- gr.Markdown("- **Difference**: OMol enforces energy–force consistency; OMol-Direct relaxes this for efficiency.")
150
- gr.Markdown("**OMat**")
151
- gr.Markdown("- **Training dataset**: OMat24 (>100M inorganic calculations, from Materials Project, Alexandria, and far-from-equilibrium samples).")
152
- gr.Markdown("- **Level of theory**: PBE/PBE+U with Materials Project settings; VASP 54 pseudopotentials; no dispersion.")
153
- gr.Markdown("- **Inputs**: No support for spin and charge. Spin polarization included but magnetic state cannot be selected.")
154
- gr.Markdown("- **Applications**: inorganic discovery, photovoltaics, alloys, superconductors, electronic/optical materials.")
155
- gr.Markdown("- **Caveats**: magnetic effects may be incompletely captured.")
156
- gr.Markdown("## Technical Foundation")
157
- gr.Markdown("All models are based on the **Orb-v3 architecture**, the latest generation of Orb universal interatomic potentials, combining transferability with quantum-level accuracy.")
158
- gr.Markdown("## Resources & Support")
159
- gr.Markdown("- [Orb-v3 paper](https://arxiv.org/abs/2504.06231)")
160
- gr.Markdown("- [Orb-Models GitHub repository](https://github.com/orbital-materials/orb-models)")
161
- gr.Markdown("- For issues/questions, please open a GitHub issue or contact the developers.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  with gr.Tab("Single Point Energy"):
164
  with gr.Row():
165
  with gr.Column(scale=2):
166
  gr.Markdown("# OrbMol — Quantum-Accurate Molecular Predictions")
167
  gr.Markdown("**Supported formats:** .xyz, .pdb, .cif, .traj, .mol, .sdf")
168
- xyz_input = gr.File(label="Upload Structure File", file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"], file_count="single")
169
- task_name_spe = gr.Radio(["OMol", "OMat", "OMol-Direct"], value="OMol", label="Model Type")
 
 
 
 
 
 
 
 
 
170
  with gr.Row():
171
  charge_input = gr.Slider(-10, 10, 0, step=1, label="Charge")
172
  spin_input = gr.Slider(1, 11, 1, step=1, label="Spin Multiplicity")
 
173
  run_spe = gr.Button("Run OrbMol Prediction", variant="primary")
 
174
  with gr.Column(variant="panel", min_width=500):
175
  spe_out = gr.Textbox(label="Energy & Forces", lines=15, interactive=False)
176
  spe_status = gr.Textbox(label="Status", interactive=False)
177
- spe_viewer = Molecule3D(label="Input Structure Viewer", reps=DEFAULT_MOLECULAR_REPRESENTATIONS, config=DEFAULT_MOLECULAR_SETTINGS)
 
 
 
 
 
 
178
  task_name_spe.change(
179
  lambda x: (
180
  gr.update(visible=x in ["OMol", "OMol-Direct"]),
@@ -183,14 +326,29 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
183
  [task_name_spe],
184
  [charge_input, spin_input]
185
  )
186
- run_spe.click(predict_molecule, [xyz_input, task_name_spe, charge_input, spin_input], [spe_out, spe_status, spe_viewer])
 
 
 
 
 
187
 
 
188
  with gr.Tab("Molecular Dynamics"):
189
  with gr.Row():
190
  with gr.Column(scale=2):
191
  gr.Markdown("## Molecular Dynamics Simulation")
192
- xyz_md = gr.File(label="Upload Structure File", file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"], file_count="single")
193
- task_name_md = gr.Radio(["OMol", "OMat", "OMol-Direct"], value="OMol", label="Model Type")
 
 
 
 
 
 
 
 
 
194
  with gr.Row():
195
  charge_md = gr.Slider(-10, 10, 0, step=1, label="Charge")
196
  spin_md = gr.Slider(1, 11, 1, step=1, label="Spin Multiplicity")
@@ -201,13 +359,21 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
201
  timestep_md = gr.Slider(0.1, 5.0, 1.0, step=0.1, label="Timestep (fs)")
202
  ensemble_md = gr.Radio(["NVE", "NVT"], value="NVE", label="Ensemble")
203
  run_md_btn = gr.Button("Run MD Simulation", variant="primary")
 
204
  with gr.Column(variant="panel", min_width=520):
205
  md_status = gr.Textbox(label="MD Status", interactive=False)
206
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
207
- md_viewer = Molecule3D(label="MD Result Viewer", reps=DEFAULT_MOLECULAR_REPRESENTATIONS, config=DEFAULT_MOLECULAR_SETTINGS)
 
 
 
 
 
 
208
  md_log = gr.Textbox(label="Log", interactive=False, lines=15)
209
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20)
210
  md_explain = gr.Markdown()
 
211
  task_name_md.change(
212
  lambda x: (
213
  gr.update(visible=x in ["OMol", "OMol-Direct"]),
@@ -216,14 +382,29 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
216
  [task_name_md],
217
  [charge_md, spin_md]
218
  )
219
- run_md_btn.click(md_wrapper, [xyz_md, task_name_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md], [md_status, md_traj, md_log, md_script, md_explain, md_viewer])
 
 
 
 
 
220
 
 
221
  with gr.Tab("Relaxation / Optimization"):
222
  with gr.Row():
223
  with gr.Column(scale=2):
224
  gr.Markdown("## Structure Relaxation/Optimization")
225
- xyz_rlx = gr.File(label="Upload Structure File", file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"], file_count="single")
226
- task_name_rlx = gr.Radio(["OMol", "OMat", "OMol-Direct"], value="OMol", label="Model Type")
 
 
 
 
 
 
 
 
 
227
  with gr.Row():
228
  steps_rlx = gr.Slider(1, 2000, 300, step=1, label="Max Steps")
229
  fmax_rlx = gr.Slider(0.001, 0.5, 0.05, step=0.001, label="Fmax (eV/Å)")
@@ -232,13 +413,21 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
232
  spin_rlx = gr.Slider(1, 11, 1, step=1, label="Spin")
233
  relax_cell = gr.Checkbox(False, label="Relax Unit Cell")
234
  run_rlx_btn = gr.Button("Run Optimization", variant="primary")
 
235
  with gr.Column(variant="panel", min_width=520):
236
  rlx_status = gr.Textbox(label="Status", interactive=False)
237
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
238
- rlx_viewer = Molecule3D(label="Optimized Structure Viewer", reps=DEFAULT_MOLECULAR_REPRESENTATIONS, config=DEFAULT_MOLECULAR_SETTINGS)
 
 
 
 
 
 
239
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15)
240
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20)
241
  rlx_explain = gr.Markdown()
 
242
  task_name_rlx.change(
243
  lambda x: (
244
  gr.update(visible=x in ["OMol", "OMol-Direct"]),
@@ -247,7 +436,12 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
247
  [task_name_rlx],
248
  [charge_rlx, spin_rlx]
249
  )
250
- run_rlx_btn.click(relax_wrapper, [xyz_rlx, task_name_rlx, steps_rlx, fmax_rlx, charge_rlx, spin_rlx, relax_cell], [rlx_status, rlx_traj, rlx_log, rlx_script, rlx_explain, rlx_viewer])
 
 
 
 
 
251
 
252
  if __name__ == "__main__":
253
- demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)
 
9
  from simulation_scripts_orbmol import load_orbmol_model, run_md_simulation, run_relaxation_simulation
10
  import hashlib
11
 
12
+ # ==== Configuración Molecule3D ====
13
  DEFAULT_MOLECULAR_REPRESENTATIONS = [
14
  {
15
  "model": 0,
 
39
  "disableFog": False,
40
  }
41
 
42
+ # ==== Conversión a PDB para Molecule3D ====
43
  def convert_to_pdb_for_viewer(file_path):
44
+ """Convierte cualquier archivo a PDB para Molecule3D"""
45
  if not file_path or not os.path.exists(file_path):
46
  return None
47
+
48
  try:
49
  atoms = read(file_path)
50
+
51
  cache_dir = os.path.join(tempfile.gettempdir(), "gradio")
52
  os.makedirs(cache_dir, exist_ok=True)
53
+
54
  pdb_path = os.path.join(cache_dir, f"mol_{hashlib.md5(file_path.encode()).hexdigest()[:12]}.pdb")
55
+
56
  write(pdb_path, atoms, format="proteindatabank")
57
+
58
  return pdb_path
59
  except Exception as e:
60
  print(f"Error converting to PDB: {e}")
61
  return None
62
 
63
+ # ==== OrbMol SPE ====
64
  def predict_molecule(structure_file, task_name, charge=0, spin_multiplicity=1):
65
+ """Single Point Energy + fuerzas (OrbMol)"""
66
  try:
67
  calc = load_orbmol_model(task_name)
68
  if not structure_file:
69
  return "Error: Please upload a structure file", "Error", None
70
+
71
  file_path = structure_file
72
  if not os.path.exists(file_path):
73
  return f"Error: File not found: {file_path}", "Error", None
74
  if os.path.getsize(file_path) == 0:
75
  return f"Error: Empty file: {file_path}", "Error", None
76
+
77
  atoms = read(file_path)
78
+
79
  if task_name in ["OMol", "OMol-Direct"]:
80
  atoms.info = {"charge": int(charge), "spin": int(spin_multiplicity)}
81
+
82
  atoms.calc = calc
83
  energy = atoms.get_potential_energy()
84
  forces = atoms.get_forces()
85
+
86
  lines = [
87
  f"Model: {task_name}",
88
  f"Total Energy: {energy:.6f} eV",
 
93
  lines.append(f"Atom {i+1}: [{fc[0]:.4f}, {fc[1]:.4f}, {fc[2]:.4f}] eV/Å")
94
  max_force = float(np.max(np.linalg.norm(forces, axis=1)))
95
  lines += ["", f"Max Force: {max_force:.4f} eV/Å"]
96
+
97
  pdb_file = convert_to_pdb_for_viewer(file_path)
98
+
99
  return "\n".join(lines), f"Calculation completed with {task_name}", pdb_file
100
+
101
  except Exception as e:
102
  import traceback
103
  traceback.print_exc()
104
  return f"Error during calculation: {e}", "Error", None
105
 
106
+ # ==== Wrappers MD y Relax ====
107
  def md_wrapper(structure_file, task_name, charge, spin, steps, tempK, timestep_fs, ensemble):
108
  try:
109
  if not structure_file:
110
  return ("Error: Please upload a structure file", None, "", "", "", None)
111
+
112
  traj_path, log_text, script_text, explanation = run_md_simulation(
113
  structure_file,
114
  int(steps),
 
121
  int(spin),
122
  )
123
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
124
+
125
  pdb_file = convert_to_pdb_for_viewer(traj_path)
126
+
127
  return (status, traj_path, log_text, script_text, explanation, pdb_file)
128
+
129
  except Exception as e:
130
  import traceback
131
  traceback.print_exc()
 
135
  try:
136
  if not structure_file:
137
  return ("Error: Please upload a structure file", None, "", "", "", None)
138
+
139
  traj_path, log_text, script_text, explanation = run_relaxation_simulation(
140
  structure_file,
141
  int(steps),
 
146
  bool(relax_cell),
147
  )
148
  status = f"Relaxation finished (<={int(steps)} steps, fmax={float(fmax)} eV/Å)"
149
+
150
  pdb_file = convert_to_pdb_for_viewer(traj_path)
151
+
152
  return (status, traj_path, log_text, script_text, explanation, pdb_file)
153
+
154
  except Exception as e:
155
  import traceback
156
  traceback.print_exc()
157
  return (f"Error: {e}", None, "", "", "", None)
158
 
159
+ # ==== UI ====
160
  with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
161
  with gr.Tabs():
162
+ # -------- HOME TAB --------
163
  with gr.Tab("Home"):
164
+ with gr.Row():
165
+ # Columna izquierda con acordeones
166
+ with gr.Column(scale=1):
167
+ gr.Markdown("## Learn more about OrbMol")
168
+
169
+ with gr.Accordion("What is OrbMol?", open=False):
170
+ gr.Markdown("""
171
+ OrbMol is a suite of quantum-accurate machine learning models for molecular predictions. Built on the **Orb-v3 architecture**, OrbMol provides fast and accurate calculations of energies, forces, and molecular properties at the level of advanced quantum chemistry methods.
172
+
173
+ The models combine the transferability of universal potentials with quantum-level accuracy, making them suitable for a wide range of applications in chemistry, materials science, and drug discovery.
174
+ """)
175
+
176
+ with gr.Accordion("Available Models", open=False):
177
+ gr.Markdown("""
178
+ **OMol** and **OMol-Direct**
179
+ - **Training dataset**: OMol25 (>100M calculations on small molecules, biomolecules, metal complexes, and electrolytes)
180
+ - **Level of theory**: ωB97M-V/def2-TZVPD with non-local dispersion; solvation treated explicitly
181
+ - **Inputs**: total charge & spin multiplicity
182
+ - **Applications**: biology, organic chemistry, protein folding, small-molecule drugs, organic liquids, homogeneous catalysis
183
+ - **Caveats**: trained only on aperiodic systems → periodic/inorganic cases may not work well
184
+ - **Difference**: OMol enforces energy–force consistency; OMol-Direct relaxes this for efficiency
185
+
186
+ **OMat**
187
+ - **Training dataset**: OMat24 (>100M inorganic calculations, from Materials Project, Alexandria, and far-from-equilibrium samples)
188
+ - **Level of theory**: PBE/PBE+U with Materials Project settings; VASP 54 pseudopotentials; no dispersion
189
+ - **Inputs**: No support for spin and charge. Spin polarization included but magnetic state cannot be selected
190
+ - **Applications**: inorganic discovery, photovoltaics, alloys, superconductors, electronic/optical materials
191
+ - **Caveats**: magnetic effects may be incompletely captured
192
+ """)
193
+
194
+ with gr.Accordion("Supported File Formats", open=False):
195
+ gr.Markdown("""
196
+ OrbMol supports the following molecular structure formats:
197
+ - `.xyz` - XYZ coordinate files
198
+ - `.pdb` - Protein Data Bank format
199
+ - `.cif` - Crystallographic Information File
200
+ - `.traj` - ASE trajectory format
201
+ - `.mol` - MDL Molfile
202
+ - `.sdf` - Structure Data File
203
+
204
+ All formats are automatically converted internally for processing.
205
+ """)
206
+
207
+ with gr.Accordion("How to Use", open=False):
208
+ gr.Markdown("""
209
+ **Single Point Energy**: Upload a molecular structure and select a model to calculate energies and forces.
210
+
211
+ **Molecular Dynamics**: Run time-dependent simulations to observe molecular behavior at different temperatures and conditions.
212
+
213
+ **Relaxation/Optimization**: Find the minimum-energy configuration of your molecular structure.
214
+
215
+ Each tab provides specific parameters you can adjust to customize your calculations.
216
+ """)
217
+
218
+ with gr.Accordion("Technical Foundation", open=False):
219
+ gr.Markdown("""
220
+ All models are based on the **Orb-v3 architecture**, the latest generation of Orb universal interatomic potentials.
221
+
222
+ Key features:
223
+ - Graph neural network architecture
224
+ - Equivariant message passing
225
+ - Multi-task learning across different quantum chemistry methods
226
+ - Billions of training examples across diverse chemical spaces
227
+ - Sub-kcal/mol accuracy on test sets
228
+ """)
229
+
230
+ with gr.Accordion("Resources & Support", open=False):
231
+ gr.Markdown("""
232
+ - [Orb-v3 paper](https://arxiv.org/abs/2504.06231)
233
+ - [Orb-Models GitHub repository](https://github.com/orbital-materials/orb-models)
234
+ - For issues/questions, please open a GitHub issue or contact the developers
235
+
236
+ **Citation**: If you use OrbMol in your research, please cite the Orb-v3 paper and the relevant dataset papers (OMol25/OMat24).
237
+ """)
238
+
239
+ # Columna derecha con contenido principal
240
+ with gr.Column(scale=2):
241
+ gr.Image("logo_color_text.png",
242
+ show_share_button=False,
243
+ show_download_button=False,
244
+ show_label=False,
245
+ show_fullscreen_button=False)
246
+
247
+ gr.Markdown("# OrbMol — Quantum-Accurate Molecular Predictions")
248
+
249
+ gr.Markdown("""
250
+ Welcome to the OrbMol demo! This interactive platform allows you to explore the capabilities of our quantum-accurate machine learning models for molecular simulations.
251
+
252
+ ## Quick Start
253
+
254
+ Use the tabs above to access different functionalities:
255
+
256
+ 1. **Single Point Energy**: Calculate energies and forces for a given molecular structure
257
+ 2. **Molecular Dynamics**: Run MD simulations using OrbMol-trained potentials
258
+ 3. **Relaxation / Optimization**: Optimize molecular structures to their minimum-energy configurations
259
+
260
+ Simply upload a molecular structure file in any supported format (`.xyz`, `.pdb`, `.cif`, `.traj`, `.mol`, `.sdf`) and select the appropriate model for your system.
261
 
262
+ ## Model Selection Guide
263
+
264
+ **Choose OMol/OMol-Direct for:**
265
+ - Organic molecules and biomolecules
266
+ - Drug-like compounds
267
+ - Metal-organic complexes
268
+ - Molecules in solution
269
+ - Systems where you need to specify charge and spin
270
+
271
+ **Choose OMat for:**
272
+ - Inorganic crystals and materials
273
+ - Periodic systems
274
+ - Bulk materials and alloys
275
+ - Solid-state compounds
276
+
277
+ Explore the accordions on the left to learn more about each model's capabilities, training data, and limitations.
278
+ """)
279
+
280
+ gr.Markdown("## Try an Example")
281
+ gr.Markdown("""
282
+ To get started quickly, navigate to any of the calculation tabs above and try one of these examples:
283
+ - **Single Point Energy**: Upload a small molecule to see energy and force predictions
284
+ - **Molecular Dynamics**: Run a short simulation at 300K to observe thermal motion
285
+ - **Relaxation**: Optimize a distorted structure to find its equilibrium geometry
286
+ """)
287
+
288
+ # -------- SPE -------- (SIN CAMBIOS)
289
  with gr.Tab("Single Point Energy"):
290
  with gr.Row():
291
  with gr.Column(scale=2):
292
  gr.Markdown("# OrbMol — Quantum-Accurate Molecular Predictions")
293
  gr.Markdown("**Supported formats:** .xyz, .pdb, .cif, .traj, .mol, .sdf")
294
+
295
+ xyz_input = gr.File(
296
+ label="Upload Structure File",
297
+ file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"],
298
+ file_count="single"
299
+ )
300
+ task_name_spe = gr.Radio(
301
+ ["OMol", "OMat", "OMol-Direct"],
302
+ value="OMol",
303
+ label="Model Type"
304
+ )
305
  with gr.Row():
306
  charge_input = gr.Slider(-10, 10, 0, step=1, label="Charge")
307
  spin_input = gr.Slider(1, 11, 1, step=1, label="Spin Multiplicity")
308
+
309
  run_spe = gr.Button("Run OrbMol Prediction", variant="primary")
310
+
311
  with gr.Column(variant="panel", min_width=500):
312
  spe_out = gr.Textbox(label="Energy & Forces", lines=15, interactive=False)
313
  spe_status = gr.Textbox(label="Status", interactive=False)
314
+
315
+ spe_viewer = Molecule3D(
316
+ label="Input Structure Viewer",
317
+ reps=DEFAULT_MOLECULAR_REPRESENTATIONS,
318
+ config=DEFAULT_MOLECULAR_SETTINGS
319
+ )
320
+
321
  task_name_spe.change(
322
  lambda x: (
323
  gr.update(visible=x in ["OMol", "OMol-Direct"]),
 
326
  [task_name_spe],
327
  [charge_input, spin_input]
328
  )
329
+
330
+ run_spe.click(
331
+ predict_molecule,
332
+ [xyz_input, task_name_spe, charge_input, spin_input],
333
+ [spe_out, spe_status, spe_viewer]
334
+ )
335
 
336
+ # -------- MD -------- (SIN CAMBIOS)
337
  with gr.Tab("Molecular Dynamics"):
338
  with gr.Row():
339
  with gr.Column(scale=2):
340
  gr.Markdown("## Molecular Dynamics Simulation")
341
+
342
+ xyz_md = gr.File(
343
+ label="Upload Structure File",
344
+ file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"],
345
+ file_count="single"
346
+ )
347
+ task_name_md = gr.Radio(
348
+ ["OMol", "OMat", "OMol-Direct"],
349
+ value="OMol",
350
+ label="Model Type"
351
+ )
352
  with gr.Row():
353
  charge_md = gr.Slider(-10, 10, 0, step=1, label="Charge")
354
  spin_md = gr.Slider(1, 11, 1, step=1, label="Spin Multiplicity")
 
359
  timestep_md = gr.Slider(0.1, 5.0, 1.0, step=0.1, label="Timestep (fs)")
360
  ensemble_md = gr.Radio(["NVE", "NVT"], value="NVE", label="Ensemble")
361
  run_md_btn = gr.Button("Run MD Simulation", variant="primary")
362
+
363
  with gr.Column(variant="panel", min_width=520):
364
  md_status = gr.Textbox(label="MD Status", interactive=False)
365
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
366
+
367
+ md_viewer = Molecule3D(
368
+ label="MD Result Viewer",
369
+ reps=DEFAULT_MOLECULAR_REPRESENTATIONS,
370
+ config=DEFAULT_MOLECULAR_SETTINGS
371
+ )
372
+
373
  md_log = gr.Textbox(label="Log", interactive=False, lines=15)
374
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20)
375
  md_explain = gr.Markdown()
376
+
377
  task_name_md.change(
378
  lambda x: (
379
  gr.update(visible=x in ["OMol", "OMol-Direct"]),
 
382
  [task_name_md],
383
  [charge_md, spin_md]
384
  )
385
+
386
+ run_md_btn.click(
387
+ md_wrapper,
388
+ [xyz_md, task_name_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
389
+ [md_status, md_traj, md_log, md_script, md_explain, md_viewer]
390
+ )
391
 
392
+ # -------- Relax -------- (SIN CAMBIOS)
393
  with gr.Tab("Relaxation / Optimization"):
394
  with gr.Row():
395
  with gr.Column(scale=2):
396
  gr.Markdown("## Structure Relaxation/Optimization")
397
+
398
+ xyz_rlx = gr.File(
399
+ label="Upload Structure File",
400
+ file_types=[".xyz", ".pdb", ".cif", ".traj", ".mol", ".sdf"],
401
+ file_count="single"
402
+ )
403
+ task_name_rlx = gr.Radio(
404
+ ["OMol", "OMat", "OMol-Direct"],
405
+ value="OMol",
406
+ label="Model Type"
407
+ )
408
  with gr.Row():
409
  steps_rlx = gr.Slider(1, 2000, 300, step=1, label="Max Steps")
410
  fmax_rlx = gr.Slider(0.001, 0.5, 0.05, step=0.001, label="Fmax (eV/Å)")
 
413
  spin_rlx = gr.Slider(1, 11, 1, step=1, label="Spin")
414
  relax_cell = gr.Checkbox(False, label="Relax Unit Cell")
415
  run_rlx_btn = gr.Button("Run Optimization", variant="primary")
416
+
417
  with gr.Column(variant="panel", min_width=520):
418
  rlx_status = gr.Textbox(label="Status", interactive=False)
419
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
420
+
421
+ rlx_viewer = Molecule3D(
422
+ label="Optimized Structure Viewer",
423
+ reps=DEFAULT_MOLECULAR_REPRESENTATIONS,
424
+ config=DEFAULT_MOLECULAR_SETTINGS
425
+ )
426
+
427
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15)
428
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20)
429
  rlx_explain = gr.Markdown()
430
+
431
  task_name_rlx.change(
432
  lambda x: (
433
  gr.update(visible=x in ["OMol", "OMol-Direct"]),
 
436
  [task_name_rlx],
437
  [charge_rlx, spin_rlx]
438
  )
439
+
440
+ run_rlx_btn.click(
441
+ relax_wrapper,
442
+ [xyz_rlx, task_name_rlx, steps_rlx, fmax_rlx, charge_rlx, spin_rlx, relax_cell],
443
+ [rlx_status, rlx_traj, rlx_log, rlx_script, rlx_explain, rlx_viewer]
444
+ )
445
 
446
  if __name__ == "__main__":
447
+ demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)