Implementing simulator

This commit is contained in:
Yeongdo Park 2022-12-08 19:52:49 +09:00
parent 1a5522f527
commit 0f7e6bec97
2 changed files with 186 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.ipynb_checkpoints
*~

184
Battery.py Normal file
View file

@ -0,0 +1,184 @@
from functools import reduce
import numpy as np
import cantera as ct
class CokeCharge:
def __init__ (self, t_charge, idx_oven):
self.t_charge = t_charge
self.t_push = None
self.idx_oven = idx_oven
self.Q = 0
def bake (self, dQ):
self.Q += dQ
def end_baking (self, t):
self.t_push = t
class Battery:
def __init__ (self, name, size, heat_program, charge_program, T_combustion_0):
self.name = name # Battery name
self.size = size # Size of battery, number of ovens
self.heat_program = heat_program # Heat program or schedule object
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)
self.T0 = T_combustion_0 # Burned gas temperature
self.sequence_idx = 0 # Integer, 0 ~ (size-1), progress index for oven sequence array
# chambers[0] - walls_0[0] - ovens[0] - walls_1[0] - chambers[1] - walls_0[1] - ...
# ... walls_1[i-1] - chambers[i] - walls_0[i] - ovens[i] - walls_1[i] - chambers[i+1] - walls_0[i+1] - ...
# ... walls_1[size-2] - chambers[size-1] - walls_0[size-1] - ovens[size-1] - walls_1[size-1] - chambers[size]
self.chambers = np.zeros(self.size+1)
self.ovens = np.zeros(self.size)
self.walls_0 = np.zeros(self.size)
self.walls_1 = np.zeros(self.size)
# 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])
# 정상 상태 만들기: 모든 문에 n_cycle 회 장입
n_cycle = 3 # 모든 문 장입 반복 횟수
period_over_dt = 11. # period/dt, 장입 간격 / 초기화 time step 크기
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_last = self.t # 마지막 장입을 정상상태 시뮬레이션 시작 시각으로 설정
# initialization time loop
for i in range(int(np.ceil(self.size * period_over_dt * n_cycle))):
""" Fill battety with normal charge rate """
self.update(dt) # Time adavancement
def next_oven (self):
''' Index of the oven to which apply push and charge '''
next_oven_id = self.oven_idx_order[self.sequence_idx % self.size]
self.sequence_idx += 1
return next_oven_id
def bake (self, dt):
# update combustion chamber equilibrium temperature
# Tad = 연료 조성과 공연비로 결정
# m_dot = 연료 발열량과 공급열량 공연비로 결정
# m(h1 - h0) = hA(Tgas - Twall) => solve with initial T0 = Tad
# Loop all combustion chambers
# update chamber wall temperatures and mass flow rates
# solve for equilibrium heat to walls
for i_chamber, chmbr in enumerate(self.chambers):
try:
wall_lower = self.walls_1[i_chamber-1]
except IndexError:
wall_lower = None
try:
wall_upper = self.walls_0[i_chamber]
except IndexError:
wall_upper = None
chmbr.update_mdot()
chmbr.update_Twall(
wall_lower.T_chamber if wall_lower else wall_upper.T_chamber,
wall_upper.T_chamber if wall_upper else wall_lower.T_chamber,
)
chmbr.solve()
Q1, Q2 = chmbr.heat()
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
# solve heat equations of all walls
# bake charge in oven
for i_oven, (oven, wall_lower, wall_upper) in enumerate(zip(self.ovens, self.walls_0, self.walls_1)):
oven.get_charge_temperature()
wall_lower.update_bc(Toven=Q1)
wall_upper.update_bc(Toven=Q2)
wall_lower.solve(dt)
wall_upper.solve(dt)
ql = wall_lower.heat_to_oven()
qu = wall_upper.heat_to_oven()
oven.bake(ql+qu)
# advance time oven brick
# from chamber heat flux boundary condition
# to oven fixed temperature boundary condition
# integrate heat to oven # 오븐 벽면 온도 우선 시간 함수로
dQ = self.dQ(dt) # array, dQ pairs of all oven taking from both walls
for cc in self.processing:
cc.bake(dQ) # bake.(dQ[cc.idx_oven])
def push_and_charge (self, coke_charge):
if len(self.processing) >= self.size:
self.push(coke_charge.t_charge)
self.charge(coke_charge)
def push (self, t):
""" Push complete coke out of oven """
coke = self.processing.pop(0)
coke.end_baking(t)
self.product.append(coke)
def charge (self, coke_charge):
self.ovens[coke_charge.i_oven].charge(coke_charge)
self.processing.append(coke_charge)
def dQ (self, dt):
return self.heat_program.dQ(self.t, self.t+dt)
def is_pc_time (self, dt):
''' P/C should be done in this time step '''
return self.t + dt >= period + self.t_last
def update (self, dt):
# dQ = self.heat_program.dQ(self.t, self.t+dt) # t, t+dt 사이 공급하는 열량, array 로 대체 필요
# t 에서 t+dt 까지 탄화실 가열
self.bake(dt)
period = self.charge_program.period(self.t) # 현재 장입 시간 간격
# 마지막 장입탄 장입 시각
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 에 추출/장입을 실행해야함
if self.t + dt >= period + self.t_last :
print(f"Push timing within [ {self.t} , {self.t + dt} ].",
f"{self.t + dt - latest_coke_charge} since last P/C. ",
f"P/C period = {self.charge_program.period(self.t)}",)
# 마지막 장입 시각 + 장입 시간 간격 이 이번 time step 에 포함됨
# 일정한 간격으로 장입 진행 중, 마지막 장입 시간 += 장입 간격
if self.t < self.t_last + period:
self.t_last += period
# 마지막 장입 이후 현재 장입 간격보다 긴 시간이 경과함 (장입 간격이 짧아짐; 감산 끝남 등)
# 이번 time step 끝을 마지막 장입 시각으로 업데이트
else:
self.t_last = self.t + dt
# 추출/장입 실행
i_oven = self.next_oven()
# oven = self.ovens[i_oven]
fresh_coal = CokeCharge(self.t + dt, i_oven)
self.push_and_charge(fresh_coal)
# 시뮬레이션 시간 업데이트
self.t += dt