diff --git a/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_0D.rst b/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_0D.rst index 7db9756d88..5b57b90321 100644 --- a/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_0D.rst +++ b/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_0D.rst @@ -4,6 +4,7 @@ This osmotically assisted reverse osmosis (OARO) unit model * is 0-dimensional * supports a single liquid phase only * supports steady-state only + * supports flat-sheet and spiral-wound module designs * is based on the solution-diffusion model and film theory * assumes isothermal conditions * assumes the feed-side flows in the forward direction @@ -177,7 +178,8 @@ Equations "Reynolds number",":math:`Re = \frac{\rho v_f d_h}{\mu}`" "Hydraulic diameter",":math:`d_h = \frac{4\epsilon_{sp}}{2/h_{ch} + (1-\epsilon_{sp})8/h_{ch}}`" "Cross-sectional area",":math:`A_c = h_{ch}W\epsilon_{sp}`" - "Membrane area",":math:`A_m = LW`" + "Membrane area (flat-plate)",":math:`A_m = LW`" + "Membrane area (spiral-wound)",":math:`A_m = 2LW`" "Pressure drop",":math:`ΔP = (\frac{ΔP}{Δx})_{avg}L`" "Feed-channel velocity",":math:`v_f = Q_f/A_c`" "Friction factor",":math:`f = 0.42+\frac{189.3}{Re}`" diff --git a/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_1D.rst b/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_1D.rst index e6f6d24b5b..b2c3ebdeff 100644 --- a/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_1D.rst +++ b/docs/technical_reference/unit_models/osmotically_assisted_reverse_osmosis_1D.rst @@ -4,6 +4,7 @@ This osmotically assisted reverse osmosis (OARO) unit model * is 1-dimensional * supports a single liquid phase only * supports steady-state only + * supports flat-sheet and spiral-wound module designs * is based on the solution-diffusion model and film theory * assumes isothermal conditions * assumes the feed-side flows in the forward direction diff --git a/docs/technical_reference/unit_models/reverse_osmosis_0D.rst b/docs/technical_reference/unit_models/reverse_osmosis_0D.rst index 01cc0be768..1f8a6328b8 100644 --- a/docs/technical_reference/unit_models/reverse_osmosis_0D.rst +++ b/docs/technical_reference/unit_models/reverse_osmosis_0D.rst @@ -4,6 +4,7 @@ This reverse osmosis (RO) unit model * is 0-dimensional * supports a single liquid phase only * supports steady-state only + * supports flat-sheet and spiral-wound module designs * is based on the solution-diffusion model and film theory * assumes isothermal conditions @@ -159,7 +160,8 @@ Equations "Reynolds number",":math:`Re = \frac{\rho v_f d_h}{\mu}`" "Hydraulic diameter",":math:`d_h = \frac{4\epsilon_{sp}}{2/h_{ch} + (1-\epsilon_{sp})8/h_{ch}}`" "Cross-sectional area",":math:`A_c = h_{ch}W\epsilon_{sp}`" - "Membrane area",":math:`A_m = LW`" + "Membrane area (flat-plate)",":math:`A_m = LW`" + "Membrane area (spiral-wound)",":math:`A_m = 2LW`" "Pressure drop",":math:`ΔP = (\frac{ΔP}{Δx})_{avg}L`" "Feed-channel velocity",":math:`v_f = Q_f/A_c`" "Friction factor",":math:`f = 0.42+\frac{189.3}{Re}`" diff --git a/docs/technical_reference/unit_models/reverse_osmosis_1D.rst b/docs/technical_reference/unit_models/reverse_osmosis_1D.rst index b0c7f34bfb..49a1396fff 100644 --- a/docs/technical_reference/unit_models/reverse_osmosis_1D.rst +++ b/docs/technical_reference/unit_models/reverse_osmosis_1D.rst @@ -4,6 +4,7 @@ This reverse osmosis (RO) unit model * is 1-dimensional * supports a single liquid phase only * supports steady-state only + * supports flat-sheet and spiral-wound module designs * is based on the solution-diffusion model and film theory * assumes isothermal conditions diff --git a/watertap/core/membrane_channel_base.py b/watertap/core/membrane_channel_base.py index 665932953c..70db4ecfa4 100644 --- a/watertap/core/membrane_channel_base.py +++ b/watertap/core/membrane_channel_base.py @@ -71,6 +71,16 @@ class TransportModel(Enum): SKK = auto() +class ModuleType(Enum): + """ + flat_sheet: flat-sheet module configuration + spiral_wound: spiral-wound module configuration + """ + + flat_sheet = auto() + spiral_wound = auto() + + class PressureChangeType(Enum): """ fixed_per_stage: pressure drop across membrane channel is a user-specified value @@ -85,12 +95,11 @@ class PressureChangeType(Enum): class FrictionFactor(Enum): """ - flat_sheet: Darcy's friction factor correlation by Guillen & Hoek - spiral_wound: Darcy's friction factor correlation by Schock & Miquel, 1987 + default_by_module_type: Will revert FrictionFactor to either the Darcy's friction factor correlation + by Guillen & Hoek (flat-plate) or by Schock & Miquel (spiral-wound) """ - flat_sheet = auto() - spiral_wound = auto() + default_by_module_type = auto() CONFIG_Template = ConfigDict() @@ -261,6 +270,24 @@ class FrictionFactor(Enum): ), ) +CONFIG_Template.declare( + "module_type", + ConfigValue( + default=ModuleType.flat_sheet, + domain=In(ModuleType), + description="Membrane geometry for flat-sheet or spiral-wound", + doc=""" + Options to account for geometry differences between flat sheet and spiral wound membranes. + + **default** - ``ModuleType.flat_sheet`` + + "``ModuleType.flat_sheet``", "Module type option for flat-sheet membrane modules" + "``ModuleType.spiral_wound``", "Module type option for spiral-wound membrane modules, this option accounts for how membranes in spiral-wound modules are folded which reduces the channel width by half" + + """, + ), +) + CONFIG_Template.declare( "has_pressure_change", ConfigValue( @@ -303,19 +330,18 @@ class FrictionFactor(Enum): CONFIG_Template.declare( "friction_factor", ConfigValue( - default=FrictionFactor.flat_sheet, + default=FrictionFactor.default_by_module_type, domain=In(FrictionFactor), description="Darcy friction factor correlation", doc=""" Options to account for friction factor correlations. - **default** - ``FrictionFactor.flat_sheet`` + **default** - ``FrictionFactor.default_by_module_type`` .. csv-table:: :header: "Configuration Options", "Description" - "``FrictionFactor.flat_sheet``", "Friction factor correlation for flat-sheet membrane modules" - "``FrictionFactor.spiral_wound``", "Friction factor correlation for spiral-wound membranes" + "``FrictionFactor.default_by_module_type``", "Friction factor correlation that is specific to the supported membrane modules type" """, ), ) @@ -358,7 +384,8 @@ def add_total_pressure_balances( has_pressure_change=True, pressure_change_type=PressureChangeType.calculated, custom_term=None, - friction_factor=FrictionFactor.flat_sheet, + module_type=ModuleType.flat_sheet, + friction_factor=FrictionFactor.default_by_module_type, ): super().add_total_pressure_balances( has_pressure_change=has_pressure_change, custom_term=custom_term @@ -378,7 +405,9 @@ def eq_equal_pressure_interface(b, t, x): self._add_pressure_change(pressure_change_type=pressure_change_type) if pressure_change_type == PressureChangeType.calculated: - self._add_calculated_pressure_change(friction_factor=friction_factor) + self._add_calculated_pressure_change( + module_type=module_type, friction_factor=friction_factor + ) def add_interface_isothermal_conditions(self): @@ -710,7 +739,9 @@ def _add_interface_stateblock(self, has_phase_equilibrium=None): ) def _add_calculated_pressure_change( - self, friction_factor=FrictionFactor.flat_sheet + self, + module_type=ModuleType.flat_sheet, + friction_factor=FrictionFactor.default_by_module_type, ): self._add_calculated_pressure_change_mass_transfer_components() @@ -749,32 +780,35 @@ def eq_velocity(b, t, x): return b.velocity[t, x] * b.area == b.properties[t, x].flow_vol_phase["Liq"] ## ========================================================================== - # Darcy friction factor based on eq. S27 in SI for Cost Optimization of Osmotically Assisted Reverse Osmosis - if friction_factor == FrictionFactor.flat_sheet: - - @self.Constraint( - self.flowsheet().config.time, - self.length_domain, - doc="Darcy friction factor constraint for flat sheet membranes", - ) - def eq_friction_factor(b, t, x): - return (b.friction_factor_darcy[t, x] - 0.42) * b.N_Re[t, x] == 189.3 - - # Darcy friction factor based on eq. 24 in Mass transfer and pressure loss in spiral wound modules (Schock & Miquel, 1987) - elif friction_factor == FrictionFactor.spiral_wound: - - @self.Constraint( - self.flowsheet().config.time, - self.length_domain, - doc="Darcy friction factor constraint for spiral-wound membranes", - ) - def eq_friction_factor(b, t, x): - return b.friction_factor_darcy[t, x] == 6.23 * b.N_Re[t, x] ** -0.3 + if friction_factor == FrictionFactor.default_by_module_type: + # Darcy friction factor based on eq. S27 in SI for Cost Optimization of Osmotically Assisted Reverse Osmosis + if module_type == ModuleType.flat_sheet: + + @self.Constraint( + self.flowsheet().config.time, + self.length_domain, + doc="Darcy friction factor constraint for flat sheet membranes", + ) + def eq_friction_factor(b, t, x): + return (b.friction_factor_darcy[t, x] - 0.42) * b.N_Re[ + t, x + ] == 189.3 + + # Darcy friction factor based on eq. 24 in Mass transfer and pressure loss in spiral wound modules (Schock & Miquel, 1987) + elif module_type == ModuleType.spiral_wound: + + @self.Constraint( + self.flowsheet().config.time, + self.length_domain, + doc="Darcy friction factor constraint for spiral-wound membranes", + ) + def eq_friction_factor(b, t, x): + return b.friction_factor_darcy[t, x] == 6.23 * b.N_Re[t, x] ** -0.3 + else: + raise ConfigurationError(f"Unrecognized module_type type {module_type}") else: - raise ConfigurationError( - f"Unrecognized friction_factor type {friction_factor}" - ) + pass ## ========================================================================== # Pressure change per unit length due to friction @@ -1021,11 +1055,3 @@ def validate_membrane_config_args(unit): unit.config.concentration_polarization_type, ) ) - - if ( - unit.config.pressure_change_type != PressureChangeType.calculated - and unit.config.friction_factor != unit.config.get("friction_factor")._default - ): - raise ConfigurationError( - "\nChanging the 'friction_factor' will have no effect if the 'pressure_change_type' is not `PressureChangeType.calculated`" - ) diff --git a/watertap/unit_models/osmotically_assisted_reverse_osmosis_1D.py b/watertap/unit_models/osmotically_assisted_reverse_osmosis_1D.py index 8d89266e54..ce42c2d784 100644 --- a/watertap/unit_models/osmotically_assisted_reverse_osmosis_1D.py +++ b/watertap/unit_models/osmotically_assisted_reverse_osmosis_1D.py @@ -208,8 +208,8 @@ def eq_connect_mass_transfer(b, t, x, p, j): ) def eq_permeate_production(b, t, x, p, j): return ( - -b.feed_side.mass_transfer_term[t, x, p, j] - == b.width * b.flux_mass_phase_comp[t, x, p, j] + -b.feed_side.mass_transfer_term[t, x, p, j] * b.length + == b.flux_mass_phase_comp[t, x, p, j] * b.area ) def calculate_scaling_factors(self): diff --git a/watertap/unit_models/osmotically_assisted_reverse_osmosis_base.py b/watertap/unit_models/osmotically_assisted_reverse_osmosis_base.py index 2f6891f7b8..748346f46f 100644 --- a/watertap/unit_models/osmotically_assisted_reverse_osmosis_base.py +++ b/watertap/unit_models/osmotically_assisted_reverse_osmosis_base.py @@ -36,6 +36,7 @@ validate_membrane_config_args, ConcentrationPolarizationType, TransportModel, + ModuleType, ) from watertap.core import InitializationMixin @@ -116,6 +117,7 @@ def build(self): balance_type=self.config.momentum_balance_type, pressure_change_type=self.config.pressure_change_type, has_pressure_change=self.config.has_pressure_change, + module_type=self.config.module_type, friction_factor=self.config.friction_factor, ) @@ -153,6 +155,7 @@ def build(self): balance_type=self.config.momentum_balance_type, pressure_change_type=self.config.pressure_change_type, has_pressure_change=self.config.has_pressure_change, + module_type=self.config.module_type, friction_factor=self.config.friction_factor, ) @@ -341,15 +344,24 @@ def _add_area(self, include_constraint=True): if include_constraint: if not hasattr(self, "eq_area"): - # Membrane area equation - @self.Constraint(doc="Total Membrane area") - def eq_area(b): - return b.area == b.length * b.width - - else: - raise ValueError( - "include_constraint was set to True inside of _add_area(), but area constraint already exists." - ) + if self.config.module_type == ModuleType.flat_sheet: + # Membrane area equation for flat plate membranes + @self.Constraint(doc="Total Membrane area") + def eq_area(b): + return b.area == b.length * b.width + + elif self.config.module_type == ModuleType.spiral_wound: + # Membrane area equation + @self.Constraint(doc="Total Membrane area") + def eq_area(b): + return b.area == b.length * 2 * b.width + + else: + raise ConfigurationError( + "Unsupported membrane module type: {}".format( + self.config.module_type + ) + ) def _add_flux_balance(self): diff --git a/watertap/unit_models/reverse_osmosis_1D.py b/watertap/unit_models/reverse_osmosis_1D.py index 5ba3e1167d..3840f173a3 100644 --- a/watertap/unit_models/reverse_osmosis_1D.py +++ b/watertap/unit_models/reverse_osmosis_1D.py @@ -188,8 +188,8 @@ def eq_connect_mass_transfer(b, t, x, p, j): ) def eq_mass_flux_equal_mass_transfer(b, t, x, p, j): return ( - b.flux_mass_phase_comp[t, x, p, j] * b.width - == -b.feed_side.mass_transfer_term[t, x, p, j] + b.flux_mass_phase_comp[t, x, p, j] * b.area + == -b.feed_side.mass_transfer_term[t, x, p, j] * b.length ) # ========================================================================== diff --git a/watertap/unit_models/reverse_osmosis_base.py b/watertap/unit_models/reverse_osmosis_base.py index 896631291c..20d795a1d8 100644 --- a/watertap/unit_models/reverse_osmosis_base.py +++ b/watertap/unit_models/reverse_osmosis_base.py @@ -36,6 +36,7 @@ validate_membrane_config_args, ConcentrationPolarizationType, TransportModel, + ModuleType, ) from watertap.costing.unit_models.reverse_osmosis import cost_reverse_osmosis @@ -100,7 +101,6 @@ def build(self): balance_type=self.config.momentum_balance_type, pressure_change_type=self.config.pressure_change_type, has_pressure_change=self.config.has_pressure_change, - friction_factor=self.config.friction_factor, ) self.feed_side.add_control_volume_isothermal_conditions() @@ -287,10 +287,24 @@ def _add_area(self, include_constraint=True): ) if include_constraint: - # Membrane area equation - @self.Constraint(doc="Total Membrane area") - def eq_area(b): - return b.area == b.length * b.width + if self.config.module_type == ModuleType.flat_sheet: + # Membrane area equation for flat plate membranes + @self.Constraint(doc="Total Membrane area") + def eq_area(b): + return b.area == b.length * b.width + + elif self.config.module_type == ModuleType.spiral_wound: + # Membrane area equation + @self.Constraint(doc="Total Membrane area") + def eq_area(b): + return b.area == b.length * 2 * b.width + + else: + raise ConfigurationError( + "Unsupported membrane module type: {}".format( + self.config.module_type + ) + ) def _add_flux_balance(self): diff --git a/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_0D.py b/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_0D.py index 762ceb2ee0..7c02b72ea9 100644 --- a/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_0D.py +++ b/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_0D.py @@ -20,7 +20,7 @@ from watertap.unit_models.osmotically_assisted_reverse_osmosis_0D import ( OsmoticallyAssistedReverseOsmosis0D, ) -from watertap.unit_models.reverse_osmosis_base import TransportModel +from watertap.unit_models.reverse_osmosis_base import TransportModel, ModuleType import watertap.property_models.NaCl_prop_pack as props from watertap.core.solvers import get_solver from idaes.core.util.scaling import ( @@ -31,7 +31,6 @@ ConcentrationPolarizationType, MassTransferCoefficient, PressureChangeType, - FrictionFactor, ) from watertap.unit_models.tests.unit_test_harness import UnitTestHarness @@ -806,7 +805,7 @@ def configure(self): return m -def build_friction_factor_spiral_wound(): +def build_module_type_spiral_wound(): """Testing 0D-OARO with FrictionFactor.spiral_wound option.""" m = ConcreteModel() m.fs = FlowsheetBlock(dynamic=False) @@ -819,7 +818,7 @@ def build_friction_factor_spiral_wound(): concentration_polarization_type=ConcentrationPolarizationType.calculated, mass_transfer_coefficient=MassTransferCoefficient.calculated, pressure_change_type=PressureChangeType.calculated, - friction_factor=FrictionFactor.spiral_wound, + module_type=ModuleType.spiral_wound, ) # fully specify system @@ -879,55 +878,55 @@ class TestOsmoticallyAssistedReverseOsmosis_friction_factor_spiral_wound( UnitTestHarness ): def configure(self): - m = build_friction_factor_spiral_wound() + m = build_module_type_spiral_wound() - self.unit_solutions[m.fs.unit.feed_side.deltaP[0]] = -0.3019e5 - self.unit_solutions[m.fs.unit.permeate_side.deltaP[0]] = -2.4123e5 - self.unit_solutions[m.fs.unit.feed_side.deltaP[0] / m.fs.unit.length] = -3940.35 + self.unit_solutions[m.fs.unit.feed_side.deltaP[0]] = -0.1516e5 + self.unit_solutions[m.fs.unit.permeate_side.deltaP[0]] = -1.199e5 + self.unit_solutions[m.fs.unit.feed_side.deltaP[0] / m.fs.unit.length] = -3958.30 self.unit_solutions[m.fs.unit.permeate_side.deltaP[0] / m.fs.unit.length] = ( - -31488.754 + -31318.596 ) self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 0.0]] = 145.197 self.unit_solutions[m.fs.unit.feed_side.velocity[0, 0.0]] = 0.1 - self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 1.0]] = 110.973 - self.unit_solutions[m.fs.unit.feed_side.velocity[0, 1.0]] = 0.0774 - self.unit_solutions[m.fs.unit.permeate_side.N_Re[0, 0.0]] = 154.231 - self.unit_solutions[m.fs.unit.permeate_side.velocity[0, 0.0]] = 0.2040 + self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 1.0]] = 111.787 + self.unit_solutions[m.fs.unit.feed_side.velocity[0, 1.0]] = 0.0779 + self.unit_solutions[m.fs.unit.permeate_side.N_Re[0, 0.0]] = 153.410 + self.unit_solutions[m.fs.unit.permeate_side.velocity[0, 0.0]] = 0.2029 self.unit_solutions[m.fs.unit.permeate_side.N_Re[0, 1.0]] = 119.793 self.unit_solutions[m.fs.unit.permeate_side.velocity[0, 1.0]] = 0.1588 self.unit_solutions[m.fs.unit.flux_mass_phase_comp_avg[0, "Liq", "H2O"]] = ( - 4.407e-3 + 4.301e-3 ) self.unit_solutions[m.fs.unit.flux_mass_phase_comp_avg[0, "Liq", "NaCl"]] = ( - 5.881e-7 + 5.837e-7 ) self.unit_solutions[ m.fs.unit.feed_side.properties_interface[0, 0.0].conc_mass_phase_comp[ "Liq", "NaCl" ] - ] = 43.978 + ] = 43.505 self.unit_solutions[ m.fs.unit.feed_side.properties_out[0].conc_mass_phase_comp["Liq", "NaCl"] - ] = 46.152 + ] = 45.833 self.unit_solutions[ m.fs.unit.feed_side.properties_interface[0, 1.0].conc_mass_phase_comp[ "Liq", "NaCl" ] - ] = 51.466 + ] = 51.292 self.unit_solutions[ m.fs.unit.permeate_side.properties_interface[0, 1.0].conc_mass_phase_comp[ "Liq", "NaCl" ] - ] = 3.520 + ] = 3.445 self.unit_solutions[ m.fs.unit.permeate_side.properties_interface[0, 0.0].conc_mass_phase_comp[ "Liq", "NaCl" ] - ] = 1.443 + ] = 1.547 self.unit_solutions[ m.fs.unit.permeate_side.properties_out[0].conc_mass_phase_comp[ "Liq", "NaCl" ] - ] = 5.007 + ] = 5.033 return m diff --git a/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_1D.py b/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_1D.py index 17fa705e1a..3fe0d3a850 100644 --- a/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_1D.py +++ b/watertap/unit_models/tests/test_osmotically_assisted_reverse_osmosis_1D.py @@ -22,7 +22,7 @@ from watertap.unit_models.osmotically_assisted_reverse_osmosis_1D import ( OsmoticallyAssistedReverseOsmosis1D, ) -from watertap.unit_models.reverse_osmosis_base import TransportModel +from watertap.unit_models.reverse_osmosis_base import TransportModel, ModuleType import watertap.property_models.NaCl_prop_pack as props from watertap.core.solvers import get_solver @@ -613,7 +613,7 @@ def configure(self): m.fs.unit.permeate_side.properties_interface[ 0, x_interface_in ].conc_mass_phase_comp["Liq", "NaCl"] - ] = 45.111 + ] = 45.1565 self.unit_solutions[ m.fs.unit.permeate_side.properties_interface[0, 1.0].conc_mass_phase_comp[ "Liq", "NaCl" @@ -1003,6 +1003,145 @@ def configure(self): return m +def build_Pdrop_spiral_wound_calculation(): + """Testing 1D-OARO with PressureChangeType.calculated option.""" + m = ConcreteModel() + m.fs = FlowsheetBlock(dynamic=False) + + m.fs.properties = props.NaClParameterBlock() + + m.fs.unit = OsmoticallyAssistedReverseOsmosis1D( + property_package=m.fs.properties, + has_pressure_change=True, + concentration_polarization_type=ConcentrationPolarizationType.calculated, + mass_transfer_coefficient=MassTransferCoefficient.calculated, + pressure_change_type=PressureChangeType.calculated, + module_type=ModuleType.spiral_wound, + ) + # fully specify system + feed_flow_mass = 5 / 18 + feed_mass_frac_NaCl = 0.075 + feed_pressure = 65e5 + feed_temperature = 273.15 + 25 + membrane_area = 70 + length = 35 + A = 1e-12 + B = 7.7e-8 + + feed_mass_frac_H2O = 1 - feed_mass_frac_NaCl + m.fs.unit.feed_inlet.flow_mass_phase_comp[0, "Liq", "NaCl"].fix( + feed_flow_mass * feed_mass_frac_NaCl + ) + m.fs.unit.feed_inlet.flow_mass_phase_comp[0, "Liq", "H2O"].fix( + feed_flow_mass * feed_mass_frac_H2O + ) + m.fs.unit.feed_inlet.pressure[0].fix(feed_pressure) + m.fs.unit.feed_inlet.temperature[0].fix(feed_temperature) + + permeate_flow_mass = 0.33 * feed_flow_mass + permeate_mass_frac_NaCl = 0.1 + permeate_mass_frac_H2O = 1 - permeate_mass_frac_NaCl + m.fs.unit.permeate_inlet.flow_mass_phase_comp[0, "Liq", "H2O"].fix( + permeate_flow_mass * permeate_mass_frac_H2O + ) + m.fs.unit.permeate_inlet.flow_mass_phase_comp[0, "Liq", "NaCl"].fix( + permeate_flow_mass * permeate_mass_frac_NaCl + ) + m.fs.unit.permeate_inlet.pressure[0].fix(5e5) + m.fs.unit.permeate_inlet.temperature[0].fix(feed_temperature) + + m.fs.unit.area.fix(membrane_area) + m.fs.unit.length.fix(length) + m.fs.unit.A_comp.fix(A) + m.fs.unit.B_comp.fix(B) + m.fs.unit.structural_parameter.fix(1200e-6) + + m.fs.unit.permeate_side.channel_height.fix(0.002) + m.fs.unit.permeate_side.spacer_porosity.fix(0.97) + m.fs.unit.feed_side.channel_height.fix(0.002) + m.fs.unit.feed_side.spacer_porosity.fix(0.97) + + # scaling + m.fs.properties.set_default_scaling( + "flow_mass_phase_comp", 1e1, index=("Liq", "H2O") + ) + m.fs.properties.set_default_scaling( + "flow_mass_phase_comp", 1e3, index=("Liq", "NaCl") + ) + calculate_scaling_factors(m) + + return m + + +class TestOsmoticallyAssistedReverseOsmosis_Pdrop_spiral_wound_calculation( + UnitTestHarness +): + def configure(self): + m = build_Pdrop_spiral_wound_calculation() + + self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 0.0]] = 434.64 + self.unit_solutions[m.fs.unit.feed_side.velocity[0, 0.0]] = 0.1361 + self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 1.0]] = 317.794 + self.unit_solutions[m.fs.unit.feed_side.velocity[0, 1.0]] = 0.1021 + self.unit_solutions[m.fs.unit.permeate_side.N_Re[0, 0.0]] = 254.272 + self.unit_solutions[m.fs.unit.permeate_side.velocity[0, 0.0]] = 0.07824 + self.unit_solutions[m.fs.unit.permeate_side.N_Re[0, 1.0]] = 136.979 + self.unit_solutions[m.fs.unit.permeate_side.velocity[0, 1.0]] = 0.04413 + + self.unit_solutions[m.fs.unit.feed_side.deltaP_stage[0]] = -77476.0524412 + self.unit_solutions[m.fs.unit.permeate_side.deltaP_stage[0]] = -24177.6101955 + + self.unit_solutions[m.fs.unit.flux_mass_phase_comp_avg[0, "Liq", "H2O"]] = ( + 9.419628912e-04 + ) + self.unit_solutions[m.fs.unit.flux_mass_phase_comp_avg[0, "Liq", "NaCl"]] = ( + 4.38572890e-06 + ) + self.unit_solutions[ + m.fs.unit.feed_outlet.flow_mass_phase_comp[0, "Liq", "H2O"] + ] = 0.1910 + self.unit_solutions[ + m.fs.unit.feed_outlet.flow_mass_phase_comp[0, "Liq", "NaCl"] + ] = 0.02052 + + self.unit_solutions[ + m.fs.unit.feed_side.properties[0, 0].conc_mass_phase_comp["Liq", "NaCl"] + ] = 78.878 + + x_interface_in = m.fs.unit.length_domain.at(2) + self.unit_solutions[ + m.fs.unit.feed_side.properties_interface[ + 0, x_interface_in + ].conc_mass_phase_comp["Liq", "NaCl"] + ] = 85.616 + self.unit_solutions[ + m.fs.unit.feed_side.properties[0, 1].conc_mass_phase_comp["Liq", "NaCl"] + ] = 103.670 + self.unit_solutions[ + m.fs.unit.feed_side.properties_interface[0, 1].conc_mass_phase_comp[ + "Liq", "NaCl" + ] + ] = 108.735 + self.unit_solutions[ + m.fs.unit.permeate_side.properties[0, 1].conc_mass_phase_comp["Liq", "NaCl"] + ] = 107.06 + self.unit_solutions[ + m.fs.unit.permeate_side.properties_interface[0, 1].conc_mass_phase_comp[ + "Liq", "NaCl" + ] + ] = 53.136 + self.unit_solutions[ + m.fs.unit.permeate_side.properties[0, 0].conc_mass_phase_comp["Liq", "NaCl"] + ] = 62.415 + self.unit_solutions[ + m.fs.unit.permeate_side.properties_interface[ + 0, x_interface_in + ].conc_mass_phase_comp["Liq", "NaCl"] + ] = 28.036 + + return m + + class TestOsmoticallyAssistedReverseOsmosis_water_recovery: water_recovery_list = [0.15, 0.2, 0.3, 0.4, 0.5, 0.55] diff --git a/watertap/unit_models/tests/test_reverse_osmosis_0D.py b/watertap/unit_models/tests/test_reverse_osmosis_0D.py index d9b97d7041..48d89d5477 100644 --- a/watertap/unit_models/tests/test_reverse_osmosis_0D.py +++ b/watertap/unit_models/tests/test_reverse_osmosis_0D.py @@ -24,14 +24,12 @@ PressureChangeType, ) -from watertap.unit_models.reverse_osmosis_base import TransportModel +from watertap.unit_models.reverse_osmosis_base import TransportModel, ModuleType import watertap.property_models.NaCl_prop_pack as props from watertap.unit_models.tests.unit_test_harness import UnitTestHarness -from watertap.core import FrictionFactor - # ----------------------------------------------------------------------------- # Get default solver for testing solver = get_solver() @@ -554,7 +552,7 @@ def build_friction_factor_spiral_wound(): concentration_polarization_type=ConcentrationPolarizationType.calculated, mass_transfer_coefficient=MassTransferCoefficient.calculated, pressure_change_type=PressureChangeType.calculated, - friction_factor=FrictionFactor.spiral_wound, + module_type=ModuleType.spiral_wound, ) # fully specify system @@ -598,35 +596,35 @@ class TestReverseOsmosis0D_friction_factor_spiral_wound(UnitTestHarness): def configure(self): m = build_friction_factor_spiral_wound() - self.unit_solutions[m.fs.unit.deltaP[0]] = -1.801003299e5 - self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 0]] = 395.840743 - self.unit_solutions[m.fs.unit.feed_side.velocity[0, 0]] = 0.2360863 - self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 1]] = 191.3192807 - self.unit_solutions[m.fs.unit.feed_side.velocity[0, 1]] = 0.1188201 + self.unit_solutions[m.fs.unit.deltaP[0]] = -4.68073933e5 + self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 0]] = 791.6814859 + self.unit_solutions[m.fs.unit.feed_side.velocity[0, 0]] = 0.472172596 + self.unit_solutions[m.fs.unit.feed_side.N_Re[0, 1]] = 374.5383911 + self.unit_solutions[m.fs.unit.feed_side.velocity[0, 1]] = 0.2329687 self.unit_solutions[m.fs.unit.flux_mass_phase_comp_avg[0, "Liq", "H2O"]] = ( - 0.00708203 + 0.0072232991 ) self.unit_solutions[m.fs.unit.flux_mass_phase_comp_avg[0, "Liq", "NaCl"]] = ( - 2.18590835e-6 + 2.11255771e-6 ) self.unit_solutions[ m.fs.unit.mixed_permeate[0].flow_mass_phase_comp["Liq", "H2O"] - ] = 0.13455865 + ] = 0.13724268 self.unit_solutions[ m.fs.unit.mixed_permeate[0].flow_mass_phase_comp["Liq", "NaCl"] - ] = 4.15322586e-5 + ] = 4.01385965e-5 self.unit_solutions[ m.fs.unit.feed_side.properties_interface[0, 0].conc_mass_phase_comp[ "Liq", "NaCl" ] - ] = 50.075075 + ] = 47.435640 self.unit_solutions[ m.fs.unit.feed_side.properties_out[0].conc_mass_phase_comp["Liq", "NaCl"] - ] = 70.73118 + ] = 72.1598903 self.unit_solutions[ m.fs.unit.feed_side.properties_interface[0, 1].conc_mass_phase_comp[ "Liq", "NaCl" ] - ] = 76.211017 + ] = 75.1415897247 return m diff --git a/watertap/unit_models/tests/test_reverse_osmosis_1D.py b/watertap/unit_models/tests/test_reverse_osmosis_1D.py index 88053602ae..0b4896a107 100644 --- a/watertap/unit_models/tests/test_reverse_osmosis_1D.py +++ b/watertap/unit_models/tests/test_reverse_osmosis_1D.py @@ -17,15 +17,12 @@ import idaes.core.util.scaling as iscale -from watertap.unit_models.reverse_osmosis_base import TransportModel +from watertap.unit_models.reverse_osmosis_base import TransportModel, ModuleType import watertap.property_models.NaCl_prop_pack as props from watertap.unit_models.tests.unit_test_harness import UnitTestHarness -from watertap.core import FrictionFactor - - from watertap.unit_models.reverse_osmosis_1D import ( ReverseOsmosis1D, ConcentrationPolarizationType, @@ -33,7 +30,6 @@ PressureChangeType, ) - # ----------------------------------------------------------------------------- # Get default solver for testing solver = get_solver() @@ -575,7 +571,7 @@ def build_friction_factor_spiral_wound(): concentration_polarization_type=ConcentrationPolarizationType.calculated, mass_transfer_coefficient=MassTransferCoefficient.calculated, pressure_change_type=PressureChangeType.calculated, - friction_factor=FrictionFactor.spiral_wound, + module_type=ModuleType.spiral_wound, transformation_scheme="BACKWARD", transformation_method="dae.finite_difference", finite_elements=3, @@ -628,22 +624,22 @@ def configure(self): self.unit_solutions[ m.fs.unit.flux_mass_phase_comp[0, x_interface_in, "Liq", "H2O"] - ] = 0.00590823 + ] = 0.00593246 self.unit_solutions[ m.fs.unit.flux_mass_phase_comp[0, x_interface_in, "Liq", "NaCl"] - ] = 1.494063e-6 + ] = 1.4481768e-6 self.unit_solutions[m.fs.unit.flux_mass_phase_comp[0, 1, "Liq", "H2O"]] = ( - 0.00474506 + 0.0041822435 ) self.unit_solutions[m.fs.unit.flux_mass_phase_comp[0, 1, "Liq", "NaCl"]] = ( - 1.559319e-6 + 1.491610924e-6 ) self.unit_solutions[ m.fs.unit.mixed_permeate[0].flow_mass_phase_comp["Liq", "H2O"] - ] = 0.1010762 + ] = 0.095819393 self.unit_solutions[ m.fs.unit.mixed_permeate[0].flow_mass_phase_comp["Liq", "NaCl"] - ] = 2.9015866e-5 + ] = 2.794556261e-5 return m