Scaling Methods#

Note

In v2.0, IDAES is beginning to deploy a new suite of scaling tools. This documentation refers to the older scaling tools. For documentation of the new scaling toolbox, see here.

This section describes scaling utility functions and methods.

Context#

Creating well scaled models is important for increasing the efficiency and reliability of solvers. Depending on property package units of measure and process scale, variables and constraints are often badly scaled.

Scaling factors can be specified for any variable or constraint. Pyomo and many solvers support the scaling_factor suffix. To eliminate the possibility of defining conflicting scaling factors in various places in the model, the IDAES standard is to define the scaling_factor suffixes in the same block as the variable or constraint that they are scaling. This ensures that each scale factor is defined in only one place, and is organized based on the model block structure.

Scaling factors in IDAES (and Pyomo) are multiplied by the variable or constraint they scale. For example, a Pressure variable in Pa units may be expected to have a magnitude of around \(10^6\) for a specific process. To scale the variable to a more reasonable magnitude, the scale factor for the variable could be defined to be \(1 \times 10^{-5}\).

While many scaling factors should be give good default values in the property packages, some (e.g. flow rates or material holdups) must be given scale factors by the user for a specific process model. Still other scale factors can be calculated from supplied scale factors, for example, mass balance scale factors could be determined from flow rate scale factors. To calculate scale factors, models may have a standard calculate_scaling_factors() method. For more specific scaling information, see the model documentation.

For much of the core IDAES framework, model constraints are automatically scaled via a simple transformation where both sides of the constraint are multiplied by a scale factor determined based on supplied variable and expression scaling factors. The goal of this is to ensure that solver tolerances are meaningful for each constraint. A constraint violation of \(1 \times 10^{-8}\) should be acceptable, but not too tight to achieve given machine precision limits. IDAES model constraints should conform approximately to this guideline after the calculate_scaling_factors() method is executed. Users should follow this guideline for constraints they write. The scaling of constraints for reasonable residual tolerances is done as a constraint transformation independent of the scaling factor suffix. Scaling factors for constraints can still be set based on other methods such as reducing very large Jacobian matrix entries.

Specifying Scaling#

Suffixes are used to specify scaling factors for IDAES models. These suffixes are created when needed by calling the set_scaling_factor() function. Using the set_scaling_factor(), get_scaling_factor(), and unset_scaling_factor() eliminates the need to deal directly with scaling suffixes, and ensures that scaling factors are stored in the IDAES standard location.

idaes.core.util.scaling.set_scaling_factor(c, v, data_objects=True, overwrite=True)[source]

Set a scaling factor for a model component. This function creates the scaling_factor suffix if needed.

Parameters:
  • c – component to supply scaling factor for

  • v – scaling factor

  • data_objects – set scaling factors for indexed data objects (default=True)

  • overwrite – whether to overwrite an existing scaling factor

Returns:

None

idaes.core.util.scaling.get_scaling_factor(c, default=None, warning=False, exception=False, hint=None)[source]

Get a component scale factor.

Parameters:
  • c – component

  • default – value to return if no scale factor exists (default=None)

  • warning – whether to log a warning if a scaling factor is not found (default=False)

  • exception – whether to raise an Exception if a scaling factor is not found (default=False)

  • hint – (str) a string to add to the warning or exception message to help locate the source.

Returns:

scaling factor (float)

idaes.core.util.scaling.unset_scaling_factor(c, data_objects=True)[source]

Delete a component scaling factor.

Parameters:

c – component

Returns:

None

Constraint Transformation#

As mentioned previously, constraints in the IDAES framework are transformed such that \(1 \times 10^{-8}\) is a reasonable criteria for convergence before any other scaling factors are applied. There are a few utility functions for scaling transformation of constraints. When transforming constraints with these functions, the scaling applies to the original constraint, not combined with any previous transformation.

idaes.core.util.scaling.constraint_scaling_transform(c, s, overwrite=True)[source]#

This transforms a constraint by the argument s. The scaling factor applies to original constraint (e.g. if one where to call this twice in a row for a constraint with a scaling factor of 2, the original constraint would still, only be scaled by a factor of 2.)

Parameters:
  • c – Pyomo constraint

  • s – scale factor applied to the constraint as originally written

  • overwrite – overwrite existing scaling factors if present (default=True)

Returns:

None

idaes.core.util.scaling.constraint_scaling_transform_undo(c)[source]#

The undoes the scaling transforms previously applied to a constraint.

Parameters:

c – Pyomo constraint

Returns:

None

idaes.core.util.scaling.get_constraint_transform_applied_scaling_factor(c, default=None)[source]#

Get a the scale factor that was used to transform a constraint.

Parameters:
  • c – constraint data object

  • default – value to return if no scaling factor exists (default=None)

Returns:

The scaling factor that has been used to transform the constraint or the default.

Calculation in Model#

Some scaling factors may also be calculated by a call to a model’s calculate_scaling_factors() method. For more information see specific model documentation.

Sometimes a scaling factor may be set on an indexed component and prorogated to it’s data objects later can be useful for example in models that use the DAE transformation, not all data objects exist until after the transformation.

idaes.core.util.scaling.propagate_indexed_component_scaling_factors(blk, typ=None, overwrite=False, descend_into=True)[source]#

Use the parent component scaling factor to set all component data object scaling factors.

Parameters:
  • blk – The block on which to search for components

  • typ – Component type(s) (default=(Var, Constraint, Expression, Param))

  • overwrite – if a data object already has a scaling factor should it be overwrittten (default=False)

  • descend_into – descend into child blocks (default=True)

Constraint Auto-Scaling#

Constraints can be scaled to automatically reduce very large entries in the Jacobian matrix with the constraint_autoscale_large_jac() function.

idaes.core.util.scaling.constraint_autoscale_large_jac(m, ignore_constraint_scaling=False, ignore_variable_scaling=False, max_grad=100, min_scale=1e-06, no_scale=False, equality_constraints_only=False)[source]#

Automatically scale constraints based on the Jacobian. This function imitates Ipopt’s default constraint scaling. This scales constraints down to avoid extremely large values in the Jacobian. This function also returns the unscaled and scaled Jacobian matrixes and the Pynumero NLP which can be used to identify the constraints and variables corresponding to the rows and comlumns.

Parameters:
  • m – model to scale

  • ignore_constraint_scaling – ignore existing constraint scaling

  • ignore_variable_scaling – ignore existing variable scaling

  • max_grad – maximum value in Jacobian after scaling, subject to minimum scaling factor restriction.

  • min_scale – minimum scaling factor allowed, keeps constraints from being scaled too much.

  • no_scale – just calculate the Jacobian and scaled Jacobian, don’t scale anything

  • equality_constraints_only – Include only the equality constraints in the Jacobian

Returns:

unscaled Jacobian CSR from, scaled Jacobian CSR from, Pynumero NLP

Inspect Scaling#

Models can be large, so it is often difficult to identify where scaling is needed and where the problem may be poorly scaled. The functions below may be helpful in inspecting a models scaling. Additionally constraint_autoscale_large_jac() described above can provide Jacobian information at the current variable values.

idaes.core.util.scaling.extreme_jacobian_columns(m=None, scaled=True, large=10000.0, small=0.0001, jac=None, nlp=None)[source]

Show very large and very small Jacobian columns. A more reliable indicator of a badly-scaled variable than badly_scaled_var_generator.

Parameters:
  • m – model

  • scaled – if true use scaled Jacobian

  • large – >= to this value is considered large

  • small – <= to this is considered small

Returns:

(list of tuples), Column norm, Variable

idaes.core.util.scaling.extreme_jacobian_rows(m=None, scaled=True, large=10000.0, small=0.0001, jac=None, nlp=None)[source]

Show very large and very small Jacobian rows. Typically indicates a badly- scaled constraint.

Parameters:
  • m – model

  • scaled – if true use scaled Jacobian

  • large – >= to this value is considered large

  • small – <= to this is considered small

Returns:

(list of tuples), Row norm, Constraint

idaes.core.util.scaling.badly_scaled_var_generator(blk, large=10000.0, small=0.001, zero=1e-10, descend_into=True, include_fixed=False)[source]

This provides a rough check for variables with poor scaling based on their current scale factors and values. For each potentially poorly scaled variable it returns the var and its current scaled value.

Note that while this method is a reasonable heuristic for non-negative variables like (absolute) temperature and pressure, molar flows, etc., it can be misleading for variables like enthalpies and fluxes.

Parameters:
  • blk – pyomo block

  • large – Magnitude that is considered to be too large

  • small – Magnitude that is considered to be too small

  • zero – Magnitude that is considered to be zero, variables with a value of zero are okay, and not reported.

Yields:

variable data object, current absolute value of scaled value

idaes.core.util.scaling.unscaled_variables_generator(blk, descend_into=True, include_fixed=False)[source]

Generator for unscaled variables

Parameters:

block

Yields:

variables with no scale factor

idaes.core.util.scaling.unscaled_constraints_generator(blk, descend_into=True)[source]

Generator for unscaled constraints

Parameters:

block

Yields:

constraints with no scale factor

idaes.core.util.scaling.map_scaling_factor(components, default=1, warning=False, func=<built-in function min>, hint=None)[source]#

Map get_scaling_factor to an iterable of Pyomo components, and call func on the result. This could be use, for example, to get the minimum or maximum scaling factor of a set of components.

Parameters:
  • components – Iterable yielding Pyomo components

  • default – The default value used when a scaling factor is missing. The default is default=1.

  • warning – Log a warning for missing scaling factors

  • func – The function to call on the resulting iterable of scaling factors. The default is min().

  • hint – Paired with warning=True, this is a string to indicate where the missing scaling factor was being accessed, to easier diagnose issues.

Returns:

The result of func on the set of scaling factors

idaes.core.util.scaling.min_scaling_factor(components, default=1, warning=True, hint=None)[source]#

Map get_scaling_factor to an iterable of Pyomo components, and get the minimum scaling factor.

Parameters:
  • iter – Iterable yielding Pyomo components

  • default – The default value used when a scaling factor is missing. If None, this will raise an exception when scaling factors are missing. The default is default=1.

  • warning – Log a warning for missing scaling factors

  • hint – Paired with warning=True, this is a string to indicate where the missing scaling factor was being accessed, to easier diagnose issues.

Returns:

Minimum scaling factor of the components in iter

idaes.core.util.scaling.get_jacobian(m, scaled=True, equality_constraints_only=False)[source]#

Get the Jacobian matrix at the current model values. This function also returns the Pynumero NLP which can be used to identify the constraints and variables corresponding to the rows and columns.

Parameters:
  • m – model to get Jacobian from

  • scaled – if True return scaled Jacobian, else get unscaled

  • equality_constraints_only – Only include equality constraints in the Jacobian calculated and scaled

Returns:

Jacobian matrix in Scipy CSR format, Pynumero nlp

idaes.core.util.scaling.jacobian_cond(m=None, scaled=True, order=None, pinv=False, jac=None)[source]

Get the condition number of the scaled or unscaled Jacobian matrix of a model.

Parameters:
  • m – calculate the condition number of the Jacobian from this model.

  • scaled – if True use scaled Jacobian, else use unscaled

  • order – norm order, None = Frobenius, see scipy.sparse.linalg.norm for more

  • pinv – Use pseudoinverse, works for non-square matrices

  • jac – (optional) previously calculated Jacobian

Returns:

(float) Condition number

Applying Scaling#

Scale factor suffixes can be passed directly to a solver. How the scale factors are used may vary by solver. Pyomo also contains tools to transform a problem to a scaled version.

Ipopt is the standard solver in IDAES. To use scale factors with Ipopt, the nlp_scaling_method option should be set to user-scaling. Be aware that this deactivates any NLP automatic scaling.