Implementing simulator
This commit is contained in:
parent
1a5522f527
commit
0f7e6bec97
2 changed files with 186 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.ipynb_checkpoints
|
||||
*~
|
||||
184
Battery.py
Normal file
184
Battery.py
Normal 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
|
||||
Loading…
Add table
Reference in a new issue