def iapws_underwood(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = iapws95.Iapws95ParameterBlock() m.fs.unit = HeatExchanger( default={ "shell": { "property_package": m.fs.properties }, "tube": { "property_package": m.fs.properties }, "delta_temperature_callback": delta_temperature_underwood_callback, "flow_pattern": HeatExchangerFlowPattern.countercurrent }) m.fs.unit.inlet_1.flow_mol[0].fix(100) m.fs.unit.inlet_1.enth_mol[0].fix(4000) m.fs.unit.inlet_1.pressure[0].fix(101325) m.fs.unit.inlet_2.flow_mol[0].fix(100) m.fs.unit.inlet_2.enth_mol[0].fix(3500) m.fs.unit.inlet_2.pressure[0].fix(101325) m.fs.unit.area.fix(1000) m.fs.unit.overall_heat_transfer_coefficient.fix(100) return m
def btx(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = BTXParameterBlock(default={"valid_phase": 'Liq'}) m.fs.unit = HeatExchanger(default={ "hot_side_name":"hot", "cold_side_name":"cold", "hot": {"property_package": m.fs.properties}, "cold": {"property_package": m.fs.properties}, "flow_pattern": HeatExchangerFlowPattern.cocurrent}) m.fs.unit.hot_inlet.flow_mol[0].fix(5) # mol/s m.fs.unit.hot_inlet.temperature[0].fix(365) # K m.fs.unit.hot_inlet.pressure[0].fix(101325) # Pa m.fs.unit.hot_inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.unit.hot_inlet.mole_frac_comp[0, "toluene"].fix(0.5) m.fs.unit.cold_inlet.flow_mol[0].fix(1) # mol/s m.fs.unit.cold_inlet.temperature[0].fix(300) # K m.fs.unit.cold_inlet.pressure[0].fix(101325) # Pa m.fs.unit.cold_inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.unit.cold_inlet.mole_frac_comp[0, "toluene"].fix(0.5) m.fs.unit.area.fix(1) m.fs.unit.overall_heat_transfer_coefficient.fix(100) return m
def basic_model(cb=delta_temperature_lmtd_callback): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = iapws95.Iapws95ParameterBlock() m.fs.unit = HeatExchanger(default={ "shell": {"property_package": m.fs.properties}, "tube": {"property_package": m.fs.properties}, "delta_temperature_callback": cb, "flow_pattern": HeatExchangerFlowPattern.countercurrent}) # Set inputs m.fs.unit.inlet_1.flow_mol[0].fix(100) m.fs.unit.inlet_1.enth_mol[0].fix(4000) m.fs.unit.inlet_1.pressure[0].fix(101325) m.fs.unit.inlet_2.flow_mol[0].fix(100) m.fs.unit.inlet_2.enth_mol[0].fix(3500) m.fs.unit.inlet_2.pressure[0].fix(101325) m.fs.unit.area.fix(1000) m.fs.unit.overall_heat_transfer_coefficient.fix(100) assert degrees_of_freedom(m) == 0 m.fs.unit.get_costing() m.fs.unit.initialize() return m
def sapon(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = SaponificationParameterBlock() m.fs.unit = HeatExchanger(default={ "shell": {"property_package": m.fs.properties}, "tube": {"property_package": m.fs.properties}, "flow_pattern": HeatExchangerFlowPattern.crossflow}) m.fs.unit.inlet_1.flow_vol[0].fix(1e-3) m.fs.unit.inlet_1.temperature[0].fix(320) m.fs.unit.inlet_1.pressure[0].fix(101325) m.fs.unit.inlet_1.conc_mol_comp[0, "H2O"].fix(55388.0) m.fs.unit.inlet_1.conc_mol_comp[0, "NaOH"].fix(100.0) m.fs.unit.inlet_1.conc_mol_comp[0, "EthylAcetate"].fix(100.0) m.fs.unit.inlet_1.conc_mol_comp[0, "SodiumAcetate"].fix(0.0) m.fs.unit.inlet_1.conc_mol_comp[0, "Ethanol"].fix(0.0) m.fs.unit.inlet_2.flow_vol[0].fix(1e-3) m.fs.unit.inlet_2.temperature[0].fix(300) m.fs.unit.inlet_2.pressure[0].fix(101325) m.fs.unit.inlet_2.conc_mol_comp[0, "H2O"].fix(55388.0) m.fs.unit.inlet_2.conc_mol_comp[0, "NaOH"].fix(100.0) m.fs.unit.inlet_2.conc_mol_comp[0, "EthylAcetate"].fix(100.0) m.fs.unit.inlet_2.conc_mol_comp[0, "SodiumAcetate"].fix(0.0) m.fs.unit.inlet_2.conc_mol_comp[0, "Ethanol"].fix(0.0) m.fs.unit.area.fix(1000) m.fs.unit.overall_heat_transfer_coefficient.fix(100) m.fs.unit.crossflow_factor.fix(0.6) return m
def test_discharge(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.steam_prop = Iapws95ParameterBlock() m.fs.therminol66_prop = ThermalOilParameterBlock() m.fs.discharge_hx = HeatExchanger( default={ "hot_side_name": "tube", "cold_side_name": "shell", "tube": { "property_package": m.fs.therminol66_prop }, "shell": { "property_package": m.fs.steam_prop }, "flow_pattern": HeatExchangerFlowPattern.countercurrent }) # Set inputs # Steam m.fs.discharge_hx.inlet_2.flow_mol[0].fix(4163) m.fs.discharge_hx.inlet_2.pressure[0].fix(1.379e+6) m.fs.discharge_hx.inlet_2.enth_mol[0].fix( htpx(T=300.15 * units.K, P=1.379e+6 * units.Pa)) # Thermal Oil m.fs.discharge_hx.inlet_1.flow_mass[0].fix(833.3) m.fs.discharge_hx.inlet_1.temperature[0].fix(256 + 273.15) m.fs.discharge_hx.inlet_1.pressure[0].fix(101325) # Designate the Area m.fs.discharge_hx.area.fix(12180) m.fs.discharge_hx.overall_heat_transfer_coefficient.fix(432.677) # Designate the U Value. m.fs.discharge_hx.initialize() m.fs.discharge_hx.heat_duty.fix(1.066e+08) m.fs.discharge_hx.area.unfix() solver = get_solver() results = solver.solve(m, tee=False) # Check for optimal solution assert results.solver.termination_condition == \ TerminationCondition.optimal assert results.solver.status == SolverStatus.ok # Tests to make sure the discharge cycle is functioning properly. assert value(m.fs.discharge_hx.outlet_1.temperature[0]) == \ pytest.approx(473.5, rel=1e-1) assert value(m.fs.discharge_hx.outlet_2.enth_mol[0]) == \ pytest.approx(27668.5, rel=1e-1)
def test_charge(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.steam_prop = Iapws95ParameterBlock() m.fs.therminol66_prop = ThermalOilParameterBlock() m.fs.charge_hx = HeatExchanger( default={ "shell": { "property_package": m.fs.steam_prop }, "tube": { "property_package": m.fs.therminol66_prop }, "flow_pattern": HeatExchangerFlowPattern.countercurrent }) # Set inputs # Steam m.fs.charge_hx.inlet_1.flow_mol[0].fix(4163) m.fs.charge_hx.inlet_1.enth_mol[0].fix( htpx(T=573.15 * units.K, P=5.0e+6 * units.Pa)) m.fs.charge_hx.inlet_1.pressure[0].fix(5.0e+6) # Thermal Oil m.fs.charge_hx.inlet_2.flow_mass[0].fix(833.3) m.fs.charge_hx.inlet_2.temperature[0].fix(200 + 273.15) m.fs.charge_hx.inlet_2.pressure[0].fix(101325) m.fs.charge_hx.area.fix(12180) m.fs.charge_hx.overall_heat_transfer_coefficient.fix(432.677) m.fs.charge_hx.initialize() m.fs.charge_hx.heat_duty.fix(1.066e+08) # Needed to make the system solve. m.fs.charge_hx.overall_heat_transfer_coefficient.unfix() solver = get_solver() results = solver.solve(m) # Check for optimal solution assert results.solver.termination_condition == \ TerminationCondition.optimal assert results.solver.status == SolverStatus.ok # Testing the exit values of the heat exchanger. assert value(m.fs.charge_hx.outlet_2.temperature[0]) == \ pytest.approx(528.83, rel=1e-1) assert value(m.fs.charge_hx.outlet_1.enth_mol[0]) == \ pytest.approx(27100.28, rel=1e-1)
def test_config(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = PhysicalParameterTestBlock() m.fs.unit = HeatExchanger( default={ "shell": { "property_package": m.fs.properties }, "tube": { "property_package": m.fs.properties } }) # Check unit config arguments # There are 8 to 10 arguments since you can add a side 1 and 2 config by # side_1, side_2, or whatever the user named them assert len(m.fs.unit.config) >= 8 and len(m.fs.unit.config) <= 10 assert not m.fs.unit.config.dynamic assert not m.fs.unit.config.has_holdup assert isinstance(m.fs.unit.config.shell, ConfigBlock) assert isinstance(m.fs.unit.config.tube, ConfigBlock) assert m.fs.unit.config.delta_temperature_callback is \ delta_temperature_lmtd_callback assert m.fs.unit.config.flow_pattern == \ HeatExchangerFlowPattern.countercurrent # Check shell config assert len(m.fs.unit.config.shell) == 7 assert m.fs.unit.config.shell.material_balance_type == \ MaterialBalanceType.useDefault assert m.fs.unit.config.shell.energy_balance_type == \ EnergyBalanceType.useDefault assert m.fs.unit.config.shell.momentum_balance_type == \ MomentumBalanceType.pressureTotal assert not m.fs.unit.config.shell.has_phase_equilibrium assert not m.fs.unit.config.shell.has_pressure_change assert m.fs.unit.config.shell.property_package is m.fs.properties # Check tube config assert len(m.fs.unit.config.tube) == 7 assert m.fs.unit.config.tube.material_balance_type == \ MaterialBalanceType.useDefault assert m.fs.unit.config.tube.energy_balance_type == \ EnergyBalanceType.useDefault assert m.fs.unit.config.tube.momentum_balance_type == \ MomentumBalanceType.pressureTotal assert not m.fs.unit.config.tube.has_phase_equilibrium assert not m.fs.unit.config.tube.has_pressure_change assert m.fs.unit.config.tube.property_package is m.fs.properties
def test_costing(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = iapws95.Iapws95ParameterBlock() m.fs.unit = HeatExchanger( default={ "shell": { "property_package": m.fs.properties }, "tube": { "property_package": m.fs.properties }, "flow_pattern": HeatExchangerFlowPattern.countercurrent }) # Set inputs m.fs.unit.inlet_1.flow_mol[0].fix(100) m.fs.unit.inlet_1.enth_mol[0].fix(4000) m.fs.unit.inlet_1.pressure[0].fix(101325) m.fs.unit.inlet_2.flow_mol[0].fix(100) m.fs.unit.inlet_2.enth_mol[0].fix(3500) m.fs.unit.inlet_2.pressure[0].fix(101325) m.fs.unit.area.fix(1000) m.fs.unit.overall_heat_transfer_coefficient.fix(100) assert degrees_of_freedom(m) == 0 m.fs.unit.initialize() m.fs.unit.get_costing() calculate_variable_from_constraint(m.fs.unit.costing.base_cost, m.fs.unit.costing.base_cost_eq) calculate_variable_from_constraint(m.fs.unit.costing.purchase_cost, m.fs.unit.costing.cp_cost_eq) assert_units_consistent(m.fs.unit.costing) results = solver.solve(m) # Check for optimal solution assert results.solver.termination_condition == TerminationCondition.optimal assert results.solver.status == SolverStatus.ok assert m.fs.unit.costing.purchase_cost.value == \ pytest.approx(529738.6793, 1e-5)
def btx(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = BTXParameterBlock(default={"valid_phase": 'Liq'}) m.fs.unit = HeatExchanger( default={ "shell": { "property_package": m.fs.properties }, "tube": { "property_package": m.fs.properties }, "flow_pattern": HeatExchangerFlowPattern.cocurrent }) return m
def sapon(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = SaponificationParameterBlock() m.fs.unit = HeatExchanger( default={ "shell": { "property_package": m.fs.properties }, "tube": { "property_package": m.fs.properties }, "flow_pattern": HeatExchangerFlowPattern.crossflow }) return m
def iapws(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = iapws95.Iapws95ParameterBlock() m.fs.unit = HeatExchanger( default={ "shell": { "property_package": m.fs.properties }, "tube": { "property_package": m.fs.properties }, "flow_pattern": HeatExchangerFlowPattern.countercurrent }) return m
def test_costing_book(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = iapws95.Iapws95ParameterBlock() m.fs.unit = HeatExchanger( default={ "shell": { "property_package": m.fs.properties }, "tube": { "property_package": m.fs.properties }, "flow_pattern": HeatExchangerFlowPattern.countercurrent }) # Set inputs m.fs.unit.inlet_1.flow_mol[0].fix(100) m.fs.unit.inlet_1.enth_mol[0].fix(4000) m.fs.unit.inlet_1.pressure[0].fix(101325) m.fs.unit.inlet_2.flow_mol[0].fix(100) m.fs.unit.inlet_2.enth_mol[0].fix(3500) m.fs.unit.inlet_2.pressure[0].fix(101325) m.fs.unit.area.fix(1000) m.fs.unit.overall_heat_transfer_coefficient.fix(100) # costing m.fs.unit.get_costing(hx_type='floating_head', length_factor='20ft', year='2018') m.fs.unit.area.fix(669.738) # m2 m.fs.unit.costing.pressure_factor.fix(1.19) m.fs.unit.costing.material_factor.fix(4.05) m.fs.costing.CE_index = 550 m.fs.unit.costing.hx_os = 1.0 calculate_variable_from_constraint(m.fs.unit.costing.base_cost_per_unit, m.fs.unit.costing.base_cost_per_unit_eq) calculate_variable_from_constraint(m.fs.unit.costing.purchase_cost, m.fs.unit.costing.cp_cost_eq) assert value(m.fs.unit.costing.base_cost) == \ pytest.approx(78802.0518, 1e-5) assert m.fs.unit.costing.purchase_cost.value == \ pytest.approx(417765.1377, 1e-5)
def test_same_name(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) with pytest.raises(NameError): m.fs.unit = HeatExchanger(default={"cold_side_name": "shell"})
HeatExchangerFlowPattern) from idaes.core.util.model_statistics import degrees_of_freedom # Import steam property package from idaes.generic_models.properties.iapws95 import htpx, Iapws95ParameterBlock from thermal_oil import ThermalOilParameterBlock m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.steam_prop = Iapws95ParameterBlock() m.fs.therminol66_prop = ThermalOilParameterBlock() m.fs.discharge_hx = HeatExchanger( default={"hot_side_name": "tube", "cold_side_name": "shell", "tube": {"property_package": m.fs.therminol66_prop}, "shell": {"property_package": m.fs.steam_prop}, "flow_pattern": HeatExchangerFlowPattern.countercurrent}) # Set inputs #Steam m.fs.discharge_hx.inlet_2.flow_mol[0].fix(4163) m.fs.discharge_hx.inlet_2.pressure[0].fix(1.379e+6) m.fs.discharge_hx.inlet_2.enth_mol[0].fix(htpx(T=300.15*units.K, P=1.379e+6*units.Pa)) #Thermal Oil m.fs.discharge_hx.inlet_1.flow_mass[0].fix(833.3) m.fs.discharge_hx.inlet_1.temperature[0].fix(256 + 273.15) m.fs.discharge_hx.inlet_1.pressure[0].fix(101325)
HeatExchangerFlowPattern) # Import steam property package from idaes.generic_models.properties.iapws95 import htpx, Iapws95ParameterBlock from thermal_oil import ThermalOilParameterBlock from idaes.core.util.model_statistics import degrees_of_freedom m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.steam_prop = Iapws95ParameterBlock() m.fs.therminol66_prop = ThermalOilParameterBlock() m.fs.charge_hx = HeatExchanger( default={"shell": {"property_package": m.fs.steam_prop}, "tube": {"property_package": m.fs.therminol66_prop}, "flow_pattern": HeatExchangerFlowPattern.countercurrent}) # Set inputs #Steam m.fs.charge_hx.inlet_1.flow_mol[0].fix(4163) m.fs.charge_hx.inlet_1.enth_mol[0].fix(htpx(T=573.15*units.K, P=5.0e+6*units.Pa)) m.fs.charge_hx.inlet_1.pressure[0].fix(5.0e+6) #Thermal Oil m.fs.charge_hx.inlet_2.flow_mass[0].fix(833.3) m.fs.charge_hx.inlet_2.temperature[0].fix(200 + 273.15) m.fs.charge_hx.inlet_2.pressure[0].fix(101325) m.fs.charge_hx.area.fix(12180)
def test_bad_option(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) with pytest.raises(KeyError): m.fs.unit = HeatExchanger(default={"I'm a bad option": "hot"})
def test_heat_exchanger(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = props.SeawaterParameterBlock() m.fs.unit = HeatExchanger( default={ "hot_side_name": "hot", "cold_side_name": "cold", "hot": { "property_package": m.fs.properties }, "cold": { "property_package": m.fs.properties }, "delta_temperature_callback": delta_temperature_chen_callback, "flow_pattern": HeatExchangerFlowPattern.countercurrent, }) # scaling m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1, index=("Liq", "H2O")) m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1e2, index=("Liq", "TDS")) iscale.set_scaling_factor(m.fs.unit.hot.heat, 1e-3) iscale.set_scaling_factor(m.fs.unit.cold.heat, 1e-3) iscale.set_scaling_factor(m.fs.unit.overall_heat_transfer_coefficient, 1e-3) iscale.set_scaling_factor(m.fs.unit.area, 1) iscale.calculate_scaling_factors(m) # ---specifications--- # state variables m.fs.unit.hot_inlet.flow_mass_phase_comp[0, "Liq", "H2O"].fix(1) m.fs.unit.hot_inlet.flow_mass_phase_comp[0, "Liq", "TDS"].fix(0.01) m.fs.unit.hot_inlet.temperature[0].fix(350) m.fs.unit.hot_inlet.pressure[0].fix(2e5) m.fs.unit.cold_inlet.flow_mass_phase_comp[0, "Liq", "H2O"].fix(0.5) m.fs.unit.cold_inlet.flow_mass_phase_comp[0, "Liq", "TDS"].fix(0.01) m.fs.unit.cold_inlet.temperature[0].fix(298) m.fs.unit.cold_inlet.pressure[0].fix(2e5) m.fs.unit.area.fix(5) m.fs.unit.overall_heat_transfer_coefficient.fix(1000) # solving assert_units_consistent(m) degrees_of_freedom(m) m.fs.unit.initialize() solver = get_solver() results = solver.solve(m, tee=False) assert_optimal_termination(results) report_io = StringIO() m.fs.unit.report(ostream=report_io) output = """ ==================================================================================== Unit : fs.unit Time: 0.0 ------------------------------------------------------------------------------------ Unit Performance Variables: Key : Value : Fixed : Bounds HX Area : 5.0000 : True : (0, None) HX Coefficient : 1000.0 : True : (0, None) Heat Duty : 89050. : False : (None, None) Expressions: Key : Value Delta T Driving : 17.810 Delta T In : 9.2239 Delta T Out : 30.689 ------------------------------------------------------------------------------------ Stream Table Hot Inlet Hot Outlet Cold Inlet Cold Outlet flow_mass_phase_comp ('Liq', 'H2O') 1.0000 1.0000 0.50000 0.50000 flow_mass_phase_comp ('Liq', 'TDS') 0.010000 0.010000 0.010000 0.010000 temperature 350.00 328.69 298.00 340.78 pressure 2.0000e+05 2.0000e+05 2.0000e+05 2.0000e+05 ==================================================================================== """ assert output == report_io.getvalue()
def btx(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) # As we lack other example prop packs with units, take the generic # BT-PR package and change the base units configuration2 = { # Specifying components "components": { 'benzene': { "type": Component, "enth_mol_ig_comp": RPP, "entr_mol_ig_comp": RPP, "pressure_sat_comp": RPP, "phase_equilibrium_form": {("Vap", "Liq"): log_fugacity}, "parameter_data": { "mw": (78.1136E-3, pyunits.kg/pyunits.mol), # [1] "pressure_crit": (48.9e5, pyunits.Pa), # [1] "temperature_crit": (562.2, pyunits.K), # [1] "omega": 0.212, # [1] "cp_mol_ig_comp_coeff": { 'A': (-3.392E1, pyunits.J/pyunits.mol/pyunits.K), # [1] 'B': (4.739E-1, pyunits.J/pyunits.mol/pyunits.K**2), 'C': (-3.017E-4, pyunits.J/pyunits.mol/pyunits.K**3), 'D': (7.130E-8, pyunits.J/pyunits.mol/pyunits.K**4)}, "enth_mol_form_vap_comp_ref": ( 82.9e3, pyunits.J/pyunits.mol), # [3] "entr_mol_form_vap_comp_ref": ( -269, pyunits.J/pyunits.mol/pyunits.K), # [3] "pressure_sat_comp_coeff": {'A': (-6.98273, None), # [1] 'B': (1.33213, None), 'C': (-2.62863, None), 'D': (-3.33399, None)}}}, 'toluene': { "type": Component, "enth_mol_ig_comp": RPP, "entr_mol_ig_comp": RPP, "pressure_sat_comp": RPP, "phase_equilibrium_form": {("Vap", "Liq"): log_fugacity}, "parameter_data": { "mw": (92.1405E-3, pyunits.kg/pyunits.mol), # [1] "pressure_crit": (41e5, pyunits.Pa), # [1] "temperature_crit": (591.8, pyunits.K), # [1] "omega": 0.263, # [1] "cp_mol_ig_comp_coeff": { 'A': (-2.435E1, pyunits.J/pyunits.mol/pyunits.K), # [1] 'B': (5.125E-1, pyunits.J/pyunits.mol/pyunits.K**2), 'C': (-2.765E-4, pyunits.J/pyunits.mol/pyunits.K**3), 'D': (4.911E-8, pyunits.J/pyunits.mol/pyunits.K**4)}, "enth_mol_form_vap_comp_ref": ( 50.1e3, pyunits.J/pyunits.mol), # [3] "entr_mol_form_vap_comp_ref": ( -321, pyunits.J/pyunits.mol/pyunits.K), # [3] "pressure_sat_comp_coeff": {'A': (-7.28607, None), # [1] 'B': (1.38091, None), 'C': (-2.83433, None), 'D': (-2.79168, None)}}}}, # Specifying phases "phases": {'Liq': {"type": LiquidPhase, "equation_of_state": Cubic, "equation_of_state_options": { "type": CubicType.PR}}, 'Vap': {"type": VaporPhase, "equation_of_state": Cubic, "equation_of_state_options": { "type": CubicType.PR}}}, # Set base units of measurement "base_units": {"time": pyunits.s, "length": pyunits.m, "mass": pyunits.t, "amount": pyunits.mol, "temperature": pyunits.degR}, # Specifying state definition "state_definition": FTPx, "state_bounds": {"flow_mol": (0, 100, 1000, pyunits.mol/pyunits.s), "temperature": (273.15, 300, 500, pyunits.K), "pressure": (5e4, 1e5, 1e6, pyunits.Pa)}, "pressure_ref": (101325, pyunits.Pa), "temperature_ref": (298.15, pyunits.K), # Defining phase equilibria "phases_in_equilibrium": [("Vap", "Liq")], "phase_equilibrium_state": {("Vap", "Liq"): SmoothVLE}, "bubble_dew_method": LogBubbleDew, "parameter_data": {"PR_kappa": {("benzene", "benzene"): 0.000, ("benzene", "toluene"): 0.000, ("toluene", "benzene"): 0.000, ("toluene", "toluene"): 0.000}}} m.fs.properties = GenericParameterBlock(default=configuration) m.fs.properties2 = GenericParameterBlock(default=configuration2) m.fs.unit = HeatExchanger(default={ "shell": {"property_package": m.fs.properties}, "tube": {"property_package": m.fs.properties2}, "flow_pattern": HeatExchangerFlowPattern.cocurrent}) m.fs.unit.inlet_1.flow_mol[0].fix(5) # mol/s m.fs.unit.inlet_1.temperature[0].fix(365) # K m.fs.unit.inlet_1.pressure[0].fix(101325) # Pa m.fs.unit.inlet_1.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.unit.inlet_1.mole_frac_comp[0, "toluene"].fix(0.5) m.fs.unit.inlet_2.flow_mol[0].fix(1) # mol/s m.fs.unit.inlet_2.temperature[0].fix(540) # degR m.fs.unit.inlet_2.pressure[0].fix(101.325) # kPa m.fs.unit.inlet_2.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.unit.inlet_2.mole_frac_comp[0, "toluene"].fix(0.5) m.fs.unit.area.fix(1) m.fs.unit.overall_heat_transfer_coefficient.fix(100) m.fs.unit.side_2.scaling_factor_pressure = 1 return m
def test_heat_exchanger(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = props.SeawaterParameterBlock() m.fs.unit = HeatExchanger( default={ "hot_side_name": "hot", "cold_side_name": "cold", "hot": { "property_package": m.fs.properties }, "cold": { "property_package": m.fs.properties }, "delta_temperature_callback": delta_temperature_chen_callback, "flow_pattern": HeatExchangerFlowPattern.countercurrent, }) # scaling m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1, index=("Liq", "H2O")) m.fs.properties.set_default_scaling("flow_mass_phase_comp", 1e2, index=("Liq", "TDS")) iscale.set_scaling_factor(m.fs.unit.hot.heat, 1e-3) iscale.set_scaling_factor(m.fs.unit.cold.heat, 1e-3) iscale.set_scaling_factor(m.fs.unit.overall_heat_transfer_coefficient, 1e-3) iscale.set_scaling_factor(m.fs.unit.area, 1) iscale.calculate_scaling_factors(m) # ---specifications--- # state variables m.fs.unit.hot_inlet.flow_mass_phase_comp[0, "Liq", "H2O"].fix(1) m.fs.unit.hot_inlet.flow_mass_phase_comp[0, "Liq", "TDS"].fix(0.01) m.fs.unit.hot_inlet.temperature[0].fix(350) m.fs.unit.hot_inlet.pressure[0].fix(2e5) m.fs.unit.cold_inlet.flow_mass_phase_comp[0, "Liq", "H2O"].fix(0.5) m.fs.unit.cold_inlet.flow_mass_phase_comp[0, "Liq", "TDS"].fix(0.01) m.fs.unit.cold_inlet.temperature[0].fix(298) m.fs.unit.cold_inlet.pressure[0].fix(2e5) m.fs.unit.area.fix(5) m.fs.unit.overall_heat_transfer_coefficient.fix(1000) # solving assert_units_consistent(m) degrees_of_freedom(m) m.fs.unit.initialize() solver = get_solver() results = solver.solve(m, tee=False) assert_optimal_termination(results) assert pytest.approx(89050.0, rel=1e-4) == value(m.fs.unit.heat_duty[0]) assert pytest.approx(1.0, rel=1e-4) == value( m.fs.unit.hot_outlet.flow_mass_phase_comp[0, "Liq", "H2O"]) assert pytest.approx(0.01, rel=1e-4) == value( m.fs.unit.hot_outlet.flow_mass_phase_comp[0, "Liq", "TDS"]) assert pytest.approx(328.69, rel=1e-4) == value( m.fs.unit.hot_outlet.temperature[0]) assert pytest.approx(2.0e5, rel=1e-4) == value(m.fs.unit.hot_outlet.pressure[0]) assert pytest.approx(0.5, rel=1e-4) == value( m.fs.unit.cold_outlet.flow_mass_phase_comp[0, "Liq", "H2O"]) assert pytest.approx(0.01, rel=1e-4) == value( m.fs.unit.cold_outlet.flow_mass_phase_comp[0, "Liq", "TDS"]) assert pytest.approx(340.78, rel=1e-4) == value( m.fs.unit.cold_outlet.temperature[0]) assert pytest.approx(2.0e5, rel=1e-4) == value(m.fs.unit.cold_outlet.pressure[0]) m.fs.unit.report()