Nanny7 commited on
Commit
47fd570
·
1 Parent(s): e921d38

Replace Psi4/psikit with PySCF for molecular orbital calculations on HF Spaces

Browse files
Files changed (3) hide show
  1. app.py +45 -37
  2. force_rebuild.txt +1 -1
  3. requirements.txt +2 -1
app.py CHANGED
@@ -112,27 +112,12 @@ def smiles_to_molecular_orbitals(smiles_input: str, name_input: str) -> str:
112
  raise gr.Error("Please provide a molecule with 30 atoms or fewer for orbital visualization.")
113
 
114
  try:
115
- from psikit import Psikit # type: ignore[import]
116
  except ImportError:
117
  return (
118
- "<p><strong>Molecular orbital rendering requires Psikit + Psi4.</strong> "
119
- "Install them locally with <code>pip install psikit psi4 py3Dmol</code> "
120
- "and run this app on your machine.</p>"
121
- "<p><strong>Alternative online tools:</strong></p>"
122
- "<ul>"
123
- "<li><a href='https://www.webmo.net/' target='_blank'>WebMO</a> - Web-based molecular modeling</li>"
124
- "<li><a href='https://gaussian.com/' target='_blank'>Gaussian</a> - Quantum chemistry software</li>"
125
- "<li><a href='https://www.chemcraftprog.com/' target='_blank'>ChemCraft</a> - Molecular visualization</li>"
126
- "</ul>"
127
- f"<p>You can copy this SMILES to these tools: <code>{canonical_smiles}</code></p>"
128
- )
129
-
130
- try:
131
- import psi4 # Check if psi4 is available
132
- except ImportError:
133
- return (
134
- "<p><strong>Psi4 is not available on this platform.</strong> "
135
- "Molecular orbital calculations require Psi4, which is not supported on Hugging Face Spaces.</p>"
136
  "<p><strong>Alternative online tools:</strong></p>"
137
  "<ul>"
138
  "<li><a href='https://www.webmo.net/' target='_blank'>WebMO</a> - Web-based molecular modeling</li>"
@@ -154,18 +139,43 @@ def smiles_to_molecular_orbitals(smiles_input: str, name_input: str) -> str:
154
  original_cwd = os.getcwd()
155
  os.chdir(tmpdir)
156
  try:
157
- pk = Psikit()
158
- pk.read_from_smiles(smiles)
159
- pk.optimize()
160
- pk.getMOview()
161
-
162
- cube_candidates = sorted(Path(tmpdir).glob("Psi_a_*A.cube"))
163
- if not cube_candidates:
164
- return (
165
- "<p>Psikit did not produce cube files. Try a smaller molecule or different conformer.</p>"
166
- )
167
-
168
- mol_block = Chem.MolToMolBlock(pk.mol)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  html_sections: list[str] = []
171
  if name_input.strip():
@@ -173,9 +183,10 @@ def smiles_to_molecular_orbitals(smiles_input: str, name_input: str) -> str:
173
  f"<p><strong>Resolved '{name_input.strip()}' to SMILES:</strong> {canonical_smiles}</p>"
174
  )
175
 
176
- labels = ["HOMO", "LUMO"]
177
- for cube_file, label in zip(cube_candidates[:2], labels):
178
- cube_data = cube_file.read_text()
 
179
  view = py3Dmol.view(width=500, height=400)
180
  view.addModel(mol_block, "mol")
181
  view.setStyle({"stick": {}})
@@ -197,9 +208,6 @@ def smiles_to_molecular_orbitals(smiles_input: str, name_input: str) -> str:
197
  if not html_sections:
198
  return "<p>Could not prepare HOMO/LUMO visualizations.</p>"
199
 
200
- if not html_sections:
201
- return "<p>Could not prepare HOMO/LUMO visualizations.</p>"
202
-
203
  return "".join(html_sections)
204
  except Exception as exc: # pragma: no cover - runtime heavy
205
  return f"<p>Unable to compute molecular orbitals: {exc}</p>"
 
112
  raise gr.Error("Please provide a molecule with 30 atoms or fewer for orbital visualization.")
113
 
114
  try:
115
+ import pyscf # type: ignore[import]
116
  except ImportError:
117
  return (
118
+ "<p><strong>PySCF is not available.</strong> "
119
+ "Install it with <code>pip install pyscf</code> "
120
+ "for molecular orbital calculations.</p>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  "<p><strong>Alternative online tools:</strong></p>"
122
  "<ul>"
123
  "<li><a href='https://www.webmo.net/' target='_blank'>WebMO</a> - Web-based molecular modeling</li>"
 
139
  original_cwd = os.getcwd()
140
  os.chdir(tmpdir)
141
  try:
142
+ # Generate 3D coordinates with RDKit
143
+ mol_3d = Chem.AddHs(mol)
144
+ AllChem.EmbedMolecule(mol_3d, randomSeed=42)
145
+ AllChem.MMFFOptimizeMolecule(mol_3d)
146
+
147
+ # Extract coordinates and atomic numbers
148
+ coords = []
149
+ atoms = []
150
+ for atom in mol_3d.GetAtoms():
151
+ pos = mol_3d.GetConformer().GetAtomPosition(atom.GetIdx())
152
+ coords.append([pos.x, pos.y, pos.z])
153
+ atoms.append(atom.GetSymbol())
154
+
155
+ # Set up PySCF molecule
156
+ mol_pyscf = pyscf.gto.Mole()
157
+ mol_pyscf.atom = list(zip(atoms, coords))
158
+ mol_pyscf.basis = 'sto-3g' # Small basis set for speed
159
+ mol_pyscf.build()
160
+
161
+ # Run Hartree-Fock calculation
162
+ mf = pyscf.scf.RHF(mol_pyscf)
163
+ mf.kernel()
164
+
165
+ # Get HOMO and LUMO indices
166
+ nocc = mol_pyscf.nelectron // 2
167
+ homo_idx = nocc - 1
168
+ lumo_idx = nocc
169
+
170
+ # Generate cube files for HOMO and LUMO
171
+ from pyscf.tools import cubegen
172
+ cube_files = []
173
+ for idx, label in [(homo_idx, 'HOMO'), (lumo_idx, 'LUMO')]:
174
+ cube_file = f'{label.lower()}.cube'
175
+ cubegen.orbital(mol_pyscf, cube_file, mf.mo_coeff[:, idx])
176
+ cube_files.append((cube_file, label))
177
+
178
+ mol_block = Chem.MolToMolBlock(mol_3d)
179
 
180
  html_sections: list[str] = []
181
  if name_input.strip():
 
183
  f"<p><strong>Resolved '{name_input.strip()}' to SMILES:</strong> {canonical_smiles}</p>"
184
  )
185
 
186
+ for cube_file, label in cube_files:
187
+ if not Path(cube_file).exists():
188
+ continue
189
+ cube_data = Path(cube_file).read_text()
190
  view = py3Dmol.view(width=500, height=400)
191
  view.addModel(mol_block, "mol")
192
  view.setStyle({"stick": {}})
 
208
  if not html_sections:
209
  return "<p>Could not prepare HOMO/LUMO visualizations.</p>"
210
 
 
 
 
211
  return "".join(html_sections)
212
  except Exception as exc: # pragma: no cover - runtime heavy
213
  return f"<p>Unable to compute molecular orbitals: {exc}</p>"
force_rebuild.txt CHANGED
@@ -1,2 +1,2 @@
1
  # Force rebuild
2
- 2025-11-08 v2
 
1
  # Force rebuild
2
+ 2025-11-08 v3
requirements.txt CHANGED
@@ -5,4 +5,5 @@ huggingface_hub==0.19.4
5
  cirpy
6
  pubchempy
7
  psikit
8
- py3Dmol
 
 
5
  cirpy
6
  pubchempy
7
  psikit
8
+ py3Dmol
9
+ pyscf