Summary
The function calculate_variable_from_constraint presently ignores bounds. "Small" bound violations frequently occur with solve_strongly_connected_components, which leads to an enormous amount of warnings in the solver logs. Should the behavior of calculate_variable_from_constraint be modified to clip variables to their bounds if doing so doesn't result in a "large" residual?
Rationale
When assisting a collaborator in using PrOMMiS, he mentioned that he was getting a ton of warnings. I had to show him an output log from a PrOMMiS example:
2026-05-26 15:11:43 [INFO] idaes.__main__: Initializing fs.solex_rougher_scrub
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].conc_mass_comp[Al]' to a
numeric value `-8.813627952784652e-08` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].conc_mol_comp[Al]' to a
numeric value `-3.266472030144476e-12` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].flow_mol_comp[Al]' to a
numeric value `-3.266484305264328e-13` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].conc_mass_comp[Ca]' to a
numeric value `-1.5760625470793493e-08` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].conc_mol_comp[Ca]' to a
numeric value `-3.9324758829293394e-13` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].flow_mol_comp[Ca]' to a
numeric value `-3.9324880157787234e-14` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].conc_mass_comp[Ce]' to a
numeric value `-3.6579450075327737e-07` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].conc_mol_comp[Ce]' to a
numeric value `-2.6106543788949036e-12` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
WARNING (W1002): Setting Var
'fs.solex_rougher_scrub.mscontactor.aqueous[0.0,1].flow_mol_comp[Ce]' to a
numeric value `-2.610654747936536e-13` outside the bounds (1e-30, None).
See also https://pyomo.readthedocs.io/en/stable/errors.html#w1002
2026-05-26 15:11:43 [INFO] idaes.init.fs.solex_rougher_scrub.mscontactor: Stream Initialization Completed.
2026-05-26 15:11:43 [INFO] idaes.init.fs.solex_rougher_scrub.mscontactor: Initialization Completed, optimal - <undefined>
and tell him to ignore all the warnings about setting variables to values outside of their bounds. It's problematic emit dozens of lines of warning messages for something that is typically not a problem, and it's also problematic that experienced users of IDAES+ ecosystem tools have learned to ignore warning messages as a matter of course.
We get these messages as a result of solve_strongly_connected_components calling calculate_variable_from_constraint, which does not take bounds into account.
Description
A simple solution would be for calculate_variable_from_constraint to clip variables back to their bounds if Newton's method terminates with a value outside of their bounds. If the constraint residual tolerance remains satisfied, the function can return without emitting any warnings. If the constraint residual tolerance is not satisfied, we can return to Newton's method. If the Newton step calculated would take the variable outside of its bounds again, then we can either reset to the value outside of its bounds that had a sufficiently small constraint residual or emit an exception.
If this method is deemed unsuitable for Pyomo, we could knock off calculate_variable_from_constraint in IDAES, modify it to use the above algorithm, and pass it to solve_strongly_connected_components as a 1x1 solver. Alternatively, we could capture all Pyomo output in the BlockTriangularizationInitializer and filter out those spurious warnings.
Additional information
This is related to point 4 in #3571. That issue deals with the problem on the solve_strongly_connected_components side, handling the ramifications of an infeasible solution in that method.
Summary
The function
calculate_variable_from_constraintpresently ignores bounds. "Small" bound violations frequently occur withsolve_strongly_connected_components, which leads to an enormous amount of warnings in the solver logs. Should the behavior ofcalculate_variable_from_constraintbe modified to clip variables to their bounds if doing so doesn't result in a "large" residual?Rationale
When assisting a collaborator in using PrOMMiS, he mentioned that he was getting a ton of warnings. I had to show him an output log from a PrOMMiS example:
and tell him to ignore all the warnings about setting variables to values outside of their bounds. It's problematic emit dozens of lines of warning messages for something that is typically not a problem, and it's also problematic that experienced users of IDAES+ ecosystem tools have learned to ignore warning messages as a matter of course.
We get these messages as a result of
solve_strongly_connected_componentscallingcalculate_variable_from_constraint, which does not take bounds into account.Description
A simple solution would be for
calculate_variable_from_constraintto clip variables back to their bounds if Newton's method terminates with a value outside of their bounds. If the constraint residual tolerance remains satisfied, the function can return without emitting any warnings. If the constraint residual tolerance is not satisfied, we can return to Newton's method. If the Newton step calculated would take the variable outside of its bounds again, then we can either reset to the value outside of its bounds that had a sufficiently small constraint residual or emit an exception.If this method is deemed unsuitable for Pyomo, we could knock off
calculate_variable_from_constraintin IDAES, modify it to use the above algorithm, and pass it tosolve_strongly_connected_componentsas a 1x1 solver. Alternatively, we could capture all Pyomo output in theBlockTriangularizationInitializerand filter out those spurious warnings.Additional information
This is related to point 4 in #3571. That issue deals with the problem on the
solve_strongly_connected_componentsside, handling the ramifications of an infeasible solution in that method.