def update_coolant_channel_lin(self): """ Calculates the coolant channel temperatures. Access to: -self.temp_layer -self.g_cool -self.k_cool Manipulate: -self.temp_cool -self.temp_cool_ele """ for q in range(self.n_cells): for w in range(1, self.nodes): self.temp_cool[q, w] =\ g_func.calc_fluid_temp_out(self.temp_cool[q, w - 1], self.temp_layer[q][0, w - 1], self.g_cool, self.k_cool) self.temp_cool_ele[q] = g_func.calc_elements_1_d(self.temp_cool[q]) if self.cool_ch_bc is True: for w in range(1, self.nodes): self.temp_cool[-1, w] =\ g_func.calc_fluid_temp_out(self.temp_cool[-1, w - 1], self.temp_layer[-1][-1, w - 1], self.g_cool, self.k_cool) self.temp_cool_ele[-1] = g_func.calc_elements_1_d(self.temp_cool[-1])
def calc_mem_resistivity_springer(self): """ Calculates the membrane resistivity for NT-PEMFC according to (Springer, 1991). Access to: -self.cathode.humidity -self.anode.humidity -self.temp_mem -self.th_mem -self.cathode.cathode.active_area_dx_ch Manipulate: -self.omega_ca -self.omega """ humidity = (self.cathode.humidity + self.anode.humidity) * 0.5 humidity_ele = g_func.calc_elements_1_d(humidity) a = 0.043 + 17.81 * humidity_ele b = -39.85 * humidity_ele**2. + 36. * humidity_ele**3. free_water_content = a + b mem_el_con = 0.005139 * free_water_content - 0.00326 mem_el_con_temp =\ np.exp(1268 * (0.0033 - 1. / self.temp_mem)) * mem_el_con self.omega_ca = self.th_mem / mem_el_con_temp * 1.e-4
def calc_species_properties(self): """ Calculates the properties of the species in the gas phase Access to: -self.temp_fluid -self.p -self.cl_type -g_fit.object.methods Manipulate: -self.cp -self.lambdas -self.visc -self.cp_ele """ if self.cl_type is True: self.cp[0] = g_fit.oxygen.calc_cp(self.temp_fluid) self.lambdas[0] = g_fit.oxygen.calc_lambda(self.temp_fluid, self.p) self.visc[0] = g_fit.oxygen.calc_visc(self.temp_fluid) else: self.cp[0] = g_fit.hydrogen.calc_cp(self.temp_fluid) self.lambdas[0] = g_fit.hydrogen.calc_lambda(self.temp_fluid, self.p) self.visc[0] = g_fit.hydrogen.calc_visc(self.temp_fluid) self.cp[1] = g_fit.water.calc_cp(self.temp_fluid) self.cp[2] = g_fit.nitrogen.calc_cp(self.temp_fluid) self.lambdas[1] = g_fit.water.calc_lambda(self.temp_fluid, self.p) self.lambdas[2] = g_fit.nitrogen.calc_lambda(self.temp_fluid, self.p) self.visc[1] = g_fit.water.calc_visc(self.temp_fluid) self.visc[2] = g_fit.nitrogen.calc_visc(self.temp_fluid) self.cp_ele = g_func.calc_elements_1_d(self.cp[0])
def calc_con(self): """ Calculates the gas phase molar concentrations. Access to: -self.p -self.mol_flow -self.temp_fluid -g.par.dict_uni['R'] Manipulate: -self.gas_con """ for w in range(g_par.dict_case['nodes']): id_lw = self.p[w] / (g_par.dict_uni['R'] * self.temp_fluid[w]) var4 = np.sum(self.mol_flow[:, w]) var2 = self.mol_flow[1][w] / var4 self.gas_con[1][w] = id_lw * var2 a = w_prop.water.calc_p_sat(self.temp_fluid[w]) e = g_par.dict_uni['R'] * self.temp_fluid[w] if self.gas_con[1][w] >= a / e: # saturated b = self.mol_flow[0][w] + self.mol_flow[2][w] c = self.mol_flow[0][w] / b d = self.mol_flow[2][w] / b self.gas_con[0][w] = (self.p[w] - a) / e * c self.gas_con[2][w] = (self.p[w] - a) / e * d self.gas_con[1][w] = a / e else: # not saturated var5 = id_lw / var4 self.gas_con[0][w] = var5 * self.mol_flow[0][w] self.gas_con[2][w] = var5 * self.mol_flow[2][w] self.gas_con_ele = g_func.calc_elements_1_d(self.gas_con[0])
def calc_cross_water_flux(self): """ Calculates the water cross flux through the membrane according to (Springer, 1991). Access to: -g_par.dict_case['vap_m_t_coef'] -self.cathode.free_w -self.anode.free_w -g_par.dict_case['mol_con_m'] -g_par.dict_uni['F'] -self.i_ca -self.temp_mem -self.th_mem Manipulate: -self.w_cross_flow """ vap_coeff = g_par.dict_case['vap_m_temp_coeff'] humidity = [self.cathode.humidity, self.anode.humidity] humidity_ele = np.array([ g_func.calc_elements_1_d(humidity[0]), g_func.calc_elements_1_d(humidity[1]) ]) a = 0.043 + 17.81 * humidity_ele b = -39.85 * humidity_ele**2. + 36. * humidity_ele**3. free_w_content = a + b zeta_plus = free_w_content[0] + free_w_content[1] \ + self.i_cd / (2. * vap_coeff * g_par.dict_case['mol_con_m'] * g_par.dict_uni['F']) zeta_negative =\ (free_w_content[0] - free_w_content[1] + 5. * self.i_cd / (2. * vap_coeff * g_par.dict_case['mol_con_m'] * g_par.dict_uni['F'])) \ / (1. + g_func.dw(self.temp_mem) * zeta_plus / (self.th_mem * vap_coeff)) m_c = 0.5 * (zeta_plus + zeta_negative) m_a = 0.5 * (zeta_plus - zeta_negative) self.w_cross_flow = \ self.i_cd / g_par.dict_uni['F'] + g_par.dict_case['mol_con_m'] \ * g_func.dw(self.temp_mem) * (m_a ** 2. - m_c ** 2.) \ / (2. * self.th_mem)
def calc_pressure(self): """ Calculates the total channel pressure for each element. Access to: -self.channel.p_in -self.u -self.Re -self.rho_gas -self.fwd_mat -self.bwd_mat -self.channel.d_h -self.channel.dx -self.p_drop_bends Manipulate: -self.p """ p_out = self.channel.p_out rho_ele = g_func.calc_elements_1_d(self.rho_gas) u_ele = g_func.calc_elements_1_d(self.u) Re_ele = g_func.calc_elements_1_d(self.Re) if self.cl_type is True: mat = self.bwd_mat self.p[-1] = p_out self.p[:-1] = p_out + 32. / self.channel.d_h \ * np.matmul(mat, rho_ele * u_ele ** 2. / Re_ele) \ * self.channel.dx\ + np.linspace(self.p_drop_bends * (g_par.dict_case['nodes']),0, g_par.dict_case['nodes']-1) else: mat = self.fwd_mat self.p[0] = p_out self.p[1:] = p_out + 32. / self.channel.d_h \ * np.matmul(mat, rho_ele * u_ele ** 2. / Re_ele) \ * self.channel.dx\ + np.linspace(0, self.p_drop_bends * (g_par.dict_case['nodes']), g_par.dict_case['nodes']-1)
def calc_temp_fluid_ele(self): """ This function sets the layer Temperatures, they can be obtained from the temperature system. Access to: - self.temp_fluid 1-D-Array, [nodes] Manipulate: - self.temp_fluid, 1-D-Array, [elements] """ self.temp_fluid_ele = g_func.calc_elements_1_d(self.temp_fluid)
def update_gas_channel_lin(self): """ Calculates the fluid temperatures in the anode and cathode channels Access to: -self.k_gas_ch -self.temp_layer -self.temp_fluid -self.g_fluid Manipulate: -self.temp_fluid """ for q in range(self.n_cells): for w in range(1, self.nodes): self.temp_fluid[0, q, w] =\ g_func.calc_fluid_temp_out(self.temp_fluid[0, q, w - 1], self.temp_layer[q][1, w - 1], self.g_fluid[0, q, w - 1], self.k_gas_ch[0, q, w - 1]) temp_fluid_ele = g_func.calc_elements_1_d(self.temp_fluid[0, q]) self.temp_fluid_ele[0, q] = np.minimum(temp_fluid_ele, self.temp_layer[q][0]) for w in range(self.n_ele - 1, -1, -1): self.temp_fluid[1, q, w] =\ g_func.calc_fluid_temp_out(self.temp_fluid[1, q, w + 1], self.temp_layer[q][4, w], self.g_fluid[1, q, w], self.k_gas_ch[1, q, w]) temp_fluid_ele = g_func.calc_elements_1_d(self.temp_fluid[1, q]) self.temp_fluid_ele[1, q] = np.minimum(temp_fluid_ele, self.temp_layer[q][4]) self.temp_fluid[0] = g_func.calc_nodes_2_d(self.temp_fluid_ele[0]) self.temp_fluid[0, :, 0] = self.temp_gas_in[0] self.temp_fluid[1] = g_func.calc_nodes_2_d(self.temp_fluid_ele[1]) self.temp_fluid[1, :, -1] = self.temp_gas_in[1]
def calc_gas_properties(self): """ Calculates the properties of the gas phase Access to: -self.spec_num -self.mass_f -self.r_species -self.cp -self.visc -self.lambdas -self.mol_f -self.temp_fluid Manipulate: -self.r_gas -self.cp_gas -self.cp_gas_ele -self.cp_ele -self.visc_gas -self.lambda_gas -self.rho_gas -self.Pr """ temp1, temp2 = [], [] for q in range(self.spec_num): temp1.append(self.mass_f[q] * self.r_species[q]) temp2.append(self.mass_f[q] * self.cp[q]) self.r_gas = sum(temp1) self.cp_gas = sum(temp2) self.cp_gas_ele = g_func.calc_elements_1_d(self.cp_gas) self.visc_gas = g_func.calc_visc_mix(self.visc, self.mol_f, self.mol_mass) self.lambda_gas = g_func.calc_lambda_mix(self.lambdas, self.mol_f, self.visc, self.mol_mass) self.rho_gas = g_func.calc_rho(self.p, self.r_gas, self.temp_fluid) self.Pr = self.visc_gas * self.cp_gas / self.lambda_gas
def output_plots(self, q): """ Coordinates the plot sequence """ self.path_plot = os.path.join(os.path.dirname(__file__), 'output/' + 'case' + q + '/plots' + '/') try: os.makedirs(self.path_plot) except OSError as e: if e.errno != errno.EEXIST: raise x_node = np.linspace(0., ch_dict.dict_cathode_channel['channel_length'], g_par.dict_case['nodes']) x_ele = g_func.calc_elements_1_d(x_node) g_func.output([ self.mdf_criteria_process, self.i_ca_criteria_process, self.temp_criteria_process ], 'ERR', 'Iteration', 'log', ['k', 'r', 'b'], 'Convergence', 0., len(self.temp_criteria_process), ['Flow Distribution', 'Current Density', 'Temperature'], self.path_plot) self.mdf_criteria_process = [] self.mdf_criteria_ano_process = [] self.mdf_criteria_cat_process = [] self.temp_criteria_process = [] self.i_ca_criteria_process = [] g_func.output_x(self.stack.i_cd, x_ele, 'Current Density $[A/m²]$', 'Channel Location $[m]$', 'linear', 'Current Density', False, [0., ch_dict.dict_cathode_channel['channel_length']], self.path_plot) if self.stack.cell_numb > 1: g_func.output([ self.stack.manifold[0].cell_stoi, self.stack.manifold[1].cell_stoi ], 'Stoichiometry', 'Cell Number', 'linear', ['k', 'r'], 'Stoichimetry Distribution', 0., self.stack.cell_numb - 1, ['Cathode', 'Anode'], self.path_plot) g_func.output([self.stack.manifold[0].cell_stoi / 2.5], 'Flow Distribution', 'Cell Number', 'linear', ['k'], 'Distribution', 0., self.stack.cell_numb - 1, ['Cathode'], self.path_plot) self.plot_cell_var( 'v', 'Voltage $[V]$', 'Channel Location $[m]$', 'linear', 'Cell Voltage', [0., ch_dict.dict_cathode_channel['channel_length']], x_ele, [0.52, 0.54]) g_func.output_x(self.stack.temp_sys.temp_cool, x_node, 'Coolant Temperature [K]', 'Channel Location $[m]$', 'linear', 'Coolant Temperature', False, [0., ch_dict.dict_cathode_channel['channel_length']], self.path_plot) self.plot_cell_var( 'temp[-1]', 'Anode BPP - GDE Temperature $[K]$', 'Channel Location $[m]$', 'linear', 'Anode Plate - GDE Temperature', [0., ch_dict.dict_cathode_channel['channel_length']], x_ele, False) self.plot_cell_var( 'temp[-2]', 'Anode GDE - MEM Temperature $[K]$', 'Channel Location $[m]$', 'linear', 'Anode GDE - Membrane Temperature', [0., ch_dict.dict_cathode_channel['channel_length']], x_ele, False) self.plot_cell_var( 'temp[2]', 'Cathode GDE - MEM Temperature $[K]$', 'Channel Location $[m]$', 'linear', 'Cathode GDL Temperature', [0., ch_dict.dict_cathode_channel['channel_length']], x_ele, False) self.plot_cell_var( 'cathode.temp_fluid', 'Cathode Fluid Temperature $[K]$', 'Channel Location $[m]$', 'linear', 'Cathode_Channel_Temperature', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'temp[1]', 'Cathode BPP-GDE Temperature $[K]$', 'Channel Location $[m]$', 'linear', 'Cathode GDE - Plate Temperature', [0., ch_dict.dict_cathode_channel['channel_length']], x_ele, False) self.plot_cell_var( 'anode.temp_fluid', 'Anode Fluid Temperature $[K]$', 'Channel Location $[m]$', 'linear', 'Anode_Channel_Temperature', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'temp[0]', 'BPP - BPP Temperature $[K]$', 'Channel Location $[m]$', 'linear', 'Coolant Plate Temperature', [0., ch_dict.dict_cathode_channel['channel_length']], x_ele, False) self.plot_cell_var( 'cathode.mol_flow[0] * 1.e3', 'Cathode Oxygen Molar Flow $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Cathode Oxygen Molar Flow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.mol_flow[1] * 1.e3', 'Cathode Water Molar Flow $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Cathode Water Molar Flow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.mol_flow[2] * 1.e3', 'Cathode Nitrogen Molar Flow $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Cathode Nitrogen Molar Flow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.mol_flow[0] * 1.e3', 'Anode Hydrogen Molar Flow $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Anode Hydrogen Molar Flow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.mol_flow[1] * 1.e3', 'Anode Water Molar Flow $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Anode Water Molar Flow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.mol_flow[2] * 1.e3', 'Anode Nitrogen Molar Flow $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Anode Nitrogen Molar Flow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.mol_f[0]', 'Oxygen Molar Fraction', 'Channel Location $[m]$', 'linear', 'Oxygen_Molar_Fraction', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.mol_f[1]', 'Cathode Gas Water Molar Fraction', 'Channel Location $[m]$', 'linear', 'Water Molar Fraction Cathode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.mol_f[2]', 'Cathode Nitrogen Molar Fraction', 'Channel Location $[m]$', 'linear', 'Nitrogen_Molar_Fraction_Cathode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.mol_f[0]', 'Hydrogen Molar Fraction', 'Channel Location $[m]$', 'linear', 'Hydrogen_Molar_Fraction_Anode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.mol_f[1]', 'Anode Gas Water Molar Fraction', 'Channel Location $[m]$', 'linear', 'Water_Molar_Fraction_Anode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.mol_f[2]', 'Anode Nitrogen Molar Fraction', 'Channel Location $[m]$', 'linear', 'Nitrogen_Molar_Fraction_Anode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.liq_w_flow * 1.e3', 'Cathode Liquid Water Flow $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Liquid Water Flow Cathode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.cond_rate * 1.e3', 'Cathode Water Condensation Rate $[mmol/s]$', 'Channel Location $[m]$', 'linear', 'Water Condensation Rate Cathode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.humidity', 'Cathode Relative Humidity', 'Channel Location $[m]$', 'linear', 'Relative Humidity Cathode', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.m_flow_gas * 1.e6', 'Cathode Channel Gas Massflow $[mg/s]$', 'Channel Location $[m]$', 'linear', 'Cathode_Channel__Gas_Massflow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.m_flow_fluid * 1.e6', 'Cathode Channel Fluid Massflow $[mg/s]$', 'Channel Location $[m]$', 'linear', 'Cathode_Channel_Fluid_Massflow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.g_fluid * 1.e3', 'Cathode Capacity Flow $[mW/K]$', 'Channel Location $[m]$', 'linear', 'Cathode Capacity Flow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.m_flow_reac * 1.e6', 'Oxygen Massflow $[mg/s]$', 'Channel Location $[m]$', 'linear', 'Oxygen_massflow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.m_flow_vap_w * 1.e6', 'Cathode Vapour Massflow $[mg/s]$', 'Channel Location $[m]$', 'linear', 'Vapour Massflow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.m_flow_reac * 1.e6', 'Hydrogen Massflow $[mg/s]$', 'Channel Location $[m]$', 'linear', 'Hydrogen_massflow', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.cp_fluid', 'Cathode Heat Capacity $[J/(kgK)]$', 'Channel Location $[m]$', 'linear', 'Cathode Heat Capacity', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'cathode.p', 'Cathode Channel Pressure $[Pa]$', 'Channel Location $[m]$', 'linear', 'Cathode Channel Pressure', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) self.plot_cell_var( 'anode.p', 'Anode Channel Pressure $[Pa]$', 'Channel Location $[m]$', 'linear', 'Anode Channel Pressure', [0., ch_dict.dict_cathode_channel['channel_length']], x_node, False) # Z-Axis-Temperature Plot x_vec_z = np.array([ 0., geom.bipolar_plate_thickness, geom.gas_diffusion_layer_thickness, geom.membrane_thickness, geom.gas_diffusion_layer_thickness ]) x_vec_e = np.array([ geom.bipolar_plate_thickness, geom.bipolar_plate_thickness, geom.gas_diffusion_layer_thickness, geom.membrane_thickness, geom.gas_diffusion_layer_thickness ]) x_vec_l = np.array([ geom.bipolar_plate_thickness, geom.bipolar_plate_thickness, geom.gas_diffusion_layer_thickness, geom.membrane_thickness, geom.gas_diffusion_layer_thickness, geom.bipolar_plate_thickness ]) x = [] for l in range(self.stack.cell_numb): if l is 0: x.append(x_vec_z) elif 0 < l < self.stack.cell_numb - 1: x.append(x_vec_e) else: x.append(x_vec_l) x = np.cumsum(np.block(x)) t = self.stack.temp_sys.temp_layer for w in range(g_par.dict_case['nodes'] - 1): t_vec = [] for l in range(self.stack.cell_numb): if l is not self.stack.cell_numb - 1: t_vec.append( np.array([ t[l][0, w], t[l][1, w], t[l][2, w], t[l][3, w], t[l][4, w] ])) else: t_vec.append( np.array([ t[l][0, w], t[l][1, w], t[l][2, w], t[l][3, w], t[l][4, w], t[l][5, w] ])) plt.plot(x, np.block(t_vec), color=plt.cm.coolwarm( (w + 1.e-20) / float(g_par.dict_case['nodes'] - 1.))) plt.xlim(0, x[-1]) plt.xlabel('Stack Location $[m]$', fontsize=16) plt.ylabel('Temperature $[K]$', fontsize=16) plt.tick_params(labelsize=14) plt.autoscale(tight=True, axis='both', enable=True) plt.tight_layout() plt.savefig(os.path.join(self.path_plot + 'Z-Cut-Temperature' + '.png')) plt.close() for q in range(self.stack.cell_numb): print(np.average(self.stack.i_cd[q, :]))