Tutorial: Electrodialysis (ED) unit

ED is a technique that uses ion exchange membranes and electricity to extract ionic compounds from aqueous solutions, with an electrical field serving as the driving force for solute separation. In this work, ED aims to purify NF permeate.

ed

In desalsim package, the ED unit is used to model the operation of an Electrodialysis technology. Upon simulation, it calculates the flow rate of the concentrate and dilute streams, their ion concentration, and the electricity requirements of the unit. The ED function consists of one class: ElectrodialysisCalc that consists of six methods: Ts_cp, w_cp, Ls_cpv, Lw_cp, p_osmo, dC (see Section 2.3).

In this tutorial, we will focus on how to use the class and its methods.

Table 1 gives an overview of the main inputs and outputs for each process unit of Electrodialysis.

Inputs and Outputs for Electrodialysis

Process

Input

Output

Electrodialysis (ED)

Feed flow rate [m³/h]

Flow rate of diluted stream [m³/h] and composition [g/L]

Ion concentration [g/L]

Flow rate of concentrate stream [m³/h] and composition [g/L]

Current density [A/m²]

Electricity requirements [kWhel]

The mathematical description of Electrodialysis is given in Mathematical description, see Section A.8.

1. Getting started

1.1. Import class

import desalsim

Then import the class:

from desalsim.ed_unit_f import ElectrodialysisCalc

Additionally, function for calculating density (density_calc.py) or constants (comparison.py) where users can add constant values like MW, prices, etc., need to be imported.

from desalsim.density_calc import density_calc
from desalsim import constants
from desalsim import scaleup

1.2. Define feed characteristics

You can initialize the feed solution by setting the flow rate, specifying the focus components and their concentration.

# Input conditions
Sc_i = 43.39  # Salinity at concentrate inlet (g/kg)
Sd_i = Sc_i   # Salinity at diluate inlet (g/kg)

# Feed concentration
components = ['Na', 'Cl', 'K', 'Mg', 'Ca', 'SO4', 'HCO3', 'H', 'OH']
Csw = [17.17, 25.47, 0.57, 0.04, 0.03, 0.10]

# Feed flow rate L/h
Qed_in = 1000

# Temperature
T = 20 + 273.15  # K

Note

Note that if you want to add more components, you need to update the components list and include the concentration of the new component in the Csw.

You can calculate the density of the feed solution and the water quantity in inflow:

d_in_ed = (density_calc(T - 273, Sc_i) / 1000)
Qed_in = 1000 / d_in_ed

# Calculate the flowrates for dilute and concentrate streams
Qed_in_c = Qed_in / 17 / Ncp
Qed_in_d = Qed_in * 16 / 17 / Ncp

Note

In this case, we assumed that the concentrate stream is 1/17 of the total feed flow rate, and the dilute stream is 16/17 of the total feed flow rate.

1.3. Set operating assumptions

You need to set operating assumptions such as the electrical current density.

# Assumptions:
Ij = 400  # Current density (A/m²)
N = 50  # Number of computational cells per cell-pair
Ncp = 1  # Number of identical parallel cell-pairs
A = 1.1  # Active area of cell-pair (m²)
Mem_eff = 0.64  # Membrane efficiency
Vcp = 8  # Applied voltage (V)
Vel = 2.1  # Voltage across the electrodes (V)

# Effective cell-pair area (m²)
Acp = scaleup.scaleup(24, 1000, Qed_in)
Acp_tot = Acp

You need to set the salinity at dilute outlet concentrate outlet in g/kg.

Sc_o = 200  # Salinity at concentrate outlet (g/kg)
Sd_o = 20   # Salinity at dilute outlet (g/kg)

Finally, you need to set assumptions related to pumping like pressure drop (dp) and pump efficiency (npump).

npump = 0.8  # Pump efficiency (units: -)
dp = 1  # Pressure drop (units: bar)

1.4. Set constants

You need to set constant parameters:

R = 0.002  # Resistance of rinse stream (ohm)
Rp = 0.015  # Resistance of polarization (ohm)
A = 1.1  # Active area of cell-pair (m²)
F = 96485.3329  # Faraday constant (C/mol)
rho_w = 1000  # Water density kg/m³

D = 1.61e-9  # Diffusion coefficient (m²/s)
tcu = 0.5
veloc = 8.9e-7  # m²/s
h = 0.5  # mm
Sh = 18

1.5. Initializations

First, you need to initialize the parameters:

# Initializations
Sc = np.zeros(N)
Sd = np.zeros(N)
Ns_c = np.zeros(N)
Ns_d = np.zeros(N)
Nw_c = np.zeros(N)
Nw_d = np.zeros(N)
Js = np.zeros(N)
Jw = np.zeros(N)
Mw_in_d_l = np.zeros(N)
Ms_d = np.zeros(N)
Mw_d = np.zeros(N)
M_d = np.zeros(N)
M_c = np.zeros(N)
Q_c = np.zeros(N)
Q_d = np.zeros(N)

Then set the initial values for the concentrate stream:

# Set initial values salt stream
Sc[0] = Sc_i
Ns_c[0] = Qed_in_c * d_in_ed * Sc[0] / MWs  # mol/hr
Ms_in_c = Qed_in_c * d_in_ed * Sc_i / 1000  # kg salt/hr
Mw_in_c = Qed_in_c * d_in_ed - Ms_in_c  # kg water/hr
Nw_c[0] = Mw_in_c * 1000 / MWw  # mol/hr
M_c[0] = Mw_in_c + Ms_in_c
Q_c[0] = Qed_in_c
# Set initial values diluate stream
Sd[0] = Sc_i  # g/kg
Ns_d[0] = Qed_in_d * d_in_ed * Sd[0] / MWs  # mol/s
Ms_in_d = Qed_in_d * d_in_ed * Sd[0] / 1000  # kg salt/hr
Mw_in_d = Qed_in_d * d_in_ed - Ms_in_d  # kg water/hr
Nw_d[0] = Mw_in_d * 1000 / MWw  # mol/hr
Mw_in_d_l[0] = Mw_in_d
Ms_d[0] = Ms_in_d
Mw_d[0] = Mw_in_d
M_d[0] = Mw_in_d + Ms_in_d
Q_d[0] = Qed_in_d

Finally, initialize the total cell-pair area.

# Initialize the Acp_tot array
Acp_tot_j = Acp_tot / N

After setting all the required inputs and initialize the values, then you can create the functions’ objectives.

2. Use ElectrodialysisCalc class

ElectrodialysisCalc is a class used to represent mass and energy balance for ED Unit. In particular, it calculates the flowrate in each channel, the outlet concentration in each channel, the external Voltage and power needed.

2.1. Overview

The following attributes are available within the ElectrodialysisCalc class:

  • MWs: Molecular weight of NaCl (g/mol)

  • MWw: Molecular weight of water (g/mol)

-R: Resistance of rinse stream (ohm) - Rp: Resistance of polarization (ohm) - A: Active area of cell-pair (m²) - F: Faraday constant (C/mol) - T: Temperature in Kelvin - dp: Parameter dp - npump: Pump efficiency - rho_w: Density of water (kg/m³) - D: Diffusion coefficient (m²/s) - tcu: ntcu parameter - h: Height (mm) - Sh: Sh parameter - Mem_eff: Membrane efficiency - Ncp: Number of cell-pairs - Qed_in: Inlet flow rate (L/h) - Qed_in_c: Concentrate inlet flow rate (L/h) - Qed_in_d: Dilute inlet flow rate (L/h)

The ElectrodialysisCalc class provides the following methods:

# Calculates the transport number for salt in concentrate compartment
Ts_cp(S)

# Calculates the transport number for water in concentrate compartment
w_cp(Sc, Sd)

# Permeability for salt in concentrate compartment
Ls_cp(Sc, Sd)

# Permeability for water in concentrate compartment
Lw_cp(S)

# Calculation for osmotic pressure in concentrate compartment
p_osmo(S, T, MWs)

# Calculate the change in concentration
dC(Ts_cp, tcu, D, Ij, h, Sh)

2.2. Create ElectrodialysisCalc objects

ElectrodialysisCalc has no inputs.

# Create an instance of the ElectrodialysisCalc class
ed_em = ElectrodialysisCalc()

2.3. Use Ts_cp, w_cp, Ls_cpv, Lw_cp, p_osmo, dC methods

The ED system is modeled by adapting a model developed by Nayar et al., keeping both the concentrate and diluate channels fully continuous, with the salinities of both channels varying along the length of the ED stack. The following code simulates the ED unit using the Ts_cp, w_cp, Ls_cpv, Lw_cp, p_osmo, and dC methods.

# Iterate over cells
for j in range(1, N):
    # Calculate salinity change
    concentration_diff = Sc[j - 1] - Sd[j - 1]
    Sc[j] = Sc[j - 1] + (Sc_o - Sc_i) / (N - 1)
    Sd[j] = Sd[j - 1] + (Sd_o - Sd_i) / (N - 1)

    # Calculate net salt flux
    Js[j] = (ElectrodialysisCalc.Ts_cp(Sd[j - 1]) * Ij / F -
             (ElectrodialysisCalc.Ls_cp(Sc[j - 1], Sd[j - 1])) * concentration_diff)

    # Calculate net water flux
    Jw[j] = (ElectrodialysisCalc.Tw_cp(Sc[j - 1], Sd[j - 1]) * Ij / F +
             ElectrodialysisCalc.Lw_cp(Sc[j - 1]) * (ElectrodialysisCalc.p_osmo(Sc[j - 1], T, MWs) -
                                                    ElectrodialysisCalc.p_osmo(Sd[j - 1], T, MWs)))

    # Calculate total concentrate and dilute molar flow rates
    Ns_c[j] = Ns_c[j - 1] + Acp_tot_j * Js[j]
    Ns_d[j] = Ns_d[j - 1] - Acp_tot_j * Js[j]
    Nw_c[j] = Nw_c[j - 1] + Acp_tot_j * Jw[j]
    Nw_d[j] = Nw_d[j - 1] - Acp_tot_j * Jw[j]

    # Update the flow rates of the concentrate and dilute streams
    Q_c[j] = Nw_c[j] * MWw / (rho_w * (1 - Sc[j] / 1000))
    Q_d[j] = Nw_d[j] * MWw / (rho_w * (1 - Sd[j] / 1000))

2.3.1. Assign the results to output parameters

You can assign the results to output parameters:

Cc_na_f = Sc[N-1] / MWs * constants.MW_Na
Cc_cl_f = Sc[N-1] / MWs * constants.MW_cl
Sc_out = [Cc_na_f, Cc_cl_f]

2.4. Calculate the concentrate stream flow rate

# Calculate the concentrate stream flow rate
Mc = (Ns_c[N-1] * MWs / 1000 + Nw_c[N-1] * MWw / 1000)  # (kg/hr)
dc_out = density_calc(T-273, Sc[N-1]) / 1000  # (kg/l)
Qc = Mc / dc_out  # Concentrate stream volume flow rate (l/hr)

i = 2
for i in range(2, len(Csw)):
    Sc_out.append(Csw[i] * Qed_in_c / Qc)  # The total effluent concentration concentrate stream

2.5. Calculate the dilute stream flow rate

# Calculations for diluate stream
Md = (Ns_d[N-1] * MWs / 1000 + Nw_d[N-1] * MWw / 1000)  # Mass flow rate (kg/hr)

Sd_f = Sd[N-1]
Cd_na_f = Sd_f / MWs * constants.MW_Na
Cd_cl_f = Sd_f / MWs * constants.MW_cl
dd_out = density_calc(T-273, Sd[N-1]) / 1000  # Density of diluate stream
Qd = Md / dd_out  # Diluate stream volume flow rate (l/hr)

Sd_out = [Cd_na_f, Cd_cl_f]

# The total effluent concentration dilute
for i in range(2, len(Csw)):
    Sd_out.append(Csw[i] * Qed_in / Qd)

2.6. Calculate energy consumption

You can calculate the total energy requirements for the ED unit using the voltage applied across an ED cell-pair (Vcp), the voltage across the electrodes (Vel), and the energy for pumping (Ppump_ed).

# Energy consumption
Ws = 0
for j in range(N):
    Ws += Ij * Acp_tot_j * (Ncp * Vcp + Vel)
print("Power required is " + str(round(Ws / 1000, 2)) + "KW")

# Calculate energy consumption for pumping
Ppump_ed = (Qed_in_d * 1 + Qed_in_c * 1 + Qc * 2 + Qd * 1) / 1000 / 3600 * 1e5 / npump
Eel_t_ed = Ws / 1000 + Ppump_ed / 1000

# Specific energy consumption
sec_ed = Eel_t_ed / (Qed_in / 1000)