-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ElectroNP ZO model with UnitModelBlockData base #1020
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1020 +/- ##
========================================
Coverage 95.82% 95.83%
========================================
Files 299 301 +2
Lines 28647 28801 +154
========================================
+ Hits 27451 27601 +150
- Misses 1196 1200 +4 ☔ View full report in Codecov by Sentry. |
@pytest.mark.solver | ||
@pytest.mark.skipif(solver is None, reason="Solver not available") | ||
@pytest.mark.component | ||
def test_solution(self, ElectroNP_frame): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth listing out the solution for the byproduct stream too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we don't have any byproduct, so I don't think we need to list them all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the byproduct stream would include the S_NH4 and S_PO4 that got removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @MarcusHolly. The treated stream would be fed back to the headworks of the plant or right before the activated sludge process, while the byproduct stream would comprise the recovered nutrients.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added byproduct test for S_PO4
and S_NH4
, but to be noticed, since we set the water recovery as 1, so the byproduct stream is assigned to a calculation error value extremely close to 0. So the byproduct concentration will be extremely high and does not make much sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@luohezhiming Maybe just add an assert value(m.fs.unit.byproduct.flow_vol[0])
so that it's more clear why the byproduct values are so high?
Co-authored-by: MarcusHolly <96305519+MarcusHolly@users.noreply.github.com>
watertap/unit_models/electroNP_ZO.py
Outdated
# Add performance variables | ||
self.recovery_frac_mass_H2O = Var( | ||
self.flowsheet().time, | ||
initialize=0.8, | ||
domain=NonNegativeReals, | ||
units=pyunits.dimensionless, | ||
bounds=(0.0, 1.0000001), | ||
doc="Mass recovery fraction of water in the treated stream", | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we're making this its own unit, separate from the ZO model framework, I wonder if we even need this recovery variable here. If included, I'd think the value would be very close to 1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I choose to fix the recovery to 1.
watertap/unit_models/electroNP_ZO.py
Outdated
# default water recovery | ||
@self.Constraint(self.flowsheet().time, doc="Default water recovery equation") | ||
def default_water_recovery_equation(b, t): | ||
return b.recovery_frac_mass_H2O[t] == 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just set the recovery_frac_mass_H2O variable to an initial value and then fix the variable within this build instead of having this constraint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, modified.
watertap/unit_models/electroNP_ZO.py
Outdated
) | ||
def default_solute_removal_equation(b, t, j): | ||
if hasattr(self.config.property_package.solute_set, "S_PO4"): | ||
return b.removal_frac_mass_comp[t, "S_PO4"] == 0.98 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would maybe have parameters defined for the values, then fix removal fractions directly to those parameter values. The user could change the parameter values as desired and have them fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add removal_P
and removal_N
as two mutable parameters.
m = ConcreteModel() | ||
m.fs = FlowsheetBlock(dynamic=False) | ||
|
||
m.fs.properties = ModifiedASM2dParameterBlock( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm.... I just thought about this, and there is a chance, due to how we've compartmentalized the property and reaction models, that some expressions/additional variables/additional constraints implemented in the reaction block could be desired in the unit model (but not sure yet since I didn't think about it deeply). Maybe this isn't an issue yet, and my concern is probably more relevant to our ADM1 formulation rather than ASM2D, but let's keep this in mind since we expect to make additions to the modified ASM2d property/reaction package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is a good point, some additional variables can be added to the unit model instead of properties model. Just for modified ASM2D package, we might need to keep the additonal_solute config for now.
watertap/unit_models/electroNP_ZO.py
Outdated
) | ||
def default_solute_removal_equation(b, t, j): | ||
if hasattr(self.config.property_package.solute_set, "S_PO4"): | ||
return b.removal_frac_mass_comp[t, "S_PO4"] == 0.98 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably make a note to go over this with electroN-P team and get their take on whether we should be summing soluble nitrogen (e..g., NH4 + NH2 + NO3 as nitrogen) or if this should suffice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a note to remind us after we talk with electroN-P team.
for (t, p, j), v in self.solute_removal_equation.items(): | ||
iscale.constraint_scaling_transform( | ||
v, | ||
iscale.get_scaling_factor( | ||
self.properties_in[t].get_material_flow_terms(p, j), | ||
default=1, | ||
warning=True, | ||
hint=" for solute removal", | ||
), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might not need these scaling transforms if we fix the variables and not build as constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still keep the variables for now.
m.fs.unit.inlet.alkalinity[0].fix(61 / 12 * units.mmol / units.liter) | ||
|
||
# Unit option | ||
m.fs.unit.energy_electric_flow_mass.fix(0.044 * units.kWh / units.kg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something just came to mind- we can probably later convert this model to not only focus on ZO formulation. Instead, we could consider having config options would would select between fixed performance or predictive performance from surrogates. In ZO config, removal fractions, etc., would just be fixed to variables, while in predictive mode, the constraint would be activated and the surrogate would be inserted there. Just food for thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a good idea, we could upgrade this model to be a surrogate modle with config option to choose, and I believe I can save a lot of time for building some basic vairables. I still name it as electroNP_ZO for now but would consider to rename it when we add the surrogate model.
Co-authored-by: Adam Atia <aatia@keylogic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made one more small comment, but otherwise LGTM
Fixes/Resolves:
Add a electroNP ZO model compatible with ASM2d
Summary/Motivation:
Changes proposed in this PR:
Legal Acknowledgement
By contributing to this software project, I agree to the following terms and conditions for my contribution: