def model(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = DSPMDEParameterBlock( default={ "solute_list": ["A", "B", "C", "D"], "diffusivity_data": { ("Liq", "A"): 1e-9, ("Liq", "B"): 1e-10, ("Liq", "C"): 1e-7, ("Liq", "D"): 1e-11, }, "mw_data": { "H2O": 18e-3, "A": 10e-3, "B": 25e-3, "C": 100e-3, "D": 25e-3 }, "stokes_radius_data": { "A": 1e-9, "B": 1e-9, "C": 1e-9, "D": 1e-10 }, "charge": { "A": 1, "B": -2, "C": 2, "D": -1 }, }) return m
def electrodialysis_cell3(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) ion_dict = { "solute_list": ["Na_+", "Cl_-", "N"], "mw_data": { "H2O": 18e-3, "Na_+": 23e-3, "Cl_-": 35.5e-3, "N": 61.8e-3 }, "electrical_mobility_data": { "Na_+": 5.19e-8, "Cl_-": 7.92e-8 }, "charge": { "Na_+": 1, "Cl_-": -1 }, } m.fs.properties = DSPMDEParameterBlock(default=ion_dict) m.fs.unit = Electrodialysis0D( default={"property_package": m.fs.properties}) m.fs.unit.config.operation_mode = "Constant_Current" return m
def model2(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = DSPMDEParameterBlock( default={"solute_list": ["A", "B", "C", "D"]}) return m
def model3(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = DSPMDEParameterBlock( default={"solute_list": ["Ca_2+", "SO4_2-", "Na_+", "Cl_-", "Mg_2+"]}) m.fs.stream = m.fs.properties.build_state_block( [0], default={"defined_state": True}) return m
def test_config(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) # NOTE: Not giving actual charges in order to test construction of # both the ion_set and solute_set m.fs.properties = DSPMDEParameterBlock( default={"solute_list": ["Ca_2+", "SO4_2-", "Na_+", "Cl_-", "Mg_2+"]}) m.fs.unit = NanofiltrationDSPMDE0D( default={"property_package": m.fs.properties}) # check unit config arguments assert len(m.fs.unit.config) == 8 assert not m.fs.unit.config.dynamic assert not m.fs.unit.config.has_holdup assert m.fs.unit.config.material_balance_type == MaterialBalanceType.useDefault assert m.fs.unit.config.momentum_balance_type == MomentumBalanceType.pressureTotal assert not m.fs.unit.config.has_pressure_change assert m.fs.unit.config.property_package is m.fs.properties assert (m.fs.unit.config.property_package.config.activity_coefficient_model == ActivityCoefficientModel.ideal) assert (m.fs.unit.config.property_package.config.density_calculation == DensityCalculation.constant) assert m.fs.unit.config.mass_transfer_coefficient == MassTransferCoefficient.fixed
def NF_frame(self): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = DSPMDEParameterBlock( default={ "solute_list": [ "Ca_2+", "SO4_2-", "Mg_2+", "Na_+", "Cl_-", ], "diffusivity_data": { ("Liq", "Ca_2+"): 9.2e-10, ("Liq", "SO4_2-"): 1.06e-9, ("Liq", "Mg_2+"): 0.706e-9, ("Liq", "Na_+"): 1.33e-9, ("Liq", "Cl_-"): 2.03e-9, }, "mw_data": { "H2O": 18e-3, "Ca_2+": 40e-3, "Mg_2+": 24e-3, "SO4_2-": 96e-3, "Na_+": 23e-3, "Cl_-": 35e-3, }, "stokes_radius_data": { "Ca_2+": 0.309e-9, "Mg_2+": 0.347e-9, "SO4_2-": 0.230e-9, "Cl_-": 0.121e-9, "Na_+": 0.184e-9, }, "charge": { "Ca_2+": 2, "Mg_2+": 2, "SO4_2-": -2, "Na_+": 1, "Cl_-": -1, }, "activity_coefficient_model": ActivityCoefficientModel.davies, "density_calculation": DensityCalculation.constant, }) m.fs.unit = NanofiltrationDSPMDE0D( default={ "property_package": m.fs.properties, "mass_transfer_coefficient": MassTransferCoefficient.spiral_wound, }) b = m.fs.unit mass_flow_in = 1 * pyunits.kg / pyunits.s feed_mass_frac = { "Ca_2+": 382e-6, "Mg_2+": 1394e-6, "SO4_2-": 2136e-6, "Cl_-": 20101.6e-6, "Na_+": 11122e-6, } # Fix mole flow rates of each ion and water for ion, x in feed_mass_frac.items(): mol_comp_flow = (x * pyunits.kg / pyunits.kg * mass_flow_in / m.fs.unit.feed_side.properties_in[0].mw_comp[ion]) m.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", ion].fix(mol_comp_flow) H2O_mass_frac = 1 - sum(x for x in feed_mass_frac.values()) H2O_mol_comp_flow = ( H2O_mass_frac * pyunits.kg / pyunits.kg * mass_flow_in / m.fs.unit.feed_side.properties_in[0].mw_comp["H2O"]) m.fs.unit.inlet.flow_mol_phase_comp[0, "Liq", "H2O"].fix(H2O_mol_comp_flow) # Use assert electroneutrality method from property model to ensure the ion concentrations provided # obey electroneutrality condition m.fs.unit.feed_side.properties_in[0].assert_electroneutrality( defined_state=True, adjust_by_ion="Cl_-", get_property="mass_frac_phase_comp", ) # Fix other inlet state variables m.fs.unit.inlet.temperature[0].fix(298.15) m.fs.unit.inlet.pressure[0].fix(4e5) # Fix the membrane variables that are usually fixed for the DSPM-DE model m.fs.unit.radius_pore.fix(0.5e-9) m.fs.unit.membrane_thickness_effective.fix(1.33e-6) m.fs.unit.membrane_charge_density.fix(-27) m.fs.unit.dielectric_constant_pore.fix(41.3) # Fix final permeate pressure to be ~atmospheric m.fs.unit.mixed_permeate[0].pressure.fix(101325) # Fix additional variables for calculating mass transfer coefficient with spiral wound correlation m.fs.unit.spacer_porosity.fix(0.85) m.fs.unit.spacer_mixing_efficiency.fix() m.fs.unit.spacer_mixing_length.fix() m.fs.unit.channel_height.fix(5e-4) m.fs.unit.recovery_vol_phase[0, "Liq"].fix(0.5) return m
def model4(): m4 = ConcreteModel() m4.fs = FlowsheetBlock(default={"dynamic": False}) m4.fs.properties = DSPMDEParameterBlock( default={ "solute_list": ["A", "B", "C", "D", "E"], "diffusivity_data": { ("Liq", "A"): 1e-9, ("Liq", "B"): 1e-10, ("Liq", "C"): 1e-7, ("Liq", "D"): 1e-11, ("Liq", "E"): 1e-11, }, "mw_data": { "H2O": 18e-3, "A": 10e-3, "B": 25e-3, "C": 100e-3, "D": 25e-3, "E": 25e-3, }, "electrical_mobility_data": { "A": 5.19e-8, "B": 8.29e-8, "C": 6.17e-8, "D": 7.92e-8, }, "stokes_radius_data": { "A": 1e-9, "B": 1e-9, "C": 1e-9, "D": 1e-10, "E": 1e-10, }, "charge": { "A": 1, "B": -2, "C": 2, "D": -1, "E": 0 }, }) # config thermo_config = { "components": { "H2O": { "type": Solvent, "valid_phase_types": PT.aqueousPhase, "dens_mol_liq_comp": Constant, "enth_mol_liq_comp": Constant, "cp_mol_liq_comp": Constant, "entr_mol_liq_comp": Constant, # Parameter data is always associated with the methods defined above "parameter_data": { "mw": (18.0153, pyunits.g / pyunits.mol), "dens_mol_liq_comp_coeff": (55.2, pyunits.kmol * pyunits.m**-3), "cp_mol_liq_comp_coeff": ( 75.312, pyunits.J / pyunits.mol / pyunits.K, ), "enth_mol_form_liq_comp_ref": (0, pyunits.kJ / pyunits.mol), "entr_mol_form_liq_comp_ref": ( 0, pyunits.J / pyunits.K / pyunits.mol, ), }, # End parameter_data }, "A": { "type": Cation, "charge": 1, "dens_mol_liq_comp": Constant, "enth_mol_liq_comp": Constant, "cp_mol_liq_comp": Constant, "entr_mol_liq_comp": Constant, "parameter_data": { "mw": (10, pyunits.g / pyunits.mol), "electrical_mobility_comp": ( 5.19e-8, pyunits.meter**2 * pyunits.volt**-1 * pyunits.second**-1, ), "dens_mol_liq_comp_coeff": (55.2, pyunits.kmol * pyunits.m**-3), "cp_mol_liq_comp_coeff": ( 75.312, pyunits.J / pyunits.mol / pyunits.K, ), "enth_mol_form_liq_comp_ref": (0, pyunits.kJ / pyunits.mol), "entr_mol_form_liq_comp_ref": ( 0, pyunits.J / pyunits.K / pyunits.mol, ), }, }, "B": { "type": Anion, "charge": -2, "dens_mol_liq_comp": Constant, "enth_mol_liq_comp": Constant, "cp_mol_liq_comp": Constant, "entr_mol_liq_comp": Constant, "parameter_data": { "mw": (25, pyunits.g / pyunits.mol), "electrical_mobility_comp": ( 8.29e-8, pyunits.meter**2 * pyunits.volt**-1 * pyunits.second**-1, ), "dens_mol_liq_comp_coeff": (55.2, pyunits.kmol * pyunits.m**-3), "cp_mol_liq_comp_coeff": ( 75.312, pyunits.J / pyunits.mol / pyunits.K, ), "enth_mol_form_liq_comp_ref": (0, pyunits.kJ / pyunits.mol), "entr_mol_form_liq_comp_ref": ( 0, pyunits.J / pyunits.K / pyunits.mol, ), }, }, "C": { "type": Cation, "charge": 2, "dens_mol_liq_comp": Constant, "enth_mol_liq_comp": Constant, "cp_mol_liq_comp": Constant, "entr_mol_liq_comp": Constant, "parameter_data": { "mw": (100, pyunits.g / pyunits.mol), "electrical_mobility_comp": ( 6.17e-8, pyunits.meter**2 * pyunits.volt**-1 * pyunits.second**-1, ), "dens_mol_liq_comp_coeff": (55.2, pyunits.kmol * pyunits.m**-3), "cp_mol_liq_comp_coeff": ( 75.312, pyunits.J / pyunits.mol / pyunits.K, ), "enth_mol_form_liq_comp_ref": (0, pyunits.kJ / pyunits.mol), "entr_mol_form_liq_comp_ref": ( 0, pyunits.J / pyunits.K / pyunits.mol, ), }, }, "D": { "type": Anion, "charge": -1, "dens_mol_liq_comp": Constant, "enth_mol_liq_comp": Constant, "cp_mol_liq_comp": Constant, "entr_mol_liq_comp": Constant, "parameter_data": { "mw": (25, pyunits.g / pyunits.mol), "electrical_mobility_comp": ( 7.92e-8, pyunits.meter**2 * pyunits.volt**-1 * pyunits.second**-1, ), "dens_mol_liq_comp_coeff": (55.2, pyunits.kmol * pyunits.m**-3), "cp_mol_liq_comp_coeff": ( 75.312, pyunits.J / pyunits.mol / pyunits.K, ), "enth_mol_form_liq_comp_ref": (0, pyunits.kJ / pyunits.mol), "entr_mol_form_liq_comp_ref": ( 0, pyunits.J / pyunits.K / pyunits.mol, ), }, }, "E": { "type": Solute, "valid_phase_types": PT.aqueousPhase, "dens_mol_liq_comp": Constant, "enth_mol_liq_comp": Constant, "cp_mol_liq_comp": Constant, "entr_mol_liq_comp": Constant, "parameter_data": { "mw": (25, pyunits.g / pyunits.mol), "dens_mol_liq_comp_coeff": (55.2, pyunits.kmol * pyunits.m**-3), "cp_mol_liq_comp_coeff": ( 75.312, pyunits.J / pyunits.mol / pyunits.K, ), "enth_mol_form_liq_comp_ref": (0, pyunits.kJ / pyunits.mol), "entr_mol_form_liq_comp_ref": ( 0, pyunits.J / pyunits.K / pyunits.mol, ), }, }, }, # End Component list "phases": { "Liq": { "type": AqueousPhase, "equation_of_state": Ideal }, }, "state_definition": FpcTP, "state_bounds": { "temperature": (273.15, 300, 650), "pressure": (5e4, 1e5, 1e6), }, "pressure_ref": 1e5, "temperature_ref": 300, "base_units": { "time": pyunits.s, "length": pyunits.m, "mass": pyunits.kg, "amount": pyunits.mol, "temperature": pyunits.K, }, } # End thermo_config definition m5 = ConcreteModel() m5.fs = FlowsheetBlock(default={"dynamic": False}) m5.fs.properties = GenericParameterBlock(default=thermo_config) return (m4, m5)
def test_assert_electroneutrality_get_property(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = DSPMDEParameterBlock( default={ "solute_list": ["Ca_2+", "SO4_2-", "Na_+", "Cl_-", "Mg_2+"], "mw_data": { "H2O": 18e-3, "Na_+": 23e-3, "Ca_2+": 40e-3, "Mg_2+": 24e-3, "Cl_-": 35e-3, "SO4_2-": 96e-3, }, "charge": { "Na_+": 1, "Ca_2+": 2, "Mg_2+": 2, "Cl_-": -1, "SO4_2-": -2 }, "density_calculation": DensityCalculation.seawater, "activity_coefficient_model": ActivityCoefficientModel.davies, }) m.fs.stream = stream = m.fs.properties.build_state_block( [0], default={"defined_state": True}) mass_flow_in = 1 * pyunits.kg / pyunits.s feed_mass_frac = { "Na_+": 11122e-6, "Ca_2+": 382e-6, "Mg_2+": 1394e-6, "SO4_2-": 2136e-6, "Cl_-": 20300e-6, } for ion, x in feed_mass_frac.items(): mol_comp_flow = (x * pyunits.kg / pyunits.kg * mass_flow_in / stream[0].mw_comp[ion]) stream[0].flow_mol_phase_comp["Liq", ion].fix(mol_comp_flow) H2O_mass_frac = 1 - sum(x for x in feed_mass_frac.values()) H2O_mol_comp_flow = (H2O_mass_frac * pyunits.kg / pyunits.kg * mass_flow_in / stream[0].mw_comp["H2O"]) stream[0].flow_mol_phase_comp["Liq", "H2O"].fix(H2O_mol_comp_flow) stream[0].temperature.fix(298.15) stream[0].pressure.fix(101325) # check get_property works with tuple stream[0].assert_electroneutrality( defined_state=True, adjust_by_ion="Cl_-", get_property=("mass_frac_phase_comp", "pressure_osm_phase"), ) # check error when adjust_by_ion is not in solute list with pytest.raises( ValueError, match="adjust_by_ion must be set to the name of an " "ion in the list of solutes.", ): stream[0].assert_electroneutrality(defined_state=True, adjust_by_ion="foo") # check error when get_property is not None and defined_state is NOT true with pytest.raises( ValueError, match="Set defined_state to true if get_property" " = flow_mass_phase_comp", ): stream[0].assert_electroneutrality(defined_state=False, get_property="flow_mass_phase_comp") # check error when state vars are fixed but defined_state is set to False with pytest.raises( AssertionError, match=re.escape( "fs.stream[0].flow_mol_phase_comp[Liq,Ca_2+] was fixed. " "Either set defined_state=True or unfix flow_mol_phase_comp " "for each solute to check that electroneutrality is satisfied." ), ): stream[0].assert_electroneutrality(defined_state=False) # check error when get_property receives anything other than str, list, or tuple of strings with pytest.raises( TypeError, match=re.escape( "get_property must be a string or list/tuple of strings."), ): stream[0].assert_electroneutrality(defined_state=True, adjust_by_ion="Cl_-", get_property=1) # check error when electroneutralit condition violated for stringent tolerance # Changed the error message to look for the correct pattern instead of # exact match of the numeric value in the string stream[0].flow_mol_phase_comp.unfix() with pytest.raises( AssertionError, match=re.escape( "Electroneutrality condition violated in fs.stream[0]. "), ): stream[0].assert_electroneutrality(defined_state=False, adjust_by_ion="Cl_-", tol=1e-18)
def test_assert_electroneutrality_get_property(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = DSPMDEParameterBlock( default={ "solute_list": ["Ca_2+", "SO4_2-", "Na_+", "Cl_-", "Mg_2+"], "diffusivity_data": { ("Liq", "Ca_2+"): 0.792e-9, ("Liq", "SO4_2-"): 1.06e-9, ("Liq", "Na_+"): 1.33e-9, ("Liq", "Cl_-"): 2.03e-9, ("Liq", "Mg_2+"): 0.706e-9, }, "mw_data": { "H2O": 18e-3, "Na_+": 23e-3, "Ca_2+": 40e-3, "Mg_2+": 24e-3, "Cl_-": 35e-3, "SO4_2-": 96e-3, }, "electrical_mobility_data": { "Na_+": 5.19e-8, "Ca_2+": 6.17e-8, "Mg_2+": 5.50e-8, "Cl_-": 7.92e-8, "SO4_2-": 8.29e-8, }, "stokes_radius_data": { "Na_+": 0.184e-9, "Ca_2+": 0.309e-9, "Mg_2+": 0.347e-9, "Cl_-": 0.121e-9, "SO4_2-": 0.230e-9, }, "charge": { "Na_+": 1, "Ca_2+": 2, "Mg_2+": 2, "Cl_-": -1, "SO4_2-": -2 }, "density_calculation": DensityCalculation.seawater, "activity_coefficient_model": ActivityCoefficientModel.davies, }) m.fs.stream = stream = m.fs.properties.build_state_block( [0], default={"defined_state": True}) mass_flow_in = 1 * pyunits.kg / pyunits.s feed_mass_frac = { "Na_+": 11122e-6, "Ca_2+": 382e-6, "Mg_2+": 1394e-6, "SO4_2-": 2136e-6, "Cl_-": 20300e-6, } for ion, x in feed_mass_frac.items(): mol_comp_flow = (x * pyunits.kg / pyunits.kg * mass_flow_in / stream[0].mw_comp[ion]) stream[0].flow_mol_phase_comp["Liq", ion].fix(mol_comp_flow) H2O_mass_frac = 1 - sum(x for x in feed_mass_frac.values()) H2O_mol_comp_flow = (H2O_mass_frac * pyunits.kg / pyunits.kg * mass_flow_in / stream[0].mw_comp["H2O"]) stream[0].flow_mol_phase_comp["Liq", "H2O"].fix(H2O_mol_comp_flow) stream[0].temperature.fix(298.15) stream[0].pressure.fix(101325) assert not stream[0].is_property_constructed("pressure_osm_phase") assert not stream[0].is_property_constructed("mass_frac_phase_comp") stream[0].assert_electroneutrality( defined_state=True, adjust_by_ion="Cl_-", get_property=["mass_frac_phase_comp", "pressure_osm_phase"], ) assert stream[0].is_property_constructed("mass_frac_phase_comp") assert stream[0].is_property_constructed("pressure_osm_phase") assert not hasattr(stream, "charge_balance") assert not stream[0].is_property_constructed("flow_vol") stream[0].assert_electroneutrality(defined_state=True, adjust_by_ion="Cl_-", get_property="flow_vol") assert stream[0].is_property_constructed("flow_vol") assert not hasattr(stream, "charge_balance") # check that charge_balance constraint is deleted after failed solve stream[0].flow_vol_phase.fix(1e5) with pytest.raises( ValueError, match="The stateblock failed to solve while computing " "concentrations to check the charge balance.", ): stream[0].assert_electroneutrality(defined_state=True, adjust_by_ion="Cl_-") assert not hasattr(stream, "charge_balance")
def test_seawater_data(): m = ConcreteModel() m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.properties = DSPMDEParameterBlock( default={ "solute_list": ["Ca_2+", "SO4_2-", "Na_+", "Cl_-", "Mg_2+"], "diffusivity_data": { ("Liq", "Ca_2+"): 0.792e-9, ("Liq", "SO4_2-"): 1.06e-9, ("Liq", "Na_+"): 1.33e-9, ("Liq", "Cl_-"): 2.03e-9, ("Liq", "Mg_2+"): 0.706e-9, }, "mw_data": { "H2O": 18e-3, "Na_+": 23e-3, "Ca_2+": 40e-3, "Mg_2+": 24e-3, "Cl_-": 35e-3, "SO4_2-": 96e-3, }, "electrical_mobility_data": { "Na_+": 5.19e-8, "Ca_2+": 6.17e-8, "Mg_2+": 5.50e-8, "Cl_-": 7.92e-8, "SO4_2-": 8.29e-8, }, "stokes_radius_data": { "Na_+": 0.184e-9, "Ca_2+": 0.309e-9, "Mg_2+": 0.347e-9, "Cl_-": 0.121e-9, "SO4_2-": 0.230e-9, }, "charge": { "Na_+": 1, "Ca_2+": 2, "Mg_2+": 2, "Cl_-": -1, "SO4_2-": -2 }, "density_calculation": DensityCalculation.seawater, "activity_coefficient_model": ActivityCoefficientModel.davies, }) m.fs.stream = stream = m.fs.properties.build_state_block( [0], default={"defined_state": True}) mass_flow_in = 1 * pyunits.kg / pyunits.s feed_mass_frac = { "Na_+": 11122e-6, "Ca_2+": 382e-6, "Mg_2+": 1394e-6, "SO4_2-": 2136e-6, "Cl_-": 20300e-6, } for ion, x in feed_mass_frac.items(): mol_comp_flow = (x * pyunits.kg / pyunits.kg * mass_flow_in / stream[0].mw_comp[ion]) stream[0].flow_mol_phase_comp["Liq", ion].fix(mol_comp_flow) H2O_mass_frac = 1 - sum(x for x in feed_mass_frac.values()) H2O_mol_comp_flow = (H2O_mass_frac * pyunits.kg / pyunits.kg * mass_flow_in / stream[0].mw_comp["H2O"]) stream[0].flow_mol_phase_comp["Liq", "H2O"].fix(H2O_mol_comp_flow) stream[0].temperature.fix(298.15) stream[0].pressure.fix(101325) stream[0].assert_electroneutrality(defined_state=True, tol=1e-2, adjust_by_ion="Cl_-") metadata = m.fs.properties.get_metadata().properties for v_name in metadata: getattr(stream[0], v_name) assert stream[0].is_property_constructed("conc_mol_phase_comp") assert_units_consistent(m) check_dof(m, fail_flag=True) m.fs.properties.set_default_scaling("flow_mol_phase_comp", 1e-1, index=("Liq", "H2O")) m.fs.properties.set_default_scaling("flow_mol_phase_comp", 1e1, index=("Liq", "Na_+")) m.fs.properties.set_default_scaling("flow_mol_phase_comp", 1e1, index=("Liq", "Cl_-")) m.fs.properties.set_default_scaling("flow_mol_phase_comp", 1e2, index=("Liq", "Ca_2+")) m.fs.properties.set_default_scaling("flow_mol_phase_comp", 1e2, index=("Liq", "SO4_2-")) m.fs.properties.set_default_scaling("flow_mol_phase_comp", 1e2, index=("Liq", "Mg_2+")) calculate_scaling_factors(m) stream.initialize() # check if any variables are badly scaled badly_scaled_var_list = list( badly_scaled_var_generator(m, large=100, small=0.01, zero=1e-10)) assert len(badly_scaled_var_list) == 0 results = solver.solve(m) assert_optimal_termination(results) assert value(stream[0].flow_vol_phase["Liq"]) == pytest.approx(9.767e-4, rel=1e-3) assert value(stream[0].flow_mol_phase_comp["Liq", "H2O"]) == pytest.approx( 53.59256, rel=1e-3) assert value(stream[0].flow_mol_phase_comp["Liq", "Na_+"]) == pytest.approx( 0.4836, rel=1e-3) assert value(stream[0].flow_mol_phase_comp["Liq", "Ca_2+"]) == pytest.approx( 0.00955, rel=1e-3) assert value(stream[0].flow_mol_phase_comp["Liq", "Mg_2+"]) == pytest.approx( 0.05808, rel=1e-3) assert value(stream[0].flow_mol_phase_comp["Liq", "Cl_-"]) == pytest.approx( 0.57443, rel=1e-3) assert value(stream[0].flow_mol_phase_comp["Liq", "SO4_2-"]) == pytest.approx( 0.02225, rel=1e-3) assert value(stream[0].dens_mass_phase["Liq"]) == pytest.approx(1023.816, rel=1e-3) assert value(stream[0].pressure_osm_phase["Liq"]) == pytest.approx( 29.132e5, rel=1e-3) assert value( stream[0].electrical_conductivity_phase["Liq"]) == pytest.approx( 8.08, rel=1e-3) assert value(stream[0].flow_vol) == pytest.approx(9.767e-4, rel=1e-3) assert value( sum(stream[0].conc_mass_phase_comp["Liq", j] for j in m.fs.properties.ion_set | m.fs.properties.solute_set)) == pytest.approx(35.9744, rel=1e-3) assert value( sum(stream[0].mass_frac_phase_comp["Liq", j] for j in m.fs.properties.ion_set | m.fs.properties.solute_set)) == pytest.approx(0.035142, rel=1e-3) assert value( sum(stream[0].mass_frac_phase_comp["Liq", j] for j in m.fs.properties.component_list)) == pytest.approx( 1, rel=1e-3) assert value( sum(stream[0].mole_frac_phase_comp["Liq", j] for j in m.fs.properties.component_list)) == pytest.approx( 1, rel=1e-3) assert value(stream[0].conc_mol_phase_comp["Liq", "Na_+"]) == pytest.approx( 495.082, rel=1e-3) assert value(stream[0].conc_mol_phase_comp["Liq", "Cl_-"]) == pytest.approx( 588.0431, rel=1e-3) assert value(stream[0].conc_mol_phase_comp["Liq", "Ca_2+"]) == pytest.approx( 9.777, rel=1e-3) assert value(stream[0].conc_mol_phase_comp["Liq", "SO4_2-"]) == pytest.approx( 22.780, rel=1e-3) assert value(stream[0].conc_mol_phase_comp["Liq", "Mg_2+"]) == pytest.approx( 59.467, rel=1e-3) assert value(stream[0].conc_mass_phase_comp["Liq", "Na_+"]) == pytest.approx( 11.387, rel=1e-3) assert value(stream[0].conc_mass_phase_comp["Liq", "Cl_-"]) == pytest.approx( 20.5815, rel=1e-3) assert value(stream[0].conc_mass_phase_comp["Liq", "Ca_2+"]) == pytest.approx( 0.391, rel=1e-3) assert value(stream[0].conc_mass_phase_comp["Liq", "SO4_2-"]) == pytest.approx( 2.187, rel=1e-3) assert value(stream[0].conc_mass_phase_comp["Liq", "Mg_2+"]) == pytest.approx( 1.427, rel=1e-3) assert value(stream[0].mole_frac_phase_comp["Liq", "Na_+"]) == pytest.approx( 8.833e-3, rel=1e-3) assert value(stream[0].mole_frac_phase_comp["Liq", "Cl_-"]) == pytest.approx( 1.049e-2, rel=1e-3) assert value(stream[0].mole_frac_phase_comp["Liq", "Ca_2+"]) == pytest.approx( 1.744e-4, rel=1e-3) assert value(stream[0].mole_frac_phase_comp["Liq", "SO4_2-"]) == pytest.approx( 4.064e-4, rel=1e-3) assert value(stream[0].mole_frac_phase_comp["Liq", "Mg_2+"]) == pytest.approx( 1.061e-3, rel=1e-3) assert value(stream[0].mass_frac_phase_comp["Liq", "Na_+"]) == pytest.approx( 1.112e-2, rel=1e-3) assert value(stream[0].mass_frac_phase_comp["Liq", "Cl_-"]) == pytest.approx( 2.01e-2, rel=1e-3) assert value(stream[0].mass_frac_phase_comp["Liq", "Ca_2+"]) == pytest.approx( 3.82e-4, rel=1e-3) assert value(stream[0].mass_frac_phase_comp["Liq", "SO4_2-"]) == pytest.approx( 2.136e-3, rel=1e-3) assert value(stream[0].mass_frac_phase_comp["Liq", "Mg_2+"]) == pytest.approx( 1.394e-3, rel=1e-3) assert value(stream[0].debye_huckel_constant) == pytest.approx(0.01554, rel=1e-3) assert value(stream[0].ionic_strength) == pytest.approx(0.73467, rel=1e-3)
def test_seawater_data(): m = ConcreteModel() m.fs = FlowsheetBlock(default={'dynamic': False}) m.fs.properties = DSPMDEParameterBlock( default={ "solute_list": ["Ca_2+", "SO4_2-", "Na_+", "Cl_-", "Mg_2+"], "diffusivity_data": { ("Liq", "Ca_2+"): 0.792e-9, ("Liq", "SO4_2-"): 1.06e-9, ("Liq", "Na_+"): 1.33e-9, ("Liq", "Cl_-"): 2.03e-9, ("Liq", "Mg_2+"): 0.706e-9 }, "mw_data": { "H2O": 18e-3, "Na_+": 23e-3, "Ca_2+": 40e-3, "Mg_2+": 24e-3, "Cl_-": 35e-3, "SO4_2-": 96e-3 }, "stokes_radius_data": { "Na_+": 0.184e-9, "Ca_2+": 0.309e-9, "Mg_2+": 0.347e-9, "Cl_-": 0.121e-9, "SO4_2-": 0.230e-9 }, "charge": { "Na_+": 1, "Ca_2+": 2, "Mg_2+": 2, "Cl_-": -1, "SO4_2-": -2 }, }) m.fs.stream = stream = m.fs.properties.build_state_block( [0], default={'defined_state': True}) mass_flow_in = 1 * pyunits.kg / pyunits.s feed_mass_frac = { 'Na_+': 11122e-6, 'Ca_2+': 382e-6, 'Mg_2+': 1394e-6, 'SO4_2-': 2136e-6, 'Cl_-': 20300e-6 } for ion, x in feed_mass_frac.items(): mol_comp_flow = x * pyunits.kg / pyunits.kg * mass_flow_in / stream[ 0].mw_comp[ion] stream[0].flow_mol_phase_comp['Liq', ion].fix(mol_comp_flow) H2O_mass_frac = 1 - sum(x for x in feed_mass_frac.values()) H2O_mol_comp_flow = H2O_mass_frac * pyunits.kg / pyunits.kg * mass_flow_in / stream[ 0].mw_comp['H2O'] stream[0].flow_mol_phase_comp['Liq', 'H2O'].fix(H2O_mol_comp_flow) stream[0].temperature.fix(298.15) stream[0].pressure.fix(101325) stream[0].assert_electroneutrality(tol=1e-2) metadata = m.fs.properties.get_metadata().properties for v_name in metadata: getattr(stream[0], v_name) assert stream[0].is_property_constructed('conc_mol_phase_comp') assert_units_consistent(m) check_dof(m, fail_flag=True) m.fs.properties.set_default_scaling('flow_mol_phase_comp', 1, index=('Liq', 'H2O')) m.fs.properties.set_default_scaling('flow_mol_phase_comp', 1, index=('Liq', 'Na_+')) m.fs.properties.set_default_scaling('flow_mol_phase_comp', 1, index=('Liq', 'Cl_-')) m.fs.properties.set_default_scaling('flow_mol_phase_comp', 1e1, index=('Liq', 'Ca_2+')) m.fs.properties.set_default_scaling('flow_mol_phase_comp', 1e1, index=('Liq', 'SO4_2-')) m.fs.properties.set_default_scaling('flow_mol_phase_comp', 1, index=('Liq', 'Mg_2+')) calculate_scaling_factors(m) # check if any variables are badly scaled badly_scaled_var_list = list(badly_scaled_var_generator(m)) assert len(badly_scaled_var_list) == 0 stream.initialize() # check if any variables are badly scaled badly_scaled_var_list = list(badly_scaled_var_generator(m)) assert len(badly_scaled_var_list) == 0 results = solver.solve(m) assert_optimal_termination(results) assert value(stream[0].flow_vol_phase['Liq']) == pytest.approx(0.001, rel=1e-3) assert value(stream[0].flow_mol_phase_comp['Liq', 'H2O']) == pytest.approx( 53.59256, rel=1e-3) assert value(stream[0].flow_mol_phase_comp['Liq', 'Na_+']) == pytest.approx( 0.4836, rel=1e-3) assert value(stream[0].flow_mol_phase_comp['Liq', 'Ca_2+']) == pytest.approx( 0.00955, rel=1e-3) assert value(stream[0].flow_mol_phase_comp['Liq', 'Mg_2+']) == pytest.approx( 0.05808, rel=1e-3) assert value(stream[0].flow_mol_phase_comp['Liq', 'Cl_-']) == pytest.approx( 0.58, rel=1e-3) assert value(stream[0].flow_mol_phase_comp['Liq', 'SO4_2-']) == pytest.approx( 0.02225, rel=1e-3) assert value(stream[0].dens_mass_phase['Liq']) == pytest.approx(1000, rel=1e-3) assert value(stream[0].pressure_osm) == pytest.approx(28.593e5, rel=1e-3) assert value(stream[0].flow_vol) == pytest.approx(0.001, rel=1e-3) assert value( sum(stream[0].conc_mass_phase_comp['Liq', j] for j in m.fs.properties.solute_set)) == pytest.approx(35.334, rel=1e-3) assert value( sum(stream[0].mass_frac_phase_comp['Liq', j] for j in m.fs.properties.solute_set)) == pytest.approx(35334e-6, rel=1e-3) assert value( sum(stream[0].mass_frac_phase_comp['Liq', j] for j in m.fs.properties.component_list)) == pytest.approx( 1, rel=1e-3) assert value( sum(stream[0].mole_frac_phase_comp['Liq', j] for j in m.fs.properties.component_list)) == pytest.approx( 1, rel=1e-3) assert value(stream[0].conc_mol_phase_comp['Liq', 'Na_+']) == pytest.approx( 483.565, rel=1e-3) assert value(stream[0].conc_mol_phase_comp['Liq', 'Cl_-']) == pytest.approx( 580, rel=1e-3) assert value(stream[0].conc_mol_phase_comp['Liq', 'Ca_2+']) == pytest.approx( 9.55, rel=1e-3) assert value(stream[0].conc_mol_phase_comp['Liq', 'SO4_2-']) == pytest.approx( 22.25, rel=1e-3) assert value(stream[0].conc_mol_phase_comp['Liq', 'Mg_2+']) == pytest.approx( 58.08, rel=1e-3) assert value(stream[0].conc_mass_phase_comp['Liq', 'Na_+']) == pytest.approx( 11.122, rel=1e-3) assert value(stream[0].conc_mass_phase_comp['Liq', 'Cl_-']) == pytest.approx( 20.3, rel=1e-3) assert value(stream[0].conc_mass_phase_comp['Liq', 'Ca_2+']) == pytest.approx( 0.382, rel=1e-3) assert value(stream[0].conc_mass_phase_comp['Liq', 'SO4_2-']) == pytest.approx( 2.136, rel=1e-3) assert value(stream[0].conc_mass_phase_comp['Liq', 'Mg_2+']) == pytest.approx( 1.394, rel=1e-3) assert value(stream[0].mole_frac_phase_comp['Liq', 'Na_+']) == pytest.approx( 8.833e-3, rel=1e-3) assert value(stream[0].mole_frac_phase_comp['Liq', 'Cl_-']) == pytest.approx( 1.059e-2, rel=1e-3) assert value(stream[0].mole_frac_phase_comp['Liq', 'Ca_2+']) == pytest.approx( 1.744e-4, rel=1e-3) assert value(stream[0].mole_frac_phase_comp['Liq', 'SO4_2-']) == pytest.approx( 4.064e-4, rel=1e-3) assert value(stream[0].mole_frac_phase_comp['Liq', 'Mg_2+']) == pytest.approx( 1.061e-3, rel=1e-3) assert value(stream[0].mass_frac_phase_comp['Liq', 'Na_+']) == pytest.approx( 1.112e-2, rel=1e-3) assert value(stream[0].mass_frac_phase_comp['Liq', 'Cl_-']) == pytest.approx( 2.03e-2, rel=1e-3) assert value(stream[0].mass_frac_phase_comp['Liq', 'Ca_2+']) == pytest.approx( 3.82e-4, rel=1e-3) assert value(stream[0].mass_frac_phase_comp['Liq', 'SO4_2-']) == pytest.approx( 2.136e-3, rel=1e-3) assert value(stream[0].mass_frac_phase_comp['Liq', 'Mg_2+']) == pytest.approx( 1.394e-3, rel=1e-3)