def _design(self): feed_solids, feed_gases, lime, ammonia, boiler_chems, bag, natural_gas, \ makeup_water = self.ins emission, ash, blowdown_water = self.outs side_streams_to_heat = self.side_streams_to_heat side_streams_lps = self.side_streams_lps system_heating_utilities = self.system_heating_utilities = {} lps = HeatUtility.get_heating_agent('low_pressure_steam') hps = HeatUtility.get_heating_agent('high_pressure_steam') # Use combustion reactions to create outs combustion_rxns = self.chemicals.get_combustion_reactions() combustible_feeds = Stream(None) emission.mol = feed_solids.mol + feed_gases.mol combustible_feeds.copy_flow(emission, tuple(self.combustibles), remove=True) combustion_rxns.force_reaction(combustible_feeds.mol) emission.mol += (combustible_feeds.mol + ammonia.mol) self.emission_rxns.force_reaction(emission.mol) # FGD lime scaled based on SO2 generated, # 20% stoichiometetric excess based on P52 of ref [1] lime.imol['Lime'] = max(0, -emission.imol['Lime'] * 1.2) emission.mol += lime.mol # Air/O2 usage not rigorously modeled emission.imol['O2'] = 0 ash.empty() for chemical in emission.chemicals: if chemical.ID not in ('Water', 'H2O') and chemical.locked_state != 'g': ash.imol[chemical.ID] = emission.imol[chemical.ID] emission.imol[chemical.ID] = 0 emission.imol[ 'Water'] = feed_solids.imol['Water'] + feed_gases.imol['Water'] ash.mol += boiler_chems.mol emission.phase = 'g' ash.phase = 's' # Assume T of emission and ash are the same as hps, which # has highest T amont all heating agents emission.T = ash.T = hps.T # Total heat generated by the boiler (kJ/hr) H_in = feed_solids.H + feed_gases.H H_out = emission.H + ash.H # Water evaporation energy is already accounted for in emission enthalpy heat_from_combustion = -(feed_solids.HHV + feed_gases.HHV) heat_generated = self.heat_generated = \ (H_in+heat_from_combustion)*self.B_eff - H_out for u in self.system.units: if u is self: continue if hasattr(u, 'heat_utilities'): for hu in u.heat_utilities: # Including low/medium/high_pressure_steam if hu.flow * hu.duty > 0: system_heating_utilities[f'{u.ID} - {hu.ID}'] = hu # Use lps to account for the energy needed for the side steam if side_streams_to_heat: if not side_streams_lps: side_streams_lps = self.side_streams_lps = HeatUtility() side_streams_lps.load_agent(lps) side_streams_lps(duty=sum([i.H for i in side_streams_to_heat]), T_in=298.15) system_heating_utilities[ 'CHP - side_streams_lps'] = side_streams_lps system_heating_demand = self.system_heating_demand = \ sum([i.duty for i in system_heating_utilities.values()]) CHP_heat_surplus = self.CHP_heat_surplus = heat_generated - system_heating_demand self.system_steam_demand = sum( [i.flow for i in system_heating_utilities.values()]) hu_cooling = HeatUtility() # CHP can meet system heating/steam demand if CHP_heat_surplus > 0: # 3600 is conversion of kJ/hr to kW (kJ/s) electricity_generated = self.electricity_generated = \ CHP_heat_surplus * self.TG_eff / 3600 # Take the opposite for cooling duty (i.e., cooling duty should be negative) # this is to condense the unused steam cooling_need = self.cooling_need = -(CHP_heat_surplus - electricity_generated) hu_cooling(duty=cooling_need, T_in=lps.T) natural_gas.empty() # CHP cannot meet system heating/steam demand, supplement with natural gas else: CH4_LHV = natural_gas.chemicals.CH4.LHV natural_gas.imol['CH4'] = CHP_heat_surplus / (CH4_LHV * self.B_eff) emission.imol['CO2'] += natural_gas.imol['CH4'] emission.imol['H2O'] += 2 * natural_gas.imol['CH4'] electricity_generated = self.electricity_generated = 0 heating_utilities = HeatUtility.sum_by_agent( system_heating_utilities.values()) for i in heating_utilities: i.reverse() if hu_cooling.duty != 0: self.heat_utilities = tuple([hu_cooling, *heating_utilities]) else: self.heat_utilities = tuple(heating_utilities) total_steam_mol = sum( [i.flow for i in system_heating_utilities.values()]) total_steam = total_steam_mol * self.chemicals.H2O.MW blowdown_water.imass['H2O'] = total_steam * self.blowdown blowdown_water.T = 373.15 # Additional need for making lime slurry makeup_water.imol[ 'H2O'] = blowdown_water.imol['H2O'] + lime.F_mol / 0.2 * 0.8 # 1.23 is $2007/hour and 2.2661 is 2007$/lb from Table 30 in ref [1], # 144.629 is the total duty from Page 131 in ref [1], # 2.20462 is kg to lb, 4.184 is kcal to kJ, ratio = system_heating_demand / (144.629 * 1e6 * 4.184) boiler_chems.imass['BoilerChems'] = 1.23 / 2.2661 / 2.20462 * ratio bag.imass['BaghouseBag'] = ratio self.design_results['Flow rate'] = total_steam self.design_results['Work'] = electricity_generated
def _design(self): feed, natural_gas, air = self.ins emission, ash = self.outs for i in (natural_gas, air, ash): i.empty() feed.phase = natural_gas.phase = air.phase = emission.phase = 'g' ash.phase = 's' emission.P = ash.P = 101325 emission.T = ash.T = 298.15 self._refresh_sys() cmps = self.components rxns = [] for cmp in cmps: if cmp.locked_state in ('l', 's') and ( not cmp.organic or cmp.degradability == 'Undegradable'): continue rxn = cmp.get_combustion_reaction() if rxn: rxns.append(rxn) combustion_rxns = self.combustion_reactions = ParallelReaction(rxns) def react(natural_gas_flow=0): emission.copy_flow(feed) emission.imol['CH4'] += natural_gas_flow natural_gas.imol['CH4'] = natural_gas_flow combustion_rxns.force_reaction(emission.mol) air.imol['O2'] = -emission.imol['O2'] emission.imol['N2'] = air.imol['N2'] = air.imol['O2'] / 0.21 * 0.79 emission.imol['O2'] = 0 H_net_feed = feed.H + feed.HHV - emission.H # substracting the energy in emission return H_net_feed # Calculate extra natural gas needed to supplement the utilities supp_utility = self.supplement_utility kwds = dict(system=self.system, operating_hours=1., exclude_units=(self, )) hus = self.heat_utilities pu = self.power_utility if supp_utility: H_needs = self.H_needs = sum_system_utility( **kwds, utility='heating', result_unit='kJ') / self.combustion_eff if supp_utility == 'power': pu.production = sum_system_utility(**kwds, utility='power', result_unit='kWh') H_needs += pu.production / self.combined_eff # Objective function to calculate the excess heat at a given natural gas flow rate def H_excess_at_natural_gas_flow(flow): return H_needs - react(flow) lb = 0 ub = react() / cmps.CH4.LHV * 2 while H_excess_at_natural_gas_flow(ub) < H_needs: lb = ub ub *= 2 IQ_interpolation(H_excess_at_natural_gas_flow, x0=lb, x1=ub, xtol=1e-3, ytol=1) # Update heating and power utilities hus = HeatUtility.sum_by_agent( tuple([i for i in self.sys_heating_utilities])) for hu in hus: hu.reverse() else: H_needs = self.H_needs = 0. self.H_net_feed = react(0) hus = () pu.production = 0 ash_IDs = [i.ID for i in cmps if not i.formula] ash.copy_flow(emission, IDs=tuple(ash_IDs), remove=True)
def __init__(self, ID='', ins=None, outs=()): Facility.__init__(self, ID, ins, outs) self.agent = HeatUtility.get_cooling_agent('cooling_water')
def _cost(self): # def _design(self): # min_app_T = self.min_app_T sys = self.system # Flow_vector = [] # T_in_vector = [] # VF_in_vector = [] # T_out_vector = [] # VF_out_vector = [] # Cp_vector = [] # LH_vector = [] # Tb_vector = [] # Td_vector = [] # duties = [] hx_utils = bst.process_tools.heat_exchanger_utilities_from_units( sys.units) hx_utils.sort(key=lambda x: x.duty) matches_hs, matches_cs, Q_hot_side, Q_cold_side, unavailables, act_hot_util_load,\ act_cold_util_load, HXs_hot_side, HXs_cold_side, new_HX_utils, hxs, T_in_arr,\ T_out_arr, pinch_T_arr, C_flow_vector, hx_utils_rearranged, streams, stream_HXs_dict,\ hot_indices, cold_indices = synthesize_network(hx_utils, T_min_app = self.T_min_app) original_purchase_costs = [hx.purchase_cost for hx in hxs] original_installed_costs = [hx.installed_cost for hx in hxs] # original_utility_costs = [hx.utility_cost for hx in hxs] new_purchase_costs_HXp = [] # new_purchase_costs_HXu = list(original_purchase_costs) new_purchase_costs_HXu = [] new_installed_costs_HXp = [] # new_installed_costs_HXu = list(original_installed_costs) new_installed_costs_HXu = [] # new_utility_costs = copy.deepcopy(original_utility_costs) new_utility_costs = [] # new_heat_utilities = copy.deepcopy(original_heat_utilities) for hx in new_HX_utils: new_installed_costs_HXu.append(hx.installed_cost) new_purchase_costs_HXu.append(hx.purchase_cost) new_utility_costs.append(hx.utility_cost) new_HXs = HXs_hot_side + HXs_cold_side for new_HX in new_HXs: new_purchase_costs_HXp.append(new_HX.purchase_cost) new_installed_costs_HXp.append(new_HX.installed_cost) # init_heating_sum, init_cooling_sum = init_hot_util_load, init_cold_util_load self.purchase_costs['Heat exchangers'] = (sum(new_purchase_costs_HXp) + sum(new_purchase_costs_HXu)) \ - (sum(original_purchase_costs)) hu_sums1 = HeatUtility.sum_by_agent(hx_utils_rearranged) # hx_utils_applicable2 = [HeatUtility() for i in range(len(hx_utils_rearranged))] # QTs2 = [] # for hx_util in new_HX_utils: # QTs2.append((hx_util.Q, hx_util.T)) # for hu, (Q, T) in zip(hx_utils_applicable2, QTs2): hu(Q, T) # hu_sums2 = HeatUtility.sum_by_agent(hx_utils_applicable2) # for hu, hx in zip(hx_utils_applicable2, new_HX_utils): hu(hx.Q, hx.T) hu_sums2 = HeatUtility.sum_by_agent( sum([hx.heat_utilities for hx in new_HX_utils], ())) # to change sign on duty without switching heat/cool (i.e. negative costs): for hu in hu_sums1: hu.reverse() hus_final = tuple(HeatUtility.sum_by_agent(hu_sums1 + hu_sums2)) self._installed_cost = (sum(new_installed_costs_HXp) + sum(new_installed_costs_HXu)) \ - (sum(original_installed_costs)) self.heat_utilities = hus_final self.new_HXs = new_HXs self.new_HX_utils = new_HX_utils self.orig_heat_utils = hx_utils_rearranged self.original_purchase_costs = original_purchase_costs self.original_utility_costs = hu_sums1 self.new_purchase_costs_HXp = new_purchase_costs_HXp self.new_purchase_costs_HXu = new_purchase_costs_HXu self.new_utility_costs = hu_sums2 self.stream_HXs_dict = stream_HXs_dict