def NRTL_model(data): """This function generates an instance of the NRTL Pyomo model using 'data' as the input argument Parameters ---------- data: pandas DataFrame, list of dictionaries, or list of json file names Data that is used to build an instance of the Pyomo model Returns ------- m: an instance of the Pyomo model for estimating parameters and covariance """ m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = BTXParameterBlock(default={ "valid_phase": ('Liq', 'Vap'), "activity_coeff_model": 'NRTL' }) m.fs.flash = Flash(default={"property_package": m.fs.properties}) # Initialize at a certain inlet condition m.fs.flash.inlet.flow_mol.fix(1) m.fs.flash.inlet.temperature.fix(368) m.fs.flash.inlet.pressure.fix(101325) m.fs.flash.inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.flash.inlet.mole_frac_comp[0, "toluene"].fix(0.5) # Set Flash unit specifications m.fs.flash.heat_duty.fix(0) m.fs.flash.deltaP.fix(0) # Fix NRTL specific variables # alpha values (set at 0.3) m.fs.properties.alpha["benzene", "benzene"].fix(0) m.fs.properties.alpha["benzene", "toluene"].fix(0.3) m.fs.properties.alpha["toluene", "toluene"].fix(0) m.fs.properties.alpha["toluene", "benzene"].fix(0.3) # initial tau values m.fs.properties.tau["benzene", "benzene"].fix(0) m.fs.properties.tau["benzene", "toluene"].fix(0.1690) m.fs.properties.tau["toluene", "toluene"].fix(0) m.fs.properties.tau["toluene", "benzene"].fix(-0.1559) # Initialize the flash unit m.fs.flash.initialize(outlvl=idaeslog.INFO_LOW) # Fix at actual temperature m.fs.flash.inlet.temperature.fix(float(data["temperature"])) # Set bounds on variables to be estimated m.fs.properties.tau["benzene", "toluene"].setlb(-5) m.fs.properties.tau["benzene", "toluene"].setub(5) m.fs.properties.tau["toluene", "benzene"].setlb(-5) m.fs.properties.tau["toluene", "benzene"].setub(5) # Return initialized flash model return m
def model(self): model = ConcreteModel() model.fs = FlowsheetBlock(default={"dynamic": False}) model.fs.param = GenericParameterBlock(default=configuration) model.fs.unit = Flash( default={ "property_package": model.fs.param, "has_heat_transfer": False, "has_pressure_change": False }) # Fix state model.fs.unit.inlet.flow_mol.fix(1) model.fs.unit.inlet.temperature.fix(200.00) model.fs.unit.inlet.pressure.fix(101325) model.fs.unit.inlet.mole_frac_comp[0, "carbon_dioxide"].fix(1 / 2) model.fs.unit.inlet.mole_frac_comp[0, "bmimPF6"].fix(1 / 2) assert degrees_of_freedom(model.fs) == 0 # Apply scaling - model will not solver without this model.fs.unit.control_volume.properties_in[ 0].calculate_scaling_factors() model.fs.unit.control_volume.properties_out[ 0].calculate_scaling_factors() return model
def model(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": True}) m.fs.params = PropertyInterrogatorBlock() m.fs.P01 = PressureChanger( default={ "property_package": m.fs.params, "thermodynamic_assumption": ThermodynamicAssumption.isentropic }) m.fs.HX02 = HeatExchanger1D( default={ "shell_side": { "property_package": m.fs.params }, "tube_side": { "property_package": m.fs.params } }) m.fs.F03 = Flash(default={"property_package": m.fs.params}) return m
def NRTL_model_opt(): """This function generates an instance of the NRTL Pyomo model Returns ------- m: an instance of the Pyomo model for uncertainty propagation """ m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = BTXParameterBlock(default={"valid_phase": ('Liq', 'Vap'), "activity_coeff_model": 'NRTL'}) m.fs.flash = Flash(default={"property_package": m.fs.properties}) # Initialize at a certain inlet condition m.fs.flash.inlet.flow_mol.fix(1) m.fs.flash.inlet.temperature.fix(368) m.fs.flash.inlet.pressure.fix(101325) m.fs.flash.inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.flash.inlet.mole_frac_comp[0, "toluene"].fix(0.5) # Set Flash unit specifications m.fs.flash.heat_duty.fix(0) m.fs.flash.deltaP.fix(0) # Fix NRTL specific variables # alpha values (set at 0.3) m.fs.properties.alpha["benzene", "benzene"].fix(0) m.fs.properties.alpha["benzene", "toluene"].fix(0.3) m.fs.properties.alpha["toluene", "toluene"].fix(0) m.fs.properties.alpha["toluene", "benzene"].fix(0.3) # initial tau values m.fs.properties.tau["benzene", "benzene"].fix(0) m.fs.properties.tau["benzene", "toluene"].fix(0.1690) m.fs.properties.tau["toluene", "toluene"].fix(0) m.fs.properties.tau["toluene", "benzene"].fix(-0.1559) # Initialize the flash unit m.fs.flash.initialize(outlvl=idaeslog.INFO_LOW) # Fix at actual temperature m.fs.flash.inlet.temperature.fix(float(368)) # Set bounds on variables to be estimated m.fs.properties.tau["benzene", "toluene"].setlb(-5) m.fs.properties.tau["benzene", "toluene"].setub(5) m.fs.properties.tau["toluene", "benzene"].setlb(-5) m.fs.properties.tau["toluene", "benzene"].setub(5) # To use kaug # objective function required # need to unfix the variables m.obj = Objective(expr = 0*m.fs.properties.tau["benzene","toluene"] + exp(-m.fs.properties.alpha['toluene','benzene'].value * m.fs.properties.tau['toluene','benzene']), sense=minimize) m.fs.properties.tau["benzene", "toluene"].fixed = False # To use kaug m.fs.properties.tau["toluene", "benzene"].fixed = False return m
def flash_model(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = PhysicalParameterTestBlock()#default={"valid_phase": # ('Liq', 'Vap')}) m.fs.flash = Flash(default={"property_package": m.fs.properties}) return m
def test_unit_dof(self, model): model.fs.unit = Flash( default={ "property_package": model.fs.param, "has_heat_transfer": False, "has_pressure_change": False }) # Fix state model.fs.unit.inlet.flow_mol.fix(1) model.fs.unit.inlet.temperature.fix(200.00) model.fs.unit.inlet.pressure.fix(101325) model.fs.unit.inlet.mole_frac_comp[0, "carbon_dioxide"].fix(1 / 2) model.fs.unit.inlet.mole_frac_comp[0, "bmimPF6"].fix(1 / 2) assert degrees_of_freedom(model.fs.unit) == 0
def demo_flowsheet(): """Semi-complicated demonstration flowsheet. """ m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.BT_props = BTXParameterBlock() m.fs.M01 = Mixer(default={"property_package": m.fs.BT_props}) m.fs.H02 = Heater(default={"property_package": m.fs.BT_props}) m.fs.F03 = Flash(default={"property_package": m.fs.BT_props}) m.fs.s01 = Arc(source=m.fs.M01.outlet, destination=m.fs.H02.inlet) m.fs.s02 = Arc(source=m.fs.H02.outlet, destination=m.fs.F03.inlet) TransformationFactory("network.expand_arcs").apply_to(m.fs) m.fs.properties = SWCO2ParameterBlock() m.fs.main_compressor = PressureChanger( default={'dynamic': False, 'property_package': m.fs.properties, 'compressor': True, 'thermodynamic_assumption': ThermodynamicAssumption.isentropic}) m.fs.bypass_compressor = PressureChanger( default={'dynamic': False, 'property_package': m.fs.properties, 'compressor': True, 'thermodynamic_assumption': ThermodynamicAssumption.isentropic}) m.fs.turbine = PressureChanger( default={'dynamic': False, 'property_package': m.fs.properties, 'compressor': False, 'thermodynamic_assumption': ThermodynamicAssumption.isentropic}) m.fs.boiler = Heater(default={'dynamic': False, 'property_package': m.fs.properties, 'has_pressure_change': True}) m.fs.FG_cooler = Heater(default={'dynamic': False, 'property_package': m.fs.properties, 'has_pressure_change': True}) m.fs.pre_boiler = Heater(default={'dynamic': False, 'property_package': m.fs.properties, 'has_pressure_change': False}) m.fs.HTR_pseudo_tube = Heater(default={'dynamic': False, 'property_package': m.fs.properties, 'has_pressure_change': True}) m.fs.LTR_pseudo_tube = Heater(default={'dynamic': False, 'property_package': m.fs.properties, 'has_pressure_change': True}) return m.fs
def flash_flowsheet(): # Model and flowsheet m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) # Flash properties m.fs.properties = BTXParameterBlock(default={"valid_phase": ('Liq', 'Vap'), "activity_coeff_model": "Ideal", "state_vars": "FTPz"}) # Flash unit m.fs.flash = Flash(default={"property_package": m.fs.properties}) m.fs.flash.inlet.flow_mol.fix(1) m.fs.flash.inlet.temperature.fix(368) m.fs.flash.inlet.pressure.fix(101325) m.fs.flash.inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.flash.inlet.mole_frac_comp[0, "toluene"].fix(0.5) m.fs.flash.heat_duty.fix(0) m.fs.flash.deltaP.fix(0) return m.fs
def build_flowsheet(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.BT_props = BTXParameterBlock() m.fs.M01 = Mixer(default={"property_package": m.fs.BT_props}) m.fs.H02 = Heater(default={"property_package": m.fs.BT_props}) m.fs.F03 = Flash(default={"property_package": m.fs.BT_props}) m.fs.s01 = Arc(source=m.fs.M01.outlet, destination=m.fs.H02.inlet) m.fs.s02 = Arc(source=m.fs.H02.outlet, destination=m.fs.F03.inlet) TransformationFactory("network.expand_arcs").apply_to(m.fs) return m
def flash_model(): """Flash unit model. Use '.fs' attribute to get the flowsheet.""" m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) # Flash properties m.fs.properties = BTXParameterBlock( default={ "valid_phase": ("Liq", "Vap"), "activity_coeff_model": "Ideal", "state_vars": "FTPz", }) # Flash unit m.fs.flash = Flash(default={"property_package": m.fs.properties}) m.fs.flash.inlet.flow_mol.fix(1) m.fs.flash.inlet.temperature.fix(368) m.fs.flash.inlet.pressure.fix(101325) m.fs.flash.inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.flash.inlet.mole_frac_comp[0, "toluene"].fix(0.5) m.fs.flash.heat_duty.fix(0) m.fs.flash.deltaP.fix(0) return m
def test_serialize_flowsheet(): # Construct the model from idaes/examples/workshops/Module_2_Flowsheet/Module_2_Flowsheet_Solution.ipynb m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.thermo_params = thermo_props.HDAParameterBlock() m.fs.reaction_params = reaction_props.HDAReactionParameterBlock( default={"property_package": m.fs.thermo_params}) m.fs.M101 = Mixer( default={ "property_package": m.fs.thermo_params, "inlet_list": ["toluene_feed", "hydrogen_feed", "vapor_recycle"] }) m.fs.H101 = Heater( default={ "property_package": m.fs.thermo_params, "has_pressure_change": False, "has_phase_equilibrium": True }) m.fs.R101 = StoichiometricReactor( default={ "property_package": m.fs.thermo_params, "reaction_package": m.fs.reaction_params, "has_heat_of_reaction": True, "has_heat_transfer": True, "has_pressure_change": False }) m.fs.F101 = Flash( default={ "property_package": m.fs.thermo_params, "has_heat_transfer": True, "has_pressure_change": True }) m.fs.S101 = Splitter( default={ "property_package": m.fs.thermo_params, "ideal_separation": False, "outlet_list": ["purge", "recycle"] }) m.fs.C101 = PressureChanger( default={ "property_package": m.fs.thermo_params, "compressor": True, "thermodynamic_assumption": ThermodynamicAssumption.isothermal }) m.fs.F102 = Flash( default={ "property_package": m.fs.thermo_params, "has_heat_transfer": True, "has_pressure_change": True }) m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet) m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet) m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet) m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet) m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet) m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.vapor_recycle) m.fs.s10 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet) fss = FlowsheetSerializer() fss.serialize_flowsheet(m.fs) unit_models = fss.get_unit_models() unit_model_names_types = [] for unit_model in unit_models: unit_model_names_types.append(unit_models[unit_model]) unit_models_names_type_truth = [{ 'name': 'M101', 'type': 'mixer' }, { 'name': 'H101', 'type': 'heater' }, { 'name': 'R101', 'type': 'stoichiometric_reactor' }, { 'name': 'F101', 'type': 'flash' }, { 'name': 'S101', 'type': 'separator' }, { 'name': 'C101', 'type': 'pressure_changer' }, { 'name': 'F102', 'type': 'flash' }] set_result = set(tuple(sorted(d.items())) for d in unit_model_names_types) set_truth = set( tuple(sorted(d.items())) for d in unit_models_names_type_truth) difference = list(set_truth.symmetric_difference(set_result)) assert len(difference) == 0 # TODO Figure out how to test ports. Maybe find out if we can find the parent component for the port? # ports = fss.get_ports() # assert ports == {"<pyomo.network.port.SimplePort object at 0x7fe8d0d79278>": "<idaes.core.process_block._ScalarMixer object at 0x7fe8d0d60360>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d792e8>": "<idaes.core.process_block._ScalarMixer object at 0x7fe8d0d60360>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d79358>": "<idaes.core.process_block._ScalarMixer object at 0x7fe8d0d60360>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d793c8>": "<idaes.core.process_block._ScalarMixer object at 0x7fe8d0d60360>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d797b8>": "<idaes.core.process_block._ScalarHeater object at 0x7fe8d0db74c8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d79828>": "<idaes.core.process_block._ScalarHeater object at 0x7fe8d0db74c8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d79a58>": "<idaes.core.process_block._ScalarStoichiometricReactor object at 0x7fe8d0de2ab0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d79ac8>": "<idaes.core.process_block._ScalarStoichiometricReactor object at 0x7fe8d0de2ab0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d79eb8>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8d0e0fdc8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41128>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8d0e0fdc8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41198>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8d0e0fdc8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0d79f98>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8d0e0fdc8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41048>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8d0e0fdc8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e410b8>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8d0e0fdc8>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41278>": "<idaes.core.process_block._ScalarSeparator object at 0x7fe8d0e45708>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41588>": "<idaes.core.process_block._ScalarSeparator object at 0x7fe8d0e45708>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e415f8>": "<idaes.core.process_block._ScalarSeparator object at 0x7fe8d0e45708>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41828>": "<idaes.core.process_block._ScalarPressureChanger object at 0x7fe8d0e686c0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41898>": "<idaes.core.process_block._ScalarPressureChanger object at 0x7fe8d0e686c0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41c88>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8e1405cf0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41eb8>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8e1405cf0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41f28>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8e1405cf0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41e48>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8e1405cf0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41dd8>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8e1405cf0>", # "<pyomo.network.port.SimplePort object at 0x7fe8d0e41d68>": "<idaes.core.process_block._ScalarFlash object at 0x7fe8e1405cf0>" # } named_edges_results = {} edges = fss.get_edges() for edge in edges: named_edges_results[edge.getname()] = [ x.getname() for x in edges[edge] ] named_edges_truth = { 'M101': ['H101'], 'H101': ['R101'], 'R101': ['F101'], 'F101': ['S101', 'F102'], 'S101': ['C101'], 'C101': ['M101'] } assert named_edges_results == named_edges_truth
def test_temp_swing(self): # Create a flash model with the CO2-H2O property package m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = GenericParameterBlock(default=configuration) m.fs.flash = Flash(default={"property_package": m.fs.properties}) # Fix inlet stream state variables m.fs.flash.inlet.flow_mol.fix(9.89433124673833) # mol/s m.fs.flash.inlet.mole_frac_comp[0, 'CO2'].fix(0.13805801934749645) m.fs.flash.inlet.mole_frac_comp[0, 'H2O'].fix(0.8619419806525035) m.fs.flash.inlet.pressure.fix(183430) # Pa m.fs.flash.inlet.temperature.fix(396.79057912844183) # K # Fix flash and its outlet conditions m.fs.flash.deltaP.fix(0) m.fs.flash.vap_outlet.temperature.fix(313.15) # Initialize the flash model m.fs.flash.initialize() # Create a dictionary of expected solution for flash outlet temperature # sweep temp_range = list(np.linspace(313, 396)) expected_vapor_frac = [ 0.14388, 0.14445, 0.14508, 0.14576, 0.1465, 0.14731, 0.14818, 0.14913, 0.15017, 0.15129, 0.15251, 0.15384, 0.15528, 0.15685, 0.15856, 0.16042, 0.16245, 0.16467, 0.16709, 0.16974, 0.17265, 0.17584, 0.17935, 0.18323, 0.18751, 0.19226, 0.19755, 0.20346, 0.21008, 0.21755, 0.22601, 0.23565, 0.24673, 0.25956, 0.27456, 0.29229, 0.31354, 0.33942, 0.37157, 0.4125, 0.46628, 0.53993, 0.64678, 0.81547, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ] expected_heat_duty = [ -396276.55508, -394859.42896, -393421.28226, -391960.40602, -390474.94512, -388962.88119, -387422.01297, -385849.93371, -384244.00483, -382601.32549, -380918.69691, -379192.58068, -377419.04976, -375593.73054, -373711.73419, -371767.57480, -369755.07135, -367667.22968, -365496.09940, -363232.59958, -360866.30485, -358385.18097, -355775.25563, -353020.20490, -350100.82935, -346994.38367, -343673.70980, -340106.10300, -336251.80960, -332062.00898, -327476.06061, -322417.68382, -316789.55435, -310465.49473, -303278.90949, -295005.17406, -285333.93764, -273823.89005, -259825.51107, -242341.82570, -219760.16114, -189290.02362, -145647.55666, -77469.59283, -3219.88910, -2631.66067, -2043.09220, -1454.17760, -864.91585, -275.30623 ] outvals = zip(expected_vapor_frac, expected_heat_duty) expected_sol = dict(zip(temp_range, outvals)) # Solve the model for a range of flash outlet temperatures # Perform flash outlet temperature sweep and test the solution for t in temp_range: m.fs.flash.vap_outlet.temperature.fix(t) res = solver.solve(m) assert res.solver.termination_condition == "optimal" frac = value(m.fs.flash.vap_outlet.flow_mol[0]) \ / value(m.fs.flash.inlet.flow_mol[0]) assert frac == pytest.approx(expected_sol[t][0], abs=1e-4) hduty = value(m.fs.flash.heat_duty[0]) assert hduty == pytest.approx(expected_sol[t][1], rel=1e-4)
def test_temp_swing(self): # Create a flash model with the CO2-H2O property package m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = GenericParameterBlock(default=configuration) m.fs.flash = Flash(default={"property_package": m.fs.properties}) # Fix inlet stream state variables m.fs.flash.inlet.flow_mol.fix(9.89433124673833) # mol/s m.fs.flash.inlet.mole_frac_comp[0, 'CO2'].fix(0.13805801934749645) m.fs.flash.inlet.mole_frac_comp[0, 'H2O'].fix(0.8619419806525035) m.fs.flash.inlet.pressure.fix(183430) # Pa m.fs.flash.inlet.temperature.fix(396.79057912844183) # K # Fix flash and its outlet conditions m.fs.flash.deltaP.fix(0) m.fs.flash.vap_outlet.temperature.fix(313.15) #Initialize the flash model initial = m.fs.flash.initialize(outlvl=0) # Create a dictionary of expected solution for flash outlet temperature #sweep temp_range = list(np.linspace(313, 396)) expected_vapor_frac = [ 0.14388, 0.14445, 0.14508, 0.14576, 0.1465, 0.14731, 0.14818, 0.14913, 0.15017, 0.15129, 0.15251, 0.15384, 0.15528, 0.15685, 0.15856, 0.16042, 0.16245, 0.16467, 0.16709, 0.16974, 0.17265, 0.17584, 0.17935, 0.18323, 0.18751, 0.19226, 0.19755, 0.20346, 0.21008, 0.21755, 0.22601, 0.23565, 0.24673, 0.25956, 0.27456, 0.29229, 0.31354, 0.33942, 0.37157, 0.4125, 0.46628, 0.53993, 0.64678, 0.81547, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ] expected_heat_duty = [ -319572.91269, -318207.35249, -316825.31456, -315425.46452, -314006.35514, -312566.41317, -311103.92414, -309617.01485, -308103.633, -306561.52359, -304988.20138, -303380.91855, -301736.62677, -300051.9324, -298323.04327, -296545.70535, -294715.12686, -292825.88683, -290871.8244, -288845.90382, -286740.04885, -284544.93807, -282249.74995, -279841.84278, -277306.349, -274625.65625, -271778.73623, -268740.26687, -265479.46928, -261958.54546, -258130.54709, -253936.4179, -249300.81058, -244126.04073, -238283.13381, -231598.19109, -223830.94744, -214639.75318, -203521.76902, -189705.16711, -171941.46564, -148070.35054, -114001.22402, -60937.07508, -3219.88715, -2631.66029, -2043.09203, -1454.17752, -864.91582, -275.30623 ] outvals = zip(expected_vapor_frac, expected_heat_duty) expected_sol = dict(zip(temp_range, outvals)) # Solve the model for a range of flash outlet temperatures # Perform flash outlet temperature sweep and test the solution for t in temp_range: m.fs.flash.vap_outlet.temperature.fix(t) res = solver.solve(m) assert res.solver.termination_condition == "optimal" frac = value(m.fs.flash.vap_outlet.flow_mol[0]) \ /value(m.fs.flash.inlet.flow_mol[0]) assert frac == pytest.approx(expected_sol[t][0], abs=1e-4) hduty = value(m.fs.flash.heat_duty[0]) assert hduty == pytest.approx(expected_sol[t][1], abs=1e-4)