Scaling Methods¶
This section describes scaling utility functions and methods.
Context¶
Creating well scaled models is important for increasing the efficiency and reliability of solvers. Since the standard units for IDAES are SI, oftentimes variables and constraints are considered badly scaled (values less than \(10^{-3}\) and greater than \(10^3\)).
Scaling factors can be specified for any variable or constraint. Pyomo and many
solvers support the scaling_factor
suffix. IDAES, as described below, also
supports the scaling_expression
suffix which can be used to calculate
scaling_factor
values (e.g. based on the scaling factors of other variables).
To eliminate the possibility of defining conflicting scaling factors in various
places in the model, the IDAES standard is to define the scaling_factor
and
scaling_expression
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 \(10^{-5}\).
Specifying Scaling¶
Suffixes are used to specify scaling factors for IDAES models.
To supply variable and constraint scaling factors, an export suffix called
scaling_factor
should be created in the same block as the variable or constraint.
Additionally, if the scaling factor for variables or constraints will be based on
other variables, a local suffix called scaling_expression
should be created.
Implementing Scaling¶
While some solvers, such as Ipopt, support scaling factors, Pyomo also supplies scaling transformations for models when solver scaling is not supported.
Neither Pyomo or other solvers use the IDAES scaling_expression
, so the scaling
expressions must be converted to scaling factors with the
calculate_scaling_factors(m, basis)
function. This function replaces the variables in
the scaling expression with the specified basis value, calculates the scaling factors,
and puts the scaling factor in the scaling_factor
suffix.
Specifically, for Ipopt, it is recommended to use the scale_constraints(m)
function
to scale the constraints before sending the model to the solver. To scale the variables, the user
must set the nlp_scaling_method
option to “user-scaling”.
Example¶
from pyomo.environ import Suffix, ConcreteModel, Var, NonNegativeReals, \
Constraint, Objective, SolverFactory
from idaes.core.util.scaling import (scale_constraints, ScalingBasis,
calculate_scaling_factors)
from math import isclose
# create badly scaled model
var_value_magnitude = 1e-12
m = ConcreteModel()
m.x = Var(initialize=var_value_magnitude, domain=NonNegativeReals)
m.y = Var(initialize=var_value_magnitude, domain=NonNegativeReals)
m.z = Var(initialize=var_value_magnitude ** 2, domain=NonNegativeReals)
m.c_1 = Constraint(expr=m.x + m.y <= var_value_magnitude)
m.c_2 = Constraint(expr=m.z == (m.x * m.y))
m.obj = Objective(expr=-m.z)
# create and specify scaling factors and expressions
m.scaling_factor = Suffix(direction=Suffix.EXPORT)
m.scaling_expression = Suffix(direction=Suffix.LOCAL)
# NOTE: the direction of the scaling_expression is LOCAL
m.scaling_factor[m.x] = 1 / var_value_magnitude
m.scaling_factor[m.y] = 1 / var_value_magnitude
m.scaling_factor[m.c_1] = 1 / var_value_magnitude
m.scaling_expression[m.z] = 1 / (m.x * m.y)
m.scaling_expression[m.c_2] = 1 / (m.x * m.y)
m.scaling_expression[m.obj] = 1 / (m.x * m.y)
# calculate scaling factors from scaling expression
calculate_scaling_factors(m, basis=ScalingBasis.InverseVarScale)
# scale constraints
scale_constraints(m)
# NOTE: After the constraints are scaled, their scaling factor and expression
# are set to 1.
# call solver with user-scaling option
solver = SolverFactory('ipopt')
solver.options = {'nlp_scaling_method': 'user-scaling'}
results = solver.solve(m, tee=False)
assert (isclose(m.z.value, (0.5 * var_value_magnitude) ** 2, rel_tol=1e-3))
Scaling Expression Basis¶
The general guideline for calculating scaling factors from scaling expressions is to use the expected magnitude of the variables. The magnitude could be estimated in different ways, but the IDAES standard is the inverse variable scale. The list below shows variable scaling bases that are provided.
- ScalingBasis.InverseVarScale:
- Use the inverse variable scaling factors in scaling expressions.
- ScalingBasis.Value:
- Use the current variable values in scaling expressions.
- ScalingBasis.Mid:
- Use the mid-point between the upper and lower bounds in scaling expressions.
- ScalingBasis.Lower:
- Use the lower bound of variables in scaling expressions.
- ScalingBasis.Upper:
- Use the lower bound of variables in scaling expressions.
- ScalingBasis.VarScale:
- This is less common, but it uses the variable scales directly. This can be used if you are using alternative scaling methods with divide by the scaling factor.
Scaling Utility Functions¶
IDAES includes some utility functions to help evaluate model scaling and to auto-scale constraints.
-
idaes.core.util.scaling.
badly_scaled_var_generator
(blk, large=10000.0, small=0.001, zero=1e-10)[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.
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.
grad_fd
(c, scaled=False, h=1e-06)[source]¶ Finite difference the gradient for a constraint, objective or named expression. This is only for use in examining scaling. For faster more accurate gradients refer to pynumero.
Parameters: - c – constraint to evaluate
- scaled – if True calculate the scaled grad (default=False)
- h – step size for calculating finite difference derivatives
Returns: (list of gradient values, list for variables in the constraint) The order of the variables corresponds to the gradient values.
-
idaes.core.util.scaling.
scale_single_constraint
(c)[source]¶ This transforms a constraint with its scaling factor. If there is no scaling factor for the constraint, the constraint is not scaled and a message is logged.
Parameters: c – Pyomo constraint Returns: None
-
idaes.core.util.scaling.
scale_constraints
(blk, descend_into=True)[source]¶ This scales all constraints with their scaling factor suffix for a model or block. After scaling the constraints, the scaling factor and expression for each constraint is set to 1 to avoid double scaling the constraints.
Parameters: - blk – Pyomo block
- descend_into – indicates whether to descend into the other blocks on blk.
- = True) ((default) –
Returns: None
-
idaes.core.util.scaling.
constraint_fd_autoscale
(c, min_scale=1e-06, max_grad=100)[source]¶ Autoscale constraints so that if there maximum partial derivative with respect to any variable is greater than max_grad at the current variable values, the method will attempt to assign a scaling factor to the constraint that makes the maximum derivative max_grad. The min_scale value provides a lower limit allowed for constraint scaling factors. If the calculated scaling factor to make the maximum derivative max_grad is less than min_scale, min_scale is used instead. Derivatives are approximated using finite difference.
Parameters: - c – constraint object
- max_grad – the largest derivative after scaling subject to min_scale
- min_scale – the minimum scale factor allowed
Returns: None