Vaishnav14220 commited on
Commit
2c47364
·
1 Parent(s): fb7d531

Switch orbital rendering to Plotly isosurface for visible HOMO visualization

Browse files
Files changed (1) hide show
  1. app.py +43 -79
app.py CHANGED
@@ -195,115 +195,79 @@ def name_to_3d_molecule(name: str, show_orbitals: bool = False) -> tuple:
195
  try:
196
  import numpy as np
197
  from pyscf import gto, scf
198
-
199
- # Build PySCF molecule object
200
  pyscf_elements = [atom.GetSymbol() for atom in mol.GetAtoms()]
201
  pyscf_coords = []
202
  for i in range(mol.GetNumAtoms()):
203
  pos = conf.GetAtomPosition(i)
204
- # Convert to Angstrom (PySCF uses Angstrom)
205
  pyscf_coords.append([pos.x, pos.y, pos.z])
206
-
207
  pyscf_atoms = [(elem, coord) for elem, coord in zip(pyscf_elements, pyscf_coords)]
208
-
209
- # Create PySCF molecule with minimal basis
210
  pyscf_mole = gto.Mole()
211
  pyscf_mole.atom = pyscf_atoms
212
  pyscf_mole.basis = 'sto-3g'
213
  pyscf_mole.unit = 'A'
214
  pyscf_mole.verbose = 0
215
  pyscf_mole.build()
216
-
217
- # Run Hartree-Fock calculation (faster than DFT)
218
  mf = scf.RHF(pyscf_mole)
219
  mf.verbose = 0
220
  mf.kernel()
221
-
222
- # Get HOMO and LUMO indices
223
  n_electrons = pyscf_mole.nelectron
224
- n_occ = n_electrons // 2
225
  homo_idx = n_occ - 1
226
- lumo_idx = n_occ
227
-
228
- # Create a coarser grid for visualization
229
  margin = 2.5
230
- grid_size = 30
231
-
232
  x_coords_np = np.array(x_coords)
233
  y_coords_np = np.array(y_coords)
234
  z_coords_np = np.array(z_coords)
235
-
236
  x_min, x_max = x_coords_np.min() - margin, x_coords_np.max() + margin
237
  y_min, y_max = y_coords_np.min() - margin, y_coords_np.max() + margin
238
  z_min, z_max = z_coords_np.min() - margin, z_coords_np.max() + margin
239
-
240
  x_grid = np.linspace(x_min, x_max, grid_size)
241
  y_grid = np.linspace(y_min, y_max, grid_size)
242
  z_grid = np.linspace(z_min, z_max, grid_size)
243
-
244
- coords_grid = np.array(np.meshgrid(x_grid, y_grid, z_grid, indexing='ij'))
245
- grid_points = coords_grid.reshape(3, -1).T
246
-
247
- # Evaluate HOMO orbital on grid
248
  ao_value = pyscf_mole.eval_gto('GTOval_sph', grid_points)
249
  mo_coeff = mf.mo_coeff[:, homo_idx]
250
  homo_values = np.dot(ao_value, mo_coeff)
251
- homo_grid = homo_values.reshape(grid_size, grid_size, grid_size)
252
-
253
- # Create isosurfaces using marching cubes
254
- try:
255
- from skimage import measure
256
-
257
- # HOMO positive isosurface
258
- iso_val = 0.03
259
- if np.abs(homo_grid).max() > iso_val:
260
- verts, faces, _, _ = measure.marching_cubes(homo_grid, level=iso_val)
261
-
262
- # Scale vertices to actual coordinates
263
- verts_scaled = np.zeros_like(verts)
264
- verts_scaled[:, 0] = x_min + verts[:, 0] * (x_max - x_min) / (grid_size - 1)
265
- verts_scaled[:, 1] = y_min + verts[:, 1] * (y_max - y_min) / (grid_size - 1)
266
- verts_scaled[:, 2] = z_min + verts[:, 2] * (z_max - z_min) / (grid_size - 1)
267
-
268
- homo_pos_trace = go.Mesh3d(
269
- x=verts_scaled[:, 0],
270
- y=verts_scaled[:, 1],
271
- z=verts_scaled[:, 2],
272
- i=faces[:, 0],
273
- j=faces[:, 1],
274
- k=faces[:, 2],
275
- color='lightblue',
276
- opacity=0.4,
277
- name='HOMO (+)',
278
- hoverinfo='name'
279
- )
280
- data_traces.append(homo_pos_trace)
281
-
282
- # HOMO negative isosurface
283
- verts_neg, faces_neg, _, _ = measure.marching_cubes(homo_grid, level=-iso_val)
284
-
285
- verts_neg_scaled = np.zeros_like(verts_neg)
286
- verts_neg_scaled[:, 0] = x_min + verts_neg[:, 0] * (x_max - x_min) / (grid_size - 1)
287
- verts_neg_scaled[:, 1] = y_min + verts_neg[:, 1] * (y_max - y_min) / (grid_size - 1)
288
- verts_neg_scaled[:, 2] = z_min + verts_neg[:, 2] * (z_max - z_min) / (grid_size - 1)
289
-
290
- homo_neg_trace = go.Mesh3d(
291
- x=verts_neg_scaled[:, 0],
292
- y=verts_neg_scaled[:, 1],
293
- z=verts_neg_scaled[:, 2],
294
- i=faces_neg[:, 0],
295
- j=faces_neg[:, 1],
296
- k=faces_neg[:, 2],
297
- color='salmon',
298
- opacity=0.4,
299
- name='HOMO (-)',
300
- hoverinfo='name'
301
- )
302
- data_traces.append(homo_neg_trace)
303
-
304
- except Exception as e:
305
- print(f"Isosurface generation failed: {e}")
306
-
307
  except Exception as e:
308
  print(f"Orbital calculation failed: {e}")
309
  import traceback
 
195
  try:
196
  import numpy as np
197
  from pyscf import gto, scf
198
+
199
+ # Build PySCF molecule object (Angstrom units)
200
  pyscf_elements = [atom.GetSymbol() for atom in mol.GetAtoms()]
201
  pyscf_coords = []
202
  for i in range(mol.GetNumAtoms()):
203
  pos = conf.GetAtomPosition(i)
 
204
  pyscf_coords.append([pos.x, pos.y, pos.z])
205
+
206
  pyscf_atoms = [(elem, coord) for elem, coord in zip(pyscf_elements, pyscf_coords)]
207
+
 
208
  pyscf_mole = gto.Mole()
209
  pyscf_mole.atom = pyscf_atoms
210
  pyscf_mole.basis = 'sto-3g'
211
  pyscf_mole.unit = 'A'
212
  pyscf_mole.verbose = 0
213
  pyscf_mole.build()
214
+
215
+ # Run Hartree-Fock for frontier orbitals
216
  mf = scf.RHF(pyscf_mole)
217
  mf.verbose = 0
218
  mf.kernel()
219
+
 
220
  n_electrons = pyscf_mole.nelectron
221
+ n_occ = max(1, n_electrons // 2)
222
  homo_idx = n_occ - 1
223
+
224
+ # Define sampling grid around molecule
 
225
  margin = 2.5
226
+ grid_size = 32
227
+
228
  x_coords_np = np.array(x_coords)
229
  y_coords_np = np.array(y_coords)
230
  z_coords_np = np.array(z_coords)
231
+
232
  x_min, x_max = x_coords_np.min() - margin, x_coords_np.max() + margin
233
  y_min, y_max = y_coords_np.min() - margin, y_coords_np.max() + margin
234
  z_min, z_max = z_coords_np.min() - margin, z_coords_np.max() + margin
235
+
236
  x_grid = np.linspace(x_min, x_max, grid_size)
237
  y_grid = np.linspace(y_min, y_max, grid_size)
238
  z_grid = np.linspace(z_min, z_max, grid_size)
239
+
240
+ grid_x, grid_y, grid_z = np.meshgrid(x_grid, y_grid, z_grid, indexing='ij')
241
+ grid_points = np.column_stack((grid_x.ravel(), grid_y.ravel(), grid_z.ravel()))
242
+
243
+ # Evaluate HOMO on grid
244
  ao_value = pyscf_mole.eval_gto('GTOval_sph', grid_points)
245
  mo_coeff = mf.mo_coeff[:, homo_idx]
246
  homo_values = np.dot(ao_value, mo_coeff)
247
+
248
+ # Skip if orbital is negligible (e.g., calculation failure)
249
+ if np.allclose(homo_values, 0):
250
+ raise RuntimeError("HOMO values are all zero; orbital visualization unavailable")
251
+
252
+ iso_val = 0.03 * np.max(np.abs(homo_values))
253
+ iso_val = max(iso_val, 0.02)
254
+
255
+ orbital_trace = go.Isosurface(
256
+ x=grid_points[:, 0],
257
+ y=grid_points[:, 1],
258
+ z=grid_points[:, 2],
259
+ value=homo_values,
260
+ isomin=-iso_val,
261
+ isomax=iso_val,
262
+ colorscale=[[0.0, '#ff6f69'], [0.5, '#ffffff'], [1.0, '#2176ff']],
263
+ surface_count=2,
264
+ opacity=0.45,
265
+ caps=dict(x_show=False, y_show=False, z_show=False),
266
+ name='HOMO orbital',
267
+ showscale=False
268
+ )
269
+ data_traces.append(orbital_trace)
270
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
  except Exception as e:
272
  print(f"Orbital calculation failed: {e}")
273
  import traceback