diff --git a/docs/technical_reference/unit_models/electrodialysis_1D.rst b/docs/technical_reference/unit_models/electrodialysis_1D.rst index 33961a5f8e..e4d6a83886 100644 --- a/docs/technical_reference/unit_models/electrodialysis_1D.rst +++ b/docs/technical_reference/unit_models/electrodialysis_1D.rst @@ -16,7 +16,7 @@ the opposite ion selectivity of cation- and anion-exchange membranes (cem and ae one cell to its adjacent cell in a cell-pair treatment unit (Figure 1). The ion-departing cell is called a **diluate channel** and the ion-entering cell a **concentrate channel**. Recovered (desalinated) water is collected from diluate channels of all cell pairs while the concentrate product can be disposed of as brine -or retreated. More overview of the electrodialysis technology can be found in the *References*. +or retreated. More overview of the electrodialysis technology can be found in [1]_, [2]_, and [3]_. .. figure:: ../../_static/unit_models/EDdiagram.png :width: 400 @@ -120,7 +120,9 @@ are parameters that should be provided in order to fully solve the model. "Cell pair number", ":math:`n`", "cell_pair_num", "None", "dimensionless", 1 "Current utilization coefficient", ":math:`\xi`", "current_utilization", "None", "dimensionless", 1 "Channel height", ":math:`d`", "channel_height", "none", ":math:`m` ", 1 - "Membrane areal resistance", ":math:`r`", "membrane_areal_resistance", "['cem', 'aem']", ":math:`\Omega m^2`", 2 + "Membrane areal resistance independent on ion concentration", ":math:`r_{const}`", "membrane_areal_resistance_const", "['cem', 'aem']", ":math:`\Omega m^2`", 2 + "Membrane areal resistance coefficient to ion concentration", ":math:`r_{coef}`", "membrane_areal_resistance_coef", "['cem', 'aem']", ":math:`\Omega mol m^{-1}`", 2 + "Spacer conductivity coefficient", ":math:`\sigma`", "spacer_conductivity_coefficient", "None", "dimensionless", 1 "Cell width", ":math:`b`", "cell_width", "None", ":math:`\text{m}`", 1 "Cell length", ":math:`l`", "cell_length", "None", ":math:`\text{m}`", 1 "Thickness of ion exchange membranes", ":math:`\delta`", "membrane_thickness", "['cem', 'aem']", ":math:`m`", 2 @@ -168,7 +170,7 @@ discretization manner using the "finite difference" or "collocation" method impl Mass balance equations are summarized in **Table 3**. Mass transfer mechanisms account for solute electrical migration, diffusion, water osmosis, and electroosmosis. Theoretical principles, e.g., continuity equation, Fick's law, and Ohm's law, -to simulate these processes are well developed and some good summaries for the electrodialysis scenario can be found in the *References*. +to simulate these processes are well developed and some good summaries for the electrodialysis scenario can be found in [1]_. .. csv-table:: **Table 3** Mass Balance Equations :header: "Description", "Equation", "Index set" @@ -186,11 +188,18 @@ Additionally, several other equations are built to describe the electrochemical "Electrical input condition", ":math:`i(x) = \frac{I}{bl}`, for 'Constant_Current'; :math:`u(x) =U` for 'Constant_Voltage'" "Ohm's law", ":math:`u(x) = i(x) r_{tot}(x)`" - "Resistance calculation", ":math:`r_{tot}(x)=n\left(r^{cem}+r^{aem}+\frac{d}{\kappa^C(x)}+\frac{d}{\kappa^D(x)}\right)+r_{el}`" + "mebrane resistance calculation \ :sup:`1`", ":math:`r^{iem}(x)=r^{iem}_{const}+\frac{r^{iem}_{coef}}{c_b^D}` [7]_" + "Total resistance calculation", ":math:`r_{tot}(x)=n\left(r^{cem}(x)+r^{aem}(x)+\frac{d}{\sigma \kappa^C(x)}+\frac{d}{\sigma \kappa^D(x)}\right)+r_{el}` \ :sup:`2`" "Electrical power consumption", ":math:`P(x)=b\int _0 ^l u(x)i(x) dx`" "Water-production-specific power consumption", ":math:`P_Q=\frac{P(x=l)}{3.6\times 10^6 nQ_{out}^D}`" "Current efficiency for desalination", ":math:`bi(x)\eta(x)=-\sum_{j \in[cation]}{\left[\left(\frac{\partial N_j ^D(x)}{\partial x}\right) z_j F\right]}`" +**Note** + + :sup:`1` We now consider the experimentally observed dependence of membrane resistance on electrolyte concentration using an empirical relationship reported by [7]_. + :sup:`2` We used a coefficient multiplied by the solution conductance, denoted by :math:`\sigma`, to account for the spacer's conductance shadowing effect. + + All equations are coded as "constraints" (Pyomo). Isothermal and isobaric conditions apply. Extended simulation @@ -201,7 +210,7 @@ This model supports extensive simulations of (1) the nonohmic potential across i Users can customize these extenions via two configurations: `has_nonohmic_potential_membrane` that triggers the calculation of nonohmic potentials across ion exchange membranes and `has_Nernst_diffusion_layer` that triggers the simulation of a concentration-polarized Nernst diffusion layer including its ohmic and nonohmic potential changes. Based on a electrochemical cell setup in Figure 2 and established theoretical -descriptions (*References*), our model accounts for the cross-membrane diffusion and Donnan potentials (nonohmic), ion concentration polarization +descriptions ([4]_, [5]_), our model accounts for the cross-membrane diffusion and Donnan potentials (nonohmic), ion concentration polarization in assumed Nernst diffusion layers (NDL), and the ohmic and nonohmic (i.e., diffusion) potentials across NDLs. These extensions make the model closer to the non-ideal physical conditions that can be encountered in real desalination practices. @@ -238,7 +247,8 @@ Some other modifications to previously defined equations are made to accommodate :header: "Original equation description", "Equation replacement", "Condition" "Ohm's law", ":math:`u(x) = i(x) r_{tot}(x) + \phi_m(x) + \phi_d^{ohm}(x) + \phi_d^{nonohm}(x)` \ :sup:`1`", "`has_nonohmic_potential_membrane == True` and/or \ `has_Nernst_diffusion_layer==True`" - "Resistance calculation", ":math:`r_{tot}(x)=n\left(r^{cem}+r^{aem}+\frac{d- \Delta_{cem}^L(x) - \Delta_{aem}^R(x)}{\kappa^C(x)}+\frac{d- \Delta_{cem}^R(x) - \Delta_{aem}^L(x)}{\kappa^D(x)}\right)+r_{el}`", "`has_Nernst_diffusion_layer==True`" + "mebrane resistance calculation", ":math:`r^{iem}(x)=r^{iem}_{const}+\frac{r^{iem}_{coef}}{c_b^D}`" + "total resistance calculation", ":math:`r_{tot}(x)=n\left(r^{cem}(x)+r^{aem}(x)+\frac{d- \Delta_{cem}^L(x) - \Delta_{aem}^R(x)}{\sigma \kappa^C(x)}+\frac{d- \Delta_{cem}^R(x) - \Delta_{aem}^L(x)}{\sigma \kappa^D(x)}\right)+r_{el}`", "`has_Nernst_diffusion_layer==True`" "mass transfer flux, concentrate, solute", ":math:`J_j^{C} = \left(t_j^{cem}-t_j^{aem} \right)\frac{\xi i(x)}{ z_j F}-\left(\frac{D_j^{cem}}{\delta ^{cem}}\left(c_{s,j}^{L,cem}(x)-c_{s,j}^{R,cem}(x) \right) +\frac{D_j^{aem}}{\delta ^{aem}} \left(c_{s,j}^{R,aem}(x)-c_{s,j}^{L,aem}(x) \right)\right)`", "`has_nonohmic_potential_membrane == True` and/or \ `has_Nernst_diffusion_layer==True`" "mass transfer flux, diluate, solute", ":math:`J_j^{D} = -\left(t_j^{cem}-t_j^{aem} \right)\frac{\xi i(x)}{ z_j F}+\left(\frac{D_j^{cem}}{\delta ^{cem}}\left(c_{s,j}^{L,cem}(x)-c_{s,j}^{R,cem}(x) \right) +\frac{D_j^{aem}}{\delta ^{aem}} \left(c_{s,j}^{R,aem}(x)-c_{s,j}^{L,aem}(x) \right)\right)`", "`has_nonohmic_potential_membrane == True` and/or \ `has_Nernst_diffusion_layer==True`" "mass transfer flux, concentrate, H\ :sub:`2`\ O", ":math:`J_j^{C} = \left(t_w^{cem}+t_w^{aem} \right)\frac{i(x)}{F}+\left(L^{cem} \left(p_{s, osm}^{cem, L}(x)-p_{s, osm}^{cem, R}(x) \right)+L^{aem} \left(p_{s, osm}^{aem, R}(x)-p_{s, osm}^{aem, L}(x) \right)\right)\frac{\rho_w}{M_w}`", "`has_Nernst_diffusion_layer==True`" @@ -250,7 +260,7 @@ Some other modifications to previously defined equations are made to accommodate Frictional pressure drop ^^^^^^^^^^^^^^^^^^^^^^^^ -This model can optionally calculate pressured drops along the flow path in the diluate and concentrate channels through config ``has_pressure_change`` and ``pressure_drop_method``. Under the assumption of identical diluate and concentrate channels and starting flow rates, the flow velocities in the two channels are approximated equal and invariant over the channel length when calculating the frictional pressure drops. This approximation is based on the evaluation that the actual velocity variation over the channel length caused by water mass transfer across the consecutive channels leads to negligible errors as compared to the uncertainties carried by the frictional pressure method itself. **Table 7** gives essential equations to simulate the pressure drop. Among extensive literatures using these equations, a good reference paper is by Wright et. al., 2018 (*References*). +This model can optionally calculate pressured drops along the flow path in the diluate and concentrate channels through config ``has_pressure_change`` and ``pressure_drop_method``. Under the assumption of identical diluate and concentrate channels and starting flow rates, the flow velocities in the two channels are approximated equal and invariant over the channel length when calculating the frictional pressure drops. This approximation is based on the evaluation that the actual velocity variation over the channel length caused by water mass transfer across the consecutive channels leads to negligible errors as compared to the uncertainties carried by the frictional pressure method itself. **Table 7** gives essential equations to simulate the pressure drop. Among extensive literatures using these equations, a good reference paper is by Wright et. al., 2018 ([6]_). .. csv-table:: **Table 7** Essential equations supporting the pressure drop calculation :header: "Description", "Equation", "Condition" @@ -301,9 +311,12 @@ Nomenclature ":math:`p_{osm}`", "Osmotic pressure", ":math:`Pa`" ":math:`r_{tot}`", "Total areal resistance", ":math:`\Omega m^2`" ":math:`r`", "Membrane areal resistance", ":math:`\Omega m^2`" + ":math:`r_const`", "Membrane areal resistance independent on ion concentration", ":math:`\Omega m^2`" + ":math:`r_coef`", "The dependent cofficient of membrane areal resistance to :math:`1/c_b`", ":math:`\Omega mol m^{-1}`" ":math:`r_{el}`", "Electrode areal resistance", ":math:`\Omega m^2`" ":math:`d`", "Channel height", ":math:`m`" ":math:`\kappa`", "Solution conductivity", ":math:`S m^{-1}\ or\ \Omega^{-1} m^{-1}`" + ":math:`\sigma`", "Spacer conductivity coefficient", ":math:`S m^{-1}\ or\ \Omega^{-1} m^{-1}`" ":math:`\eta`", "Current efficiency for desalination", "dimensionless" ":math:`P`", "Power consumption", ":math:`W`" ":math:`P_Q`", "Specific power consumption", ":math:`kW\ h\ m^{-3}`" @@ -351,18 +364,16 @@ Nomenclature References ---------- -Strathmann, H. (2010). Electrodialysis, a mature technology with a multitude of new applications. -Desalination, 264(3), 268-288. +.. [1] Strathmann, H. (2010). Electrodialysis, a mature technology with a multitude of new applications. Desalination, 264(3), 268-288. + +.. [2] Strathmann, H. (2004). Ion-exchange membrane separation processes. Elsevier. Ch. 4. -Strathmann, H. (2004). Ion-exchange membrane separation processes. Elsevier. Ch. 4. +.. [3] Campione, A., Cipollina, A., Bogle, I. D. L., Gurreri, L., Tamburini, A., Tedesco, M., & Micale, G. (2019). A hierarchical model for novel schemes of electrodialysis desalination. Desalination, 465, 79-93. -Campione, A., Cipollina, A., Bogle, I. D. L., Gurreri, L., Tamburini, A., Tedesco, M., & Micale, G. (2019). -A hierarchical model for novel schemes of electrodialysis desalination. Desalination, 465, 79-93. +.. [4] Campione, A., Gurreri, L., Ciofalo, M., Micale, G., Tamburini, A., & Cipollina, A. (2018). Electrodialysis for water desalination: A critical assessment of recent developments on process fundamentals, models and applications. Desalination, 434, 121-160. -Campione, A., Gurreri, L., Ciofalo, M., Micale, G., Tamburini, A., & Cipollina, A. (2018). -Electrodialysis for water desalination: A critical assessment of recent developments on process -fundamentals, models and applications. Desalination, 434, 121-160. +.. [5] Spiegler, K. S. (1971). Polarization at ion exchange membrane-solution interfaces. Desalination, 9(4), 367-385. -Spiegler, K. S. (1971). Polarization at ion exchange membrane-solution interfaces. Desalination, 9(4), 367-385. +.. [6] Wright, N. C., Shah, S. R., & Amrose, S. E. (2018). A robust model of brackish water electrodialysis desalination with experimental comparison at different size scales. Desalination, 443, 27-43. -Wright, N. C., Shah, S. R., & Amrose, S. E. (2018). A robust model of brackish water electrodialysis desalination with experimental comparison at different size scales. Desalination, 443, 27-43. \ No newline at end of file +.. [7] Galama, A. H., Vermaas, D. A., Veerman, J., Saakes, M., Rijnaarts, H. H. M., Post, J. W., & Nijmeijer, K. (2014). Membrane resistance: The effect of salinity gradients over a cation exchange membrane. Journal of membrane science, 467, 279-291. \ No newline at end of file diff --git a/watertap/flowsheets/electrodialysis/electrodialysis_1stack.py b/watertap/flowsheets/electrodialysis/electrodialysis_1stack.py index e6e4edd3e5..bc07ebca0c 100644 --- a/watertap/flowsheets/electrodialysis/electrodialysis_1stack.py +++ b/watertap/flowsheets/electrodialysis/electrodialysis_1stack.py @@ -205,8 +205,10 @@ def set_operating_conditions(m): m.fs.EDstack.cell_pair_num.fix(100) m.fs.EDstack.current_utilization.fix(1) m.fs.EDstack.channel_height.fix(2.7e-4) - m.fs.EDstack.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.EDstack.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.EDstack.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.EDstack.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.EDstack.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.EDstack.membrane_areal_resistance_coef["aem"].fix(0) m.fs.EDstack.cell_width.fix(0.1) m.fs.EDstack.cell_length.fix(0.79) m.fs.EDstack.membrane_thickness["aem"].fix(1.3e-4) @@ -220,6 +222,7 @@ def set_operating_conditions(m): m.fs.EDstack.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.EDstack.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.EDstack.spacer_porosity.fix(1) + m.fs.EDstack.spacer_conductivity_coefficient.fix(1) # check zero degrees of freedom check_dof(m) @@ -266,7 +269,7 @@ def optimize_system(m, solver=None, checkpoint=None, fail_flag=True): # Choose and unfix variables to be optimized m.fs.EDstack.voltage_applied[0].unfix() m.fs.EDstack.cell_pair_num.unfix() - m.fs.EDstack.cell_pair_num.set_value(10) + m.fs.EDstack.cell_pair_num.set_value(30) # Give narrower bounds to optimizing variables if available m.fs.EDstack.voltage_applied[0].setlb(0.5) m.fs.EDstack.voltage_applied[0].setub(20) @@ -280,8 +283,9 @@ def optimize_system(m, solver=None, checkpoint=None, fail_flag=True): print("---report model statistics---\n ", report_statistics(m.fs)) if solver is None: solver = get_solver() - results = solver.solve(m, tee=True) - check_solve(results, checkpoint=checkpoint, logger=_log, fail_flag=fail_flag) + solve(m, solver=solver, tee=True) + m.fs.EDstack.cell_pair_num.fix(round(value(m.fs.EDstack.cell_pair_num))) + solve(m, solver=solver, tee=True) def display_model_metrics(m): @@ -319,6 +323,7 @@ def display_model_metrics(m): data=[ value(m.fs.EDstack.recovery_mass_H2O[0]), value(m.fs.mem_area), + value(m.fs.EDstack.cell_pair_num), value(m.fs.EDstack.voltage_applied[0]), value(m.fs.costing.specific_energy_consumption), value(m.fs.costing.LCOW), @@ -327,6 +332,7 @@ def display_model_metrics(m): index=[ "Water recovery by mass", "Total membrane area (aem or cem), m2", + "Cell pair number", "Operation Voltage, V", "Specific energy consumption, kWh/m3", "Levelized cost of water, $/m3", diff --git a/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc.py b/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc.py index 387a2ddb07..9781b4db90 100644 --- a/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc.py +++ b/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc.py @@ -277,8 +277,10 @@ def _condition_base(m): m.fs.EDstack.water_trans_number_membrane["aem"].fix(4.3) m.fs.EDstack.water_permeability_membrane["cem"].fix(2.16e-14) m.fs.EDstack.water_permeability_membrane["aem"].fix(1.75e-14) - m.fs.EDstack.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.EDstack.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.EDstack.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.EDstack.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.EDstack.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.EDstack.membrane_areal_resistance_coef["aem"].fix(0) m.fs.EDstack.solute_diffusivity_membrane["cem", "Na_+"].fix(3.28e-11) m.fs.EDstack.solute_diffusivity_membrane["aem", "Na_+"].fix(3.28e-11) m.fs.EDstack.solute_diffusivity_membrane["cem", "Cl_-"].fix(3.28e-11) @@ -299,6 +301,7 @@ def _condition_base(m): # Spacer properties m.fs.EDstack.spacer_porosity.fix(0.83) m.fs.EDstack.spacer_specific_area.fix(10400) + m.fs.EDstack.spacer_conductivity_coefficient.fix(1) # Electrochemical properties m.fs.EDstack.electrodes_resistance.fix(0) diff --git a/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc_ui.py b/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc_ui.py index 383b9428fe..a0c463795c 100644 --- a/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc_ui.py +++ b/watertap/flowsheets/electrodialysis/electrodialysis_1stack_conc_recirc_ui.py @@ -240,23 +240,23 @@ def export_variables(flowsheet=None, exports=None, build_options=None, **kwargs) ) exports.add( - obj=fs.EDstack.membrane_areal_resistance["cem"], + obj=fs.EDstack.membrane_areal_resistance_const["cem"], name="Areal resistnace of CEM", ui_units=pyunits.ohm * pyunits.meter**2, display_units="ohm m^2", rounding=2, - description="Areal resistnace of the cation exchange membrane", + description="Constant areal resistance of the cation exchange membrane measured in concentrated electrolyte.", is_input=True, input_category="Membrane properties", is_output=False, ) exports.add( - obj=fs.EDstack.membrane_areal_resistance["aem"], + obj=fs.EDstack.membrane_areal_resistance_const["aem"], name="Areal resistnace of AEM", ui_units=pyunits.ohm * pyunits.meter**2, display_units="ohm m^2", rounding=2, - description="Areal resistnace of the anion exchange membrane", + description="Constant areal resistance of the anion exchange membrane measured in concentrated electrolyte.", is_input=True, input_category="Membrane properties", is_output=False, diff --git a/watertap/flowsheets/electrodialysis/tests/test_electrodialysis_1stack.py b/watertap/flowsheets/electrodialysis/tests/test_electrodialysis_1stack.py index cc05c56123..a19d773f90 100644 --- a/watertap/flowsheets/electrodialysis/tests/test_electrodialysis_1stack.py +++ b/watertap/flowsheets/electrodialysis/tests/test_electrodialysis_1stack.py @@ -173,7 +173,6 @@ def test_optimization(self, electrodialysis_1D1stack): edfs.optimize_system(m) isinstance(m.fs.objective, Objective) assert m.fs.objective.expr == m.fs.costing.LCOW - assert degrees_of_freedom(m) == 1 assert value(m.fs.feed.properties[0].flow_vol_phase["Liq"]) == pytest.approx( 8.7e-5, abs=1e-6 @@ -188,14 +187,16 @@ def test_optimization(self, electrodialysis_1D1stack): assert value(m.fs.disposal_salinity) == pytest.approx(18.1124, rel=1e-3) assert value(m.fs.EDstack.recovery_mass_H2O[0]) == pytest.approx( - 0.4846, rel=1e-3 + 0.48455, rel=1e-3 + ) + assert value(m.fs.mem_area) == pytest.approx(1.1060, rel=1e-3) + assert value(m.fs.EDstack.voltage_applied[0]) == pytest.approx( + 7.03676, rel=1e-3 ) - assert value(m.fs.mem_area) == pytest.approx(1.0980, rel=1e-3) - assert value(m.fs.EDstack.voltage_applied[0]) == pytest.approx(7.0325, rel=1e-3) assert value(m.fs.costing.specific_energy_consumption) == pytest.approx( - 2.3062, rel=1e-3 + 2.2922, rel=1e-3 ) - assert value(m.fs.costing.LCOW) == pytest.approx(0.42546, rel=1e-3) + assert value(m.fs.costing.LCOW) == pytest.approx(0.42547, rel=1e-3) @pytest.mark.unit def test_main_fun(self, electrodialysis_1D1stack): diff --git a/watertap/unit_models/electrodialysis_1D.py b/watertap/unit_models/electrodialysis_1D.py index 3a42a17bb7..55d5d98219 100644 --- a/watertap/unit_models/electrodialysis_1D.py +++ b/watertap/unit_models/electrodialysis_1D.py @@ -540,7 +540,13 @@ def build(self): initialize=0.7, bounds=(0.01, 1), units=pyunits.dimensionless, - doc='The porosity of spacer in the ED channels. This is also referred to elsewhere as "void fraction" or "volume parameters"', + doc='The prosity of spacer in the ED channels. This is also referred to elsewhere as "void fraction"', + ) + self.spacer_conductivity_coefficient = Var( + initialize=1, + bounds=(0.01, 1.01), + units=pyunits.dimensionless, + doc="A coefficient accounting for the effect of spacer on the solution conductivity", ) # Material and Operational properties @@ -580,12 +586,28 @@ def build(self): units=pyunits.meter * pyunits.second**-1 * pyunits.pascal**-1, doc="Water permeability coefficient", ) - self.membrane_areal_resistance = Var( + self.membrane_areal_resistance_x = Var( + self.membrane_set, + self.diluate.length_domain, + initialize=2e-4, + bounds=(1e-6, 1), + units=pyunits.ohm * pyunits.meter**2, + doc="Areal resistance of membrane", + ) + self.membrane_areal_resistance_const = Var( self.membrane_set, initialize=2e-4, bounds=(1e-6, 1), units=pyunits.ohm * pyunits.meter**2, - doc="Surface resistance of membrane", + doc="Constant areal resistance of membrane at infinity-approximated electrolyte concentration", + ) + self.membrane_areal_resistance_coef = Var( + self.membrane_set, + initialize=0, + bounds=(0, 100), + domain=NonNegativeReals, + units=pyunits.ohm * pyunits.mol * pyunits.m**-1, + doc="Coefficient of membrane areal resistance to 1/c, where c is the electrolyte concentration", ) self.electrodes_resistance = Var( initialize=0, @@ -775,6 +797,29 @@ def eq_get_velocity_concentrate(self, t, x): == self.concentrate.properties[t, x].flow_vol_phase["Liq"] ) + @self.Constraint( + self.flowsheet().time, + self.membrane_set, + self.diluate.length_domain, + doc="Calculate membrane areal resistance at L=x", + ) + def eq_get_membrane_areal_resisance_x(self, t, memb, x): + return ( + self.membrane_areal_resistance_x[memb, x] + * sum( + self.diluate.properties[t, x].conc_mol_phase_comp["Liq", j] + * self.config.property_package.charge_comp[j] + for j in self.cation_set + ) + == self.membrane_areal_resistance_const[memb] + * sum( + self.diluate.properties[t, x].conc_mol_phase_comp["Liq", j] + * self.config.property_package.charge_comp[j] + for j in self.cation_set + ) + + self.membrane_areal_resistance_coef[memb] + ) + @self.Constraint( self.flowsheet().time, self.diluate.length_domain, @@ -784,20 +829,28 @@ def eq_get_total_areal_resistance_x(self, t, x): if self.config.has_Nernst_diffusion_layer: return self.total_areal_resistance_x[t, x] == ( ( - self.membrane_areal_resistance["aem"] - + self.membrane_areal_resistance["cem"] + self.membrane_areal_resistance_x["aem", x] + + self.membrane_areal_resistance_x["cem", x] + ( self.channel_height - self.dl_thickness_x["cem", "cathode_left", t, x] - self.dl_thickness_x["aem", "anode_right", t, x] ) - * self.concentrate.properties[t, x].elec_cond_phase["Liq"] ** -1 + * ( + self.spacer_conductivity_coefficient + * self.concentrate.properties[t, x].elec_cond_phase["Liq"] + ) + ** -1 + ( self.channel_height - self.dl_thickness_x["cem", "anode_right", t, x] - self.dl_thickness_x["aem", "cathode_left", t, x] ) - * self.diluate.properties[t, x].elec_cond_phase["Liq"] ** -1 + * ( + self.spacer_conductivity_coefficient + * self.diluate.properties[t, x].elec_cond_phase["Liq"] + ) + ** -1 ) * self.cell_pair_num + self.electrodes_resistance @@ -805,13 +858,22 @@ def eq_get_total_areal_resistance_x(self, t, x): else: return self.total_areal_resistance_x[t, x] == ( ( - self.membrane_areal_resistance["aem"] - + self.membrane_areal_resistance["cem"] + self.membrane_areal_resistance_x["aem", x] + + self.membrane_areal_resistance_x["cem", x] + self.channel_height * ( - self.concentrate.properties[t, x].elec_cond_phase["Liq"] + ( + self.spacer_conductivity_coefficient + * self.concentrate.properties[t, x].elec_cond_phase[ + "Liq" + ] + ) + ** -1 + + ( + self.spacer_conductivity_coefficient + * self.diluate.properties[t, x].elec_cond_phase["Liq"] + ) ** -1 - + self.diluate.properties[t, x].elec_cond_phase["Liq"] ** -1 ) ) * self.cell_pair_num @@ -2081,20 +2143,22 @@ def initialize_build( .concentrate.properties[set] .conc_mol_phase_comp["Liq", j] ) - self[k].total_areal_resistance_x[set].set_value( - ( - self[k].membrane_areal_resistance["aem"] - + self[k].membrane_areal_resistance["cem"] - + self[k].channel_height - * ( - self[k].concentrate.properties[set].elec_cond_phase["Liq"] - ** -1 - + self[k].diluate.properties[set].elec_cond_phase["Liq"] - ** -1 - ) + self[k].total_areal_resistance_x[...].set_value( + ( + self[k].membrane_areal_resistance_const["aem"] + + self[k].membrane_areal_resistance_const["cem"] + + self[k].channel_height + * ( + self[k].concentrate.properties[set].elec_cond_phase["Liq"] ** -1 + + self[k].diluate.properties[set].elec_cond_phase["Liq"] ** -1 ) - * self[k].cell_pair_num - + self[k].electrodes_resistance + ) + * self[k].cell_pair_num + + self[k].electrodes_resistance + ) + for memb in self[k].membrane_set: + self[k].membrane_areal_resistance_x[memb, :].set_value( + self[k].membrane_areal_resistance_const[memb] ) # --------------------------------------------------------------------- @@ -2157,10 +2221,12 @@ def calculate_scaling_factors(self): iscale.set_scaling_factor(self.membrane_thickness, 1e4) if ( - iscale.get_scaling_factor(self.membrane_areal_resistance, warning=True) + iscale.get_scaling_factor( + self.membrane_areal_resistance_const, warning=True + ) is None ): - iscale.set_scaling_factor(self.membrane_areal_resistance, 1e4) + iscale.set_scaling_factor(self.membrane_areal_resistance_const, 1e4) if ( iscale.get_scaling_factor(self.solute_diffusivity_membrane, warning=True) @@ -2284,7 +2350,10 @@ def calculate_scaling_factors(self): # For vars below, the users can choose but not required to provide scaling factors. # No warnings if no providing. - + iscale.set_scaling_factor( + self.membrane_areal_resistance_x, + iscale.get_scaling_factor(self.membrane_areal_resistance_const["cem"]), + ) for ind in self.total_areal_resistance_x: if ( iscale.get_scaling_factor( @@ -2293,7 +2362,10 @@ def calculate_scaling_factors(self): is None ): sf = ( - iscale.get_scaling_factor(self.membrane_areal_resistance) ** 2 + iscale.get_scaling_factor( + self.membrane_areal_resistance_const["cem"] + ) + ** 2 + iscale.get_scaling_factor(self.channel_height) ** 2 * ( iscale.get_scaling_factor( @@ -2863,17 +2935,17 @@ def _get_performance_contents(self, time_point=0): return { "vars": { - "Total electrical power consumption": self.diluate.power_electrical_x[ + "Total electrical power consumption(Watt)": self.diluate.power_electrical_x[ time_point, self.diluate.length_domain.last() ], - "Specific electrical power consumption, ED stack": self.specific_power_electrical[ + "Specific electrical power consumption, ED stack (kW*h/m**3)": self.specific_power_electrical[ time_point ], "Water recovery by mass": self.recovery_mass_H2O[time_point], - "Channel inlet velocity, diluate": self.velocity_diluate[ + "Channel inlet velocity, diluate (m/s)": self.velocity_diluate[ time_point, self.diluate.length_domain.first() ], - "Channel inlet velocity, concentrate": self.velocity_concentrate[ + "Channel inlet velocity, concentrate (m/s)": self.velocity_concentrate[ time_point, self.diluate.length_domain.first() ], }, diff --git a/watertap/unit_models/tests/test_electrodialysis_1D.py b/watertap/unit_models/tests/test_electrodialysis_1D.py index 0cfc460398..e4cdc395ba 100644 --- a/watertap/unit_models/tests/test_electrodialysis_1D.py +++ b/watertap/unit_models/tests/test_electrodialysis_1D.py @@ -100,7 +100,7 @@ def test_build_model(self, electrodialysis_1d_cell1): assert isinstance(m.fs.unit.ion_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_permeability_membrane, Var) - assert isinstance(m.fs.unit.membrane_areal_resistance, Var) + assert isinstance(m.fs.unit.membrane_areal_resistance_const, Var) assert isinstance(m.fs.unit.current_density_x, Var) assert isinstance(m.fs.unit.voltage_applied, Var) assert isinstance(m.fs.unit.voltage_x, Var) @@ -124,7 +124,7 @@ def test_build_model(self, electrodialysis_1d_cell1): def test_stats_constant_vol(self, electrodialysis_1d_cell1): m = electrodialysis_1d_cell1 assert_units_consistent(m) - assert degrees_of_freedom(m) == 34 + assert degrees_of_freedom(m) == 37 # Specify a system # Note: Testing scenarios in this file are primarily in accord with an experimental # setup reported by Campione et al. in Desalination 465 (2019): 79-93. @@ -138,8 +138,10 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell1): m.fs.unit.cell_pair_num.fix(10) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(2.7e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.1) m.fs.unit.cell_length.fix(0.79) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -153,6 +155,7 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell1): m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.unit.spacer_porosity.fix(1) + m.fs.unit.spacer_conductivity_coefficient.fix(1) # check ion transfer number requirements assert ( @@ -261,10 +264,12 @@ def test_performance_contents(self, electrodialysis_1d_cell1): perform_dict = m.fs.unit._get_performance_contents() assert "vars" in perform_dict assert value( - perform_dict["vars"]["Total electrical power consumption"] + perform_dict["vars"]["Total electrical power consumption(Watt)"] ) == pytest.approx(3.0, rel=5e-3) assert value( - perform_dict["vars"]["Specific electrical power consumption, ED stack"] + perform_dict["vars"][ + "Specific electrical power consumption, ED stack (kW*h/m**3)" + ] ) == pytest.approx(0.197, rel=5e-3) assert value(perform_dict["vars"]["Water recovery by mass"]) == pytest.approx( 0.485, rel=5e-3 @@ -382,7 +387,7 @@ def test_build_model(self, electrodialysis_1d_cell2): assert isinstance(m.fs.unit.ion_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_permeability_membrane, Var) - assert isinstance(m.fs.unit.membrane_areal_resistance, Var) + assert isinstance(m.fs.unit.membrane_areal_resistance_const, Var) assert isinstance(m.fs.unit.current_applied, Var) assert isinstance(m.fs.unit.current_density_x, Var) assert isinstance(m.fs.unit.voltage_x, Var) @@ -417,8 +422,10 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell2): m.fs.unit.cell_pair_num.fix(10) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(2.7e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.1) m.fs.unit.cell_length.fix(0.79) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -432,6 +439,7 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell2): m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.unit.spacer_porosity.fix(1) + m.fs.unit.spacer_conductivity_coefficient.fix(1) # check ion transfer number requirements assert ( @@ -535,10 +543,12 @@ def test_performance_contents(self, electrodialysis_1d_cell2): perform_dict = m.fs.unit._get_performance_contents() assert "vars" in perform_dict assert value( - perform_dict["vars"]["Total electrical power consumption"] + perform_dict["vars"]["Total electrical power consumption(Watt)"] ) == pytest.approx(5.83, rel=5e-3) assert value( - perform_dict["vars"]["Specific electrical power consumption, ED stack"] + perform_dict["vars"][ + "Specific electrical power consumption, ED stack (kW*h/m**3)" + ] ) == pytest.approx(0.390, rel=5e-3) assert value(perform_dict["vars"]["Water recovery by mass"]) == pytest.approx( 0.480, rel=5e-3 @@ -594,7 +604,7 @@ def test_build_model(self, electrodialysis_1d_cell3): assert isinstance(m.fs.unit.ion_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_permeability_membrane, Var) - assert isinstance(m.fs.unit.membrane_areal_resistance, Var) + assert isinstance(m.fs.unit.membrane_areal_resistance_const, Var) assert isinstance(m.fs.unit.current_applied, Var) assert isinstance(m.fs.unit.current_density_x, Var) assert isinstance(m.fs.unit.voltage_x, Var) @@ -618,7 +628,7 @@ def test_build_model(self, electrodialysis_1d_cell3): def test_stats_constant_vol(self, electrodialysis_1d_cell3): m = electrodialysis_1d_cell3 assert_units_consistent(m) - assert degrees_of_freedom(m) == 38 + assert degrees_of_freedom(m) == 41 # Specify a system # set the operational parameters m.fs.unit.water_trans_number_membrane["cem"].fix(5.8) @@ -630,8 +640,10 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell3): m.fs.unit.cell_pair_num.fix(10) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(2.7e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.1) m.fs.unit.cell_length.fix(0.79) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -647,6 +659,7 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell3): m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.unit.spacer_porosity.fix(1) + m.fs.unit.spacer_conductivity_coefficient.fix(1) # check ion transfer number requirements assert ( @@ -762,10 +775,12 @@ def test_performance_contents(self, electrodialysis_1d_cell3): perform_dict = m.fs.unit._get_performance_contents() assert "vars" in perform_dict assert value( - perform_dict["vars"]["Total electrical power consumption"] + perform_dict["vars"]["Total electrical power consumption(Watt)"] ) == pytest.approx(5.837, rel=5e-3) assert value( - perform_dict["vars"]["Specific electrical power consumption, ED stack"] + perform_dict["vars"][ + "Specific electrical power consumption, ED stack (kW*h/m**3)" + ] ) == pytest.approx(0.3896, rel=5e-3) assert value(perform_dict["vars"]["Water recovery by mass"]) == pytest.approx( 0.480, rel=5e-3 @@ -821,7 +836,7 @@ def test_build_model(self, electrodialysis_1d_cell4): assert isinstance(m.fs.unit.ion_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_permeability_membrane, Var) - assert isinstance(m.fs.unit.membrane_areal_resistance, Var) + assert isinstance(m.fs.unit.membrane_areal_resistance_const, Var) assert isinstance(m.fs.unit.current_density_x, Var) assert isinstance(m.fs.unit.voltage_applied, Var) assert isinstance(m.fs.unit.voltage_x, Var) @@ -862,8 +877,10 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell4): m.fs.unit.cell_pair_num.fix(10) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(5e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.1) m.fs.unit.cell_length.fix(0.79) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -877,6 +894,7 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell4): m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.unit.spacer_porosity.fix(1) + m.fs.unit.spacer_conductivity_coefficient.fix(1) # check ion transfer number requirements assert ( @@ -989,10 +1007,12 @@ def test_performance_contents(self, electrodialysis_1d_cell4): perform_dict = m.fs.unit._get_performance_contents() assert "vars" in perform_dict assert value( - perform_dict["vars"]["Total electrical power consumption"] + perform_dict["vars"]["Total electrical power consumption(Watt)"] ) == pytest.approx(1.4735, rel=1e-3) assert value( - perform_dict["vars"]["Specific electrical power consumption, ED stack"] + perform_dict["vars"][ + "Specific electrical power consumption, ED stack (kW*h/m**3)" + ] ) == pytest.approx(0.0955, rel=1e-3) assert value(perform_dict["vars"]["Water recovery by mass"]) == pytest.approx( 0.4925, rel=1e-3 @@ -1051,7 +1071,7 @@ def test_build_model(self, electrodialysis_1d_cell5): assert isinstance(m.fs.unit.ion_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_permeability_membrane, Var) - assert isinstance(m.fs.unit.membrane_areal_resistance, Var) + assert isinstance(m.fs.unit.membrane_areal_resistance_const, Var) assert isinstance(m.fs.unit.current_density_x, Var) assert isinstance(m.fs.unit.voltage_applied, Var) assert isinstance(m.fs.unit.voltage_x, Var) @@ -1101,8 +1121,10 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell5): m.fs.unit.cell_pair_num.fix(10) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(5e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.1) m.fs.unit.cell_length.fix(0.79) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -1116,6 +1138,7 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell5): m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.unit.spacer_porosity.fix(1) + m.fs.unit.spacer_conductivity_coefficient.fix(1) # set the inlet stream m.fs.unit.inlet_diluate.pressure.fix(101325) @@ -1201,10 +1224,12 @@ def test_performance_contents(self, electrodialysis_1d_cell5): perform_dict = m.fs.unit._get_performance_contents() assert "vars" in perform_dict assert value( - perform_dict["vars"]["Total electrical power consumption"] + perform_dict["vars"]["Total electrical power consumption(Watt)"] ) == pytest.approx(1.3907, rel=1e-3) assert value( - perform_dict["vars"]["Specific electrical power consumption, ED stack"] + perform_dict["vars"][ + "Specific electrical power consumption, ED stack (kW*h/m**3)" + ] ) == pytest.approx(0.0900, rel=1e-3) assert value(perform_dict["vars"]["Water recovery by mass"]) == pytest.approx( 0.4928, rel=1e-3 @@ -1271,8 +1296,10 @@ def test_stats_constant_vol(self, edcell_ilim_empi, edcell_ilim_theo): m.fs.unit.cell_pair_num.fix(10) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(5e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.1) m.fs.unit.cell_length.fix(0.79) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -1286,6 +1313,7 @@ def test_stats_constant_vol(self, edcell_ilim_empi, edcell_ilim_theo): m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.unit.spacer_porosity.fix(0.83) + m.fs.unit.spacer_conductivity_coefficient.fix(1) # set the inlet stream m.fs.unit.inlet_diluate.pressure.fix(101325) @@ -1440,7 +1468,7 @@ def test_build_model(self, electrodialysis_1d_cell6): assert isinstance(m.fs.unit.ion_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_trans_number_membrane, Var) assert isinstance(m.fs.unit.water_permeability_membrane, Var) - assert isinstance(m.fs.unit.membrane_areal_resistance, Var) + assert isinstance(m.fs.unit.membrane_areal_resistance_const, Var) assert isinstance(m.fs.unit.current_density_x, Var) assert isinstance(m.fs.unit.current_applied, Var) assert isinstance(m.fs.unit.voltage_x, Var) @@ -1490,8 +1518,10 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell6): m.fs.unit.cell_pair_num.fix(10) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(5e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.1) m.fs.unit.cell_length.fix(0.79) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -1505,6 +1535,7 @@ def test_stats_constant_vol(self, electrodialysis_1d_cell6): m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) m.fs.unit.spacer_porosity.fix(1) + m.fs.unit.spacer_conductivity_coefficient.fix(1) # set the inlet stream m.fs.unit.inlet_diluate.pressure.fix(101325) @@ -1590,10 +1621,12 @@ def test_performance_contents(self, electrodialysis_1d_cell6): perform_dict = m.fs.unit._get_performance_contents() assert "vars" in perform_dict assert value( - perform_dict["vars"]["Total electrical power consumption"] + perform_dict["vars"]["Total electrical power consumption(Watt)"] ) == pytest.approx(12.904, rel=1e-3) assert value( - perform_dict["vars"]["Specific electrical power consumption, ED stack"] + perform_dict["vars"][ + "Specific electrical power consumption, ED stack (kW*h/m**3)" + ] ) == pytest.approx(0.8627, rel=1e-3) assert value(perform_dict["vars"]["Water recovery by mass"]) == pytest.approx( 0.4791, rel=1e-3 @@ -1770,8 +1803,10 @@ def test_deltaP_various_methods(self, ed_m0, ed_m1, ed_m2, ed_m3, ed_m4, ed_m5): m.fs.unit.cell_pair_num.fix(56) m.fs.unit.current_utilization.fix(1) m.fs.unit.channel_height.fix(7.1e-4) - m.fs.unit.membrane_areal_resistance["cem"].fix(1.89e-4) - m.fs.unit.membrane_areal_resistance["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_const["cem"].fix(1.89e-4) + m.fs.unit.membrane_areal_resistance_const["aem"].fix(1.77e-4) + m.fs.unit.membrane_areal_resistance_coef["cem"].fix(0) + m.fs.unit.membrane_areal_resistance_coef["aem"].fix(0) m.fs.unit.cell_width.fix(0.197) m.fs.unit.cell_length.fix(1.68) m.fs.unit.membrane_thickness["aem"].fix(1.3e-4) @@ -1784,9 +1819,9 @@ def test_deltaP_various_methods(self, ed_m0, ed_m1, ed_m2, ed_m3, ed_m4, ed_m5): m.fs.unit.ion_trans_number_membrane["aem", "Na_+"].fix(0) m.fs.unit.ion_trans_number_membrane["cem", "Cl_-"].fix(0) m.fs.unit.ion_trans_number_membrane["aem", "Cl_-"].fix(1) - m.fs.unit.spacer_porosity.fix(0.83) m.fs.unit.voltage_applied.fix(40) m.fs.unit.spacer_porosity.fix(0.83) + m.fs.unit.spacer_conductivity_coefficient.fix(1) m.fs.properties.set_default_scaling( "flow_mol_phase_comp", 0.1, index=("Liq", "H2O") )