Add support for isothermal conditions in control volumes.#1558
Add support for isothermal conditions in control volumes.#1558andrewlee94 merged 15 commits intoIDAES:mainfrom
Conversation
Co-authored-by: Adam Atia <[email protected]>
| return ( | ||
| b.properties[t, b.length_domain.prev(x)].temperature | ||
| == b.properties[t, x].temperature |
There was a problem hiding this comment.
It looks like the constraint would be skipped at the outlet when using forward scheme, but what does this mean for temperature at the outlet?
There was a problem hiding this comment.
Actually, most of this is not needed as there is no partial derivative. The way this is written, it has to skip the first point no matter what.
There was a problem hiding this comment.
I might be misunderstanding, but as written, it appears that for backwards transformation, temperature at the inlet (x=0) would be set equal to the temperature of the next element, and this equality would be propagated across adjacent pairs for the whole length domain. So the temperature for each element would be covered.
However, for the forward transformation case, it seems that all elements except the last element would be covered by the equality constraint.
There was a problem hiding this comment.
OK, now I think the issue is fixed.
There was a problem hiding this comment.
Can we also rename enthalpy_balances to isothermal_constraint or something here?
| m.fs = Flowsheet(dynamic=False) | ||
| m.fs.pp = PhysicalParameterTestBlock() | ||
| m.fs.rp = ReactionParameterTestBlock(property_package=m.fs.pp) | ||
| m.fs.pp.del_component(m.fs.pp.phase_equilibrium_idx) |
There was a problem hiding this comment.
Why is this necessary?
| m.fs.pp.del_component(m.fs.pp.phase_equilibrium_idx) | |
| m.fs.pp.del_component(m.fs.pp.phase_equilibrium_idx) |
There was a problem hiding this comment.
It isn't - just left over from copying an old test (where it was likely not needed either).
| == m.fs.cv.properties_out[t].temperature | ||
| ) | ||
|
|
||
| assert_units_consistent(m.fs.cv) |
There was a problem hiding this comment.
Interesting- I thought I remember the units check failing for dynamic cases, or is that only when has_holdup=True as well?
There was a problem hiding this comment.
It will fail for anything with a partial derivative. Here we get aways with it because we don't have a derivative.
There was a problem hiding this comment.
Not necessarily. Generally for spatial domains we normalize the ContinuousSet to run from 0 to 1, adding in the flow length later. Those should pass. Any ContinuousSet with dimensions, however, will cause it to fail.
| ConfigurationError, | ||
| match="fs.cv: isothermal energy balance option requires that has_heat_transfer is False. " | ||
| "If you are trying to solve for heat duty to achieve isothermal operation, please use " | ||
| "a full energy balance as add a constraint to equate inlet and outlet temperatures.", |
There was a problem hiding this comment.
This error message needs some revision: "a full energy balance as add a constraint to equate inlet and outlet temperatures."
| ConfigurationError, | ||
| match="fs.cv: isothermal energy balance option requires that has_work_transfer is False. " | ||
| "If you are trying to solve for work under isothermal operation, please use " | ||
| "a full energy balance as add a constraint to equate inlet and outlet temperatures.", |
There was a problem hiding this comment.
Same issue- just need to revise this segment of the error message and propagate through.
| m.fs.cv.add_isothermal_constraint() | ||
|
|
||
| assert isinstance(m.fs.cv.enthalpy_balances, Constraint) | ||
| assert len(m.fs.cv.enthalpy_balances) == 1 # x==0 is skipped |
There was a problem hiding this comment.
I thought the length of enthalpy_balances would be fine_elements - 1. Maybe I am missing something (or the test is failing).
There was a problem hiding this comment.
The model has not been discretised, so there are only 2 points.
There was a problem hiding this comment.
Oh! I see now. Didn't catch that--didn't apply transformation.
| m.fs.cv.add_isothermal_constraint() | ||
|
|
||
| assert isinstance(m.fs.cv.enthalpy_balances, Constraint) | ||
| assert len(m.fs.cv.enthalpy_balances) == 4 # x==0 is skipped |
There was a problem hiding this comment.
Similarly, would expect this to be of length equal to (finite_elements - 1) * len(time_set)
There was a problem hiding this comment.
It is, it is just (2-1)*4 = 4.
There was a problem hiding this comment.
finite elements=10 not 2 here
There was a problem hiding this comment.
OK, just saw your previous response. Any reason not to apply transformation and check?
There was a problem hiding this comment.
Reduce test overhead.
There was a problem hiding this comment.
Could be good just to do a transformation with, say, 3 finite elements.
There was a problem hiding this comment.
I debated it, but decided that was as much a test of Pyomo functionality as of IDAES (and thus I was going to trust Pyomo).
There was a problem hiding this comment.
I realised there is a reason to test this, but not for the obvious reason - when using the domain.prev() method it works on the domain as it appears at the time of the call, meaning that it will always create T[0, 0] == T[0, 1] and then fill in intermediate points. In this case, it should not matter, but it needs to be tested.
adam-a-a
left a comment
There was a problem hiding this comment.
LGTM - I don't think it would hurt too much to add a test with transformation applied to 1d CV (with 2 - 3 finite elements), but I'll leave that to other reviewers and @andrewlee94
dallan-keylogic
left a comment
There was a problem hiding this comment.
Some minor changes, otherwise it looks good.
| has_heat_of_reaction=False, | ||
| has_heat_transfer=False, | ||
| has_work_transfer=False, | ||
| has_enthalpy_transfer=False, | ||
| custom_term=None, |
There was a problem hiding this comment.
Should we add Type Hints here?
There was a problem hiding this comment.
Might as well - if we don't do it now it probably won't get done.
| @self.Constraint(self.flowsheet().time, doc="Energy balances") | ||
| def enthalpy_balances(b, t): | ||
| return b.properties_in[t].temperature == b.properties_out[t].temperature |
There was a problem hiding this comment.
Can we rename this constraint to something that better describe what it does? Otherwise you might, for example, get enthalpy scaling on a constraint that should have temperature scaling.
There was a problem hiding this comment.
I debated whether the change the name - my reason for keeping it the same was for consistency of naming between different configurations (so that the "energy balance" would always have the same name no matter what option you chose).
However, I did not think about scaling, and having a descriptive name would be far more useful there for people doing custom scaling. I'll change it.
| return ( | ||
| b.properties[t, b.length_domain.prev(x)].temperature | ||
| == b.properties[t, x].temperature |
There was a problem hiding this comment.
Can we also rename enthalpy_balances to isothermal_constraint or something here?
dallan-keylogic
left a comment
There was a problem hiding this comment.
A few more documentation quibbles.
| `enthalpy_balances(t)`: | ||
|
|
||
| .. math:: T_{in, t} == T_{out, t} |
There was a problem hiding this comment.
This is now outdated
| `enthalpy_balances(t)`: | ||
|
|
||
| .. math:: T_{t, x-1} == T_{t, x} |
| Method should accept time and phase list as arguments. | ||
|
|
||
| Returns: | ||
| Constraint object representing enthalpy balances |
There was a problem hiding this comment.
Might be good to update this to reflect isothermal constraint.
| Method should accept time and phase list as arguments. | ||
|
|
||
| Returns: | ||
| Constraint object representing enthalpy balances |
There was a problem hiding this comment.
Might be good to update this to reflect isothermal constraint.
Fixes None
Summary/Motivation:
WateTAP has a number of cases where they would like to use isothermal conditions in place of an energy balance. Currently, they use a mix-in to support this, but this adds an addition argument that is effectively redundant. Instead, it would be better to have explicit support for isothermal conditions as part of the core ControlVolume classes.
However, isothermal conditions do not make sense for all unit models, and there are a few cases where unit models have effectively implemented their own isothermal conditions (notable PressureChanger). Thus, to avoid potential edge cases in unit models until they can be updated, a new ExtendedControlVolume0D and ExtenededControlVolume1D class have been created as an interim solution. It is envisioned that unit models will gradually be updated to be more explicit about what balance types make sense, at which point the new and old control volumes can be merged.
Changes proposed in this PR:
isothermaloption toEnergyBalanceTypeEnum.BalanceTypeNotSupportedexceptions toControlVolume0DandControlVolume1Difisothermaloption is selected, with pointer to the new control volume classes.ExtendedControlVolume0DandExtendedControlVolume1Dclasses with support for isothermal balances.Legal Acknowledgement
By contributing to this software project, I agree to the following terms and conditions for my contribution: