Spaces:
Running
Running
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +54 -23
src/streamlit_app.py
CHANGED
@@ -1298,29 +1298,61 @@ if atoms is not None:
|
|
1298 |
|
1299 |
if os.path.exists(traj_filename):
|
1300 |
try:
|
1301 |
-
|
1302 |
-
|
1303 |
-
|
1304 |
-
|
1305 |
-
|
1306 |
-
for i, atoms in enumerate(trajectory):
|
1307 |
-
trajectory_xyz += f"{len(atoms)}\n"
|
1308 |
-
# Try to get energy if available
|
1309 |
-
try:
|
1310 |
-
energy = atoms.get_potential_energy()
|
1311 |
-
trajectory_xyz += f"Step {i}: Energy = {energy:.6f} eV\n"
|
1312 |
-
except:
|
1313 |
-
trajectory_xyz += f"Step {i}: Optimization trajectory\n"
|
1314 |
-
|
1315 |
-
for atom in atoms:
|
1316 |
-
trajectory_xyz += f"{atom.symbol} {atom.position[0]:.6f} {atom.position[1]:.6f} {atom.position[2]:.6f}\n"
|
1317 |
-
|
1318 |
st.markdown("### Optimization Trajectory")
|
1319 |
st.write(f"Captured {len(trajectory)} optimization steps")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1320 |
@st.fragment
|
1321 |
def show_trajectory_download_button():
|
1322 |
-
|
1323 |
-
|
|
|
|
|
|
|
1324 |
st.download_button(
|
1325 |
label="Download Optimization Trajectory (XYZ)",
|
1326 |
data=trajectory_xyz,
|
@@ -1328,14 +1360,13 @@ if atoms is not None:
|
|
1328 |
mime="chemical/x-xyz"
|
1329 |
)
|
1330 |
show_trajectory_download_button()
|
1331 |
-
|
1332 |
-
|
1333 |
except Exception as e:
|
1334 |
st.warning(f"Could not process trajectory: {e}")
|
1335 |
-
|
1336 |
finally:
|
1337 |
-
# Clean up trajectory file
|
1338 |
os.unlink(traj_filename)
|
|
|
1339 |
|
1340 |
except Exception as e:
|
1341 |
st.error(f"🔴 Calculation error: {str(e)}")
|
|
|
1298 |
|
1299 |
if os.path.exists(traj_filename):
|
1300 |
try:
|
1301 |
+
from ase.io import read
|
1302 |
+
from ase.visualize import view
|
1303 |
+
import py3Dmol
|
1304 |
+
|
1305 |
+
trajectory = read(traj_filename, index=':')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1306 |
st.markdown("### Optimization Trajectory")
|
1307 |
st.write(f"Captured {len(trajectory)} optimization steps")
|
1308 |
+
|
1309 |
+
# Store the trajectory in session state
|
1310 |
+
if "traj_frames" not in st.session_state:
|
1311 |
+
st.session_state.traj_frames = trajectory
|
1312 |
+
st.session_state.traj_index = 0
|
1313 |
+
|
1314 |
+
# Navigation Buttons
|
1315 |
+
col1, col2, col3, col4 = st.columns(4)
|
1316 |
+
with col1:
|
1317 |
+
if st.button("⏮ First"):
|
1318 |
+
st.session_state.traj_index = 0
|
1319 |
+
with col2:
|
1320 |
+
if st.button("◀ Previous") and st.session_state.traj_index > 0:
|
1321 |
+
st.session_state.traj_index -= 1
|
1322 |
+
with col3:
|
1323 |
+
if st.button("Next ▶") and st.session_state.traj_index < len(st.session_state.traj_frames) - 1:
|
1324 |
+
st.session_state.traj_index += 1
|
1325 |
+
with col4:
|
1326 |
+
if st.button("Last ⏭"):
|
1327 |
+
st.session_state.traj_index = len(st.session_state.traj_frames) - 1
|
1328 |
+
|
1329 |
+
# Show current frame
|
1330 |
+
current_atoms = st.session_state.traj_frames[st.session_state.traj_index]
|
1331 |
+
st.write(f"Frame {st.session_state.traj_index + 1}/{len(st.session_state.traj_frames)}")
|
1332 |
+
|
1333 |
+
# Convert to xyz string for py3Dmol
|
1334 |
+
def atoms_to_xyz_string(atoms):
|
1335 |
+
xyz_str = f"{len(atoms)}\nStep {st.session_state.traj_index}, Energy = {atoms.get_potential_energy():.6f} eV\n"
|
1336 |
+
for atom in atoms:
|
1337 |
+
xyz_str += f"{atom.symbol} {atom.position[0]:.6f} {atom.position[1]:.6f} {atom.position[2]:.6f}\n"
|
1338 |
+
return xyz_str
|
1339 |
+
|
1340 |
+
xyz_str = atoms_to_xyz_string(current_atoms)
|
1341 |
+
view = py3Dmol.view(width=400, height=400)
|
1342 |
+
view.addModel(xyz_str, "xyz")
|
1343 |
+
view.setStyle({'stick': {}})
|
1344 |
+
view.zoomTo()
|
1345 |
+
view.setBackgroundColor("white")
|
1346 |
+
st.components.v1.html(view._make_html(), height=400, width=400)
|
1347 |
+
|
1348 |
+
# Download entire trajectory
|
1349 |
@st.fragment
|
1350 |
def show_trajectory_download_button():
|
1351 |
+
trajectory_xyz = ""
|
1352 |
+
for i, atoms in enumerate(st.session_state.traj_frames):
|
1353 |
+
trajectory_xyz += f"{len(atoms)}\nStep {i}, Energy = {atoms.get_potential_energy():.6f} eV\n"
|
1354 |
+
for atom in atoms:
|
1355 |
+
trajectory_xyz += f"{atom.symbol} {atom.position[0]:.6f} {atom.position[1]:.6f} {atom.position[2]:.6f}\n"
|
1356 |
st.download_button(
|
1357 |
label="Download Optimization Trajectory (XYZ)",
|
1358 |
data=trajectory_xyz,
|
|
|
1360 |
mime="chemical/x-xyz"
|
1361 |
)
|
1362 |
show_trajectory_download_button()
|
1363 |
+
|
|
|
1364 |
except Exception as e:
|
1365 |
st.warning(f"Could not process trajectory: {e}")
|
1366 |
+
|
1367 |
finally:
|
|
|
1368 |
os.unlink(traj_filename)
|
1369 |
+
|
1370 |
|
1371 |
except Exception as e:
|
1372 |
st.error(f"🔴 Calculation error: {str(e)}")
|