spinel
NewMaterials science toolkit with skills for crystal structure analysis, phase diagrams, electronic structure, XRD, instrument data parsing, materials screening, and battery analysis
Overview
Battery Analysis
Critical Rules
- Always specify the battery chemistry — Li-ion, Na-ion, solid-state, etc. Voltage windows, stability criteria, and analysis methods differ significantly.
- Cycling data must be parsed from the native potentiostat format — CSV exports lose metadata (mass loading, cell area, protocol details). Use
galvanifor Biologic .mpr,cellpyfor Arbin/Maccor. - Report capacities normalized correctly — mAh/g (gravimetric) requires accurate active mass. mAh/cm² (areal) requires electrode area. Always state which.
- Voltage profiles shift with C-rate — don't compare 0.1C and 1C profiles directly without noting the rate.
- Coulombic efficiency is the most important cycling metric — CE > 99.9% is typically needed for practical cells. Plot CE on a separate y-axis with expanded scale.
- For computational screening, always check electrochemical stability window (voltage vs Li/Li+) using the Materials Project phase diagram, not just thermodynamic stability.
Potentiostat Data Parsing
Biologic (.mpr files)
from galvani import BioLogic
mpr = BioLogic.MPRfile("cycling_data.mpr")
df = mpr.data
# Common columns: time/s, Ewe/V, I/mA, capacity/mA.h, cycle number
print(df.columns.tolist())
# Basic cycling plot
import matplotlib.pyplot as plt
fig, ax1 = plt.subplots(figsize=(10, 5))
ax1.plot(df["capacity/mA.h"], df["Ewe/V"])
ax1.set_xlabel("Capacity (mAh)")
ax1.set_ylabel("Voltage (V)")
plt.savefig("voltage_profile.png", dpi=150)Arbin / Maccor (via cellpy)
from cellpy import cellreader
# Load raw data — cellpy handles Arbin .res and Maccor formats
cell = cellreader.CellpyCell()
cell.from_raw("arbin_data.res")
# Get summary per cycle
summary = cell.cell.summary
print(f"Cycles: {len(summary)}")
print(f"First discharge capacity: {summary.iloc[0]['discharge_capacity']:.1f} mAh/g")
# Get step data for voltage profiles
steps = cell.cell.steps
# Capacity vs cycle number
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
ax1.plot(summary.index, summary["discharge_capacity"], 'o-')
ax1.set_xlabel("Cycle")
ax1.set_ylabel("Discharge Capacity (mAh/g)")
ax2.plot(summary.index, summary["coulombic_efficiency"] * 100, 'o-')
ax2.set_xlabel("Cycle")
ax2.set_ylabel("Coulombic Efficiency (%)")
ax2.set_ylim([99, 101])
plt.tight_layout()
plt.savefig("cycling_summary.png", dpi=150)Electrochemical Impedance Spectroscopy (EIS)
from impedance import preprocessing
from impedance.models.circuits import CustomCircuit
# Load EIS data (frequency, Z_real, Z_imag)
f, Z = preprocessing.readCSV("eis_data.csv")
# Ignore points below 0 (instrument artifacts)
f, Z = preprocessing.ignoreBelowX(f, Z)
# Define equivalent circuit
# R0 = ohmic resistance, R1-CPE1 = charge transfer, W1 = Warburg diffusion
circuit = "R0-p(R1,CPE1)-W1"
initial_guess = [10, 100, 1e-4, 0.8, 500]
circuit_model = CustomCircuit(circuit, initial_guess=initial_guess)
circuit_model.fit(f, Z)
print(f"Ohmic resistance: {circuit_model.parameters_[0]:.2f} Ω")
print(f"Charge transfer resistance: {circuit_model.parameters_[1]:.2f} Ω")
# Nyquist plot
fig, ax = plt.subplots(figsize=(8, 8))
ax.plot(Z.real, -Z.imag, 'o', label="Data")
Z_fit = circuit_model.predict(f)
ax.plot(Z_fit.real, -Z_fit.imag, '-', label="Fit")
ax.set_xlabel("Z' (Ω)")
ax.set_ylabel("-Z'' (Ω)")
ax.set_aspect("equal")
ax.legend()
plt.savefig("nyquist.png", dpi=150)Computational Battery Screening
Electrode voltage and capacity prediction
from mp_api.client import MPRester
from pymatgen.apps.battery.insertion_battery import InsertionElectrode
from pymatgen.analysis.phase_diagram import PhaseDiagram
from pymatgen.entries.compatibility import MaterialsProjectCompatibility
with MPRester() as mpr:
# Get all entries in the Li-Mn-O system
entries = mpr.get_entries_in_chemsys(["Li", "Mn", "O"])
# Apply compatibility corrections
compat = MaterialsProjectCompatibility()
entries = compat.process_entries(entries)
# Build insertion electrode (Li into MnO2 framework)
# This calculates voltage profile and theoretical capacity
ie = InsertionElectrode.from_entries(entries, working_ion="Li")
print(f"Average voltage: {ie.get_average_voltage():.2f} V vs Li/Li+")
print(f"Theoretical capacity: {ie.get_capacity_grav():.0f} mAh/g")
print(f"Energy density: {ie.get_energy_grav():.0f} Wh/kg")Electrochemical stability window
from mp_api.client import MPRester
from pymatgen.analysis.phase_diagram import PhaseDiagram
with MPRester() as mpr:
# Check stability of a solid electrolyte against Li metal
entries = mpr.get_entries_in_chemsys(["Li", "P", "S"])
pd = PhaseDiagram(entries)
# Get stability window — voltage range where electrolyte doesn't decompose
# This is critical for solid-state battery electrolyte selection
from pymatgen.analysis.phase_diagram import GrandPotentialPhaseDiagram
# Sweep Li chemical potential to find stability window
for voltage in [0, 1, 2, 3, 4, 5]:
mu_li = -voltage # μ_Li = -eV vs Li/Li+
# Check if the material is stable at this potential
# ... (use GrandPotentialPhaseDiagram)Physics-Based Modeling (PyBaMM)
import pybamm
# Single Particle Model — fast, good for initial analysis
model = pybamm.lithium_ion.SPM()
# Or full Doyle-Fuller-Newman model — more accurate
# model = pybamm.lithium_ion.DFN()
# Use built-in parameter set
param = pybamm.ParameterValues("Chen2020")
# Simulate 1C discharge
sim = pybamm.Simulation(model, parameter_values=param)
sim.solve([0, 3600]) # 1 hour = 1C
# Plot
sim.plot(["Terminal voltage [V]", "Current [A]",
"Negative particle concentration [mol.m-3]",
"Positive particle concentration [mol.m-3]"])Common Battery Metrics
| Metric | Good Target | How to Calculate |
|---|---|---|
| Gravimetric capacity | >150 mAh/g (cathode) | Discharge capacity / active mass |
| Coulombic efficiency | >99.9% | Discharge capacity / charge capacity × 100 |
| Rate capability | >80% at 2C vs 0.1C | Capacity at high rate / capacity at low rate |
| Cycle retention | >80% after 500 cycles | Capacity at cycle N / capacity at cycle 1 |
| ICE (1st cycle) | >85% | 1st discharge / 1st charge × 100 |
| Voltage hysteresis | <0.2 V | Average charge V - average discharge V |
| ASR (impedance) | <20 Ω·cm² | From EIS fitting |
Common Pitfalls
- •Mass loading errors propagate directly to capacity — verify active mass carefully.
- •Formation cycles (first 1-3 cycles) should be analyzed separately — SEI formation causes irreversible capacity loss.
- •Temperature matters — always report cell temperature. Capacity increases ~1%/°C.
- •Calendar aging — cells degrade even when not cycling. Note rest periods.
- •Two-electrode vs three-electrode — coin cell data mixes cathode and anode contributions. Use reference electrode for single-electrode analysis.
Reference
See references/cellpy-guide.md for detailed potentiostat data handling. See references/battery-screening.md for computational screening workflows.
Install & Usage
mkdir -p .claude/skillsmkdir -p .claude/skills && curl -o .claude/skills/spinel.md https://raw.githubusercontent.com/charlesxjyang/spinel-plugin/main/SKILL.md/spinelFrequently Asked Questions
What is spinel?
Materials science toolkit with skills for crystal structure analysis, phase diagrams, electronic structure, XRD, instrument data parsing, materials screening, and battery analysis
How to install spinel?
To install spinel, create the .claude/skills directory in your project, then run the curl command to download the skill file. Once installed, invoke it in Claude Code with /spinel.
What is spinel best for?
spinel is a community categorized under Development. It is designed for: materials-science, chemistry, pymatgen, crystallography, battery, electrochemistry, dft. Created by Charles Yang.