def test_units1_costing(build_costing): m = build_costing # Accounts with Feedwater Flow to HP section of HRSG, as the # reference/scaling parameter - Exhibit 5-15 FW_accounts = ['3.1', '3.3', '8.4'] # Accounts with Raw water withdrawal as the reference/scaling parameter # Exhibit 5-14 RW_withdraw_accounts = ['3.2', '3.4', '3.5', '9.5', '14.6'] m.fs.b2 = pyo.Block() m.fs.b2.raw_water_withdrawal = pyo.Var(initialize=2902) # gpm m.fs.b2.raw_water_withdrawal.fix() get_PP_costing(m.fs.b2, RW_withdraw_accounts, m.fs.b2.raw_water_withdrawal, 'gpm', 6) # Accounts with fuel gas flowrate as the reference/scaling parameter # Exhibit 5-15 stream 2, Exhibit 5-8 FuelG_accounts = ['3.6', '3.9', '6.1', '6.3', '6.4'] m.fs.b3 = pyo.Block() # Obtain Fuel gas flowrate in acm fuelgas_value = 205630 # lb/hr m.fs.b3.fg_flowrate = pyo.Var(initialize=fuelgas_value) # lb/hr m.fs.b3.fg_flowrate.fix() get_PP_costing(m.fs.b3, FuelG_accounts, m.fs.b3.fg_flowrate, 'lb/hr', 6) # Accounts with process water discharge as the reference/scaling parameter # Exhibit 5-14 PW_discharge_accounts = ['3.7'] m.fs.b4 = pyo.Block() m.fs.b4.process_water_discharge = pyo.Var(initialize=657) # gpm m.fs.b4.process_water_discharge.fix() get_PP_costing(m.fs.b4, PW_discharge_accounts, m.fs.b4.process_water_discharge, 'gpm', 6) # Initialize costing costing_initialization(m.fs) assert degrees_of_freedom(m) == 0 # Solve the model results = solver.solve(m, tee=True) assert pyo.check_optimal_termination(results) # Accounts with raw water withdrawal as reference parameter assert pytest.approx(26.435, abs=0.5) \ == sum(pyo.value(m.fs.b2.costing.total_plant_cost[ac]) for ac in RW_withdraw_accounts) # Accounts with fuel gas as reference parameter assert pytest.approx(158.415, abs=0.5) \ == sum(pyo.value(m.fs.b3.costing.total_plant_cost[ac]) for ac in FuelG_accounts) # Accounts with process water discharge as reference parameter assert pytest.approx(11.608, abs=0.5) \ == sum(pyo.value(m.fs.b4.costing.total_plant_cost[ac]) for ac in PW_discharge_accounts)
def test_flowsheet_costing(build_costing): m = build_costing # Build cost constraints build_flowsheet_cost_constraint(m) # Initialize costing costing_initialization(m.fs) assert degrees_of_freedom(m) == 0 # Solve the model results = solver.solve(m, tee=True) assert pyo.check_optimal_termination(results) # Verify total plant costs assert pytest.approx(574.85, abs=0.1) == pyo.value(m.fs.flowsheet_cost)
def test_flowsheet_costing(build_costing): m = build_costing # Build cost constraints build_flowsheet_cost_constraint(m) # Initialize costing costing_initialization(m.fs) assert degrees_of_freedom(m) == 0 # Solve the model results = solver.solve(m, tee=True) assert results.solver.termination_condition == \ pyo.TerminationCondition.optimal assert results.solver.status == pyo.SolverStatus.ok # Verify total plant costs assert pytest.approx(574.85, abs=0.1) == pyo.value(m.fs.flowsheet_cost)
def test_units3_costing(build_costing): m = build_costing # Accounts with steam turbine gross power as the reference/scaling # parameter # Exhibit 5-9 Steam_turbine_gross_power_accounts = ['8.1', '8.2', '8.5', '14.3'] m.fs.b9 = pyo.Block() # Obtain steam turbine gross power in kW ST_gross_power = 263 * 1000 # kW m.fs.b9.st_gross_power = pyo.Var(initialize=ST_gross_power) # kW m.fs.b9.st_gross_power.fix() get_PP_costing(m.fs.b9, Steam_turbine_gross_power_accounts, m.fs.b9.st_gross_power, 'kW', 6) # Accounts with condenser duty as the reference/scaling parameter # Exhibit 5-9 Condenser_duty_accounts = ['8.3'] m.fs.b10 = pyo.Block() # Obtain condenser duty in MMBtu/hr condenser_duty = 1332 # MMBtu/hr m.fs.b10.cond_duty = pyo.Var(initialize=condenser_duty) # MMBtu/hr m.fs.b10.cond_duty.fix() get_PP_costing(m.fs.b10, Condenser_duty_accounts, m.fs.b10.cond_duty, 'MMBtu/hr', 6) # Accounts with cooling tower duty as the reference/scaling parameter # Exhibit 5-16 Cooling_tower_accounts = ['9.1'] m.fs.b11 = pyo.Block() # Obtain cooling tower duty in MMBtu/hr (includes condenser, Acid gas # removal, and other cooling loads) cooling_tower_duty = 1357 # MMBtu/hr m.fs.b11.cool_tower_duty = pyo.Var(initialize=cooling_tower_duty) # MMBtu/hr m.fs.b11.cool_tower_duty.fix() get_PP_costing(m.fs.b11, Cooling_tower_accounts, m.fs.b11.cool_tower_duty, 'MMBtu/hr', 6) # Accounts with circulating water flowrate as the reference/scaling # parameter Circ_water_accounts = ['9.2', '9.3', '9.4', '9.6', '9.7', '14.5'] m.fs.b12 = pyo.Block() # Obtain circulating water flowrate in gpm cir_water_flowrate = 217555 # gpm m.fs.b12.circ_water_flow = pyo.Var(initialize=cir_water_flowrate) # gpm m.fs.b12.circ_water_flow.fix() get_PP_costing(m.fs.b12, Circ_water_accounts, m.fs.b12.circ_water_flow, 'gpm', 6) # Accounts with total plant gross power as the reference/scaling parameter # Exhibit 5-9 plant_gross_power_accounts = [ '11.1', '11.7', '11.9', '13.1', '13.2', '13.3', '14.4', '14.7', '14.8', '14.9', '14.10' ] m.fs.b13 = pyo.Block() # Obtain total plant gross power in kW plant_gross_power = 740000 # kW m.fs.b13.gross_power = pyo.Var(initialize=plant_gross_power) # kW m.fs.b13.gross_power.fix() get_PP_costing(m.fs.b13, plant_gross_power_accounts, m.fs.b13.gross_power, 'kW', 6) # Accounts with auxilliary load as the reference/scaling parameter # Exhibit 5-9 auxilliary_load_accounts = [ '11.2', '11.3', '11.4', '11.5', '11.6', '12.1', '12.2', '12.3', '12.4', '12.5', '12.6', '12.7', '12.8', '12.9' ] m.fs.b14 = pyo.Block() # Obtain auxilliary load in kW aux_load = 14 * 1000 # kW m.fs.b14.auxilliary_load = pyo.Var(initialize=aux_load) # kW m.fs.b14.auxilliary_load.fix() get_PP_costing(m.fs.b14, auxilliary_load_accounts, m.fs.b14.auxilliary_load, 'kW', 6) # Accounts with STG,CTG output as the reference/scaling parameter # Case B31A Account 9 - Pg 501 rev 4 baseline report stg_ctg_accounts = ['11.8'] m.fs.b15 = pyo.Block() # Obtain STG,CTG output in kW stg_ctg_op = 689800 # kW m.fs.b15.stg_ctg_output = pyo.Var(initialize=stg_ctg_op) # kW m.fs.b15.stg_ctg_output.fix() get_PP_costing(m.fs.b15, stg_ctg_accounts, m.fs.b15.stg_ctg_output, 'kW', 6) # Accounts with gas turbine power as the reference/scaling parameter # Exhibit 5-9 gasturbine_accounts = ['14.1'] m.fs.b16 = pyo.Block() # Obtain gas turbine power in kW gt_power = 477 * 1000 # kW m.fs.b16.gas_turbine_power = pyo.Var(initialize=gt_power) # kW m.fs.b16.gas_turbine_power.fix() get_PP_costing(m.fs.b16, gasturbine_accounts, m.fs.b16.gas_turbine_power, 'kW', 6) # Initialize costing costing_initialization(m.fs) assert degrees_of_freedom(m) == 0 # Solve the model results = solver.solve(m, tee=True) assert results.solver.termination_condition == \ pyo.TerminationCondition.optimal assert results.solver.status == pyo.SolverStatus.ok # Accounts with condenser duty as reference parameter assert pytest.approx(14.27, abs=0.1) \ == sum(pyo.value(m.fs.b10.costing.total_plant_cost[ac]) for ac in Condenser_duty_accounts) # Accounts with cooling tower duty as reference parameter assert pytest.approx(14.73, abs=0.2) \ == sum(pyo.value(m.fs.b11.costing.total_plant_cost[ac]) for ac in Cooling_tower_accounts)
def test_units2_costing(build_costing): m = build_costing # Accounts with flue gas flowrate as the reference/scaling parameter # Exhibit 5-15 stream 3, Exhibit 5-8 FG_accounts = ['7.6'] m.fs.b5 = pyo.Block() # Obtain Flue gas flowrate in acm fluegas_value = (8658430 / 60) / 0.025 # ft3/min m.fs.b5.fg_flowrate = pyo.Var(initialize=fluegas_value) # ft3/min m.fs.b5.fg_flowrate.fix() get_PP_costing(m.fs.b5, FG_accounts, m.fs.b5.fg_flowrate, 'acfm', 6) # Accounts with combustion turbine gross power as the reference/scaling # parameter # Exhibit 5-9 CT_grosspower_accounts = ['6.5'] m.fs.b6 = pyo.Block() # Obtain combustion turbine gross power in kW CT_gross_power = 477 * 1000 # kW m.fs.b6.ct_gross_power = pyo.Var(initialize=CT_gross_power) # kW m.fs.b6.ct_gross_power.fix() get_PP_costing(m.fs.b6, CT_grosspower_accounts, m.fs.b6.ct_gross_power, 'kW', 6) # Accounts with HRSG duty as the reference/scaling parameter # Exhibit 5-8, streams 3 and 4 HRSG_duty_accounts = ['7.1', '7.2'] m.fs.b7 = pyo.Block() # Obtain HRSG duty in MMBtu/hr, overall energy balance HRSG_duty = -(-538.1 + 277.1) * 8658430 / (10**6) # MMBtu/hr m.fs.b7.hrsg_duty = pyo.Var(initialize=HRSG_duty) # MMBtu/hr m.fs.b7.hrsg_duty.fix() get_PP_costing(m.fs.b7, HRSG_duty_accounts, m.fs.b7.hrsg_duty, 'MMBtu/hr', 6) # Accounts with gas flow to stack as the reference/scaling parameter # Exhibit 5-8, stream 4 Stack_flow_gas_accounts = ['7.3', '7.4', '7.5'] m.fs.b8 = pyo.Block() # Obtain gas flowrate to stack in ft3/min stack_flow_gas = (8658430 / 60) / 0.061 # ft3/min m.fs.b8.stack_flow_gas = pyo.Var(initialize=stack_flow_gas) # ft3/min m.fs.b8.stack_flow_gas.fix() get_PP_costing(m.fs.b8, Stack_flow_gas_accounts, m.fs.b8.stack_flow_gas, 'acfm', 6) # Initialize costing costing_initialization(m.fs) assert degrees_of_freedom(m) == 0 # Solve the model results = solver.solve(m, tee=True) assert results.solver.termination_condition == \ pyo.TerminationCondition.optimal assert results.solver.status == pyo.SolverStatus.ok # Accounts with HRSG duty as reference parameter assert pytest.approx(90.794, abs=0.1) \ == sum(pyo.value(m.fs.b7.costing.total_plant_cost[ac]) for ac in HRSG_duty_accounts)
def test_sCO2_costing(): # Create a Concrete Model as the top level object m = pyo.ConcreteModel() # Add a flowsheet object to the model m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.get_costing(year='2017') # ###################################################### # Primary Heater m.fs.boiler = pyo.Block() m.fs.boiler.heat_duty = pyo.Var(initialize=1461.5e6) m.fs.boiler.heat_duty.fix() m.fs.boiler.temp = pyo.Var(initialize=620) # C m.fs.boiler.temp.fix() get_sCO2_unit_cost(m.fs.boiler, 'Coal-fired heater', m.fs.boiler.heat_duty * (1e-6), temp_C=m.fs.boiler.temp) # ###################################################### # CO2 Turbine m.fs.turbine = pyo.Block() m.fs.turbine.work_isentropic = pyo.Var(initialize=1006.2e6) m.fs.turbine.work_isentropic.fix() m.fs.turbine.temp = pyo.Var(initialize=620) m.fs.turbine.temp.fix() get_sCO2_unit_cost(m.fs.turbine, 'Axial turbine', m.fs.turbine.work_isentropic * (1e-6), temp_C=m.fs.turbine.temp, n_equip=1) # ###################################################### # Generator m.fs.generator = pyo.Block() m.fs.generator.work_isentropic = pyo.Var(initialize=1006.2e6) get_sCO2_unit_cost(m.fs.generator, 'Generator', m.fs.turbine.work_isentropic * (1e-6), n_equip=1) # ###################################################### # High Temperature Recuperator m.fs.HTR = pyo.Block() m.fs.HTR.heat_duty = pyo.Var(initialize=1461e6) # W m.fs.HTR.heat_duty.fix() m.fs.HTR.LMTD = pyo.Var(initialize=21.45) m.fs.HTR.LMTD.fix() m.fs.HTR.temp = pyo.Var(initialize=453) m.fs.HTR.temp.fix() m.fs.HTR.UA = pyo.Var(initialize=1e8) # gives units of W/K @m.fs.Constraint() def HTR_UA_rule(b): return (b.HTR.UA * b.HTR.LMTD == b.HTR.heat_duty) get_sCO2_unit_cost(m.fs.HTR, 'Recuperator', m.fs.HTR.UA, temp_C=m.fs.HTR.temp) # ###################################################### # Low Temperature Recuperator m.fs.LTR = pyo.Block() m.fs.LTR.heat_duty = pyo.Var(initialize=911.7e6) # W m.fs.LTR.heat_duty.fix() m.fs.LTR.LMTD = pyo.Var(initialize=5.21) m.fs.LTR.LMTD.fix() m.fs.LTR.temp = pyo.Var(initialize=216) m.fs.LTR.temp.fix() m.fs.LTR.UA = pyo.Var(initialize=1e8) @m.fs.Constraint() def LTR_UA_rule(b): return (b.LTR.UA * b.LTR.LMTD == b.LTR.heat_duty) get_sCO2_unit_cost(m.fs.LTR, 'Recuperator', m.fs.LTR.UA, temp_C=m.fs.LTR.temp) # ###################################################### # CO2 Cooler, costed using the recouperator not dry cooler m.fs.co2_cooler = pyo.Block() m.fs.co2_cooler.heat_duty = pyo.Var(initialize=739421217) m.fs.co2_cooler.heat_duty.fix() m.fs.co2_cooler.temp = pyo.Var(initialize=81) m.fs.co2_cooler.temp.fix() # Estimating LMTD # Cost from report: $27,780 thousand # Back-calculated UA: 41819213 W/K # Heat duty from report: 2523 MMBTu/hr --> 739421217 W # Estimated LMTD: 17.68 K m.fs.co2_cooler.LMTD = pyo.Var(initialize=5) m.fs.co2_cooler.UA = pyo.Var(initialize=1e5) m.fs.co2_cooler.LMTD.fix(17.68) @m.fs.Constraint() def co2_cooler_UA_rule(b): return (b.co2_cooler.UA * b.co2_cooler.LMTD == b.co2_cooler.heat_duty) get_sCO2_unit_cost(m.fs.co2_cooler, 'Recuperator', m.fs.co2_cooler.UA, temp_C=m.fs.co2_cooler.temp) # ###################################################### # Main Compressor - 5.99 m^3/s in Baseline620 m.fs.main_compressor = pyo.Block() m.fs.main_compressor.flow_vol = pyo.Var(initialize=5.99) m.fs.main_compressor.flow_vol.fix() get_sCO2_unit_cost(m.fs.main_compressor, 'Barrel type compressor', m.fs.main_compressor.flow_vol, n_equip=5.0) # ###################################################### # Main Compressor Motor m.fs.main_compressor_motor = pyo.Block() m.fs.main_compressor_motor.work_isentropic = pyo.Var(initialize=159.7e6) m.fs.main_compressor_motor.work_isentropic.fix() get_sCO2_unit_cost(m.fs.main_compressor_motor, 'Open drip-proof motor', m.fs.main_compressor_motor.work_isentropic * (1e-6), n_equip=5.0) # ###################################################### # Recompressor - 6.89 m^3/s in Baseline620 m.fs.bypass_compressor = pyo.Block() m.fs.bypass_compressor.flow_vol = pyo.Var(initialize=6.89) m.fs.bypass_compressor.flow_vol.fix() get_sCO2_unit_cost(m.fs.bypass_compressor, 'Barrel type compressor', m.fs.bypass_compressor.flow_vol, n_equip=4.0) # ###################################################### # Recompressor Motor m.fs.bypass_compressor_motor = pyo.Block() m.fs.bypass_compressor_motor.work_isentropic = pyo.Var(initialize=124.3e6) m.fs.bypass_compressor_motor.work_isentropic.fix() get_sCO2_unit_cost(m.fs.bypass_compressor_motor, 'Open drip-proof motor', m.fs.bypass_compressor_motor.work_isentropic * (1e-6), n_equip=4.0) # add total cost build_flowsheet_cost_constraint(m) # add initialize costing_initialization(m.fs) # try solving solver = get_solver() results = solver.solve(m, tee=True) assert results.solver.termination_condition == \ pyo.TerminationCondition.optimal assert pytest.approx(pyo.value(m.fs.boiler.costing.equipment_cost), abs=1e-1) == 216300 / 1e3 assert pytest.approx(pyo.value(m.fs.turbine.costing.equipment_cost), abs=1e-1) == 13160 / 1e3 assert pytest.approx(pyo.value(m.fs.generator.costing.equipment_cost), abs=1e-1) == 4756 / 1e3 assert pytest.approx(pyo.value(m.fs.HTR.costing.equipment_cost), abs=1e-1) == 40150 / 1e3 assert pytest.approx(pyo.value(m.fs.LTR.costing.equipment_cost), abs=1e-1) == 81860 / 1e3 assert pytest.approx(pyo.value(m.fs.co2_cooler.costing.equipment_cost), abs=1e-1) == 27780 / 1e3 assert pytest.approx(pyo.value( m.fs.main_compressor.costing.equipment_cost), abs=1e-1) == 31640 / 1e3 assert pytest.approx(pyo.value( m.fs.bypass_compressor.costing.equipment_cost), abs=1e-1) == 26360 / 1e3 assert pytest.approx( pyo.value(m.fs.main_compressor_motor.costing.equipment_cost) + pyo.value(m.fs.bypass_compressor_motor.costing.equipment_cost), abs=1e-1) == 29130 / 1e3 assert pytest.approx(pyo.value( m.fs.bypass_compressor.costing.equipment_cost), abs=1e-1) == 26360 / 1e3 return m
def test_PP_costing(): # Create a Concrete Model as the top level object m = pyo.ConcreteModel() # Add a flowsheet object to the model m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.get_costing(year='2018') # check that the model solved properly and has 0 degrees of freedom assert (degrees_of_freedom(m) == 0) ########################################################################### # Create costing constraints # ########################################################################### # coal flow rate # accounts 1.x and 2.x are coal handling, preparation and feed # accounts 4.x are for boiler BOP and foundations coal_accounts = [ '1.1', '1.2', '1.3', '1.4', '2.1', '2.2', '4.11', '4.15', '4.16' ] m.fs.boiler = pyo.Block() m.fs.boiler.coal_mass_flow = pyo.Var(initialize=7238.95) # tpd m.fs.boiler.coal_mass_flow.fix() get_PP_costing(m.fs.boiler, coal_accounts, m.fs.boiler.coal_mass_flow, 'tpd', 2) # total fuel feed # accounts 3.x are for start up systems and miscellaneous plant equipment # accounts 7.x are for ductwork and stack foundations fuel_accounts = ['3.6', '3.9', '7.3', '7.5'] m.fs.fuel_feed = pyo.Block() m.fs.fuel_feed.total_fuel_feed = pyo.Var(initialize=603246) # lb/hr m.fs.fuel_feed.total_fuel_feed.fix() get_PP_costing(m.fs.fuel_feed, fuel_accounts, m.fs.fuel_feed.total_fuel_feed, 'lb/hr', 2) # HP BFW flow rate # accounts 3.x are for feedwater systems # account 4.9 is for the boiler # account 8.4 is steam piping BFW_accounts = ['3.1', '3.3', '3.5', '4.9', '8.4'] m.fs.bfp = pyo.Block() m.fs.bfp.BFW_mass_flow = pyo.Var(initialize=5316158) # lb/hr m.fs.bfp.BFW_mass_flow.fix() get_PP_costing(m.fs.bfp, BFW_accounts, m.fs.bfp.BFW_mass_flow, 'lb/hr', 2) # Steam turbine power # accounts 8.x are for the steam turbine and its foundations power_accounts = ['8.1'] m.fs.turb = pyo.Block() m.fs.turb.power = pyo.Var(initialize=769600) # kW m.fs.turb.power.fix() get_PP_costing(m.fs.turb, power_accounts, m.fs.turb.power, 'kW', 2) # Condernser duty cond_accounts = ['8.3'] m.fs.condenser = pyo.Block() m.fs.condenser.duty_MMBtu = pyo.Var(initialize=2016) # MMBtu/hr m.fs.condenser.duty_MMBtu.fix() get_PP_costing(m.fs.condenser, cond_accounts, m.fs.condenser.duty_MMBtu, "MMBtu/hr", 2) # Circulating water flow rate # accounts 9.x are for circulating water systems # account 14.5 is for the pumphouse circ_accounts = ['9.2', '9.3', '9.4', '9.6', '9.7', '14.5'] m.fs.circulating_water = pyo.Block() m.fs.circulating_water.vol_flow = pyo.Var(initialize=463371) # gpm m.fs.circulating_water.vol_flow.fix() get_PP_costing(m.fs.circulating_water, circ_accounts, m.fs.circulating_water.vol_flow, 'gpm', 2) # Ash flow rate # accounts are for ash storage and handling ash_accounts = ['10.6', '10.7', '10.9'] m.fs.ash_handling = pyo.Block() m.fs.ash_handling.ash_mass_flow = pyo.Var(initialize=66903) # lb/hr m.fs.ash_handling.ash_mass_flow.fix() get_PP_costing(m.fs.ash_handling, ash_accounts, m.fs.ash_handling.ash_mass_flow, 'lb/hr', 2) # add total cost build_flowsheet_cost_constraint(m) # add initialize costing_initialization(m.fs) # try solving solver = get_solver() results = solver.solve(m, tee=True) assert results.solver.termination_condition == \ pyo.TerminationCondition.optimal # all numbers come from the NETL excel file: # "201.001.001_BBR4 COE Spreadsheet_Rev0U_20190919_njk.xlsm" assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['1.1']), abs=1e-1) == 2306 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['1.2']), abs=1e-1) == 6385 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['1.3']), abs=1e-1) == 59527 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['1.4']), abs=1e-1) == 8086 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['2.1']), abs=1e-1) == 4073 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['2.2']), abs=1e-1) == 13976 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['4.11']), abs=1e-1) == 3751 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['4.15']), abs=1e-1) == 197 / 1e3 assert pytest.approx(pyo.value( m.fs.boiler.costing.total_plant_cost['4.16']), abs=1e-1) == 1014 / 1e3 assert pytest.approx(pyo.value( m.fs.fuel_feed.costing.total_plant_cost['3.6']), abs=1e-1) == 4864 / 1e3 assert pytest.approx(pyo.value( m.fs.fuel_feed.costing.total_plant_cost['3.9']), abs=1e-1) == 522 / 1e3 assert pytest.approx(pyo.value( m.fs.fuel_feed.costing.total_plant_cost['7.3']), abs=1e-1) == 1710 / 1e3 assert pytest.approx(pyo.value( m.fs.fuel_feed.costing.total_plant_cost['7.5']), abs=1e-1) == 647 / 1e3 assert pytest.approx(pyo.value(m.fs.bfp.costing.total_plant_cost['3.1']), abs=1e-1) == 19233 / 1e3 assert pytest.approx(pyo.value(m.fs.bfp.costing.total_plant_cost['3.3']), abs=1e-1) == 6897 / 1e3 assert pytest.approx(pyo.value(m.fs.bfp.costing.total_plant_cost['3.5']), abs=1e-1) == 2366 / 1e3 assert pytest.approx(pyo.value(m.fs.bfp.costing.total_plant_cost['4.9']), abs=1e-1) == 570418 / 1e3 assert pytest.approx(pyo.value(m.fs.bfp.costing.total_plant_cost['8.4']), abs=1e-1) == 81916 / 1e3 assert pytest.approx(pyo.value(m.fs.turb.costing.total_plant_cost['8.1']), abs=1e-1) == 110166 / 1e3 assert pytest.approx(pyo.value( m.fs.condenser.costing.total_plant_cost['8.3']), abs=1e-1) == 20447 / 1e3 assert pytest.approx(pyo.value( m.fs.circulating_water.costing.total_plant_cost['9.2']), abs=1e-1) == 4133 / 1e3 assert pytest.approx(pyo.value( m.fs.circulating_water.costing.total_plant_cost['9.3']), abs=1e-1) == 25518 / 1e3 assert pytest.approx(pyo.value( m.fs.circulating_water.costing.total_plant_cost['9.4']), abs=1e-1) == 19859 / 1e3 assert pytest.approx(pyo.value( m.fs.circulating_water.costing.total_plant_cost['9.6']), abs=1e-1) == 2870 / 1e3 assert pytest.approx(pyo.value( m.fs.circulating_water.costing.total_plant_cost['9.7']), abs=1e-1) == 2690 / 1e3 assert pytest.approx(pyo.value( m.fs.circulating_water.costing.total_plant_cost['14.5']), abs=1e-1) == 464 / 1e3 assert pytest.approx(pyo.value( m.fs.ash_handling.costing.total_plant_cost['10.6']), abs=1e-1) == 6429 / 1e3 assert pytest.approx(pyo.value( m.fs.ash_handling.costing.total_plant_cost['10.7']), abs=1e-1) == 10725 / 1e3 assert pytest.approx(pyo.value( m.fs.ash_handling.costing.total_plant_cost['10.9']), abs=1e-1) == 2564 / 1e3 assert pytest.approx(pyo.value(m.fs.flowsheet_cost), abs=1e-1) == 993753 / 1e3 return m
def test_power_plant_costing(): # Create a Concrete Model as the top level object m = pyo.ConcreteModel() # Add a flowsheet object to the model m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.get_costing(year='2018') ########################################################################### # Create costing constraints # ########################################################################### # subcritical PC coal_accounts = ['1.1', '1.2', '1.3'] m.fs.subcritical_PC = pyo.Block() m.fs.subcritical_PC.coal_feed_rate = pyo.Var(initialize=7613.37) # tpd m.fs.subcritical_PC.coal_feed_rate.fix() get_PP_costing(m.fs.subcritical_PC, coal_accounts, m.fs.subcritical_PC.coal_feed_rate, 'tpd', 1) # two-stage, slurry-feed IGCC feedwater_accounts = ['3.1', '3.3', '3.5'] m.fs.IGCC_1 = pyo.Block() m.fs.IGCC_1.feedwater_flow_rate = pyo.Var(initialize=1576062.15) # lb/hr m.fs.IGCC_1.feedwater_flow_rate.fix() get_PP_costing(m.fs.IGCC_1, feedwater_accounts, m.fs.IGCC_1.feedwater_flow_rate, 'lb/hr', 3) # single-stage, slurry-feed, IGCC syngas_accounts = ['6.1', '6.2', '6.3'] m.fs.IGCC_2 = pyo.Block() m.fs.IGCC_2.syngas_flow_rate = pyo.Var(initialize=182335.921) # lb/hr m.fs.IGCC_2.syngas_flow_rate.fix() get_PP_costing(m.fs.IGCC_2, syngas_accounts, m.fs.IGCC_2.syngas_flow_rate, 'lb/hr', 4) # single-stage, dry-feed, IGCC HRSG_accounts = ['7.1', '7.2'] m.fs.IGCC_3 = pyo.Block() m.fs.IGCC_3.HRSG_duty = pyo.Var(initialize=1777.86) # MMBtu/hr m.fs.IGCC_3.HRSG_duty.fix() get_PP_costing(m.fs.IGCC_3, HRSG_accounts, m.fs.IGCC_3.HRSG_duty, 'MMBtu/hr', 5) # NGCC steam_turbine_accounts = ['8.1', '8.2', '8.5'] m.fs.NGCC = pyo.Block() m.fs.NGCC.turbine_power = pyo.Var(initialize=212500) # kW m.fs.NGCC.turbine_power.fix() get_PP_costing(m.fs.NGCC, steam_turbine_accounts, m.fs.NGCC.turbine_power, 'kW', 6) # AUSC PC AUSC_accounts = ['4.9', '8.4'] m.fs.AUSC = pyo.Block() m.fs.AUSC.feedwater_flow = pyo.Var(initialize=3298815.58) # lb/hr m.fs.AUSC.feedwater_flow.fix() get_PP_costing(m.fs.AUSC, AUSC_accounts, m.fs.AUSC.feedwater_flow, 'lb/hr', 7) # add total cost build_flowsheet_cost_constraint(m) # add initialize costing_initialization(m.fs) # try solving solver = get_solver() results = solver.solve(m, tee=True) assert results.solver.termination_condition == \ pyo.TerminationCondition.optimal # all numbers come from the NETL excel file # "201.001.001_BBR4 COE Spreadsheet_Rev0U_20190919_njk.xlsm" assert pytest.approx(pyo.value( m.fs.subcritical_PC.costing.total_plant_cost['1.1']), abs=1e-1) == 2379 / 1e3 assert pytest.approx(pyo.value( m.fs.subcritical_PC.costing.total_plant_cost['1.2']), abs=1e-1) == 6588 / 1e3 assert pytest.approx(pyo.value( m.fs.subcritical_PC.costing.total_plant_cost['1.3']), abs=1e-1) == 61409 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_1.costing.total_plant_cost['3.1']), abs=1e-1) == 10807 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_1.costing.total_plant_cost['3.3']), abs=1e-1) == 2564 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_1.costing.total_plant_cost['3.5']), abs=1e-1) == 923 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_2.costing.total_plant_cost['6.1']), abs=1e-1) == 117850 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_2.costing.total_plant_cost['6.2']), abs=1e-1) == 3207 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_2.costing.total_plant_cost['6.3']), abs=1e-1) == 3770 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_3.costing.total_plant_cost['7.1']), abs=1e-1) == 53530 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_3.costing.total_plant_cost['7.2']), abs=1e-1) == 19113 / 1e3 assert pytest.approx(pyo.value(m.fs.NGCC.costing.total_plant_cost['8.1']), abs=1e-1) == 49468 / 1e3 assert pytest.approx(pyo.value(m.fs.NGCC.costing.total_plant_cost['8.2']), abs=1e-1) == 565 / 1e3 assert pytest.approx(pyo.value(m.fs.NGCC.costing.total_plant_cost['8.5']), abs=1e-1) == 4094 / 1e3 assert pytest.approx(pyo.value(m.fs.AUSC.costing.bare_erected_cost['4.9']), abs=1e-1) == 295509 / 1e3 assert pytest.approx(pyo.value(m.fs.AUSC.costing.bare_erected_cost['8.4']), abs=1e-1) == 57265 / 1e3 return m