A19grey commited on
Commit
af9d37a
·
1 Parent(s): a7e196c

I can't draw water molecule but giving up for now

Browse files
Files changed (4) hide show
  1. app.py +23 -2
  2. history.md +14 -0
  3. molecules.json +1 -1
  4. visualization.py +123 -21
app.py CHANGED
@@ -52,6 +52,21 @@ import subprocess
52
  import sys
53
  import json
54
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  def install_dependencies():
57
  """Install required packages from requirements.txt."""
@@ -304,22 +319,28 @@ def create_interface():
304
  def update_molecule_info(molecule_choice):
305
  """Update description and scale range when molecule is selected."""
306
  try:
 
307
  mol_data = molecules[molecule_choice]
308
 
309
  # Format parameters display
310
  params_html = format_molecule_params(mol_data)
 
311
 
312
  # Get scale range values with defaults
313
  min_scale = mol_data.get('scale_range', {}).get('min', 0.1)
314
  max_scale = mol_data.get('scale_range', {}).get('max', 3.0)
315
  default_scale = mol_data.get('default_scale', 1.0)
316
  step_size = mol_data.get('scale_range', {}).get('step', 0.05)
 
317
 
318
  # Create molecule visualization
 
319
  mol_list = create_molecule_viewer(molecule_choice, default_scale)
320
  if mol_list is None or not mol_list:
321
- print(f"No molecule visualization created for {molecule_choice}", file=sys.stderr)
322
  mol_list = []
 
 
323
 
324
  return [
325
  params_html, # Update params display
@@ -332,7 +353,7 @@ def create_interface():
332
  mol_list # Update 3D view
333
  ]
334
  except Exception as e:
335
- print(f"Error updating molecule info: {e}", file=sys.stderr)
336
  return [
337
  "<div>Error loading molecule parameters</div>",
338
  gr.update(
 
52
  import sys
53
  import json
54
  import os
55
+ import logging
56
+
57
+ # Configure logging
58
+ logging.basicConfig(level=logging.DEBUG,
59
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
60
+ handlers=[
61
+ logging.StreamHandler(), # This will output to console
62
+ logging.FileHandler('app_molecule.log') # This will output to file
63
+ ])
64
+ logger = logging.getLogger(__name__)
65
+ logger.setLevel(logging.DEBUG) # Ensure logger itself is at DEBUG level
66
+
67
+ # Force all handlers to DEBUG level
68
+ for handler in logger.handlers:
69
+ handler.setLevel(logging.DEBUG)
70
 
71
  def install_dependencies():
72
  """Install required packages from requirements.txt."""
 
319
  def update_molecule_info(molecule_choice):
320
  """Update description and scale range when molecule is selected."""
321
  try:
322
+ logger.info(f"Updating molecule info for: {molecule_choice}")
323
  mol_data = molecules[molecule_choice]
324
 
325
  # Format parameters display
326
  params_html = format_molecule_params(mol_data)
327
+ logger.debug(f"Generated parameter HTML for {molecule_choice}")
328
 
329
  # Get scale range values with defaults
330
  min_scale = mol_data.get('scale_range', {}).get('min', 0.1)
331
  max_scale = mol_data.get('scale_range', {}).get('max', 3.0)
332
  default_scale = mol_data.get('default_scale', 1.0)
333
  step_size = mol_data.get('scale_range', {}).get('step', 0.05)
334
+ logger.debug(f"Scale parameters - min: {min_scale}, max: {max_scale}, default: {default_scale}")
335
 
336
  # Create molecule visualization
337
+ logger.info(f"Creating molecule visualization for {molecule_choice}")
338
  mol_list = create_molecule_viewer(molecule_choice, default_scale)
339
  if mol_list is None or not mol_list:
340
+ logger.error(f"No molecule visualization created for {molecule_choice}")
341
  mol_list = []
342
+ else:
343
+ logger.info(f"Successfully created visualization with {len(mol_list)} molecules")
344
 
345
  return [
346
  params_html, # Update params display
 
353
  mol_list # Update 3D view
354
  ]
355
  except Exception as e:
356
+ logger.error(f"Error updating molecule info: {str(e)}", exc_info=True)
357
  return [
358
  "<div>Error loading molecule parameters</div>",
359
  gr.update(
history.md CHANGED
@@ -1,5 +1,19 @@
1
  # Development History
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ## 2024-03-20
4
  - Split VQE simulation into two steps:
5
  * Added "Generate Hamiltonian" button to first compute and display Hamiltonian parameters
 
1
  # Development History
2
 
3
+ ## 2024-01-06 (Update 10)
4
+ - Extensive debugging of molecule visualization issues:
5
+ * Added comprehensive logging to track molecule creation and visualization
6
+ * Modified RDKit molecule creation to handle hydrogens explicitly
7
+ * Attempted multiple approaches for H2O and H2 creation:
8
+ - Direct SMILES parsing
9
+ - RWMol with explicit atom and bond creation
10
+ - Geometry template-based coordinate generation
11
+ * Added proper valence calculation and sanitization
12
+ * Added explicit bond creation and verification
13
+ * Issue remains unresolved: H-containing molecules (H2, H2O, etc.) fail to display
14
+ * Non-H molecules (CO, N2) display correctly
15
+ * Next steps: Consider alternative visualization approaches or different molecule viewer component
16
+
17
  ## 2024-03-20
18
  - Split VQE simulation into two steps:
19
  * Added "Generate Hamiltonian" button to first compute and display Hamiltonian parameters
molecules.json CHANGED
@@ -2,7 +2,7 @@
2
  "H2": {
3
  "name": "Hydrogen molecule",
4
  "formula": "H₂",
5
- "smiles": "[H][H]",
6
  "basis": "sto-3g",
7
  "multiplicity": 1,
8
  "charge": 0,
 
2
  "H2": {
3
  "name": "Hydrogen molecule",
4
  "formula": "H₂",
5
+ "smiles": "[HH]",
6
  "basis": "sto-3g",
7
  "multiplicity": 1,
8
  "charge": 0,
visualization.py CHANGED
@@ -12,8 +12,18 @@ from gradio_molgallery3d import MolGallery3D
12
  import json
13
 
14
  # Configure logging
 
 
 
 
 
 
15
  logger = logging.getLogger(__name__)
16
- logger.setLevel(logging.INFO)
 
 
 
 
17
 
18
  def format_molecule_params(molecule_data: dict) -> str:
19
  """
@@ -153,48 +163,140 @@ def create_molecule_viewer(molecule_id: str, scale_factor: float) -> MolGallery3
153
  return None
154
 
155
  molecule_data = molecules[molecule_id]
 
156
 
157
  # Special handling for different molecules
 
158
  if molecule_id == "H2":
159
- mol = Chem.MolFromSmiles("[H][H]")
160
- if mol is None:
161
- mol = Chem.MolFromSmiles("[HH]") # Alternative SMILES for H2
 
 
 
 
 
 
 
162
  elif molecule_id == "H2O":
163
- mol = Chem.MolFromSmiles("O")
164
- mol = Chem.AddHs(mol)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  else:
166
  # Create molecule using SMILES
 
167
  mol = Chem.MolFromSmiles(molecule_data['smiles'])
168
- if mol is None:
169
- logger.error(f"Could not create molecule from SMILES: {molecule_data['smiles']}")
170
- return None
171
- mol = Chem.AddHs(mol)
 
 
172
 
173
  if mol is None:
174
  logger.error(f"Failed to create molecule for {molecule_id}")
175
  return None
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  # Generate 3D coordinates with distance matrix
178
  try:
179
- AllChem.EmbedMolecule(mol, randomSeed=42)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
- # Scale the molecule coordinates
182
- conf = mol.GetConformer()
183
- positions = conf.GetPositions()
184
- centroid = np.mean(positions, axis=0)
185
 
186
- for i in range(mol.GetNumAtoms()):
187
- pos = positions[i]
188
- scaled_pos = centroid + (pos - centroid) * scale_factor
189
- conf.SetAtomPosition(i, scaled_pos)
 
 
 
 
 
 
 
 
 
190
 
191
  logger.info(f"Successfully created 3D coordinates for {molecule_id}")
 
 
 
 
 
 
 
 
 
 
192
  return [mol] # Return the molecule as a list as expected by MolGallery3D
193
 
194
  except Exception as e:
195
- logger.error(f"Failed to generate 3D coordinates: {e}")
196
  return None
197
 
198
  except Exception as e:
199
- logger.error(f"Failed to create molecule viewer: {e}")
200
  return None
 
12
  import json
13
 
14
  # Configure logging
15
+ logging.basicConfig(level=logging.DEBUG,
16
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
17
+ handlers=[
18
+ logging.StreamHandler(), # This will output to console
19
+ logging.FileHandler('molecule_creation.log') # This will output to file
20
+ ])
21
  logger = logging.getLogger(__name__)
22
+ logger.setLevel(logging.DEBUG) # Ensure logger itself is at DEBUG level
23
+
24
+ # Force all handlers to DEBUG level
25
+ for handler in logger.handlers:
26
+ handler.setLevel(logging.DEBUG)
27
 
28
  def format_molecule_params(molecule_data: dict) -> str:
29
  """
 
163
  return None
164
 
165
  molecule_data = molecules[molecule_id]
166
+ logger.debug(f"Molecule data loaded: {molecule_data}")
167
 
168
  # Special handling for different molecules
169
+ mol = None
170
  if molecule_id == "H2":
171
+ logger.debug("Creating H2 molecule")
172
+ # Create H2 using RWMol for explicit control
173
+ mol = Chem.RWMol()
174
+ h1 = mol.AddAtom(Chem.Atom(1)) # Add first H atom
175
+ h2 = mol.AddAtom(Chem.Atom(1)) # Add second H atom
176
+ mol.AddBond(h1, h2, Chem.BondType.SINGLE) # Add single bond
177
+ mol = mol.GetMol()
178
+ Chem.SanitizeMol(mol)
179
+ logger.debug(f"H2 creation result: {mol is not None}")
180
+
181
  elif molecule_id == "H2O":
182
+ logger.debug("Creating H2O molecule")
183
+ # Create H2O using RWMol for explicit control
184
+ mol = Chem.RWMol()
185
+
186
+ # Add atoms with explicit valence
187
+ o = mol.AddAtom(Chem.Atom(8)) # Oxygen
188
+ oxygen = mol.GetAtomWithIdx(o)
189
+ oxygen.SetFormalCharge(0)
190
+ oxygen.SetNoImplicit(True)
191
+
192
+ h1 = mol.AddAtom(Chem.Atom(1)) # First hydrogen
193
+ h1_atom = mol.GetAtomWithIdx(h1)
194
+ h1_atom.SetFormalCharge(0)
195
+ h1_atom.SetNoImplicit(True)
196
+
197
+ h2 = mol.AddAtom(Chem.Atom(1)) # Second hydrogen
198
+ h2_atom = mol.GetAtomWithIdx(h2)
199
+ h2_atom.SetFormalCharge(0)
200
+ h2_atom.SetNoImplicit(True)
201
+
202
+ # Add bonds
203
+ mol.AddBond(o, h1, Chem.BondType.SINGLE)
204
+ mol.AddBond(o, h2, Chem.BondType.SINGLE)
205
+
206
+ # Convert to immutable molecule and sanitize
207
+ mol = mol.GetMol()
208
+ Chem.SanitizeMol(mol)
209
+ logger.debug(f"H2O creation result: {mol is not None}")
210
+
211
  else:
212
  # Create molecule using SMILES
213
+ logger.debug(f"Creating molecule from SMILES: {molecule_data['smiles']}")
214
  mol = Chem.MolFromSmiles(molecule_data['smiles'])
215
+ logger.debug(f"Initial molecule creation result: {mol is not None}")
216
+ if mol is not None:
217
+ logger.debug("Adding hydrogens to molecule")
218
+ mol = Chem.AddHs(mol)
219
+ Chem.SanitizeMol(mol)
220
+ logger.debug(f"Molecule with hydrogens result: {mol is not None}")
221
 
222
  if mol is None:
223
  logger.error(f"Failed to create molecule for {molecule_id}")
224
  return None
225
 
226
+ logger.debug(f"Molecule created with {mol.GetNumAtoms()} atoms")
227
+ for atom in mol.GetAtoms():
228
+ # Calculate valence before checking hydrogens
229
+ atom.UpdatePropertyCache()
230
+ logger.debug(f"Atom {atom.GetIdx()}: Symbol={atom.GetSymbol()}, " +
231
+ f"Explicit Hs={atom.GetNumExplicitHs()}, " +
232
+ f"Implicit Hs={atom.GetNumImplicitHs()}, " +
233
+ f"Valence={atom.GetTotalValence()}")
234
+
235
+ # Log bond information
236
+ logger.debug(f"Number of bonds: {mol.GetNumBonds()}")
237
+ for bond in mol.GetBonds():
238
+ logger.debug(f"Bond between {bond.GetBeginAtom().GetSymbol()}{bond.GetBeginAtomIdx()} and " +
239
+ f"{bond.GetEndAtom().GetSymbol()}{bond.GetEndAtomIdx()}, type: {bond.GetBondType()}")
240
+
241
  # Generate 3D coordinates with distance matrix
242
  try:
243
+ logger.debug("Attempting to generate 3D coordinates")
244
+ # Use geometry template if available
245
+ if 'geometry_template' in molecule_data:
246
+ logger.debug("Using geometry template for 3D coordinates")
247
+ conf = Chem.Conformer(mol.GetNumAtoms())
248
+ for i, (_, coords) in enumerate(molecule_data['geometry_template']):
249
+ # Scale coordinates by the scale factor
250
+ scaled_coords = np.array(coords) * scale_factor
251
+ conf.SetAtomPosition(i, scaled_coords)
252
+ mol.AddConformer(conf)
253
+ result = 0 # Template-based embedding always succeeds
254
+ else:
255
+ result = AllChem.EmbedMolecule(mol, randomSeed=42)
256
+
257
+ logger.debug(f"3D coordinate generation result: {result}") # 0 means success, -1 means failure
258
+
259
+ if result == -1:
260
+ logger.debug("Standard embedding failed, trying with ETKDGv2")
261
+ params = AllChem.ETKDGv2()
262
+ result = AllChem.EmbedMolecule(mol, params, randomSeed=42)
263
+ logger.debug(f"ETKDGv2 embedding result: {result}")
264
 
265
+ if result == -1:
266
+ logger.error("Failed to generate 3D coordinates")
267
+ return None
 
268
 
269
+ # Scale the molecule coordinates if not using template
270
+ if 'geometry_template' not in molecule_data:
271
+ conf = mol.GetConformer()
272
+ positions = conf.GetPositions()
273
+ logger.debug(f"Generated 3D coordinates:\n{positions}")
274
+ centroid = np.mean(positions, axis=0)
275
+ logger.debug(f"Molecule centroid: {centroid}")
276
+
277
+ for i in range(mol.GetNumAtoms()):
278
+ pos = positions[i]
279
+ scaled_pos = centroid + (pos - centroid) * scale_factor
280
+ conf.SetAtomPosition(i, scaled_pos)
281
+ logger.debug(f"Atom {i} ({mol.GetAtomWithIdx(i).GetSymbol()}) scaled position: {scaled_pos}")
282
 
283
  logger.info(f"Successfully created 3D coordinates for {molecule_id}")
284
+
285
+ # Verify final state
286
+ logger.debug("Final molecule state:")
287
+ logger.debug(f"Number of atoms: {mol.GetNumAtoms()}")
288
+ logger.debug(f"Number of bonds: {mol.GetNumBonds()}")
289
+ logger.debug(f"Has conformer: {mol.GetNumConformers() > 0}")
290
+
291
+ # Final sanitization check
292
+ Chem.SanitizeMol(mol)
293
+
294
  return [mol] # Return the molecule as a list as expected by MolGallery3D
295
 
296
  except Exception as e:
297
+ logger.error(f"Failed to generate 3D coordinates: {e}", exc_info=True)
298
  return None
299
 
300
  except Exception as e:
301
+ logger.error(f"Failed to create molecule viewer: {e}", exc_info=True)
302
  return None