diff --git a/src/watertap_contrib/reflo/unit_models/chemical_softening.py b/src/watertap_contrib/reflo/unit_models/chemical_softening.py index ee60ed2a..c8891f92 100644 --- a/src/watertap_contrib/reflo/unit_models/chemical_softening.py +++ b/src/watertap_contrib/reflo/unit_models/chemical_softening.py @@ -175,7 +175,7 @@ def build(self): non_hardness_comps = [ j for j in self.config.property_package.solute_set - if j not in ["Ca_2+", "Mg_2+"] + if j not in ["Ca_2+", "Mg_2+", "Alkalinity_2-"] ] # MW of components @@ -1028,6 +1028,109 @@ def eq_mass_balance_mg(b): to_units=pyunits.kg / pyunits.s, ) + # TODO: + # single stage lime (example in book Crittenden): source water alkalinity - Ca hardness + residual Ca hardness + # excess lime (example in book Crittenden): source water alkalinity - Ca hardness - excess lime dose + residual Ca hardness + # single stage lime soda (only hydroxide alkalinity): source water alkalinity + soda ash - total hardness + residual hardness + # excess lime soda (only hydroxide alkalinity): source water alkalinity + soda ash - total hardness + residual hardness + + if ( + self.config.softening_procedure_type + is SofteningProcedureType.single_stage_lime + ): + + @self.Constraint(doc="Alkalinity mass balance") + def eq_effluent_alk(b): + return b.properties_out[0].flow_mass_phase_comp[ + "Liq", "Alkalinity_2-" + ] == b.properties_in[0].flow_mass_phase_comp[ + "Liq", "Alkalinity_2-" + ] - pyunits.convert( + b.Ca_CaCO3 * b.properties_in[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + pyunits.convert( + b.properties_out[0].conc_mass_phase_comp["Liq", "Ca_2+"] + * b.Ca_CaCO3_conv + * b.properties_out[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + + elif self.config.softening_procedure_type is SofteningProcedureType.excess_lime: + + @self.Constraint(doc="Alkalinity mass balance") + def eq_effluent_alk(b): + return b.properties_out[0].flow_mass_phase_comp[ + "Liq", "Alkalinity_2-" + ] == b.properties_in[0].flow_mass_phase_comp[ + "Liq", "Alkalinity_2-" + ] - pyunits.convert( + b.total_hardness * b.properties_in[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) - pyunits.convert( + b.excess_CaO * b.properties_in[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + pyunits.convert( + b.properties_out[0].conc_mass_phase_comp["Liq", "Ca_2+"] + * b.Ca_CaCO3_conv + * b.properties_out[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + pyunits.convert( + b.properties_out[0].conc_mass_phase_comp["Liq", "Ca_2+"] + * b.Ca_CaCO3_conv + * b.properties_out[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + pyunits.convert( + b.properties_out[0].conc_mass_phase_comp["Liq", "Mg_2+"] + * b.Mg_CaCO3_conv + * b.properties_out[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + + elif ( + self.config.softening_procedure_type + is SofteningProcedureType.single_stage_lime_soda + ): + + @self.Constraint(doc="Alkalinity mass balance") + def eq_effluent_alk(b): + return b.properties_out[0].flow_mass_phase_comp[ + "Liq", "Alkalinity_2-" + ] == pyunits.convert( + b.properties_out[0].conc_mass_phase_comp["Liq", "Ca_2+"] + * b.Ca_CaCO3_conv + * b.properties_out[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + + elif ( + self.config.softening_procedure_type + is SofteningProcedureType.excess_lime_soda + ): + + @self.Constraint(doc="Alkalinity mass balance") + def eq_effluent_alk(b): + return b.properties_out[0].flow_mass_phase_comp[ + "Liq", "Alkalinity_2-" + ] == pyunits.convert( + b.properties_out[0].conc_mass_phase_comp["Liq", "Ca_2+"] + * b.Ca_CaCO3_conv + * b.properties_out[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + pyunits.convert( + b.properties_out[0].conc_mass_phase_comp["Liq", "Mg_2+"] + * b.Mg_CaCO3_conv + * b.properties_out[0].flow_vol_phase["Liq"], + to_units=pyunits.kg / pyunits.s, + ) + + @self.Constraint(doc="Alkalinity mass balance") + def eq_mass_balance_alk(b): + return ( + b.properties_waste[0].flow_mass_phase_comp["Liq", "Alkalinity_2-"] + == b.properties_in[0].flow_mass_phase_comp["Liq", "Alkalinity_2-"] + - b.properties_out[0].flow_mass_phase_comp["Liq", "Alkalinity_2-"] + ) + if ["TSS"] in comps: @self.Constraint(doc="Sludge production") diff --git a/src/watertap_contrib/reflo/unit_models/tests/test_chemical_softening.py b/src/watertap_contrib/reflo/unit_models/tests/test_chemical_softening.py index 4b007399..104f1c1c 100644 --- a/src/watertap_contrib/reflo/unit_models/tests/test_chemical_softening.py +++ b/src/watertap_contrib/reflo/unit_models/tests/test_chemical_softening.py @@ -165,7 +165,7 @@ def test_build(self, chem_soft_frame): assert isinstance(port, Port) assert len(port.vars) == 3 - assert number_variables(m) == 96 + assert number_variables(m) == 95 assert number_total_constraints(m) == 62 assert number_unused_variables(m) == 17 @@ -206,7 +206,7 @@ def test_solution(self, chem_soft_frame): soft_results = { "ca_eff_target": 0.008, "mg_eff_target": 0.002427, - "removal_efficiency": {"SiO2": 0.7, "Alkalinity_2-": 0.7}, + # "removal_efficiency": {"SiO2": 0.7, "Alkalinity_2-": 0.7}, "volume_mixer": 1.0535825, "volume_floc": 65.8489, "volume_sed": 342.4143, @@ -416,7 +416,7 @@ def test_build(self, chem_soft_frame): assert isinstance(port, Port) assert len(port.vars) == 3 - assert number_variables(m) == 86 + assert number_variables(m) == 85 assert number_total_constraints(m) == 51 assert number_unused_variables(m) == 18 @@ -458,7 +458,7 @@ def test_solution(self, chem_soft_frame): soft_results = { "ca_eff_target": 0.008, "mg_eff_target": 0.002427, - "removal_efficiency": {"Alkalinity_2-": 0.7}, + # "removal_efficiency": {"Alkalinity_2-": 0.7}, "volume_mixer": 13.89, "volume_floc": 868.29, "volume_sed": 4515.12, @@ -672,7 +672,7 @@ def test_build(self, chem_soft_frame): assert isinstance(port, Port) assert len(port.vars) == 3 - assert number_variables(m) == 86 + assert number_variables(m) == 85 assert number_total_constraints(m) == 52 assert number_unused_variables(m) == 18 @@ -714,7 +714,7 @@ def test_solution(self, chem_soft_frame): soft_results = { "ca_eff_target": 0.012, "mg_eff_target": 0.000728, - "removal_efficiency": {"Alkalinity_2-": 0.7}, + # "removal_efficiency": {"Alkalinity_2-": 0.7}, "volume_mixer": 13.89, "volume_floc": 868.29, "volume_sed": 4515.12, @@ -931,7 +931,7 @@ def test_build(self, chem_soft_frame): assert isinstance(port, Port) assert len(port.vars) == 3 - assert number_variables(m) == 86 + assert number_variables(m) == 85 assert number_total_constraints(m) == 52 assert number_unused_variables(m) == 18 @@ -973,7 +973,7 @@ def test_solution(self, chem_soft_frame): soft_results = { "ca_eff_target": 0.012, "mg_eff_target": 0.000728, - "removal_efficiency": {"Alkalinity_2-": 0.7}, + # "removal_efficiency": {"Alkalinity_2-": 0.7}, "volume_mixer": 13.89, "volume_floc": 868.29, "volume_sed": 4515.12, @@ -1192,7 +1192,7 @@ def test_build(self, chem_soft_frame): assert isinstance(port, Port) assert len(port.vars) == 3 - assert number_variables(m) == 96 + assert number_variables(m) == 95 assert number_total_constraints(m) == 62 assert number_unused_variables(m) == 17