idaes-pse icon indicating copy to clipboard operation
idaes-pse copied to clipboard

Time-indexed parameters and discretizing the time domain

Open dallan-keylogic opened this issue 2 years ago • 2 comments

While working on the SOEC project, we discovered a quirk of discretizing the time domain using pyomo.environ.TransformationFactory("dae.finite_difference"). When more finite elements are requested than can be supported by the flowsheet time_set, Pyomo creates new time points between the existing ones. However, even if a time-indexed Var was fixed for all time points prior to the discretization, it is not fixed at the new time points created. This created confusion, because more degrees of freedom were appearing beyond the designated "manipulated variables".

Two questions raised by this experience are:

  1. Is this even a problem?
  2. If so, is this an IDAES problem or a Pyomo problem?

Debugging degrees of freedom issues can be tedious and frustrating, so we want to have default behavior that makes sense for the majority of cases. We have several unit models, like the heat_exchanger_lc and heat_exchanger_1D, that have variables, in their case heat transfer coefficients, that are indexed by time but almost always treated as fixed parameters. A user could fix them at the time points that exist when creating the flowsheet, but if Pyomo creates more time points additional degrees of freedom will appear.

  • Is this a problem with the models? Should they not be indexing these variables by time (and space, in the case of the 1D exchanger) if they're going to be treated as constants? Should that be a config option instead? What about flowsheets with fixed boundary conditions (e.g., the composition of inlet air)? Mole fractions should be indexed by time, but would result in this behavior.
  • Should Pyomo be smart enough to see the variables fixed at an equal value for all time and fix the variables at the new time points created?
  • Should users be discretizing the flowsheet in time relatively early on? Should users not be depending on Pyomo to create these additional time points? How can we let users know that they shouldn't be doing that?
  • When creating a standalone dynamic flowsheet, should the method that creates the flowsheet also discretize it in time?

dallan-keylogic avatar Jun 10 '22 19:06 dallan-keylogic

My first response is that that is an expected behaviour in Pyomo and that users need to be aware of this. Simply put, Pyomo has no way of knowing that you want variables to be fixed when it creates them, so they are all unfixed by default. Users also need to be aware of how Pyomo fills in points in this case, as its approach is almost definitely what they want; I think Pyomo finds the largest interval in the current set of points and inserts a new point halfway between the existing points and then iterates. I.e. if you had a set of 5 evenly spaced points already and then did a transformation setting 5 finite elements (i.e. one extra point), it would not shift your existing points, but would add the new point halfway between points 0 and 1 (and thus an uneven distribution with 2 elements with half the original size followed by 3 points at the original size).

However, a few things I will note:

  • You generally shouldn't be fixing time indexed variable before the transformation is completed, precisely because of this.
  • If you are providing a set of points to the discretization, you have one of two cases: i) you are providing a limited set of point and expect Pyomo to fill them in (the general case) and thus shouldn't be fixing anything yet, or ii) you are providing and exhaustive set and end to make sure you match the number of points in the transformation.

TLDR: you need to complete model construction before you start trying to set DoF, etc. I.e., discretization of domains needs to happen early in the process (immediately after all models are constructed), and you should not set DoF until after that.

andrewlee94 avatar Jul 13 '22 17:07 andrewlee94

Alright, since it looks like the consensus choice is to discretize domains early, that has a couple of implications.

  1. Fixing variables must always be viewed as a fragile operation. When creating the SOEC, I wondered whether I should specify a no flux condition by adding the simple constraint
@self.Constraint(tset, iznodes)
            def no_heat_flux_fuel_interconnect_eqn(b, t, iz):
                return 0 == interconnect_heat_flux_x1[t, iz]

or whether I should interconnect_heat_flux_x1.fix(0). In light of this conversation, adding the constraint is the clear choice, and the task of trying to reduce the number of constraints should be done after the fact with an equality constraint eliminator. 2. When creating example dynamic flowsheets, discretization should be done while constructing the flowsheet, therefore necessitating the user specify the discretization ahead of time, either directly though tset or indirectly somehow.

dallan-keylogic avatar Jul 13 '22 17:07 dallan-keylogic

@dallan-keylogic Has this issue been resolved, or is it something on going (and if so, is it something for a specific release or should it become a discussion)?

andrewlee94 avatar Aug 18 '22 19:08 andrewlee94

I've pretty much decided that we need to discretize the time domain before anyone starts fixing variables. ~~This bears onto the current heat exchanger draft PR~~ (Edit: Not actually true), will try to finish a mini-review today.

dallan-keylogic avatar Aug 18 '22 19:08 dallan-keylogic

I'll close this for now, as it seems it is resolved.

andrewlee94 avatar Aug 25 '22 18:08 andrewlee94