import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from utils.data import (
FF_PERFORMANCE, ARRHENIUS_PARAMS, DFT_MECHANISMS,
SEI_MATERIALS, ML_MODELS, SIM_CAMPAIGN,
DFT_CONFIG_TYPES, DFT_FILE_FORMATS,
ELECTROLYTE_DECOMP, MECHANICAL_PROPS, THERMAL_SAFETY,
ANODE_MATERIALS, ADDITIVES, DECOMP_PRODUCTS,
REACTION_PATHWAYS, VALIDATION_RECS,
get_loss_curve, build_diffusion_table, build_arrhenius_lines,
build_strain_curves, build_eos_curves, build_rdf_data,
build_cycle_life_curves, build_rate_capability,
build_msd_curves, build_ion_mobility_map,
build_dendrite_risk, diffusion_coefficient, R_GAS,
# SIB cathode data
SIB_STRUCTURES, SIB_FORMATION_ENERGIES, SIB_AVG_CHARGES,
SIB_CATHODE_RANKING, SIB_DIFFUSION, SIB_VOLTAGE,
SIB_PIPELINE_STAGES, SIB_SCREENED,
build_bader_df,
)
from utils.plots import (
ff_performance_chart, loss_curve_chart, arrhenius_plot,
diffusion_bar_chart, strain_energy_plot, eos_plot, rdf_plot,
sei_ranking_chart, sei_radar, ml_model_scatter,
activation_energy_comparison, msd_plot,
cycle_life_plot, rate_capability_plot, thermal_safety_plot,
electrolyte_ranking_chart, anode_ranking_chart, additive_ranking_chart,
multi_objective_pareto, ion_mobility_plot, dendrite_risk_plot,
reaction_pathway_plot, mechanical_spider,
# SIB plots
sib_structure_overview, sib_lattice_radar, sib_bader_box,
sib_bader_heatmap, sib_charge_transfer_bar, sib_formation_energy_chart,
sib_cathode_ranking_chart, sib_cathode_radar, sib_diffusion_bar,
sib_screened_bubble, sib_pipeline_status,
)
st.set_page_config(
page_title="Battery-AI Simulation Engine ยท LiB + SIB",
page_icon="๐",
layout="wide",
initial_sidebar_state="expanded",
)
st.markdown("""
""", unsafe_allow_html=True)
# โโ Cache โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
@st.cache_data
def load_static():
return (
get_loss_curve(),
build_diffusion_table(),
build_arrhenius_lines(),
build_strain_curves(),
build_eos_curves(),
build_msd_curves(),
build_ion_mobility_map(),
build_dendrite_risk(),
build_cycle_life_curves(),
build_rate_capability(),
)
(loss_df, diff_df, arr_df, strain_df, eos_df,
msd_df, mob_df, dendrite_df, cycle_df, rate_df) = load_static()
# โโ Sidebar โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with st.sidebar:
st.markdown("## ๐ Battery-AI Engine")
st.caption("Force Field & Simulation Platform")
st.divider()
st.markdown("#### Global Filters")
sel_ff = st.multiselect(
"Force Fields",
["Yun et al.", "Wang et al.", "This Work"],
default=["Yun et al.", "Wang et al.", "This Work"],
)
sel_system = st.selectbox(
"Li System",
["LiF", "Liโ.โF (10% vacancies)", "Liโ.โF (10% interstitials)"],
)
sel_temp = st.select_slider("Temperature (K)", [300, 400, 500], value=300)
sel_rdf_ff = st.radio("RDF Force Field", ["This Work", "Yun et al."], horizontal=True)
st.divider()
st.markdown("#### Live Diffusivity Calculator")
c_T = st.slider("Temperature (K)", 250, 700, 300, step=10)
c_ff = st.selectbox("Force Field", ["This Work", "Yun et al.", "Wang et al."])
c_sys = st.selectbox("System",
["LiF", "Liโ.โF (10% vacancies)", "Liโ.โF (10% interstitials)"],
key="sb_sys")
_p = ARRHENIUS_PARAMS[c_sys][c_ff]
_D = diffusion_coefficient(_p["D0"], _p["Ea"], c_T)
st.metric(f"D at {c_T} K", f"{_D:.3e} cmยฒ/s", delta=f"Eโ = {_p['Ea']} kJ/mol")
st.divider()
st.markdown("#### ๐ท Na-Ion Battery")
sel_sib_mat = st.multiselect(
"SIB Cathode Materials",
["NaFePOโ", "NaโMnNiOโ"],
default=["NaFePOโ", "NaโMnNiOโ"],
key="sb_sib_mat",
)
st.divider()
st.caption("Battery-ION ยท LiB + SIB")
# โโ Header & KPIs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
st.title("๐ Battery-AI Force Field & Simulation Engine")
st.markdown(
"End-to-end AI platform: **DFT data โ ML force-field training โ MD simulation โ "
"battery property prediction โ ranked material recommendations.** "
"Covers both **Li-ion (LiB)** and **Na-ion (SIB)** cathode systems."
)
kpis = [
("DFT Simulations", "300+", "training database (LiB)"),
("SIB Structures", "4", "NaFePOโ + NaโMnNiOโ (UC + SC)"),
("Energy Rยฒ (New FF)", "0.293", "vs โ0.093 prior"),
("D @300K (LiF FF)", "3.44ร10โปโธ", "cmยฒ/s"),
("NaFePOโ Eform", "โ2.38 eV/atom", "DFT computed"),
("NaโMnNiOโ Eform", "โ1.542 eV/atom", "DFT computed"),
("NaFePOโ AI Score", "89/100", "AI cathode ranking"),
("Na D (b-axis)", "8.5ร10โปยนโฐ cmยฒ/s", "predicted ML-NEB"),
]
cols = st.columns(len(kpis))
for col, (label, val, sub) in zip(cols, kpis):
with col:
st.markdown(f"""
""", unsafe_allow_html=True)
st.markdown("
", unsafe_allow_html=True)
# โโ Tabs: 9 tabs โ 8 LiB + 1 new SIB (Na-Ion Battery) โโโโโโโโโโโโโโโโโโโโโโโโ
tabs = st.tabs([
"๐ Workflow Overview",
"๐ DFT Data Input",
"โก ML Force Field Trainer",
"๐ฌ MD Simulation Engine",
"๐ค AI Property Predictor",
"๐งช SEI Analysis",
"๐ AI Ranking Engine",
"๐ Deliverables & Validation",
"๐ท Na-Ion Battery (SIB)",
])
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 1 โ Workflow Overview
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[0]:
st.markdown('Core Workflow Pipeline
', unsafe_allow_html=True)
st.caption(
"The tool takes DFT data as input, then uses ML/AI to automate "
"force-field training, MD simulation, battery property prediction, and material ranking."
)
# Visual pipeline
pipeline_steps = [
("๐ฅ", "Input DFT Data",
"Energy, forces, charges, relaxed structures, defect structures, surfaces, strain data, diffusion pathways"),
("๐งน", "AI Data Processor",
"Cleans DFT data, checks quality, removes duplicates, labels configurations, builds training datasets"),
("๐ง ", "ML Force Field Training",
"Trains M3GNet / NequIP / CHGNet / DeepMD / SchNet / ALIGNN-FF. Also supports AI-assisted ReaxFF optimisation"),
("โ๏ธ", "AI Simulation Manager",
"Auto-runs: Li-ion diffusion ยท SEI formation ยท LiF stability ยท electrolyte decomposition ยท dendrite growth ยท anodeโcathode interface"),
("๐", "Battery Property Predictor",
"Predicts: ionic diffusivity ยท activation energy ยท SEI stability ยท decomp. risk ยท mechanical stability ยท thermal safety ยท cycle-life ยท capacity retention"),
("๐", "AI Ranking Engine",
"Multi-objective scoring of materials, electrolytes, additives. Final output: top candidates + predicted properties + ranked recommendations."),
]
for icon, title, body in pipeline_steps:
with st.expander(f"{icon} **{title}**", expanded=False):
st.markdown(body)
st.divider()
# Pipeline flow figure
fig_pipe = go.Figure()
labels = [s[1] for s in pipeline_steps]
x_pos = list(range(len(labels)))
fig_pipe.add_trace(go.Scatter(
x=x_pos, y=[1] * len(x_pos), mode="markers+text",
marker=dict(size=52, color=["#3A86FF","#8B5CF6","#FF4757","#F59E0B","#06B6D4","#4ade80"],
line=dict(width=2, color="#fff")),
text=[s[0] for s in pipeline_steps], textfont=dict(size=20),
hovertext=labels, hoverinfo="text",
))
for i, lbl in enumerate(labels):
fig_pipe.add_annotation(x=i, y=0.82, text=f"{lbl}",
showarrow=False, font=dict(size=10, color="#EEE"),
align="center")
for i in range(len(labels) - 1):
fig_pipe.add_annotation(x=i + 0.52, y=1, text="โ",
showarrow=False, font=dict(size=22, color="#aaa"))
fig_pipe.update_layout(
height=200, showlegend=False,
xaxis=dict(showgrid=False, zeroline=False, showticklabels=False, range=[-0.5, 5.5]),
yaxis=dict(showgrid=False, zeroline=False, showticklabels=False, range=[0.6, 1.2]),
plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
margin=dict(t=10, b=10, l=10, r=10),
)
st.plotly_chart(fig_pipe, use_container_width=True, key="pipeline_viz")
st.divider()
c1, c2 = st.columns(2)
with c1:
st.markdown("#### Tool Modules Summary")
modules = pd.DataFrame({
"Module": ["1. DFT Data Input", "2. AI Dataset Builder",
"3. ML Force Field Trainer", "4. MD Simulation Engine",
"5. AI Property Predictor", "6. Ranking & Report Generator"],
"Focus": ["Upload & validate DFT files", "Organise into 9 configuration types",
"Train M3GNet/CHGNet/NequIP/DeepMD", "NVT/NPT runs via LAMMPS",
"8 predicted battery properties", "Multi-objective material ranking"],
"Tech": ["ASE, pymatgen", "pymatgen, ASE", "PyTorch, ParAMS",
"LAMMPS, PACKMOL", "EinsteinโSmoluchowski, CI-NEB", "Streamlit, Plotly"],
})
st.dataframe(modules, use_container_width=True, hide_index=True)
with c2:
st.markdown("#### Final Tool Output (8 Deliverables)")
deliverables = pd.DataFrame({
"#": list(range(1, 9)),
"Deliverable": [
"Ranked battery material candidates",
"AI-trained force field model",
"MD simulation results",
"Diffusion coefficient & activation energy",
"SEI stability prediction",
"Electrolyte decomposition risk",
"LIB performance summary",
"Experimental validation roadmap",
],
"Tab": ["AI Ranking Engine", "ML FF Trainer", "MD Simulation Engine",
"AI Property Predictor", "SEI Analysis",
"AI Property Predictor", "Deliverables", "Deliverables"],
})
st.dataframe(deliverables, use_container_width=True, hide_index=True)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 2 โ DFT Data Input (Module 1 + 2)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[1]:
st.markdown('Module 1: DFT Data Upload
', unsafe_allow_html=True)
st.caption("Users upload DFT results in any of the supported formats. The AI Data Processor then validates, labels, and organises them into training groups.")
c1, c2 = st.columns([1, 1.2])
with c1:
st.markdown("#### Accepted File Formats")
st.dataframe(DFT_FILE_FORMATS, use_container_width=True, hide_index=True)
st.markdown("#### Simulated Upload Interface")
st.info("In the live tool, users drag-and-drop DFT files here. The processor auto-detects format and extracts energies, forces, and charges.")
uploaded = st.file_uploader(
"Upload DFT file (demo โ any file accepted for preview)",
type=["xyz","cif","txt","csv","json"],
accept_multiple_files=False,
)
if uploaded:
st.success(f"Received: **{uploaded.name}** ({uploaded.size:,} bytes) โ format auto-detected, queued for processing.")
else:
st.caption("No file uploaded โ showing database statistics below.")
with c2:
st.markdown("#### Training Database Quality Metrics")
quality = pd.DataFrame({
"Metric": ["Total DFT simulations", "Database entries (energy+force+charge)",
"Energy accuracy target", "Force accuracy target",
"Duplicate check", "Autocorrelation reduction", "Data accessibility"],
"Value": ["300+", "3,000+", "< 0.01 eV/atom", "< 5.1ร10โปยณ eV/ร
",
"Stochastic sampling", "Minimised by design", "Open-access"],
})
st.dataframe(quality, use_container_width=True, hide_index=True)
# Dataset composition pie
df_pie = DFT_CONFIG_TYPES.copy()
fig_pie = px.pie(df_pie, names="Configuration Type", values="Entries in DB",
title="DFT Database Composition by Configuration Type",
color_discrete_sequence=px.colors.qualitative.Plotly, hole=0.4)
fig_pie.update_layout(height=360, plot_bgcolor="rgba(0,0,0,0)",
paper_bgcolor="rgba(0,0,0,0)", font=dict(color="#EEE"),
legend=dict(bgcolor="rgba(0,0,0,0)", font=dict(size=10)),
margin=dict(t=50, b=10))
st.plotly_chart(fig_pie, use_container_width=True, key="db_pie")
st.divider()
st.markdown('Module 2: AI Dataset Builder โ 9 Configuration Types
',
unsafe_allow_html=True)
st.caption(
"Automatically creates training groups covering all battery-relevant phenomena. "
"ReaxFF/ML force fields fail if the training set does not cover the target phenomenon."
)
st.dataframe(DFT_CONFIG_TYPES, use_container_width=True, hide_index=True)
st.divider()
c1, c2 = st.columns(2)
with c1:
st.markdown("#### Database Configuration Counts")
fig_bar = px.bar(DFT_CONFIG_TYPES, x="Entries in DB", y="Configuration Type",
orientation="h", color="Configuration Type",
color_discrete_sequence=px.colors.qualitative.Plotly,
title="Entries per Configuration Type")
fig_bar.update_layout(height=360, showlegend=False,
plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
font=dict(color="#EEE"), margin=dict(t=45, b=10, l=220))
fig_bar.update_xaxes(gridcolor="rgba(255,255,255,0.1)")
st.plotly_chart(fig_bar, use_container_width=True, key="config_bar")
with c2:
st.markdown("#### Simulation Campaign Log")
st.dataframe(SIM_CAMPAIGN, use_container_width=True, hide_index=True)
st.markdown("""
**Key simulation parameters:**
- DFT code: VASP/BAND (PBE functional, DZ NAO basis)
- k-point accuracy: < 0.01 eV/atom
- ab initio MD: DFTB (Grimme xTB)
- LAMMPS ReaxFF-MD: 500 ps NVT, ฮดt = 0.25 fs
""")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 3 โ ML Force Field Trainer (Module 3)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[2]:
st.markdown('Module 3: ML Force Field Trainer
',
unsafe_allow_html=True)
st.caption(
"Trains AI force fields to replace expensive DFT. First version: "
"DFT data โ M3GNet / CHGNet / NequIP โ MD simulation. "
"Advanced: AI-assisted ReaxFF parameter optimisation via CMA-ES."
)
c1, c2 = st.columns([1.4, 1])
with c1:
st.markdown("#### Force Field Prediction Accuracy")
st.plotly_chart(ff_performance_chart(FF_PERFORMANCE), use_container_width=True, key="ff_perf")
with c2:
st.markdown("#### Metrics")
perf_df = pd.DataFrame(FF_PERFORMANCE).rename(columns={
"Force Field": "FF", "Energy Rยฒ": "E Rยฒ", "Energy RMSE (eV)": "E RMSE",
"Force Rยฒ": "F Rยฒ", "Force RMSE (eV/ร
)": "F RMSE"})
st.dataframe(perf_df.style.background_gradient(subset=["E Rยฒ","F Rยฒ"], cmap="RdYlGn"),
use_container_width=True, hide_index=True)
st.markdown("""
**Key finding:** Both Yun et al. and Wang et al. produce negative
energy Rยฒ (โ0.093) โ systematic failure to describe solid LiF.
The new FF reaches Rยฒ=0.293 for energy and 0.377 for forces,
recovering physical solid-state behaviour.
""")
st.divider()
st.markdown('CMA-ES Optimisation Convergence (1.3 ร 10โด iterations)
',
unsafe_allow_html=True)
st.plotly_chart(loss_curve_chart(loss_df), use_container_width=True, key="loss_curve")
st.caption("Bond interactions optimised first (0โ5,000 iter), then van der Waals (5,000โ13,000 iter). Angular/torsional terms could not converge โ degenerate loss gradients.")
st.divider()
st.markdown('ML Model Benchmark โ Energy MAE, Force MAE, Speed
',
unsafe_allow_html=True)
st.caption("Bubble size = inference speed (larger = faster). Recommended: CHGNet or NequIP for this dataset size (~3,000 entries).")
st.plotly_chart(ml_model_scatter(ML_MODELS), use_container_width=True, key="ml_scatter")
st.divider()
c1, c2 = st.columns(2)
with c1:
st.markdown("#### Model Specifications")
st.dataframe(ML_MODELS[["Model","Architecture","Energy MAE (meV/atom)","Force MAE (meV/ร
)","Rยฒ Energy"]],
use_container_width=True, hide_index=True)
with c2:
st.markdown("#### Recommended Training Pipeline")
st.markdown("""
**MVP (first version):**
1. DFT data โ **M3GNet / CHGNet / NequIP**
2. ~3,000 labelled configurations
3. Train energy + force head
4. Export as LAMMPS-compatible model
5. Run NVT MD at 300/400/500 K
**Advanced (ReaxFF path):**
1. DFT data โ **ParAMS + CMA-ES**
2. Step-wise: bonds โ vdW โ angles
3. Up to 13,000 optimisation iterations
4. Validate against CI-NEB barriers
**ReaxFF parameter categories:**
General (41) ยท Atoms (32/type) ยท Bonds (16/bond) ยท
Off-diagonal (6) ยท Angles (7) ยท Dihedral (7) ยท H-bonds (4)
""")
st.divider()
st.markdown("#### CI-NEB Energy Barrier Comparison")
neb_data = pd.DataFrame({
"Mechanism": ["Vacancy", "Direct-hopping", "Knock-off (est.)"],
"DFT Zheng et al. (kJ/mol)": [63.7, 52.1, 24.1],
"DFT this work (kJ/mol)": [64.3, 87.5, "โ"],
"New ReaxFF MD Eโ (kJ/mol)": [11.0, 11.0, 11.0],
"Status": ["Underestimated 5.8ร", "Underestimated 8ร", "Underestimated 2.2ร"],
})
st.dataframe(neb_data, use_container_width=True, hide_index=True)
st.warning("Activation energies from MD are still 2โ8ร below DFT CI-NEB barriers. Future training sets must explicitly include Li-transport pathway configurations.")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 4 โ MD Simulation Engine (Module 4)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[3]:
st.markdown('Module 4: AI Simulation Manager
',
unsafe_allow_html=True)
st.caption(
"Auto-runs: NVT/NPT ยท Li-ion diffusion ยท SEI interface ยท "
"electrolyte decomposition ยท LiF stability ยท anodeโelectrolyte interface ยท dendrite growth"
)
subtab_md = st.tabs(["๐ Diffusion & Arrhenius", "๐ฌ Crystal Stability", "๐ก๏ธ RDF Evolution",
"๐ MSD Analysis", "โ ๏ธ Dendrite Growth Risk"])
# โโ MD Sub-tab 1: Diffusion
with subtab_md[0]:
c_a, c_b = st.columns(2)
with c_a:
filtered_arr = arr_df[
arr_df["Force Field"].isin(sel_ff) | (arr_df["Force Field"] == "DFT reference")
]
st.plotly_chart(arrhenius_plot(filtered_arr, sel_system),
use_container_width=True, key="arrhenius")
with c_b:
filtered_diff = diff_df[diff_df["Force Field"].isin(sel_ff)]
st.plotly_chart(diffusion_bar_chart(filtered_diff, sel_temp),
use_container_width=True, key="diff_bar")
st.plotly_chart(activation_energy_comparison(), use_container_width=True, key="ea_comp")
st.markdown("#### Diffusion Data Table")
disp = diff_df[diff_df["Force Field"].isin(sel_ff)].copy()
disp["D (cmยฒ/s)"] = disp["D (cmยฒ/s)"].apply(lambda x: f"{x:.3e}")
st.dataframe(disp[["System","Force Field","Temperature (K)","D (cmยฒ/s)","logโโ(D)"]]
.sort_values(["System","Force Field","Temperature (K)"]),
use_container_width=True, hide_index=True)
st.markdown("""
**New FF at 300 K (LiF):** D = 3.44 ร 10โปโธ cmยฒ/s โ ~1000ร lower than Yun/Wang (3.56 ร 10โปโต cmยฒ/s).
Electrolyte Liโบ diffusivity: 0.5โ1.4 ร 10โปโต cmยฒ/s.
New FF correctly places LiF in the solid-state regime.
""")
# โโ MD Sub-tab 2: Crystal Stability
with subtab_md[1]:
c1, c2 = st.columns(2)
with c1:
st.plotly_chart(strain_energy_plot(strain_df), use_container_width=True, key="strain")
st.caption("Shear strain ฮตโโ โ old FFs show inverted concavity (negative cโโ elastic constant). New FF recovers parabolic minimum near equilibrium.")
with c2:
st.plotly_chart(eos_plot(eos_df), use_container_width=True, key="eos")
st.caption("Murnaghan EOS โ old FFs: no energy minimum. New FF agrees with DFT even at ยฑ30% volume change.")
st.markdown("#### LiF Crystal Phases (Materials Project data)")
crystal_data = pd.DataFrame({
"Phase": ["Stable FCC (Fm3ฬm)", "Metastable HEX (P6โmc)", "Metastable BCC (Pm3ฬm)"],
"Space Group": ["Fm3ฬm", "P6โmc", "Pm3ฬm"],
"Lattice": ["Face-Centered Cubic", "Hexagonal", "Body-Centered Cubic"],
"Formation Energy (DFT, eV)": [-4.31, -4.18, -3.95],
"First LiโF Distance (ร
)": [2.01, 1.96, 2.08],
"New FF Accuracy": ["Excellent", "Good", "Moderate"],
})
st.dataframe(crystal_data, use_container_width=True, hide_index=True)
# โโ MD Sub-tab 3: RDF
with subtab_md[2]:
st.caption("LiโF g(r) during 500 ps NVT at 300 K. Crystalline LiF: sharp peaks at 2.01 ร
, 4.02 ร
, 5.69 ร
. LiF melt point = 1121 K โ any amorphization at 300 K is unphysical.")
rdf_sel = build_rdf_data(sel_rdf_ff)
st.plotly_chart(rdf_plot(rdf_sel, sel_rdf_ff), use_container_width=True, key="rdf_sel")
c1, c2 = st.columns(2)
with c1:
st.markdown("#### Old FFs โ Amorphization within 2 ps")
rdf_old = build_rdf_data("Yun et al.")
st.plotly_chart(rdf_plot(rdf_old, "Yun et al."), use_container_width=True, key="rdf_old")
with c2:
st.markdown("#### New FF โ Crystalline Order Preserved")
rdf_new = build_rdf_data("This Work")
st.plotly_chart(rdf_plot(rdf_new, "This Work"), use_container_width=True, key="rdf_new")
# โโ MD Sub-tab 4: MSD
with subtab_md[3]:
st.caption("MSD slope = 6D (EinsteinโSmoluchowski). New FF gives 100โ1000ร lower slope โ correct solid-state Li transport.")
st.plotly_chart(msd_plot(msd_df), use_container_width=True, key="msd_plot")
st.markdown("""
**Diffusion from MSD:** D = ฮฑโ/6, where ฮฑโ is the MSD linear slope (least-squares fit).
Simulations run for 500 ps; MSD sampled every 50 steps (12.5 fs interval).
""")
# โโ MD Sub-tab 5: Dendrite
with subtab_md[4]:
st.caption("Higher overpotential for Li plating โ greater dendrite nucleation risk. LiF-rich SEI suppresses dendrites by providing uniform Liโบ flux (low local overpotential).")
st.plotly_chart(dendrite_risk_plot(dendrite_df), use_container_width=True, key="dendrite")
st.markdown("""
**Dendrite mechanism:** Non-uniform SEI creates hotspots of high local current density,
lowering the nucleation barrier. LiF-rich SEI (uniform, mechanically stiff) distributes
Liโบ flux evenly, raising the overpotential threshold for dendrite nucleation.
**SEI role:** Mechanical stiffness of LiF (Young's modulus 109 GPa) suppresses dendrite
penetration, while high ionic conductivity reduces local current hotspots.
""")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 5 โ AI Property Predictor (Module 5) โ all 8 properties
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[4]:
st.markdown('Module 5: AI Property Predictor โ 8 Battery Properties
',
unsafe_allow_html=True)
prop_tabs = st.tabs([
"โก Ionic Diffusivity", "๐ฅ Activation Energy",
"๐ก๏ธ SEI Stability", "๐ฅ Electrolyte Decomp. Risk",
"๐ช Mechanical Stability", "๐ก๏ธ Thermal Safety",
"โป๏ธ Cycle-Life Risk", "๐ Capacity Retention",
])
# โโ P1: Ionic Diffusivity
with prop_tabs[0]:
st.markdown("**Predicted by:** Arrhenius D = Dโ ยท exp(โEโ/RT) from MSD slopes")
c1, c2 = st.columns(2)
with c1:
arr_filt = arr_df[arr_df["Force Field"].isin(sel_ff) | (arr_df["Force Field"] == "DFT reference")]
st.plotly_chart(arrhenius_plot(arr_filt, sel_system), use_container_width=True, key="prop_arrh")
with c2:
st.metric("D (LiF, 300K, New FF)", "3.44 ร 10โปโธ cmยฒ/s", delta="~1000ร lower than prior FFs")
st.metric("D (LiF, 300K, Yun/Wang)", "3.56 ร 10โปโต cmยฒ/s", delta="โ electrolyte-like โ unphysical")
st.metric("D (electrolyte Liโบ)", "0.5โ1.4 ร 10โปโต cmยฒ/s", delta="Ref. Lee et al. 2002")
st.markdown("New FF correctly places LiF in the **solid-state regime**, 2 orders of magnitude below the electrolyte.")
# โโ P2: Activation Energy
with prop_tabs[1]:
st.markdown("**Predicted by:** Arrhenius slope = โEโ/R from log(D) vs 1/T linear regression")
st.plotly_chart(activation_energy_comparison(), use_container_width=True, key="prop_ea")
st.dataframe(pd.DataFrame({
"System": ["LiF","LiF","LiF","Liโ.โF","Liโ.โF","Liโ.โF","Liโ.โF","Liโ.โF","Liโ.โF"],
"Force Field": ["Yun et al.","Wang et al.","This Work"]*3,
"Eโ (kJ/mol)": [7.50,7.0,11.0,7.1,6.810,5.1,7.6,6.22,6.0],
"Eโ err (kJ/mol)": [0.02,0.2,1.6,1.4,0.013,0.5,0.5,0.04,0.8],
}), use_container_width=True, hide_index=True)
st.warning("All FF Eโ values (5โ11 kJ/mol) are well below the DFT CI-NEB barriers (24โ87 kJ/mol). Activation energies are underestimated โ future training must include transport-pathway configurations.")
# โโ P3: SEI Stability
with prop_tabs[2]:
st.markdown("**Predicted by:** Multi-criteria scoring (ionic conductivity, electronic insulation, mechanical, thermal)")
c1, c2 = st.columns([1.3, 1])
with c1:
st.plotly_chart(sei_ranking_chart(SEI_MATERIALS), use_container_width=True, key="prop_sei_rank")
with c2:
radar_sel = st.multiselect("Compare components (radar)",
SEI_MATERIALS["Component"].tolist(),
default=["LiF (FEC-derived)","LiโCOโ","LiโO"],
key="prop_radar_sel")
if radar_sel:
st.plotly_chart(sei_radar(SEI_MATERIALS, radar_sel),
use_container_width=True, key="prop_radar")
# โโ P4: Electrolyte Decomp. Risk
with prop_tabs[3]:
st.markdown("**Predicted by:** Decomposition onset voltage, ionic conductivity, electrochemical window, temperature stability")
st.plotly_chart(electrolyte_ranking_chart(ELECTROLYTE_DECOMP),
use_container_width=True, key="prop_elec_rank")
st.dataframe(ELECTROLYTE_DECOMP[["Electrolyte","Decomp. Onset (V vs Li/Liโบ)",
"Decomp. Risk Score (1=low)","LiF SEI Formation?",
"Ionic Conductivity (mS/cm)","Decomp. Products"]],
use_container_width=True, hide_index=True)
st.markdown("""
**FEC advantage:** 1M LiPFโ + 10% FEC has the lowest decomp. risk score (3.1) and highest LiF SEI yield
among liquid electrolytes. FEC decomposes selectively to produce LiF-dominant SEI,
confirmed by DFT and ReaxFF simulations.
""")
st.markdown("#### Decomposition Products by Precursor")
st.dataframe(DECOMP_PRODUCTS, use_container_width=True, hide_index=True)
st.markdown("#### Reaction Pathway: FEC โ LiF")
st.plotly_chart(reaction_pathway_plot(REACTION_PATHWAYS),
use_container_width=True, key="prop_rxn_path")
# โโ P5: Mechanical Stability
with prop_tabs[4]:
st.markdown("**Predicted by:** Elastic constants from energy-strain DFT calculations (Cโโ, Cโโ, Cโโ for FCC LiF)")
mech_sel = st.multiselect("Select materials for radar",
MECHANICAL_PROPS["Material"].tolist(),
default=["LiF","LiโCOโ","Graphite anode","Silicon anode"],
key="mech_sel")
if mech_sel:
st.plotly_chart(mechanical_spider(MECHANICAL_PROPS, mech_sel),
use_container_width=True, key="prop_mech_radar")
st.dataframe(MECHANICAL_PROPS, use_container_width=True, hide_index=True)
st.info("**LiF Young's modulus: 109 GPa** โ stiffest SEI component. Suppresses dendrite penetration and accommodates volume changes better than organic components.")
# โโ P6: Thermal Safety
with prop_tabs[5]:
st.markdown("**Predicted by:** Thermal decomposition onset temperatures from literature + ReaxFF thermal MD")
st.plotly_chart(thermal_safety_plot(THERMAL_SAFETY), use_container_width=True, key="prop_thermal")
st.dataframe(THERMAL_SAFETY, use_container_width=True, hide_index=True)
st.success("**LiF melting point: 1121.35 K (848 ยฐC)** โ far above all operating temperatures. The highest thermal stability of any SEI component.")
st.error("**Thermal runaway onset: ~130 ยฐC** โ triggered by SEI breakdown releasing exothermic energy. LiF-rich SEI delays this onset by ~20โ40 ยฐC vs. organic-dominated SEI.")
# โโ P7: Cycle-Life Risk
with prop_tabs[6]:
st.markdown("**Predicted by:** SEI growth model โ capacity fade rate โ SEI decomposition frequency")
st.plotly_chart(cycle_life_plot(cycle_df), use_container_width=True, key="prop_cycle")
st.markdown("""
**Key predictions:**
- LiF-rich SEI: >88% capacity retention after 200 cycles, >80% after 500 cycles
- Artificially engineered LiF SEI: >90% after 500 cycles
- No SEI engineering: drops below 80% (EOL) around cycle 200
- End-of-Life threshold (80%) used per IEC 62660-2 standard
""")
# โโ P8: Capacity Retention (Rate Capability)
with prop_tabs[7]:
st.markdown("**Predicted by:** Rate capability from MD-derived diffusion coefficients at different C-rates")
st.plotly_chart(rate_capability_plot(rate_df), use_container_width=True, key="prop_rate")
st.markdown("""
**Interpretation:**
- LiF SEI maintains higher capacity at high C-rates due to lower Liโบ transport resistance
- Si anode shows dramatic capacity drop above 2C โ volume expansion disrupts SEI continuity
- Li metal + LiF SEI: best absolute capacity and rate performance (no anode volume change)
""")
st.markdown("#### Ion Mobility Map โ Liโบ Through SEI Depth")
st.plotly_chart(ion_mobility_plot(mob_df), use_container_width=True, key="prop_mob")
st.caption("Inorganic LiF inner layer (0โ5 nm): D โ 3.44ร10โปโธ cmยฒ/s. Mixed zone (5โ12 nm): gradient. Organic outer layer (12โ20 nm): D โ 22ร10โปโธ cmยฒ/s.")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 6 โ SEI Analysis
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[5]:
st.markdown('SEI Component Analysis & LiF Formation
',
unsafe_allow_html=True)
c1, c2 = st.columns([1.3, 1])
with c1:
st.plotly_chart(sei_ranking_chart(SEI_MATERIALS), use_container_width=True, key="sei_rank")
with c2:
st.markdown("#### Scoring Weights")
st.markdown("""
| Property | Weight |
|---|---|
| Electronic Insulation | 30% |
| Ionic Conductivity | 25% |
| Mechanical Stability | 20% |
| Thermal Stability | 15% |
| Decomp. Risk (โ) | 10% |
""")
st.info("**LiF** scores highest: exceptional electronic insulation (9.8/10), "
"high ionic transport, lowest decomp. risk. Ko & Yoon, Ceram. Int. 2019.")
st.divider()
c1, c2 = st.columns(2)
with c1:
radar_sei = st.multiselect("Radar โ select components",
SEI_MATERIALS["Component"].tolist(),
default=["LiF (FEC-derived)","LiโCOโ","LiโO"],
key="sei_tab_radar")
if radar_sei:
st.plotly_chart(sei_radar(SEI_MATERIALS, radar_sei),
use_container_width=True, key="sei_radar_tab")
with c2:
st.markdown("#### Full SEI Dataset")
st.dataframe(
SEI_MATERIALS.style.background_gradient(subset=["Overall Score"], cmap="RdYlGn"),
use_container_width=True, hide_index=True)
st.divider()
st.markdown("#### FEC Decomposition โ LiF Formation Pathway")
st.plotly_chart(reaction_pathway_plot(REACTION_PATHWAYS),
use_container_width=True, key="sei_rxn_path")
st.dataframe(REACTION_PATHWAYS, use_container_width=True, hide_index=True)
st.divider()
st.markdown("#### Ion Mobility Through SEI Layers")
st.plotly_chart(ion_mobility_plot(mob_df), use_container_width=True, key="sei_mob")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 7 โ AI Ranking Engine (Module 6)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[6]:
st.markdown('Module 6: AI Ranking Engine โ Multi-Objective Material Scoring
',
unsafe_allow_html=True)
st.caption(
"Ranks materials, additives, and electrolytes using multi-objective scoring. "
"Final output: top battery candidates + predicted properties + simulation evidence + ranked recommendations."
)
rank_tabs = st.tabs(["๐งช SEI Components", "๐ Electrolytes", "โก Anode Materials", "โ Additives", "๐ Pareto Analysis"])
# โโ R1: SEI
with rank_tabs[0]:
st.plotly_chart(sei_ranking_chart(SEI_MATERIALS), use_container_width=True, key="rank_sei")
st.dataframe(SEI_MATERIALS.sort_values("Overall Score", ascending=False),
use_container_width=True, hide_index=True)
# โโ R2: Electrolytes
with rank_tabs[1]:
st.plotly_chart(electrolyte_ranking_chart(ELECTROLYTE_DECOMP),
use_container_width=True, key="rank_elec")
st.dataframe(
ELECTROLYTE_DECOMP[["Electrolyte","Overall Score","Decomp. Risk Score (1=low)",
"Ionic Conductivity (mS/cm)","Electrochemical Window (V)",
"Temperature Stability (ยฐC)","LiF SEI Formation?","Decomp. Products"]]
.sort_values("Overall Score", ascending=False),
use_container_width=True, hide_index=True,
)
st.success("**Top recommendation:** 1M LiPFโ + 10% FEC in EC/DMC โ highest LiF SEI formation, lowest decomp. risk among liquid electrolytes. Confirmed by FEC โ LiF reaction pathway simulations.")
# โโ R3: Anode Materials
with rank_tabs[2]:
st.plotly_chart(anode_ranking_chart(ANODE_MATERIALS), use_container_width=True, key="rank_anode")
st.dataframe(ANODE_MATERIALS.sort_values("Overall Score", ascending=False),
use_container_width=True, hide_index=True)
st.markdown("""
**Volume expansion** is the critical challenge for Si and Sn anodes โ disrupts SEI continuity every cycle.
The LiF SEI is more resilient to volume changes than organic SEI due to its high Young's modulus (109 GPa).
""")
# โโ R4: Additives
with rank_tabs[3]:
st.plotly_chart(additive_ranking_chart(ADDITIVES), use_container_width=True, key="rank_add")
st.dataframe(ADDITIVES.sort_values("Overall Score", ascending=False),
use_container_width=True, hide_index=True)
st.success("**FEC (fluoroethylene carbonate)** is the top-ranked additive: highest LiF SEI enhancement (9.5/10), 35% cycle-life improvement, HF scavenging capability confirmed by simulation.")
# โโ R5: Pareto
with rank_tabs[4]:
st.markdown("#### Multi-Objective Pareto โ Capacity vs. Volume Expansion (bubble = cycle stability)")
st.plotly_chart(multi_objective_pareto(ANODE_MATERIALS), use_container_width=True, key="pareto")
st.caption("Ideal anode: upper-left corner (high capacity, low expansion). Bubble size = cycle stability score. Graphite + LiF SEI is the most practical current choice.")
st.divider()
st.markdown("#### Electrolyte Score Decomposition")
elec_fig = px.bar(
ELECTROLYTE_DECOMP.melt(id_vars=["Electrolyte"],
value_vars=["Ionic Conductivity (mS/cm)",
"Electrochemical Window (V)",
"Temperature Stability (ยฐC)"]),
x="Electrolyte", y="value", color="variable", barmode="group",
title="Electrolyte Property Comparison",
color_discrete_sequence=px.colors.qualitative.Plotly,
)
elec_fig.update_layout(height=380, plot_bgcolor="rgba(0,0,0,0)",
paper_bgcolor="rgba(0,0,0,0)", font=dict(color="#EEE"),
legend=dict(bgcolor="rgba(0,0,0,0)"),
xaxis=dict(tickangle=-20), margin=dict(t=55, b=60))
elec_fig.update_xaxes(gridcolor="rgba(255,255,255,0.1)")
elec_fig.update_yaxes(gridcolor="rgba(255,255,255,0.1)")
st.plotly_chart(elec_fig, use_container_width=True, key="elec_decomp_bar")
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 8 โ Final Report & Experimental Validation
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[7]:
st.markdown('Final Tool Output โ 8 Deliverables
',
unsafe_allow_html=True)
deliverable_details = [
("1", "Ranked Battery Material Candidates",
"SEI: LiF > LiโCOโ > LiโO. Electrolyte: FEC-based > standard EC/DMC. Anode: Graphite (near-term), Li metal (future). Additive: FEC (35% cycle-life improvement).",
"๐"),
("2", "AI-Trained Force Field Model",
"New ReaxFF: E Rยฒ=0.293, F Rยฒ=0.377. D(300K)=3.44ร10โปโธ cmยฒ/s โ 1000ร improvement. Available: CHGNet/NequIP models trained on 3,000+ DFT configurations.",
"๐ง "),
("3", "MD Simulation Results",
"500 ps NVT at 300/400/500 K. Systems: LiF, Liโ.โF, Liโ.โF. RDF confirms crystalline order preservation. MSD confirms correct solid-state diffusion.",
"โ๏ธ"),
("4", "Diffusion Coefficient & Activation Energy",
"D(LiF,300K) = 3.44ร10โปโธ cmยฒ/s. Eโ(LiF) = 11.0 ยฑ 1.6 kJ/mol. CI-NEB barriers: vacancy 64.3 kJ/mol, direct-hop 87.5 kJ/mol (still underestimated by FF).",
"๐"),
("5", "SEI Stability Prediction",
"LiF: Overall Score 8.65/10. Electronic insulation 9.8/10. Thermal onset 842ยฐC. Mechanical stiffness 109 GPa (Young's modulus). Best SEI component for LIBs.",
"๐ก๏ธ"),
("6", "Electrolyte Decomposition Risk",
"EC/DMC+FEC: Decomp. risk 3.1/10 (lowest liquid). Onset 1.1 V vs Li/Liโบ. Primary products: LiF (dominant), LiโCOโ. Solid electrolytes (LGPS): risk 1.5/10.",
"๐ฅ"),
("7", "LIB Performance Summary",
"Capacity retention: LiF SEI >88% @200cy, >80% @500cy. Rate capability: LiF SEI maintains 300 mAh/g @10C (graphite). Thermal runaway delayed by ~30ยฐC with LiF SEI.",
"๐"),
("8", "Experimental Validation Recommendations",
"8 prioritised experiments: XPS depth profiling, cryo-TEM, EIS, EELS, in-situ NMR, GITT, ARC calorimetry, long-term cycling. See table below.",
"๐ฌ"),
]
for num, title, details, icon in deliverable_details:
with st.expander(f"{icon} **{num}. {title}**", expanded=(num == "1")):
st.markdown(details)
st.divider()
st.markdown('Experimental Validation Roadmap
',
unsafe_allow_html=True)
st.dataframe(VALIDATION_RECS, use_container_width=True, hide_index=True)
st.divider()
st.markdown('MVP โ Full Production Roadmap
',
unsafe_allow_html=True)
roadmap = pd.DataFrame({
"Phase": ["MVP (now)", "Phase 2", "Phase 3", "Phase 4"],
"Focus": [
"LiF-rich SEI in Li-ion battery (graphite anode)",
"Expand SEI: LiโCOโ, LiโO, organic components",
"Si & Li-metal anodes โ large volume expansion",
"Full battery pack: multi-scale โ system level",
],
"New Training Data": [
"300+ DFT for LiF (done)",
"+500 DFT: LiโCOโ, LiโO, organic ROCOโLi",
"+1000 DFT: Si-Li, Li-Li, large supercells",
"Continuum + atomistic coupling",
],
"ML Model": [
"ReaxFF (CMA-ES) / CHGNet / NequIP",
"NequIP / DeepMD on multi-component SEI",
"Graph NN with large-cell support",
"Multi-scale ML + FEM coupling",
],
"Target": [
"D within 2ร of CI-NEB; >88% cap. retention",
"Mixed SEI composition prediction",
"Volume expansion + dendrite model",
"Thermal + electrochemical cell model",
],
})
st.dataframe(roadmap, use_container_width=True, hide_index=True)
st.divider()
st.markdown('ReaxFF Parameter Summary
', unsafe_allow_html=True)
c1, c2 = st.columns(2)
with c1:
param_data = pd.DataFrame({
"Type": ["General", "Atoms (per NA)", "Bonds (per bond)", "Off-diagonal", "Angles", "Dihedral", "H-bonds"],
"Parameters per entry": [41, 32, 16, 6, 7, 7, 4],
})
fig_params = px.bar(param_data, x="Type", y="Parameters per entry",
color="Type", title="ReaxFF Coefficient Distribution",
color_discrete_sequence=px.colors.qualitative.Plotly)
fig_params.update_layout(height=300, showlegend=False,
plot_bgcolor="rgba(0,0,0,0)", paper_bgcolor="rgba(0,0,0,0)",
font=dict(color="#EEE"), margin=dict(t=45, b=40))
fig_params.update_xaxes(gridcolor="rgba(255,255,255,0.1)")
fig_params.update_yaxes(gridcolor="rgba(255,255,255,0.1)")
st.plotly_chart(fig_params, use_container_width=True, key="reaxff_params")
with c2:
st.markdown("#### ReaxFF Coefficient Breakdown")
coeff_df = pd.DataFrame({
"Type": ["General", "Atoms", "Bonds", "Off-diagonal", "Angles", "Dihedral", "H-bonds"],
"Count": [41, 32, 16, 6, 7, 7, 4],
"Description": [
"Global FF parameters",
"Per atomic species",
"Per bond pair",
"Cross terms",
"3-body interactions",
"4-body torsional",
"Hydrogen-bond terms",
],
})
st.dataframe(coeff_df, use_container_width=True, hide_index=True)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# TAB 9 โ Na-Ion Battery (SIB)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with tabs[8]:
st.markdown('Na-Ion Battery (SIB) โ DFT Cathode Data
',
unsafe_allow_html=True)
st.markdown(
"DFT-computed data for two sodium-ion cathode materials: **NaFePOโ** and **NaโMnNiOโ**. "
"The 8-stage AI pipeline maps each DFT result to a specific AI workflow stage โ "
"from structure encoding to intelligent cathode ranking."
)
# Sub-tabs within the SIB tab
sib_tabs = st.tabs([
"๐ DFT Database",
"โก Formation Energy",
"๐ฌ Bader Charge Analysis",
"๐ Na Diffusion",
"๐ Cathode Ranking",
"๐ค AI Pipeline",
"๐ฎ AI Screening",
"๐ Voltage & Capacity",
])
# โโ SIB Sub-tab 1: DFT Database โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[0]:
st.markdown("### Crystal Structure Database")
st.markdown(
"Four fully-relaxed DFT structures computed with VASP (GGA+U), "
"forming the **seed dataset** for the Battery Foundation Model."
)
# KPI row for SIB structures
sib_kpis = [
("NaFePOโ Unit Cell", "28 atoms", "a=5.10, b=6.94, c=9.11 ร
"),
("NaFePOโ Supercell", "128 atoms", "2ร2ร1 ยท โ746.93 eV"),
("NaโMnNiOโ Unit Cell", "24 atoms", "a=b=3.052, c=32.148 ร
ยท hexagonal"),
("NaโMnNiOโ Supercell", "96 atoms", "2ร2ร1 ยท โ517.270 eV"),
]
sib_kcols = st.columns(4)
for col, (lbl, val, sub) in zip(sib_kcols, sib_kpis):
with col:
st.markdown(f"""
""", unsafe_allow_html=True)
st.markdown("
", unsafe_allow_html=True)
st.markdown("#### Structure Summary Table")
st.dataframe(
SIB_STRUCTURES.style.background_gradient(
subset=["Total Energy (eV)", "Formation Energy (eV/atom)"], cmap="Blues"
),
use_container_width=True,
)
st.markdown("#### Total Energy & Formation Energy Comparison")
st.plotly_chart(sib_structure_overview(SIB_STRUCTURES), use_container_width=True,
key="sib_structure_overview")
st.markdown("#### Lattice Parameter Radar")
all_mats = SIB_STRUCTURES["Material"].tolist()
sel_mats_radar = st.multiselect(
"Select structures", all_mats, default=all_mats[:2], key="sib_lat_radar_sel"
)
if sel_mats_radar:
st.plotly_chart(sib_lattice_radar(SIB_STRUCTURES, sel_mats_radar),
use_container_width=True, key="sib_lattice_radar")
st.markdown("#### Key Structural Properties")
st.info("""
**NaFePOโ (Olivine structure):**
- Orthorhombic symmetry (Pnma) ยท all angles 90ยฐ
- Strong 1D diffusion channels along b-axis (shortest path Na โ vacancy)
- Supercell 2ร2ร1: 128 atoms ideal for Na diffusion MD simulations
**NaโMnNiOโ (Layered oxide):**
- Hexagonal symmetry ยท ฮณ=120ยฐ ยท large c-axis (32 ร
)
- 2D diffusion in ab-plane; c-axis interlayer hopping limited
- Mnยณโบ/Niยฒโบ redox centres โ higher voltage potential (3.45 V)
""")
# โโ SIB Sub-tab 2: Formation Energy โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[1]:
st.markdown("### Formation Energy Analysis โ Stage 3: Formation Energy Predictor")
st.markdown(
"Formation energies from DFT calculations are used to train an AI model that "
"can screen **millions of hypothetical cathodes** without running DFT."
)
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("NaFePOโ Eform", "โ2.38 eV/atom", "DFT")
with col2:
st.metric("NaโMnNiOโ Eform", "โ1.542 eV/atom", "DFT")
with col3:
st.metric("NaโVโ(POโ)โ Eform", "โ2.85 eV/atom", "Literature reference")
with col4:
st.metric("Stability rank: NaFePOโ", "#2 of 8", "Most stable DFT-computed")
st.plotly_chart(sib_formation_energy_chart(SIB_FORMATION_ENERGIES),
use_container_width=True, key="sib_form_e")
st.markdown("#### Formation Energy Table")
st.dataframe(
SIB_FORMATION_ENERGIES.style.background_gradient(
subset=["Formation Energy (eV/atom)"], cmap="Greens_r"
),
use_container_width=True,
)
st.info(
"**Interpretation:** More negative Eform = thermodynamically more stable. "
"NaFePOโ (โ2.38 eV/atom) is significantly more stable than NaโMnNiOโ (โ1.542 eV/atom). "
"The AI formation energy predictor learns from these two ground-truth points to "
"extrapolate across the composition space."
)
# โโ SIB Sub-tab 3: Bader Charge Analysis โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[2]:
st.markdown("### Bader Charge Analysis โ Stage 4: Charge Distribution Model")
st.markdown(
"Bader charges computed from DFT calculations are targets for the AI charge "
"distribution model. These predict **oxidation state, charge transfer, and redox activity** "
"โ critical inputs to the voltage predictor."
)
bader_df = build_bader_df()
st.markdown("#### Average Charges Heatmap (all 4 structures)")
st.plotly_chart(sib_bader_heatmap(bader_df), use_container_width=True,
key="sib_bader_heatmap")
st.markdown("#### Average Cation Charges Comparison")
st.plotly_chart(sib_charge_transfer_bar(bader_df), use_container_width=True,
key="sib_charge_transfer")
st.markdown("#### Per-atom Bader Charge Distribution")
sib_mat_sel = st.selectbox(
"Select material", ["NaFePOโ", "NaโMnNiOโ"],
key="sib_bader_mat_sel"
)
sib_struct_sel = st.radio(
"Select structure",
["Unit Cell", "Supercell 2ร2ร1"],
horizontal=True, key="sib_bader_struct_sel"
)
struct_label = (
f"Unit Cell ({28 if sib_mat_sel == 'NaFePOโ' else 24} atoms)"
if sib_struct_sel == "Unit Cell"
else f"Supercell 2ร2ร1 ({128 if sib_mat_sel == 'NaFePOโ' else 96} atoms)"
)
sub_bader = bader_df[
(bader_df["Material"] == sib_mat_sel) &
(bader_df["Structure"] == struct_label)
]
if not sub_bader.empty:
st.plotly_chart(sib_bader_box(sub_bader.assign(Material=sib_mat_sel), sib_mat_sel),
use_container_width=True, key="sib_bader_box")
st.markdown("#### Summary Table โ Average Charges")
st.dataframe(SIB_AVG_CHARGES, use_container_width=True)
st.info("""
**Key charge insights:**
- **Naโบ in NaFePOโ:** +0.890 e โ consistent with Naโบ ionic character
- **Fe in NaFePOโ:** +1.486 e โ confirms Feยฒโบ oxidation state (partially covalent FeโO bonds)
- **P in NaFePOโ:** +5.0 e โ fully ionic Pโตโบ (phosphate POโยณโป group)
- **Mn in NaโMnNiOโ:** +1.729 e โ Mnยณโบ state; active redox centre
- **Ni in NaโMnNiOโ:** +1.283 e โ Niยฒโบ state; will oxidize to Niยณโบ on desodiation
- **O charge range:** โ1.13 to โ1.87 e โ wider range in NaFePOโ (multiple O environments)
""")
# โโ SIB Sub-tab 4: Na Diffusion โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[3]:
st.markdown("### Naโบ Diffusion Prediction โ Stage 5: Sodium Diffusion Prediction")
st.markdown(
"Using the 128-atom NaFePOโ and 96-atom NaโMnNiOโ supercells, Na vacancy and "
"interstitial migration pathways are generated. ML-NEB predicts migration barriers "
"and diffusion coefficients."
)
c1, c2, c3, c4 = st.columns(4)
with c1:
st.metric("Best D (NaFePOโ)", "8.5ร10โปยนโฐ cmยฒ/s", "b-axis vacancy hop")
with c2:
st.metric("Min Barrier (NaFePOโ)", "0.18 eV", "b-axis olivine tunnel")
with c3:
st.metric("Best D (NaโMnNiOโ)", "6.8ร10โปยนยน cmยฒ/s", "ab-plane vacancy")
with c4:
st.metric("Min Barrier (NaโMnNiOโ)", "0.25 eV", "2D ab-plane hop")
st.plotly_chart(sib_diffusion_bar(SIB_DIFFUSION), use_container_width=True,
key="sib_diffusion_bar")
st.markdown("#### Diffusion Mechanism Details")
st.dataframe(
SIB_DIFFUSION.style.background_gradient(
subset=["Migration Barrier Ea (eV)"], cmap="Reds"
),
use_container_width=True,
)
st.info("""
**Diffusion insights:**
- **NaFePOโ (olivine):** Strongly anisotropic โ b-axis is the primary Naโบ channel
(Eโ=0.18 eV) while c-axis is nearly blocked (Eโ=0.55 eV)
- **NaโMnNiOโ (layered):** 2D diffusion in ab-plane (Eโ=0.25 eV); large interlayer
spacing (32 ร
) severely limits c-direction hopping (Eโ=0.68 eV)
- Both materials show **higher barriers than Li in LiF** (~64 kJ/mol โ 0.66 eV),
but Na diffusion benefits from a larger ionic radius increasing tunnel size
""")
# โโ SIB Sub-tab 5: Cathode Ranking โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[4]:
st.markdown("### AI Cathode Ranking โ Stage 8: Intelligent Cathode Ranking")
st.markdown(
"The AI ranks cathode candidates using a weighted 5-property score. "
"DFT-computed data (NaFePOโ: **89/100**, NaโMnNiOโ: **82/100**) anchors the ranking."
)
r1, r2, r3 = st.columns(3)
with r1:
st.metric("๐ฅ NaFePOโ AI Score", "89.0 / 100", "DFT-validated")
with r2:
st.metric("๐ฅ NaโMnNiOโ AI Score", "82.0 / 100", "DFT-validated")
with r3:
st.metric("Screening pool", "8 materials", "2 DFT + 3 AI + 3 literature")
st.plotly_chart(sib_cathode_ranking_chart(SIB_CATHODE_RANKING),
use_container_width=True, key="sib_cathode_ranking")
st.markdown("#### Cathode Property Radar")
avail_mats = SIB_CATHODE_RANKING["Material"].tolist()
sel_radar_mats = st.multiselect(
"Select cathodes to compare",
avail_mats,
default=avail_mats[:3],
key="sib_radar_mats",
)
if sel_radar_mats:
st.plotly_chart(sib_cathode_radar(SIB_CATHODE_RANKING, sel_radar_mats),
use_container_width=True, key="sib_cathode_radar")
st.markdown("#### Full Ranking Table")
st.dataframe(
SIB_CATHODE_RANKING.style.background_gradient(
subset=["AI Score (0โ100)"], cmap="YlGn"
).format({"AI Score (0โ100)": "{:.1f}", "AI Score": "{:.2f}"}),
use_container_width=True,
)
st.markdown("#### Ranking Weights")
wt_cols = st.columns(5)
for col, (prop, wt) in zip(wt_cols, [
("Stability", "25%"), ("Voltage", "25%"),
("Diffusion", "20%"), ("Capacity", "20%"), ("Safety", "10%"),
]):
col.metric(prop, wt)
# โโ SIB Sub-tab 6: AI Pipeline โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[5]:
st.markdown("### 8-Stage AI Pipeline")
st.markdown(
"Each piece of DFT data maps to a specific AI pipeline stage. "
"This view shows which stages are complete, ready, or in progress."
)
st.plotly_chart(sib_pipeline_status(SIB_PIPELINE_STAGES),
use_container_width=True, key="sib_pipeline_status")
st.markdown("#### Detailed Pipeline Mapping")
for _, row in SIB_PIPELINE_STAGES.iterrows():
status_emoji = {
"Done": "โ
", "Ready": "๐ต", "Trained": "๐ก",
"Predicted": "๐ฃ", "Training": "๐ด",
}.get(row["Status"], "โช")
with st.expander(f"{status_emoji} Stage {row['Stage']}: {row['Name']} โ {row['Status']}"):
cols = st.columns(2)
with cols[0]:
st.markdown("**DFT Input:**")
st.info(row["DFT Input"])
with cols[1]:
st.markdown("**AI Output:**")
st.success(row["AI Output"])
st.markdown("#### Legend")
leg_cols = st.columns(5)
for col, (color, label) in zip(leg_cols, [
("๐ข", "Done โ data already computed"),
("๐ต", "Ready โ can run immediately"),
("๐ก", "Trained โ model ready"),
("๐ฃ", "Predicted โ AI output available"),
("๐ด", "Training โ in progress"),
]):
col.markdown(f"{color} {label}")
# โโ SIB Sub-tab 7: AI Screening โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[6]:
st.markdown("### AI-Screened Hypothetical Cathodes โ Stage 3 Output")
st.markdown(
"Once trained on the DFT-validated entries, the formation energy predictor "
"screens hypothetical compositions. Below are the first 10 candidates including "
"the two DFT-validated anchor points."
)
st.plotly_chart(sib_screened_bubble(SIB_SCREENED),
use_container_width=True, key="sib_screened_bubble")
st.markdown("#### Screened Cathode Table")
st.dataframe(
SIB_SCREENED.style.background_gradient(
subset=["Predicted Voltage (V)", "Predicted Capacity (mAh/g)"], cmap="Blues"
).background_gradient(
subset=["Predicted Eform (eV/atom)"], cmap="Greens_r"
),
use_container_width=True,
)
st.info("""
**Reading the bubble chart:**
- **X-axis:** Predicted voltage vs Na/Naโบ (higher โ more energy dense)
- **Y-axis:** Predicted capacity in mAh/g (higher โ more charge storage)
- **Bubble size:** Absolute value of formation energy (larger โ more stable)
- **Colour:** Red = DFT-verified, Green = AI-predicted
**Top AI candidate:** NaโMn0.5Co0.5Oโ โ highest capacity (200 mAh/g) and voltage (3.55 V)
but lower stability (Eform = โ1.72 eV/atom). Needs DFT validation.
""")
st.markdown("#### Next DFT Calculations Recommended")
next_dft = pd.DataFrame({
"Structure": [
"Naโ.โโโ
FePOโ (vacancy)", "Naโ.โโ
FePOโ (vacancy)",
"FePOโ (fully desodiated)", "NaFePOโ + NEB path",
"NaโMnNiOโ + NEB path", "NaFePOโ elastic tensor",
"NaFePOโ PDOS/bandgap",
],
"Purpose": [
"Partial desodiation state", "Half desodiation state",
"Fully charged state", "Na migration barrier (DFT NEB)",
"Na migration barrier (DFT NEB)", "Mechanical stability",
"Electronic properties โ conductivity",
],
"AI Stage": [
"Stage 2 (Dataset)", "Stage 2 (Dataset)",
"Stage 3 (Eform)", "Stage 5 (Diffusion)",
"Stage 5 (Diffusion)", "Stage 7 (Performance)",
"Stage 7 (Performance)",
],
"Priority": ["High", "High", "High", "Critical", "Critical", "Medium", "Medium"],
})
st.dataframe(
next_dft.style.applymap(
lambda v: "color: #f87171" if v == "Critical" else
"color: #F59E0B" if v == "High" else
"color: #4ade80",
subset=["Priority"],
),
use_container_width=True,
)
# โโ SIB Sub-tab 8: Voltage & Capacity โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
with sib_tabs[7]:
st.markdown("### Voltage & Capacity Prediction โ Stage 7: Battery Performance")
st.markdown(
"Predicted from charge distribution (Stage 4) combined with formation energy (Stage 3). "
"The FeยฒโบโFeยณโบ and MnยณโบโMnโดโบ redox couples determine operating voltage."
)
v1, v2, v3, v4 = st.columns(4)
with v1:
st.metric("NaFePOโ Voltage", "2.87 V vs Na/Naโบ", "Feยฒโบ/Feยณโบ couple")
with v2:
st.metric("NaโMnNiOโ Voltage", "3.45 V vs Na/Naโบ", "Mnยณโบ/Niยฒโบ couple")
with v3:
st.metric("NaFePOโ Capacity", "154 mAh/g", "1 Na per formula unit")
with v4:
st.metric("NaโMnNiOโ Capacity", "195 mAh/g", "2 Na per formula unit")
st.markdown("#### Voltage State Table (DFT computed)")
st.dataframe(SIB_VOLTAGE, use_container_width=True)
# Simple voltage vs capacity scatter
fig_vc = px.scatter(
SIB_SCREENED,
x="Predicted Voltage (V)", y="Predicted Capacity (mAh/g)",
color="Source", symbol="Stability",
size=[20] * len(SIB_SCREENED),
text="Material",
title="Voltage vs Capacity โ All Cathode Candidates",
color_discrete_map={"DFT": "#FF4757", "AI": "#4ade80"},
labels={"Predicted Voltage (V)": "Voltage (V vs Na/Naโบ)"},
)
fig_vc.update_traces(textposition="top center", textfont_size=8)
fig_vc.add_hline(y=150, line_dash="dot", line_color="#aaa",
annotation_text="Min target: 150 mAh/g")
fig_vc.add_vline(x=2.5, line_dash="dot", line_color="#aaa",
annotation_text="Min target: 2.5 V")
fig_vc.update_layout(
plot_bgcolor="#0E1117", paper_bgcolor="#0E1117",
font_color="#e5e7eb", height=450,
)
st.plotly_chart(fig_vc, use_container_width=True, key="sib_vc_scatter")
st.info("""
**Energy density comparison:**
- **NaFePOโ:** 2.87 V ร 154 mAh/g โ **442 Wh/kg** (theoretical)
- **NaโMnNiOโ:** 3.45 V ร 195 mAh/g โ **674 Wh/kg** (theoretical)
- **LiB LiFePOโ (reference):** 3.45 V ร 170 mAh/g โ 586 Wh/kg
NaโMnNiOโ shows competitive energy density with LiFePOโ while using
earth-abundant Mn/Ni instead of scarce Li.
""")
st.markdown("#### Industrial Vision โ Battery Foundation Model")
st.markdown("""
The DFT-computed dataset is the **seed** for the Battery Foundation Model:
| Input | AI Engine Module | Output |
|-------|-----------------|--------|
| DFT structures | Structure Encoder (GNN) | Latent material representation |
| Formation energies | Formation Energy Predictor | Screen 10โถ candidates |
| Bader charges | Charge Distribution Model | Voltage prediction |
| Supercell structures | Diffusion Predictor | Na-ion conductivity |
| MD trajectories | Cycle-Life Predictor | Degradation forecast |
| Experimental data | Calibration layer | Validated recommendations |
**Recommended next steps:**
1. Add vacancy structures (Naโ.โโโ
FePOโ, Naโ.โโ
FePOโ)
2. Run NEB calculations for both materials
3. Compute elastic tensors and electronic bandgaps
4. Integrate finite-temperature (300/500/700 K) MD trajectories
5. Expand to full cathode library (10+ materials) for the production platform
""")