Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions meatools/meatools.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Metadata-Version: 2.1
Name: meatools
Version: 0.1.0
Author: Jiangyuan John Feng, Shicheng Xu
Requires: python
Requires: numpy
Requires: cantera
Requires: matplotlib
Requires: scipy
20 changes: 20 additions & 0 deletions meatools/meatools.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
setup.py
meatools/__init__.py
meatools/cli.py
meatools/ecsa_dry.py
meatools/ecsa_normal.py
meatools/impedence_calc.py
meatools/lsv.py
meatools/test_squence.py
meatools.egg-info/PKG-INFO
meatools.egg-info/SOURCES.txt
meatools.egg-info/dependency_links.txt
meatools.egg-info/entry_points.txt
meatools.egg-info/top_level.txt
meatools/subcomands/__init__.py
meatools/subcomands/ecsa_dry.py
meatools/subcomands/ecsa_normal.py
meatools/subcomands/impedence_calc.py
meatools/subcomands/lsv.py
meatools/subcomands/mea_proccess.py
meatools/subcomands/test_squence.py
1 change: 1 addition & 0 deletions meatools/meatools.egg-info/dependency_links.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

2 changes: 2 additions & 0 deletions meatools/meatools.egg-info/entry_points.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[console_scripts]
mea = meatools.cli:main
1 change: 1 addition & 0 deletions meatools/meatools.egg-info/top_level.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
meatools
Empty file added meatools/meatools/__init__.py
Empty file.
Binary file not shown.
Binary file added meatools/meatools/__pycache__/cli.cpython-312.pyc
Binary file not shown.
38 changes: 38 additions & 0 deletions meatools/meatools/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import argparse
from .subcomands import mea_proccess

def main():
parser=argparse.ArgumentParser(prog="mea", description="MEATOOLs CLI Toolkit")
subparsers=parser.add_subparsers(dest="command")

lte_parser=subparsers.add_parser("ttseq",help='Run test sequence analysis')
lte_parser.set_defaults(func=mea_proccess.run_test_sequence)

lte_parser=subparsers.add_parser("otr",help='Run OTR/Impedance analysis')
lte_parser.set_defaults(func=mea_proccess.run_otr)

lte_parser=subparsers.add_parser("ecsa",help='Run ECSA analysis')
lte_parser.set_defaults(func=mea_proccess.run_ecsa)

lte_parser=subparsers.add_parser("ecsadry",help='Run ECSA-dry analysis')
lte_parser.set_defaults(func=mea_proccess.run_ecsa_dry)

lte_parser=subparsers.add_parser("lsv",help='Run LSV analysis')
lte_parser.set_defaults(func=mea_proccess.run_lsv)

lte_parser=subparsers.add_parser("conclude",help='Extract key value from results directory')
lte_parser.set_defaults(func=mea_proccess.run_conclude)

lte_parser=subparsers.add_parser("all",help='Run all analysis')
lte_parser.set_defaults(func=mea_proccess.run_all)


lte_parser=subparsers.add_parser("eis",help='Run EIS analysis')
lte_parser.set_defaults(func=mea_proccess.run_eis)


args=parser.parse_args()
if hasattr(args,'func'):
args.func(args)
else:
parser.print_help()
162 changes: 162 additions & 0 deletions meatools/meatools/ecsa_dry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import re,os,json
import os
from scipy import interpolate
from scipy.stats import mstats
from glob import glob
from datetime import datetime
from pathlib import Path

class NumpyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.ndarray):
return obj.tolist()
elif isinstance(obj, np.generic):
return obj.item()
return super().default(obj)

def find_and_sort_load_dta_files(root_folder='.'):
files = glob(os.path.join(root_folder, '**', '*cv*.DTA'), recursive=True)
file_info = [(os.path.getmtime(f), f) for f in files]
file_info.sort(reverse=False)
return file_info

def find_cv_subfolders(root_dir):
root_path = Path(root_dir)
csv_folders = {str(p.parent.relative_to(root_path))
for p in root_path.glob('**/'+searchKey)}
log.write("Subfolders containing CV DTA files:\n")
csv_folders=sorted(csv_folders)
for folder in csv_folders:
log.write(f"- {folder}\n" if folder != '.' else "- (root directory)\n")
return csv_folders

def plot_COtripping(file_info):
data_dump={}
for i, (mtime, filepath) in enumerate(file_info, 1):
dump={}
readable_time = datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S')
dump["time_stamp"]=readable_time
dump["file"]=filepath

with open(filepath, 'r') as f:
for _ in range(65):
next(f)
content_from_line65 = f.read()

u = re.split('CURVE', content_from_line65)
oldUpper = x_CO*0

for j in range(len(u)):
with open('temp', 'w') as fileID:
fileID.write(u[j])
A = np.loadtxt('temp', skiprows=2, usecols=range(8))
plt.subplot(2,3,j+1)
plt.plot(A[:,2],A[:,3])
if j>0 and j<(len(u)-1):
scanRate=np.median(np.abs(np.diff(A[:,2])/np.diff(A[:,1])))
# print('rate='+str(scanRate)+' V/s')
# print('Vmin='+str(np.min(A[:,2]))+' V'

CVall = A[:, [2, 3]]
startV = CVall[0, 0]
updData = CVall[:, :2]
mask1 = (updData[:, 0] > 0.3) & (updData[:, 0] < 0.6) & (np.concatenate(([0], np.diff(updData[:, 0]))) > 0)
double1 = updData[mask1, :]
mask2 = (updData[:, 0] > 0.3) & (updData[:, 0] < 0.6) & (np.concatenate(([0], np.diff(updData[:, 0]))) < 0)
double2 = updData[mask2, :]

double1 = double1[np.argsort(double1[:, 0])]
double2 = double2[np.argsort(double2[:, 0])]
double1 = double1[np.concatenate(([True], np.diff(double1[:, 0]) != 0)), :]
double2 = double2[np.concatenate(([True], np.diff(double2[:, 0]) != 0)), :]

# CO stripping area
maskCO = (updData[:, 0] > 0.5) & (np.concatenate(([0], np.diff(updData[:, 0]))) > 0)
topLimits = updData[maskCO, :]
fCO = interpolate.interp1d(topLimits[:, 0], topLimits[:, 1], bounds_error=False)
newUpper = fCO(x_CO)
plt.subplot(2,3,1)
plt.plot(x_CO,newUpper)
oldUpper =np.maximum(oldUpper,newUpper)

# Interpolation
x_new = np.arange(0.35, 0.451, 0.001)
f1 = interpolate.interp1d(double1[:, 0], double1[:, 1], bounds_error=False)
double1_interp = f1(x_new)
f2 = interpolate.interp1d(double2[:, 0], double2[:, 1], bounds_error=False)
double2_interp = f2(x_new)

ddouble = np.abs(double1_interp - double2_interp)
ddouble = ddouble[~np.isnan(ddouble)]
doubleMean = np.median(ddouble)
# print(f"dd: {doubleMean}")

# Process updData
updData = updData[np.concatenate(([True], np.diff(updData[:, 0]) > 0)), :]
base = mstats.mquantiles(updData[(updData[:, 0] > 0.4) & (updData[:, 0] < 0.6), 1], 0.25)
updData[:, 1] = updData[:, 1] - base
updData = updData[updData[:, 1] > 0, :]
updData = updData[(updData[:, 0] <= 0.4) & (updData[:, 0] > ECAcutoff), :]
updData = updData[np.argsort(updData[:, 0]), :]

area = np.sum(np.diff(updData[:, 0]) * updData[:-1, 1]) # in mAV
QH = area / scanRate
ECA = QH / 2.1e-4
# print(f"ECA: {ECA}")
dump[f"curve_{str(j)}"]={}
dump[f"curve_{str(j)}"]["rate (V/s)"]=scanRate
dump[f"curve_{str(j)}"]["Vmin (V)"]=np.min(A[:,2])
dump[f"curve_{str(j)}"]["dd"]=doubleMean
dump[f"curve_{str(j)}"]["ECA"]=ECA

elif j==0:
CVall = A[:, [2, 3]]
updData = CVall[:, :2]
maskCO = (updData[:, 0] > 0.5) & (np.concatenate(([0], np.diff(updData[:, 0]))) > 0)
topLimits = updData[maskCO, :]
fCO = interpolate.interp1d(topLimits[:, 0], topLimits[:, 1], bounds_error=False)
COdesorb = fCO(x_CO)
if os.path.exists('temp'):
os.remove('temp')
data_dump[f"file_{str(i)}"]=dump

return oldUpper, COdesorb, data_dump


if __name__=="__main__":
os.makedirs('logs',exist_ok=True)
os.makedirs('results/ecsa_dry/',exist_ok=True)
log=open('logs/ecsa_normal.log','w')
index=1
results={}

searchKey='Cathode CO*/*cv*.DTA'
ECAcutoff = 0.08
x_CO = np.arange(0.5, 0.95, 0.001)
u_subfolders=find_cv_subfolders('.')

for i, folderName in enumerate(u_subfolders,start=1):
results[f"dir_{str(i)}"]={}

plt.figure(index)
index+=1
file_info = find_and_sort_load_dta_files(u_subfolders[i-1])
[oldUpper,COdesorb,data]=plot_COtripping(file_info)
plt.savefig(f'results/ecsa_dry/ECSA_Dry_{i}-1.png')

plt.figure(index)
index+=1
plt.plot(x_CO,oldUpper,'r--')
plt.plot(x_CO,COdesorb,'b-')
COECA=np.nansum( np.mean(np.diff(x_CO))*(COdesorb-oldUpper))
plt.savefig(f'results/ecsa_dry/ECSA_Dry_{i}-2.png')

results[f"dir_{str(i)}"]["data"]=data
results[f"dir_{str(i)}"]["COECA"]=COECA
with open('results/ecsa_dry/ecsa_results.json','w') as results_file:
json.dump(results,results_file,indent=2,cls=NumpyEncoder)

log.close()
Loading