Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unscaling model after solving using propagate_solution(scaled_model, original_model) throws error #3273

Closed
fahim831 opened this issue May 25, 2024 · 5 comments · Fixed by #3275
Labels

Comments

@fahim831
Copy link

fahim831 commented May 25, 2024

Summary

I am trying to scale, solve, and unscale a pyomo model. The code itself worked well until I tried to scale but it didn't get a solution probably due to scaling issues. Now, after scaling, the model solves but I get an error when I try to scale it back. Unfortunately, I couldn't find any application in the doc on how to actually use the ```propagate_solution''' method.

I will try to provide a few lines of code to summarize what I'm doing without making it extensively long. The last line is what gives me the error

Steps to reproduce the issue

# example.py
from pyomo.environ import *
from pyomo.dae import *

model = ConcreteModel()

model.t = ContinuousSet(bounds=(0, 5))
model.x = ContinuousSet(bounds=(0, 3))
model.y = Var(model.t, model.x)
model.z = Var(model.t, model.x)
model.dydt = DerivativeVar(model.y, wrt=model.t)
model.dzdt = DerivativeVar(model.z, wrt=model.t)
model.dydx = DerivativeVar(model.y, wrt=model.x)
model.dzdx = DerivativeVar(model.z, wrt=model.x)

2 differential equations here in y and z
2 algebraic equations here in y and z

Discretize both y and z

# create the scaling factors
model.scaling_factor = Suffix(direction=Suffix.EXPORT)
model.scaling_factor[model.diffeq1] = 10 # scale diffeq1
model.scaling_factor[model.z] = 0.1 # scale z
# transform the model
scaled_model = TransformationFactory('core.scale_model').create_using(model)

solver = SolverFactory('ipopt')
results = solver.solve(scaled_model, tee=True)

model = TransformationFactory('core.scale_model').propagate_solution(scaled_model, model)

Error Message

$ # ERROR: evaluating object as numeric value: scaled_dydt[0,0]
        (object: <class 'pyomo.core.base.var._GeneralVarData'>)
    No value for uninitialized NumericValue object scaled_dydt[0,0]
Traceback (most recent call last):
  File "/Users/$USER/filename", line 291, in <module>
    model = TransformationFactory('core.scale_model').propagate_solution(scaled_model, model)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/$USER/anaconda3/envs/lib/python3.12/site-packages/pyomo/core/plugins/transform/scaling.py", line 326, in propagate_solution
    value(scaled_v[k]) / component_scaling_factor_map[scaled_v[k]],
    ^^^^^^^^^^^^^^^^^^
  File "/Users/$USER/anaconda3/envs/watertap-dev/lib/python3.12/site-packages/pyomo/common/numeric_types.py", line 318, in value
    raise ValueError(
ValueError: No value for uninitialized NumericValue object scaled_dydt[0,0]

Information on your system

Pyomo version: 6.7.1
Python version: 3.12
Operating system: Mac OS Sonoma
How Pyomo was installed (PyPI, conda, source): conda
Solver (if applicable): ipopt

@fahim831 fahim831 added the bug label May 25, 2024
@Robbybp
Copy link
Contributor

Robbybp commented May 28, 2024

Hi @fahim831, I was able to reproduce your issue with the following modification of your example:

# example.py
from pyomo.environ import *
from pyomo.dae import *

model = ConcreteModel()

model.t = ContinuousSet(bounds=(0, 5))
model.x = ContinuousSet(bounds=(0, 3))
model.y = Var(model.t, model.x)
model.z = Var(model.t, model.x)
model.dydt = DerivativeVar(model.y, wrt=model.t)
model.dzdt = DerivativeVar(model.z, wrt=model.t)
model.dydx = DerivativeVar(model.y, wrt=model.x)
model.dzdx = DerivativeVar(model.z, wrt=model.x)

# 2 differential equations here in y and z
# 2 algebraic equations here in y and z
# 
# Discretize both y and z

@model.Constraint(model.t, model.x)
def diffeq1(m, t, x):
    return m.dydt[t, x] == m.z[t, x] - m.y[t, x]

model.obj = Objective(
    expr=sum(model.y[t, x]**2 + model.z[t, x]**2 for t in model.t for x in model.x),
    sense=minimize,
)

TransformationFactory("dae.finite_difference").apply_to(model, wrt=model.t, nfe=10, scheme="BACKWARD")
TransformationFactory("dae.finite_difference").apply_to(model, wrt=model.x, nfe=10, scheme="BACKWARD")

# create the scaling factors
model.scaling_factor = Suffix(direction=Suffix.EXPORT)
model.scaling_factor[model.diffeq1] = 10 # scale diffeq1
model.scaling_factor[model.z] = 0.1 # scale z
# transform the model
scaled_model = TransformationFactory('core.scale_model').create_using(model)

solver = SolverFactory('ipopt')
results = solver.solve(scaled_model, tee=True)

model = TransformationFactory('core.scale_model').propagate_solution(scaled_model, model)

This is because the derivative variables at (0,0) are (a) not initialized and (b) not used in the model (with backwards difference, anyway). A workaround is to initialize the derivative variables, e.g. model.dydt = DerivativeVar(model.y, wrt=model.t, initialize=0), but we should probably handle this in propagate_solution anyway. I'll look into it and see if this is a quick fix.

@fahim831
Copy link
Author

Hi @Robbybp, thanks. I was able to make it run after initializing all the derivatives at 0. Although, after it runs and finds a solution, when I call model.y, I get this new error (probably unrelated to the propagate_solution definition, however):
AttributeError: 'NoneType' object has no attribute 'y'

I am guessing the solver is outputting a false positive for the optimal solution being found? Because when I check the results from solver.solve, I get this:

Solution: 
- number of solutions: 0
  number of solutions displayed: 0

@Robbybp
Copy link
Contributor

Robbybp commented May 28, 2024

From a quick glance, this is probably because propagate_solution returns None, and we are resetting model to this return value. Just changing the last line to

TransformationFactory('core.scale_model').propagate_solution(scaled_model, model)

should fix that.

@fahim831
Copy link
Author

Thanks! That was the issue.

@Robbybp
Copy link
Contributor

Robbybp commented Jun 25, 2024

#2817 appears to be related.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants