1. 29 Apr, 2019 9 commits
  2. 09 Apr, 2019 7 commits
    • Tjerk Vreeken's avatar
      Add mixin to linearize goal order · 6d5cc07d
      Tjerk Vreeken authored
      For some problems it is preferred to not introduce any non-linear terms in
      the objective. For example, when using a MILP solver, one wants the entire
      problem to remain linear. This sometimes clashed with the desire for an
      order 2 goal, which steers the solution in the direction of many small
      exceedences instead of one large exceedence. An order 1 goal does not
      distuinguish between the two.
      
      This commit adds functionality to linearly approximate the goal order.
      That way, one can keep the problem fully linear, why getting some of the
      benefits of higher order goals back.
      
      By default, all goals will be linearized when inheriting from
      LinearizedOrderGPMixin. This behavior can also be overridden by setting
      `linearize_goal_order` to False in goal_programming_options(). The
      linearization can also be controlled on the level of a goal by making a
      goal inherit from LinearizedOrderGoal and setting `linearize_order` to
      either True or False.
      
      Typical use-cases for this fine-grained control are:
      - `linearize_goal_order` is True (default) to avoid a QP problem turning
        into a QCP problem when `keep_soft_constraints` is set. The last
        priority can however be solved as a QP problem (instead of LP), because
        this quadratic objective will _not_ turn into a constraint.
      - For performance reasons, one might want to linearize specific higher
        order goals, but keep others as-is.
      
      Aside from solvers which only handle LP and not QP, using a linearly
      approximated goal order is also useful when `keep_soft_constraints` is
      set. A quadratic problem in priority 1 would mean a quadratically
      _constrained_ problem in priority 2 with that option, something that can
      be much harder to solve.
      
      Note that higher order minimization goals do not work cannot be
      linearized. This is because a function range is lacking over which to
      linearize. Instead, users are requested to give these minimization goals
      e.g. a target_min = target_max = 0.0 (and a proper function range), such
      that they can be linearized. Minimization goals with order 1 are
      supported, as they do not have to be linearized.
      6d5cc07d
    • Tjerk Vreeken's avatar
    • Tjerk Vreeken's avatar
      Support absolute goal order for minimization goals · f17773e2
      Tjerk Vreeken authored
      One would typically use order=2 to minimize the absolute value of the goal
      function, but that makes nominals a bit harder and easily leads to scaling
      issues. A more involved option commonly used by users is to introduce an
      auxiliary variable and additional constraints to minimize the absolute
      value of the goal function.
      
      It is the latter logic that this commit adds to a new mixin, such that
      the user now only has to instantiate an "MinAbsGoalProgrammingMixin"
      instance. The auxiliary variable and accompanying constraints are
      automatically added behind the scenes.
      
      Closes #1065
      f17773e2
    • Tjerk Vreeken's avatar
      Allow nominals for path and extra variables · 7a7e954b
      Tjerk Vreeken authored
      Up until now, we required the user to properly scale their additional
      path and extra variables. In practice this meant that the user had to
      multiply the variable with its nominal in every constraint where they
      were using it, and also when extracting the results.
      
      This commit adds support for nominals for path and extra variables, such
      that this process is no longer required. These variables can now be
      used and scaled in the same way that variables from the Modelica model
      are.
      
      Closes #1063
      7a7e954b
    • Tjerk Vreeken's avatar
      Make tests faster by skipping Modelica libraries · c30319b6
      Tjerk Vreeken authored
      A lot of time was spent in Pymoca's transfer_model to compile the model.
      That is because since d1bc9d42 we have RTC-Tools Channel Flow as a
      dependency, so we would parse its entire library again for every model.
      
      The RTC-Tools tests do not need any RTC-Tools Channel Flow components
      (or other libraries for that matter), only the examples do. Therefore,
      we can explicitly disable additional library folders using the
      compiler_options() method to make compilation of a model much faster.
      c30319b6
    • Tjerk Vreeken's avatar
      CollInt: Explicitly disallow nominals for path and extra variables · 4113297a
      Tjerk Vreeken authored
      If one specifies a nominal not equal to 1.0 for a path variable, the
      bounds and the seed of this variable will be scaled wrong. For extra
      variables, a nominal is simply ignored, which may be confusing in itself
      when trying to properly scale a problem.
      
      We therefore now explicitly disallow nominals for path variables by
      raising an exception to prevent inconsistently applied scaling. For
      extra variables we warn the user that their nominals will be ignored.
      4113297a
    • Tjerk Vreeken's avatar
      GPMixin: Fix wrong IPOPT option when using minimization goals · c34903cc
      Tjerk Vreeken authored
      We check if the DAE (the set of equality constraints) is linear, and tell
      IPOPT if we find that is the case for performance reasons. Any user added
      equality constraints are assumed to be linear as well, but for those added
      by GoalProgrammingMixin for minimization goals that is not necessarily the
      case. We should therefore make sure to _not_ tell IPOPT that it can assume
      the equality constraints to be linear when adding such a constraint.
      
      Note that this only applies when `fix_minimized_values` is set to True
      (which is the default for IPOPT/BONMIN, but not for other solvers), and
      the user is using `keep_soft_constraints` or has a minimization goal in
      any but the last priority.
      
      Closes #1103
      c34903cc
  3. 08 Apr, 2019 1 commit
    • Tjerk Vreeken's avatar
      CollInt: Fix RuntimeError for underspecified CasADi Function · c824c1bb
      Tjerk Vreeken authored
      Regression introduced in cab3c6ac. When expanding a CasADi function, one
      needs to be sure that all variables in the output are listed as inputs.
      For CasADi 3.4.5, not doing this would result in random other input
      symbols being used for the missing ones. For CasADi 3.5+ (not yet
      released at time of this commit), a RuntimeError is raised.
      
      As we do not want to calculate the affinity of the DAE w.r.t. the
      parameters and constant inputs, we get rid of them before checking.
      Before commit cab3c6ac, the values with which they were substituted was
      effectively 0.0. Now, we use random values between 0 and 1 for a
      slightly better check.
      
      Note that the affinity check has always been imperfect, and still is
      (even with the random values). It is likely the check will be deprecated
      in the future, to be replaced with an optional (default off) check on
      the _entire_ optimization problem.
      
      Closes #1096
      c824c1bb
  4. 05 Apr, 2019 1 commit
    • Tjerk Vreeken's avatar
      PIMixin: Fix overriding initial state values · 391502da
      Tjerk Vreeken authored
      If a user was using ModelicaMixin and PIMixin, the initial state values
      from ModelicaMixin were skipped. We have to be sure to call the respective
      super() method. Note that CSVMixin's initial_state() also calls super().
      
      Also note that ModelicaMixin's initial_state() does not call super(), to
      avoid getting stuck in an endless loop due to OptimizationProblem's
      implementation of initial_state() and history(). This is a separate bug,
      which cannot easily be addressed without significantly refactoring the way
      history and initial states are stored.
      
      Closes #1110
      391502da
  5. 04 Apr, 2019 5 commits
  6. 19 Mar, 2019 1 commit
    • Tjerk Vreeken's avatar
      Revert "CollInt: Fix missing parameter check to include NaN" · 542c5216
      Tjerk Vreeken authored
      This reverts commit 038975e7.
      
      There are many models that have parameters that are not used. For
      example, species transport in RTC-Tools Channel Flow might use a
      "V_nominal" for linearization, but if there are no species this
      parameter is never used.
      
      We would rather like to check on parameters that are actually used, but
      that would be an expensive check to always perform for every run. It is
      probably better to put a check like that behind an optional flag for
      performing such checks.
      542c5216
  7. 15 Mar, 2019 13 commits
    • Tjerk Vreeken's avatar
      pi.py: Fix duplicating read units for all ensembles · c7985d80
      Tjerk Vreeken authored
      When we duplicate variables over all ensemble members, we should not
      only copy the values but also the unit.
      c7985d80
    • Tjerk Vreeken's avatar
      pi.py: Fix duplicating read values for all ensembles · 4280c608
      Tjerk Vreeken authored
      When an ensemble member is not specified for a certain variable in the
      input, we want to add the same variable-values pair to all ensembles.
      The loop that was supposed to do this was a no-op, as it used
      `ensemble_member` (which is zero in this case), instead of the loop
      index.
      
      Note that we remove the underscore prefix that indicated that the loop
      index was unused.
      4280c608
    • Tjerk Vreeken's avatar
      pi.py: Fix set variable for more than ensemble member · 698720a6
      Tjerk Vreeken authored
      We would encounter an IndexError when trying to set a variable for an
      ensemble member other than zero, because self.__units was not properly
      (re)initialized for all ensemble members.
      698720a6
    • Tjerk Vreeken's avatar
      Annotate AliasDict element types in API · 1fb30470
      Tjerk Vreeken authored
      For dictionaries and lists we typically indicate what the type of the
      elements are, but this was not yet possible for the commonly used
      AliasDict class.
      
      This commit adds type annotation support to the AliasDict class, and
      also clarifies the API with the correct element types in all places that
      an AliasDict is expected or returned.
      1fb30470
    • Tjerk Vreeken's avatar
      CollInt: Remove unnecessary resolving of initial values · 55faee67
      Tjerk Vreeken authored
      The methods history() and initial_state() do not return symbolic values,
      and resolving of these values is therefore not needed in
      CollocatedIntegratedOptimizationProblem. For symbolic initial state
      values from the model, we make sure to resolve them right away in
      ModelicaMixin.
      
      The code that we remove/change in this commit was a remainder of the
      JModelica era, where resolving with parameter values was not done in
      ModelicaMixin.
      
      Note that, depending on the completeness of the history data, initial
      derivatives can be a function of the (symbolic) initial state. They are
      however not not a function of e.g. symbolic parameters.
      55faee67
    • Tjerk Vreeken's avatar
      CollInt: Remove unnecessary resolving of constant inputs · 988042a4
      Tjerk Vreeken authored
      The method constant_inputs() returns Timeseries, which cannot be
      symbolic. Resolving of these values is therefore not needed in this
      class. For symbolic constant inputs from a Modelica model we make sure
      to resolve them in ModelicaMixin.
      
      The code that we remove/change in this commit was a remainder of the
      JModelica era, where resolving of symbolic expressions with parameter
      values was not done in ModelicaMixin.
      988042a4
    • Tjerk Vreeken's avatar
      CollInt: Remove unnecessary resolving of bounds · 63bf9cb2
      Tjerk Vreeken authored
      The method bounds() does not return symbolic values, and resolving of
      these values is therefore not needed in this class. For symbolic bounds
      from a Modelica model we make sure to resolve them in ModelicaMixin.
      
      The code that we remove/change in this commit was a remainder of the
      JModelica era, where resolving of symbolic expressions with parameter
      values was not done in ModelicaMixin.
      63bf9cb2
    • Tjerk Vreeken's avatar
      CollInt: Fix missing parameter check to include NaN · 038975e7
      Tjerk Vreeken authored
      Instead of only checking for missing parameters, we check for NaN as
      well. This is because ModelicaMixin sets all parameters to their
      respective values, even if they have no value set (=NaN).
      038975e7
    • Tjerk Vreeken's avatar
      ModelicaMixin: Fix symbolic parameter substitution checks · 133e8be2
      Tjerk Vreeken authored
      If not all parameters that occur in a symbolic expression are specified,
      it can either result in a (still) symbolic expression, or NaN. We
      checked the former, but did not yet check the latter.
      
      Note that the reason that expressions result in NaN is because some of
      the parameters are NaN. This in turn is caused by ModelicaMixin not
      skipping parameters in the model for which a value is not set (NaN).
      133e8be2
    • Tjerk Vreeken's avatar
      ModelicaMixin: Remove useless constant_inputs() implementation · 9f52be89
      Tjerk Vreeken authored
      If a constant input is given a default value in the Modelica model,
      Pymoca will turn this assignment into an equation. All constant inputs
      (and control inputs), whether they have been given a default value or
      not in the Modelica model, will therefore have a value attribute equal
      to NaN.
      
      Note that this means we also cannot (easily) detect if a value has been
      given to a constant input in the Modelica file. If a user gives the same
      constant input another value in RTC-Tools, the system of equations could
      become infeasible.
      9f52be89
    • Tjerk Vreeken's avatar
      ModelicaMixin: Fix reading of symbolic initial states · 3213fc10
      Tjerk Vreeken authored
      The initial_state() method has to return a numeric value. For symbolic
      initial state that means that we need to substitute the parameters, just
      like e.g. bounds() and seed() already did.
      
      Note that, unlike e.g. the seed() method in ModelicaMixin, we raise an
      exception if the symbolic expression cannot be resolved. This is because
      a wrong/missing initial state is worse than a wrong seed value.
      3213fc10
    • Tjerk Vreeken's avatar
    • Tjerk Vreeken's avatar
      ModelicaMixin: Fix reading of symbolic start attributes · 3e4fbba1
      Tjerk Vreeken authored
      Regression in 10da03cb. Only for SX symbols does a symbolic expression
      turn into a NaN. For symbolic MX expressions a RuntimeError is raised.
      
      We also have to do the Python type conversion on the _substituted_
      value, not the original MX value (which will result in a RuntimeError).
      
      Lastly, if we cannot resolve the seed value, we should continue to the
      next symbol instead of still setting the seed.
      3e4fbba1
  8. 27 Feb, 2019 1 commit
    • Tjerk Vreeken's avatar
      Timeseries: Fix constructor for ca.DM and support float arguments · 2199c96f
      Tjerk Vreeken authored
      According to the typing hints, a ca.DM should have been supported, but
      it would fail with an Exception because it does not support len().
      
      Furthermore, the code in the constructor seemed to suggest support for
      floats (and integers), due to the "np.full_like" branch. The typing
      hints did however not cover this, and neither did it work in practice
      because of the len() call.
      2199c96f
  9. 25 Feb, 2019 1 commit
    • Tjerk Vreeken's avatar
      GPMixin: Fix Exception when target min or max empty Timeseries · 053baa9a
      Tjerk Vreeken authored
      If target_min and target_max are both empty Timeseries (full of NaNs),
      the "is_empty" attribute is True and the Goal is skipped in its
      entirety. However, in case only one of the two targets is empty, we
      would get an Exception in CollInt due to setting an empty constraint of
      size MX(1x0).
      
      This bug was introduced in commit a788207e when support for vector goals
      was added. To make sure that results for a vector goal are exactly equal
      to its non-vector counterpart, the slicing of a (vector) soft constraint
      was added in the relevant section of code. This slicing did not account
      for the possibility of no element of the constraint expression being
      active.
      053baa9a
  10. 21 Feb, 2019 1 commit