formatting Battery.py, added 2022-12-23 TMS data
This commit is contained in:
parent
c377de82ce
commit
6f51e2f479
4 changed files with 14006 additions and 162 deletions
92
Battery.py
92
Battery.py
|
|
@ -10,6 +10,7 @@ import pde
|
|||
import cantera as ct
|
||||
from scipy import optimize
|
||||
|
||||
|
||||
class CombustionChamber:
|
||||
def __init__(self, mdot, ct_object, burned_state, hA=700):
|
||||
self.mdot = mdot # kg/s
|
||||
|
|
@ -28,11 +29,14 @@ class CombustionChamber:
|
|||
self.Area = 6.7 * 16.7
|
||||
|
||||
def update_mdot(self, mdot_new):
|
||||
if mdot_new : self.mdot = mdot_new
|
||||
if mdot_new:
|
||||
self.mdot = mdot_new
|
||||
|
||||
def update_Twall(self, Twall0=None, Twall1=None):
|
||||
if Twall0: self.Twall0 = Twall0
|
||||
if Twall1: self.Twall1 = Twall1
|
||||
if Twall0:
|
||||
self.Twall0 = Twall0
|
||||
if Twall1:
|
||||
self.Twall1 = Twall1
|
||||
|
||||
def energy_balance_equation(self, Tout):
|
||||
self.gas.TP = Tout, None
|
||||
|
|
@ -57,11 +61,13 @@ class CombustionChamber:
|
|||
|
||||
def heat(self, Tout=None):
|
||||
''' Heat(W) to walls '''
|
||||
if Tout is None: Tout = self.T1
|
||||
if Tout is None:
|
||||
Tout = self.T1
|
||||
Tgas = (self.T0 + Tout) / 2
|
||||
|
||||
return self.hA * (Tgas - self.Twall0), self.hA * (Tgas - self.Twall1)
|
||||
|
||||
|
||||
class CokeCharge:
|
||||
|
||||
def __init__(self, t_charge, idx_oven):
|
||||
|
|
@ -76,9 +82,11 @@ class CokeCharge:
|
|||
def end_baking(self, t):
|
||||
self.t_push = t
|
||||
|
||||
|
||||
brick_thickness = 0.14 # m,
|
||||
n_grid_brick = 16 # Number of Grid points inside
|
||||
wall_grid = pde.CartesianGrid([[0, brick_thickness]], n_grid_brick, periodic=False)
|
||||
wall_grid = pde.CartesianGrid(
|
||||
[[0, brick_thickness]], n_grid_brick, periodic=False)
|
||||
wall_area = 6.7 * 16.7 # m^2 , Oven cross section area
|
||||
|
||||
# op_grad2 = wall_grid.make_operator_no_bc('gradient_squared', backend='scipy')
|
||||
|
|
@ -89,6 +97,7 @@ wall_area = 6.7 * 16.7 # m^2 , Oven cross section area
|
|||
# op_info_grad = wall_grid._get_operator_info('gradient')
|
||||
# op_info_lap = wall_grid._get_operator_info('laplace')
|
||||
|
||||
|
||||
class CokeOvenBrickHeatEqn(pde.PDEBase):
|
||||
"""Implementation of the Heat equation"""
|
||||
|
||||
|
|
@ -134,7 +143,8 @@ class CokeOvenBrickHeatEqn(pde.PDEBase):
|
|||
k = self.kCoef1 * state + self.kCoef0
|
||||
cp = self.cpCoef1 * state + self.cpCoef0
|
||||
|
||||
state_grad_k_grad = self.kCoef1 * state_grad2 # state_grad.dot(state_grad)
|
||||
state_grad_k_grad = self.kCoef1 * \
|
||||
state_grad2 # state_grad.dot(state_grad)
|
||||
|
||||
return (state_grad_k_grad + k * state_lap) / cp / self.rho
|
||||
|
||||
|
|
@ -156,13 +166,15 @@ class CokeOvenBrickHeatEqn(pde.PDEBase):
|
|||
return pde_rhs
|
||||
'''
|
||||
|
||||
|
||||
class RefractoryWall:
|
||||
def __init__(self, T0):
|
||||
self.T_oven = T0
|
||||
self.T_chamber = T0
|
||||
self.q_chamber = 0.
|
||||
self.T_internal = pde.ScalarField(wall_grid, T0)
|
||||
self.eqn = CokeOvenBrickHeatEqn(bc=[{"derivative": 0}, {"value": self.T_oven}])
|
||||
self.eqn = CokeOvenBrickHeatEqn(
|
||||
bc=[{"derivative": 0}, {"value": self.T_oven}])
|
||||
|
||||
def update_bc(self, Q=None, T_oven=None):
|
||||
# Q = - k(T) gradT
|
||||
|
|
@ -178,7 +190,8 @@ class RefractoryWall:
|
|||
# solution = self.eqn.solve (eqn, bc)
|
||||
self.T_internal = self.eqn.solve(
|
||||
self.T_internal, t_range=dt, dt=30., tracker='consistency', backend="numpy")
|
||||
self.T_chamber = self.T_internal.get_boundary_values(axis=0, upper=False, bc=self.eqn.bc)
|
||||
self.T_chamber = self.T_internal.get_boundary_values(
|
||||
axis=0, upper=False, bc=self.eqn.bc)
|
||||
|
||||
def heat_to_oven(self):
|
||||
""" NOT YET IMPLEMENTED """
|
||||
|
|
@ -197,6 +210,7 @@ def Twall_model(x):
|
|||
'''
|
||||
return np.interp(x, Twall_table[0], Twall_table[1])
|
||||
|
||||
|
||||
class OvenChamber:
|
||||
def __init__(self):
|
||||
self.content = None
|
||||
|
|
@ -218,10 +232,12 @@ class OvenChamber:
|
|||
""" Update content with fresh coal is charged """
|
||||
self.content = coal_charge
|
||||
|
||||
|
||||
def wall_solve_wrapper(t_range, wall):
|
||||
wall.solve(t_range)
|
||||
return wall.T_internal, wall.T_chamber
|
||||
|
||||
|
||||
class Battery:
|
||||
|
||||
def load_state(self):
|
||||
|
|
@ -244,15 +260,18 @@ class Battery:
|
|||
self.charge_program = charge_program # Charge program of schedule object
|
||||
self.t = 0 # Battery time
|
||||
self.t_last = 0 # Time of last Push/Charge
|
||||
self.processing = [] # List of Coke charges under processing(drying)
|
||||
self.product = [] # List of Coke charges done(completed)
|
||||
# List of Coke charges under processing(drying)
|
||||
self.processing = []
|
||||
# List of Coke charges done(completed)
|
||||
self.product = []
|
||||
self.gas = ct.Solution('gri30.xml')
|
||||
self.gas.TPX = burned_gas_state # Burned gas T, P, X
|
||||
T0, P0, X0 = self.gas.TPX
|
||||
self.T0 = T0
|
||||
self.P0 = P0
|
||||
self.X0 = X0
|
||||
self.sequence_idx = 0 # Integer, 0 ~ (size-1), progress index for oven sequence array
|
||||
# Integer, 0 ~ (size-1), progress index for oven sequence array
|
||||
self.sequence_idx = 0
|
||||
|
||||
self.wall_t_history = []
|
||||
self.gas_t_history = []
|
||||
|
|
@ -290,7 +309,8 @@ class Battery:
|
|||
|
||||
# For 1~4 Coke Ovens with n+5 P/C sequence
|
||||
start_indices = [1, 3, 5, 2, 4]
|
||||
self.oven_idx_order = np.concatenate([np.array(range(i0 - 1, self.size, 5)) for i0 in start_indices])
|
||||
self.oven_idx_order = np.concatenate(
|
||||
[np.array(range(i0 - 1, self.size, 5)) for i0 in start_indices])
|
||||
|
||||
if init_from_file:
|
||||
print("Initializaton from file")
|
||||
|
|
@ -323,7 +343,8 @@ class Battery:
|
|||
normal_period = self.charge_program.period(-1) # 감산 전 장입 간격 (주기)
|
||||
dt = normal_period / period_over_dt # Simulation Time Step
|
||||
|
||||
self.t = - normal_period * self.size * n_cycle # 정상상태 생성 모사 시간 = 장입 간격 * 총 장입 횟수
|
||||
self.t = - normal_period * self.size * \
|
||||
n_cycle # 정상상태 생성 모사 시간 = 장입 간격 * 총 장입 횟수
|
||||
self.t_last = self.t # 마지막 장입을 정상상태 시뮬레이션 시작 시각으로 설정
|
||||
|
||||
# initialization time loop
|
||||
|
|
@ -363,14 +384,19 @@ class Battery:
|
|||
|
||||
chmbr.update_mdot(self.mdot(self.t)/self.size)
|
||||
chmbr.update_Twall(
|
||||
Twall0=(wall_lower.T_chamber if wall_lower else wall_upper.T_chamber),
|
||||
Twall1=(wall_upper.T_chamber if wall_upper else wall_lower.T_chamber),
|
||||
Twall0=(
|
||||
wall_lower.T_chamber if wall_lower else wall_upper.T_chamber),
|
||||
Twall1=(
|
||||
wall_upper.T_chamber if wall_upper else wall_lower.T_chamber),
|
||||
)
|
||||
print(f"t={self.t:6.2} : {chmbr.Twall0} K | Chamber {i_chamber} | {chmbr.Twall1} K ")
|
||||
print(
|
||||
f"t={self.t:6.2} : {chmbr.Twall0} K | Chamber {i_chamber} | {chmbr.Twall1} K ")
|
||||
chmbr.solve()
|
||||
Q1, Q2 = chmbr.heat() # W (J/s)
|
||||
if wall_lower: wall_lower.update_bc(Q=Q1)
|
||||
if wall_upper: wall_upper.update_bc(Q=Q2)
|
||||
if wall_lower:
|
||||
wall_lower.update_bc(Q=Q1)
|
||||
if wall_upper:
|
||||
wall_upper.update_bc(Q=Q2)
|
||||
|
||||
# Loop all ovens
|
||||
# update oven wall temperatures using coke charge age
|
||||
|
|
@ -383,7 +409,8 @@ class Battery:
|
|||
wall_upper.update_bc(T_oven=T_oven)
|
||||
|
||||
with Pool(12) as pool:
|
||||
wall_sln = pool.starmap(wall_solve_wrapper, [((dt*60*60), w) for w in self.walls_0+self.walls_1])
|
||||
wall_sln = pool.starmap(wall_solve_wrapper, [(
|
||||
(dt*60*60), w) for w in self.walls_0+self.walls_1])
|
||||
|
||||
# wall_lower.solve(dt * 60 * 60) # convert hours to seconds
|
||||
# wall_upper.solve(dt * 60 * 60) # convert hours to seconds
|
||||
|
|
@ -437,7 +464,8 @@ class Battery:
|
|||
period = self.charge_program.period(self.t) # 현재 장입 시간 간격
|
||||
|
||||
# 마지막 장입탄 장입 시각
|
||||
latest_coke_charge = self.processing[-1].t_charge if len(self.processing) > 0 else self.t_last
|
||||
latest_coke_charge = self.processing[-1].t_charge if len(
|
||||
self.processing) > 0 else self.t_last
|
||||
|
||||
# t_last + period 가 t, t + dt 사이에 들어오는 것 검사
|
||||
# t + dt 가 다음 추출/장입 시각 이후일 때 => 이번 time step 에 추출/장입을 실행해야함
|
||||
|
|
@ -461,12 +489,14 @@ class Battery:
|
|||
f"{self.t + dt - latest_coke_charge:7.3} since last P/C. ",
|
||||
f"period = {self.charge_program.period(self.t):7.3}",)
|
||||
|
||||
|
||||
# 시뮬레이션 시간 업데이트
|
||||
self.t += dt
|
||||
|
||||
self.gas_t_history.append((self.t, [chmbr.T1 for chmbr in self.chambers]))
|
||||
self.wall_t_history.append((self.t, [(wl.T_chamber, wl.T_internal.data, wl.T_oven, wu.T_oven, wu.T_internal.data, wu.T_chamber) for wl, wu in zip(self.walls_0, self.walls_1)]))
|
||||
self.gas_t_history.append(
|
||||
(self.t, [chmbr.T1 for chmbr in self.chambers]))
|
||||
self.wall_t_history.append((self.t, [(wl.T_chamber, wl.T_internal.data, wl.T_oven, wu.T_oven,
|
||||
wu.T_internal.data, wu.T_chamber) for wl, wu in zip(self.walls_0, self.walls_1)]))
|
||||
|
||||
|
||||
def coke_oven_exhaust_stoichiometry(phi=1.0, return_unburned=False):
|
||||
|
||||
|
|
@ -479,7 +509,8 @@ def coke_oven_exhaust_stoichiometry (phi=1.0, return_unburned=False):
|
|||
mix.TP = 25+273.15, ct.one_atm
|
||||
mix.set_equivalence_ratio(phi=phi, fuel=coke_oven_fuel, oxidizer=air)
|
||||
|
||||
element_X = {ename: mix.elemental_mole_fraction(ename) for ename in mix.element_names}
|
||||
element_X = {ename: mix.elemental_mole_fraction(
|
||||
ename) for ename in mix.element_names}
|
||||
|
||||
exhaust = ct.Solution('gri30.xml')
|
||||
exhaust.TPX = (25+273.15, ct.one_atm,
|
||||
|
|
@ -496,6 +527,7 @@ def coke_oven_exhaust_stoichiometry (phi=1.0, return_unburned=False):
|
|||
else:
|
||||
return exhaust.mole_fraction_dict(threshold=-1)
|
||||
|
||||
|
||||
class HeatSchedule:
|
||||
def __init__(self, xp, fp):
|
||||
self.xp = xp
|
||||
|
|
@ -506,6 +538,7 @@ class HeatSchedule:
|
|||
x = np.linspace(t0, t1, 31)
|
||||
return np.trapz(self.f(x), x)
|
||||
|
||||
|
||||
class ChargeSchedule:
|
||||
def __init__(self, normal_load, service_start, service_time, service_load, aux_start, aux_time, aux_load):
|
||||
self.xp = np.array([service_start, service_start, service_start+service_time, service_start+service_time,
|
||||
|
|
@ -521,6 +554,7 @@ class ChargeSchedule:
|
|||
def period(self, t):
|
||||
return 24 / self.f(t)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Define the oxidizer composition, here air with 21 mol-% O2 and 79 mol-% N2
|
||||
|
|
@ -553,14 +587,16 @@ if __name__ == "__main__":
|
|||
gas_in_state = gas.TPX
|
||||
|
||||
# Time(Hours) - GJ/rev
|
||||
sample_program = np.array(open('sample_heat_221128_3A.txt').read().split(), dtype=np.double).reshape((-1,2))
|
||||
sample_program = np.array(open(
|
||||
'sample_heat_221128_3A-Plan2.txt').read().split(), dtype=np.double).reshape((-1, 2))
|
||||
|
||||
heating_plan = HeatSchedule(*sample_program.T)
|
||||
charging_plan = ChargeSchedule( 82, 9, 13, 1e-12, 9+13+18, 4, 1e-12 )
|
||||
charging_plan = ChargeSchedule(82, 9, 12, 1e-12, 9+13+18, 4, 1e-12)
|
||||
n_doors = 66
|
||||
|
||||
load_state = False
|
||||
bat3A = Battery("3A", n_doors, heating_plan, charging_plan, gas_in_state, hv, init_from_file=load_state)
|
||||
load_state = True
|
||||
bat3A = Battery("3A", n_doors, heating_plan, charging_plan,
|
||||
gas_in_state, hv, init_from_file=load_state)
|
||||
|
||||
if not load_state:
|
||||
with open('gas.history', 'wb') as gas_history_file:
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
11501
POSCO_GY_COKE_OVEN_TMS/4COKE_OVEN_TMS_221223-25.csv
Normal file
11501
POSCO_GY_COKE_OVEN_TMS/4COKE_OVEN_TMS_221223-25.csv
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue