def initialise_target(self, c, key): r""" Return a starting value for pressure and enthalpy at inlet. Parameters ---------- c : tespy.connections.connection.Connection Connection to perform initialisation on. key : str Fluid property to retrieve. Returns ------- val : float Starting value for pressure/enthalpy in SI units. .. math:: val = \begin{cases} 4 \cdot 10^5 & \text{key = 'p'}\\ h\left(p, 300 \text{K} \right) & \text{key = 'h' at inlet 1}\\ h\left(p, 220 \text{K} \right) & \text{key = 'h' at outlet 2} \end{cases} """ if key == 'p': return 50e5 elif key == 'h': if c.target_id == 'in1': T = 300 + 273.15 return h_mix_pT(c.get_flow(), T) else: T = 220 + 273.15 return h_mix_pT(c.get_flow(), T)
def energy_balance(self): r""" Calculate the residual in energy balance of the water electrolyzer. The residual is the negative to the necessary power input. Returns ------- res : float Residual value. .. math:: \begin{split} res = & \dot{m}_{in,2} \cdot \left( h_{in,2} - h_{in,2,ref} \right)\\ & - \dot{m}_{out,3} \cdot e_0\\ & -\dot{m}_{in,1} \cdot \left( h_{out,1} - h_{in,1} \right)\\ & - \dot{m}_{out,2} \cdot \left( h_{out,2} - h_{out,2,ref} \right)\\ & - \dot{m}_{out,3} \cdot \left( h_{out,3} - h_{out,3,ref} \right)\\ \end{split} Note ---- The temperature for the reference state is set to 20 °C, thus the feed water must be liquid as proposed in the calculation of the minimum specific energy consumption for electrolysis: :func:`tespy.components.reactors.water_electrolyzer.calc_e0`. The part of the equation regarding the cooling water is implemented with negative sign as the energy for cooling is extracted from the reactor. - Reference temperature: 293.15 K. - Reference pressure: 1 bar. """ T_ref = 293.15 p_ref = 1e5 # equations to set a reference point for each h2o, h2 and o2 h_refh2o = h_mix_pT([1, p_ref, 0, self.inl[1].fluid.val], T_ref) h_refh2 = h_mix_pT([1, p_ref, 0, self.outl[2].fluid.val], T_ref) h_refo2 = h_mix_pT([1, p_ref, 0, self.outl[1].fluid.val], T_ref) val = (self.inl[1].m.val_SI * (self.inl[1].h.val_SI - h_refh2o) - self.outl[2].m.val_SI * self.e0 - self.inl[0].m.val_SI * (self.outl[0].h.val_SI - self.inl[0].h.val_SI) - self.outl[1].m.val_SI * (self.outl[1].h.val_SI - h_refo2) - self.outl[2].m.val_SI * (self.outl[2].h.val_SI - h_refh2)) return val
def initialise_target(self, c, key): r""" Return a starting value for pressure and enthalpy at inlet. Parameters ---------- c : tespy.connections.connection.Connection Connection to perform initialisation on. key : str Fluid property to retrieve. Returns ------- val : float Starting value for pressure/enthalpy in SI units. .. math:: val = \begin{cases} 5 \cdot 10^5 & \text{key = 'p'}\\ h\left(T=293.15, p=5 \cdot 10^5\right) & \text{key = 'h'} \end{cases} """ if key == 'p': return 5e5 elif key == 'h': flow = c.get_flow() T = 20 + 273.15 return h_mix_pT(flow, T)
def initialise_source(self, c, key): r""" Returns a starting value for pressure and enthalpy at component's outlet. Parameters ---------- c : tespy.connections.connection Connection to perform initialisation on. key : str Fluid property to retrieve. Returns ------- val : float Starting value for pressure/enthalpy in SI units. .. math:: val = \begin{cases} 5 \cdot 10^5 & \text{key = 'p'}\\ h\left(T=323.15, p=5 \cdot 10^5\right) & \text{key = 'h'} \end{cases} """ if key == 'p': return 5e5 elif key == 'h': flow = [c.m.val0, 5e5, c.h.val_SI, c.fluid.val] T = 50 + 273.15 return h_mix_pT(flow, T)
def desuperheat(ude): ttd_min = ude.params['ttd_min'] return ( ude.conns[0].h.val_SI - ude.conns[1].h.val_SI - ude.params['distance'] * ( ude.conns[0].h.val_SI - h_mix_pT( ude.conns[1].get_flow(), T_mix_ph(ude.conns[2].get_flow()) + ttd_min)))
def energy_balance_func(self): r""" Calculate the energy balance of the diabatic combustion chamber. Returns ------- residual : float Residual value of equation. .. math:: \begin{split} 0 = & \sum_i \dot{m}_{in,i} \cdot \left( h_{in,i} - h_{in,i,ref} \right)\\ & -\dot{m}_{out,2}\cdot\left( h_{out,1}-h_{out,1,ref} \right)\\ & + LHV_{fuel} \cdot\left(\sum_i\dot{m}_{in,i}\cdot x_{fuel,in,i}- \dot{m}_{out,1} \cdot x_{fuel} \right) \cdot \eta \end{split}\\ \forall i \in \text{inlets} Note ---- The temperature for the reference state is set to 25 °C, thus the water may be liquid. In order to make sure, the state is referring to the lower heating value, the state of the water in the flue gas is fored to gaseous. - Reference temperature: 298.15 K. - Reference pressure: 1 bar. """ T_ref = 298.15 p_ref = 1e5 res = 0 for i in self.inl: res += i.m.val_SI * (i.h.val_SI - h_mix_pT( [0, p_ref, 0, i.fluid.val], T_ref, force_gas=True)) for o in self.outl: res -= o.m.val_SI * (o.h.val_SI - h_mix_pT( [0, p_ref, 0, o.fluid.val], T_ref, force_gas=True)) res += self.calc_ti() * self.eta.val return res
def initialise_source(self, c, key): r""" Return a starting value for pressure and enthalpy at outlet. Parameters ---------- c : tespy.connections.connection Connection to perform initialisation on. key : str Fluid property to retrieve. Returns ------- val : float Starting value for pressure/enthalpy in SI units. .. math:: val = \begin{cases} 10 \cdot 10^5 & \text{key = 'p'}\\ h\left(p, 473.15 \text{K} \right) & \text{key = 'h' at outlet 1}\\ h\left(p, 473.15 \text{K} \right) & \text{key = 'h' at outlet 2}\\ h\left(p, 523.15 \text{K} \right) & \text{key = 'h' at outlet 3} \end{cases} """ if key == 'p': return 10e5 elif key == 'h': flow = c.to_flow() if c.source_id == 'out1': T = 200 + 273.15 return h_mix_pT(flow, T) elif c.source_id == 'out2': T = 200 + 273.15 return h_mix_pT(flow, T) else: T = 250 + 273.15 return h_mix_pT(flow, T)
def energy_balance_func(self): r""" Calculate the energy balance of the adiabatic combustion chamber. Returns ------- residual : float Residual value of equation. .. math:: \begin{split} 0 = & \sum_i \dot{m}_{in,i} \cdot \left( h_{in,i} - h_{in,i,ref} \right)\\ & -\dot{m}_{out,2}\cdot\left( h_{out,1}-h_{out,1,ref} \right)\\ & + LHV_{fuel} \cdot\left(\sum_i\dot{m}_{in,i}\cdot x_{fuel,in,i}- \dot{m}_{out,1} \cdot x_{fuel} \right) \end{split}\\ \forall i \in \text{inlets} Note ---- The temperature for the reference state is set to 100 °C, as the custom fluid properties are inacurate at the dew-point of water in the flue gas! - Reference temperature: 373.15 K. - Reference pressure: 1 bar. """ T_ref = 373.15 p_ref = 1e5 res = 0 for i in self.inl: res += i.m.val_SI * ( i.h.val_SI - h_mix_pT([0, p_ref, 0, i.fluid.val], T_ref)) for o in self.outl: res -= o.m.val_SI * ( o.h.val_SI - h_mix_pT([0, p_ref, 0, o.fluid.val], T_ref)) return res + self.calc_ti()
def energy_balance_deriv(self, increment_filter, k): r""" Partial derivatives for reactor energy balance. Parameters ---------- increment_filter : ndarray Matrix for filtering non-changing variables. k : int Position of derivatives in Jacobian matrix (k-th equation). """ # derivatives determined from calc_P function T_ref = 298.15 p_ref = 1e5 h_refh2o = h_mix_pT([1, p_ref, 0, self.inl[1].fluid.val], T_ref) h_refh2 = h_mix_pT([1, p_ref, 0, self.outl[2].fluid.val], T_ref) h_refo2 = h_mix_pT([1, p_ref, 0, self.outl[1].fluid.val], T_ref) # derivatives cooling water inlet self.jacobian[k, 0, 0] = self.inl[0].h.val_SI - self.outl[0].h.val_SI self.jacobian[k, 0, 2] = self.inl[0].m.val_SI # derivatives feed water inlet self.jacobian[k, 1, 0] = (self.inl[1].h.val_SI - h_refh2o) self.jacobian[k, 1, 2] = self.inl[1].m.val_SI # derivative cooling water outlet self.jacobian[k, 2, 2] = -self.inl[0].m.val_SI # derivatives oxygen outlet self.jacobian[k, 3, 0] = -(self.outl[1].h.val_SI - h_refo2) self.jacobian[k, 3, 2] = -self.outl[1].m.val_SI # derivatives hydrogen outlet self.jacobian[k, 4, 0] = -(self.outl[2].h.val_SI - h_refh2 + self.e0) self.jacobian[k, 4, 2] = -self.outl[2].m.val_SI # derivatives for variable P if self.P.is_var: self.jacobian[k, 5 + self.P.var_pos, 0] = 1
def calc_parameters(self): r"""Postprocessing parameter calculation.""" CombustionChamber.calc_parameters(self) T_ref = 298.15 p_ref = 1e5 res = 0 for i in self.inl: res += i.m.val_SI * (i.h.val_SI - h_mix_pT( [0, p_ref, 0, i.fluid.val], T_ref, force_gas=True)) for o in self.outl: res -= o.m.val_SI * (o.h.val_SI - h_mix_pT( [0, p_ref, 0, o.fluid.val], T_ref, force_gas=True)) self.eta.val = -res / self.ti.val self.Q_loss.val = -(1 - self.eta.val) * self.ti.val if self.inl[1].p.val < self.inl[0].p.val: msg = ( "The pressure at inlet 2 is lower than the pressure at inlet 1 " "at component " + self.label + ".") logging.warning(msg)
def derivatives(self, vec_z): r""" Calculate partial derivatives for given equations. Returns ------- mat_deriv : ndarray Matrix of partial derivatives. """ ###################################################################### # derivatives fluid, mass flow and reactor pressure are static k = self.num_nw_fluids * 4 + 5 ###################################################################### # derivatives for energy balance equations T_ref = 293.15 p_ref = 1e5 h_refh2o = h_mix_pT([1, p_ref, 0, self.inl[1].fluid.val], T_ref) h_refh2 = h_mix_pT([1, p_ref, 0, self.outl[2].fluid.val], T_ref) h_refo2 = h_mix_pT([1, p_ref, 0, self.outl[1].fluid.val], T_ref) # derivatives cooling water inlet self.mat_deriv[k, 0, 0] = -( self.outl[0].h.val_SI - self.inl[0].h.val_SI) self.mat_deriv[k, 0, 2] = self.inl[0].m.val_SI # derivatives feed water inlet self.mat_deriv[k, 1, 0] = (self.inl[1].h.val_SI - h_refh2o) self.mat_deriv[k, 1, 2] = self.inl[1].m.val_SI # derivative cooling water outlet self.mat_deriv[k, 2, 2] = - self.inl[0].m.val_SI # derivatives oxygen outlet self.mat_deriv[k, 3, 0] = - (self.outl[1].h.val_SI - h_refo2) self.mat_deriv[k, 3, 2] = - self.outl[1].m.val_SI # derivatives hydrogen outlet self.mat_deriv[k, 4, 0] = - self.e0 - (self.outl[2].h.val_SI - h_refh2) self.mat_deriv[k, 4, 2] = - self.outl[2].m.val_SI # derivatives for variable P if self.P.is_var: self.mat_deriv[k, 5 + self.P.var_pos, 0] = 1 k += 1 ###################################################################### # derivatives for temperature at gas outlets # derivatives for outlet 1 if not vec_z[3, 1]: self.mat_deriv[k, 3, 1] = dT_mix_dph(self.outl[1].to_flow()) if not vec_z[3, 2]: self.mat_deriv[k, 3, 2] = dT_mix_pdh(self.outl[1].to_flow()) # derivatives for outlet 2 if not vec_z[4, 1]: self.mat_deriv[k, 4, 1] = - dT_mix_dph(self.outl[2].to_flow()) if not vec_z[4, 2]: self.mat_deriv[k, 4, 2] = - dT_mix_pdh(self.outl[2].to_flow()) k += 1 ###################################################################### # derivatives for power vs. hydrogen production if self.e.is_set: self.mat_deriv[k, 4, 0] = - self.e.val # derivatives for variable P if self.P.is_var: self.mat_deriv[k, 5 + self.P.var_pos, 0] = 1 # derivatives for variable e if self.e.is_var: self.mat_deriv[k, 5 + self.e.var_pos, 0] = -( self.outl[2].m.val_SI) k += 1 ###################################################################### # derivatives for pressure ratio if self.pr_c.is_set: self.mat_deriv[k, 0, 1] = self.pr_c.val self.mat_deriv[k, 2, 1] = - 1 k += 1 ###################################################################### # derivatives for zeta value if self.zeta.is_set: f = self.zeta_func if not vec_z[0, 0]: self.mat_deriv[k, 0, 0] = self.numeric_deriv( f, 'm', 0, zeta='zeta') if not vec_z[0, 1]: self.mat_deriv[k, 0, 1] = self.numeric_deriv( f, 'p', 0, zeta='zeta') if not vec_z[0, 2]: self.mat_deriv[k, 0, 2] = self.numeric_deriv( f, 'h', 0, zeta='zeta') if not vec_z[2, 1]: self.mat_deriv[k, 2, 1] = self.numeric_deriv( f, 'p', 2, zeta='zeta') if not vec_z[2, 2]: self.mat_deriv[k, 2, 2] = self.numeric_deriv( f, 'h', 2, zeta='zeta') # derivatives for variable zeta if self.zeta.is_var: self.mat_deriv[k, 5 + self.zeta.var_pos, 0] = ( self.numeric_deriv( f, 'zeta', 5, zeta='zeta')) k += 1 ###################################################################### # derivatives for heat flow if self.Q.is_set: self.mat_deriv[k, 0, 0] = -( self.inl[0].h.val_SI - self.outl[0].h.val_SI) self.mat_deriv[k, 0, 2] = - self.inl[0].m.val_SI self.mat_deriv[k, 2, 2] = self.inl[0].m.val_SI k += 1 ###################################################################### # specified efficiency (efficiency definition: e0 / e) if self.eta.is_set: self.mat_deriv[k, 4, 0] = - self.e0 / self.eta.val # derivatives for variable P if self.P.is_var: self.mat_deriv[k, 5 + self.P.var_pos, 0] = 1 k += 1 ###################################################################### # specified characteristic line for efficiency if self.eta_char.is_set: self.mat_deriv[k, 4, 0] = self.numeric_deriv( self.eta_char_func, 'm', 4) # derivatives for variable P if self.P.is_var: self.mat_deriv[k, 5 + self.P.var_pos, 0] = 1 k += 1
def derivatives(self): r""" Calculates matrix of partial derivatives for given equations. Returns ------- mat_deriv : ndarray Matrix of partial derivatives. """ mat_deriv = [] ###################################################################### # derivatives for cooling liquid composition deriv = np.zeros((self.num_fl, 5 + self.num_vars, self.num_fl + 3)) j = 0 for fluid, x in self.inl[0].fluid.val.items(): deriv[j, 0, 3 + j] = 1 deriv[j, 2, 3 + j] = -1 j += 1 mat_deriv += deriv.tolist() # derivatives to constrain fluids to inlets/outlets deriv = np.zeros((3, 5 + self.num_vars, self.num_fl + 3)) i = 0 for fluid in self.inl[0].fluid.val.keys(): if fluid == self.h2o: deriv[0, 1, 3 + i] = -1 elif fluid == self.o2: deriv[1, 3, 3 + i] = -1 elif fluid == self.h2: deriv[2, 4, 3 + i] = -1 i += 1 mat_deriv += deriv.tolist() # derivatives to ban fluids off inlets/outlets deriv = np.zeros((3 * len(self.inl[1].fluid.val.keys()) - 3, 5 + self.num_vars, self.num_fl + 3)) i = 0 j = 0 for fluid in self.inl[1].fluid.val.keys(): if fluid != self.h2o: deriv[j, 1, 3 + i] = -1 j += 1 if fluid != self.o2: deriv[j, 3, 3 + i] = -1 j += 1 if fluid != self.h2: deriv[j, 4, 3 + i] = -1 j += 1 i += 1 mat_deriv += deriv.tolist() ###################################################################### # derivatives for mass balance equations # deritatives for mass flow balance in the heat exchanger deriv = np.zeros((3, 5 + self.num_vars, self.num_fl + 3)) deriv[0, 0, 0] = 1 deriv[0, 2, 0] = -1 # derivatives for mass flow balance for oxygen output o2 = molar_masses[self.o2] / (molar_masses[self.o2] + 2 * molar_masses[self.h2]) deriv[1, 1, 0] = o2 deriv[1, 3, 0] = -1 # derivatives for mass flow balance for hydrogen output deriv[2, 1, 0] = (1 - o2) deriv[2, 4, 0] = -1 mat_deriv += deriv.tolist() ###################################################################### # derivatives for pressure equations # derivatives for pressure oxygen outlet deriv = np.zeros((2, 5 + self.num_vars, self.num_fl + 3)) deriv[0, 1, 1] = 1 deriv[0, 3, 1] = -1 # derivatives for pressure hydrogen outlet deriv[1, 1, 1] = 1 deriv[1, 4, 1] = -1 mat_deriv += deriv.tolist() ###################################################################### # derivatives for energy balance equations deriv = np.zeros((1, 5 + self.num_vars, self.num_fl + 3)) T_ref = 293.15 p_ref = 1e5 h_refh2o = h_mix_pT([1, p_ref, 0, self.inl[1].fluid.val], T_ref) h_refh2 = h_mix_pT([1, p_ref, 0, self.outl[2].fluid.val], T_ref) h_refo2 = h_mix_pT([1, p_ref, 0, self.outl[1].fluid.val], T_ref) # derivatives cooling water inlet deriv[0, 0, 0] = - (self.outl[0].h.val_SI - self.inl[0].h.val_SI) deriv[0, 0, 2] = self.inl[0].m.val_SI # derivatives feed water inlet deriv[0, 1, 0] = (self.inl[1].h.val_SI - h_refh2o) deriv[0, 1, 2] = self.inl[1].m.val_SI # derivative cooling water outlet deriv[0, 2, 2] = - self.inl[0].m.val_SI # derivatives oxygen outlet deriv[0, 3, 0] = - (self.outl[1].h.val_SI - h_refo2) deriv[0, 3, 2] = - self.outl[1].m.val_SI # derivatives hydrogen outlet deriv[0, 4, 0] = - self.e0 - (self.outl[2].h.val_SI - h_refh2) deriv[0, 4, 2] = - self.outl[2].m.val_SI # derivatives for variable P if self.P.is_var: deriv[0, 5 + self.P.var_pos, 0] = 1 mat_deriv += deriv.tolist() ###################################################################### # derivatives for temperature at gas outlets deriv = np.zeros((1, 5 + self.num_vars, self.num_fl + 3)) # derivatives for outlet 1 deriv[0, 3, 1] = dT_mix_dph(self.outl[1].to_flow()) deriv[0, 3, 2] = dT_mix_pdh(self.outl[1].to_flow()) # derivatives for outlet 2 deriv[0, 4, 1] = - dT_mix_dph(self.outl[2].to_flow()) deriv[0, 4, 2] = - dT_mix_pdh(self.outl[2].to_flow()) mat_deriv += deriv.tolist() ###################################################################### # derivatives for power vs. hydrogen production if self.e.is_set: deriv = np.zeros((1, 5 + self.num_vars, self.num_fl + 3)) deriv[0, 4, 0] = - self.e.val # derivatives for variable P if self.P.is_var: deriv[0, 5 + self.P.var_pos, 0] = 1 # derivatives for variable e if self.e.is_var: deriv[0, 5 + self.e.var_pos, 0] = - self.outl[2].m.val_SI mat_deriv += deriv.tolist() ###################################################################### # derivatives for pressure ratio if self.pr_c.is_set: deriv = np.zeros((1, 5 + self.num_vars, self.num_fl + 3)) deriv[0, 0, 1] = self.pr_c.val deriv[0, 2, 1] = - 1 mat_deriv += deriv.tolist() ###################################################################### #pr_c.val = pressure ratio Druckverlust (als Faktor vorgegeben) # derivatives for zeta value if self.zeta.is_set: deriv = np.zeros((1, 5 + self.num_vars, self.num_fl + 3)) deriv[0, 0, 0] = self.numeric_deriv(self.zeta_func, 'm', 0) deriv[0, 0, 1] = self.numeric_deriv(self.zeta_func, 'p', 0) deriv[0, 0, 2] = self.numeric_deriv(self.zeta_func, 'h', 0) deriv[0, 2, 1] = self.numeric_deriv(self.zeta_func, 'p', 2) deriv[0, 2, 2] = self.numeric_deriv(self.zeta_func, 'h', 2) # derivatives for variable zeta if self.zeta.is_var: deriv[0, 5 + self.zeta.var_pos, 0] = ( self.numeric_deriv(self.zeta_func, 'zeta', 5)) mat_deriv += deriv.tolist() ###################################################################### # derivatives for heat flow if self.Q.is_set: deriv = np.zeros((1, 5 + self.num_vars, self.num_fl + 3)) deriv[0, 0, 0] = - (self.inl[0].h.val_SI - self.outl[0].h.val_SI) deriv[0, 0, 2] = - self.inl[0].m.val_SI deriv[0, 2, 2] = self.inl[0].m.val_SI mat_deriv += deriv.tolist() ###################################################################### # specified efficiency (efficiency definition: e0 / e) if self.eta.is_set: deriv = np.zeros((1, 5 + self.num_vars, self.num_fl + 3)) deriv[0, 4, 0] = - self.e0 / self.eta.val # derivatives for variable P if self.P.is_var: deriv[0, 5 + self.P.var_pos, 0] = 1 mat_deriv += deriv.tolist() ###################################################################### # specified characteristic line for efficiency if self.eta_char.is_set: mat_deriv += self.eta_char_deriv() ###################################################################### return np.asarray(mat_deriv)