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)}")
|