Skip to content

Conversation

@dallan-keylogic
Copy link
Contributor

Summary/Motivation:

Changes scale_model to True in the .nl writer config to enable IDAES to take advantage of writer-time scaling. Additionally, Exceptions have been added when the user attempts to use set_scaling_factor on a constraint that has already been transformed using constraint_scaling_transform and, conversely, when the user attempts to use constraint_scaling_transform on a constraint which already has a scaling factor.

Legal Acknowledgement

By contributing to this software project, I agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the license terms described in the LICENSE.txt file at the top level of this directory.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

@dallan-keylogic dallan-keylogic added the CI:run-integration triggers_workflow: Integration label Aug 25, 2025
@idaes-build idaes-build removed the CI:run-integration triggers_workflow: Integration label Aug 25, 2025
@dallan-keylogic dallan-keylogic marked this pull request as ready for review August 25, 2025 15:43
@codecov
Copy link

codecov bot commented Aug 25, 2025

Codecov Report

❌ Patch coverage is 92.30769% with 2 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (scaling_toolbox@f9cf6d1). Learn more about missing BASE report.

Files with missing lines Patch % Lines
idaes/core/scaling/util.py 81.81% 0 Missing and 2 partials ⚠️
Additional details and impacted files
@@                Coverage Diff                 @@
##             scaling_toolbox    #1653   +/-   ##
==================================================
  Coverage                   ?   77.04%           
==================================================
  Files                      ?      395           
  Lines                      ?    63939           
  Branches                   ?    10512           
==================================================
  Hits                       ?    49264           
  Misses                     ?    12195           
  Partials                   ?     2480           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines 250 to 251
"Attempted to set constraint scaling factor for indexed constraint "
"with transformed ConstraintData children. Please use only one of "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Attempted to set constraint scaling factor for indexed constraint "
"with transformed ConstraintData children. Please use only one of "
f"Attempted to set constraint scaling factor for indexed constraint {c.name}"
f"with transformed ConstraintData children. Please use only one of "

I think it could be useful to directly point to the constraint where the issue arises, in the case that the user might not be applying scaling to constraints manually, one at a time.

scaling_factor = sfFinder.find(component_data=c)
if scaling_factor is not None:
raise RuntimeError(
"Attempted to transform constraint with existing scaling factor. "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Attempted to transform constraint with existing scaling factor. "
f"Attempted to transform Constraint {c.name} with existing scaling factor. "

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, it'd be nice to call out the exact constraint with the issue when the user is not carefully scaling constraints one at a time.

pyomo.common.config.ConfigValue(
domain=Bool,
default=False, # TODO: Change to true once transition complete
default=True,
Copy link
Contributor

@adam-a-a adam-a-a Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high-level: what happens when we do not set scale_model to True by default? At this point, I am a bit mixed up on what's happening with regard to scaling and how the solver will "see" things.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When scale_model == False, then scaling factors are not applied to the model at the time an .nl file is written for the solver. Constraints transformed through constraint_scaling_transform will have their scaled form passed to the solver. If you pass the nlp_scaling_method=user-scaling option to IPOPT, IPOPT will use the user-provided scaling factors when computing and inverting the barrier hessian instead of its own gradient-scaling method. However, it will not use scaled values of the variables when computing the distance of a variable to its bounds or when computing the constraint residual (the latter fact being the reason that constraint_scaling_transform was created).

Now that scale_model==True, solvers that support the new .nl writer (definitely IPOPT, I'm not sure about other solvers) will only see the scaled model. The Jacobian will be computed using the scaled variables, and IPOPT will apply its gradient-based scaling on top of the user scaling factors (which is a good thing). Scaled values of variables will be used to compute the distance to bounds and scaled values will be used in computing the constraint residual (so we no longer need constraint_scaling_transform).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In light the benefits described in your second paragraph, why would one want to set scale_model == False? Is there a situation when that would be more useful than True?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior to Pyomo 6.9.3, there was a bug in how scaling factors were applied in linear named Expressions---namely, they weren't applied in such expressions. Because those Expressions gave incorrect values, most models in the IDAES repo either failed to solve or gave erroneous results. It was fixed in this release, which is why I'm making this change now.

The only situation where you wouldn't want to scale the model is if you suspect a constraint has both a scaling factor set and has been transformed through constraint_scaling_transform. Then using scale_model == True results in double scaling, whereas with scale_model == False the double scaling would be less of a problem. That's why I went through and added a bunch of Exceptions if the user tried double scaling things.

set_scaling_factor(m.c2, 1e-3)
with pytest.raises(RuntimeError, match=match("c3")):
set_scaling_factor(m.c3, 1e-3)
with pytest.raises(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a test of the correct way to apply scaling to c4?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid I don't follow. I test applying a scaling factor both to the constraint as a whole as well as the individual indices. What other case do you want to test?

Copy link
Contributor

@bpaul4 bpaul4 Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I see now that the allowed case is also being tested. I only saw the error check on c4 before.

@dallan-keylogic dallan-keylogic changed the base branch from main to scaling_toolbox August 26, 2025 17:28
Copy link
Contributor

@adam-a-a adam-a-a left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - just some pylint test failing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants