formatting Battery.py, added 2022-12-23 TMS data

This commit is contained in:
Yeongdo Park 2023-01-04 20:03:26 +09:00
parent c377de82ce
commit 6f51e2f479
4 changed files with 14006 additions and 162 deletions

View file

@ -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

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long