Integrating Pyomo into larger Python program

1,322 views
Skip to first unread message

Miles Abarr

unread,
May 4, 2017, 2:14:14 PM5/4/17
to Pyomo Forum
Hi,

I am very new to Pyomo, but seem to have gotten it running with the glpk solver. I am trying to integrate pyomo into some already-built Python models to optimize some inputs. I have a steady-state heat exchanger model that is basically trying to minimize the temperature difference between two fluids while satisfying a simple constraint. I am trying to use pyomo to adjust the mass flows of the fluids to do this, and I got something that runs, but it is saying the constraint function is constant, and therefore is not optimizing. Here are the outputs I get:

WARNING: Constant objective detected, replacing with a placeholder to prevent solver failure.
# ==========================================================
# = Solver Results                                         =
# ==========================================================
# ----------------------------------------------------------
#   Problem Information
# ----------------------------------------------------------
Problem:
- Name: unknown
  Lower bound: 418.919688579
  Upper bound: 418.919688579
  Number of objectives: 1
  Number of constraints: 2
  Number of variables: 5
  Number of nonzeros: 5
  Sense: maximize
# ----------------------------------------------------------
#   Solver Information
# ----------------------------------------------------------
Solver:
- Status: ok
  Termination condition: optimal
  Statistics:
    Branch and bound:
      Number of bounded subproblems: 1
      Number of created subproblems: 1
  Error rc: 0
  Time: 0.00999999046326
# ----------------------------------------------------------
#   Solution Information
# ----------------------------------------------------------
Solution:
- number of solutions: 0
  number of solutions displayed: 0
Displaying Solution
------------------------------------------------------------
x : Size=4, Index=t
    Key : Lower : Value : Upper : Fixed : Stale : Domain
      1 :     1 :   1.0 :    24 : False : False : NonNegativeIntegers
      2 :     1 :   1.0 :    24 : False : False : NonNegativeIntegers
      3 :     1 :   1.0 :    24 : False : False : NonNegativeIntegers
      4 :     1 :   1.0 :    24 : False : False : NonNegativeIntegers


My guess is that it is how I set up the objective function. What i am doing is taking a pyomo variable, inserting its value into another python variable, doing a much of math with that, then returning a value. Here is some of the key code:


import pyomo.environ as po
model = po.ConcreteModel()
model.t = po.RangeSet(1, len(self.mode_list))
model.x = po.Var(model.t, initialize=1, bounds=(1, 24), domain=po.NonNegativeIntegers)

def objective_function(model):
for i in model.t:
mode_list[i-1].run_time = model.x[i].value
...bunch of math to get objective as a Python float...
return objective

mode_list is a list of objects containing the attribute run_time, which does  bunch of math to determine mass flows and the heat transfer dynamics.

So do I have to completely alter all of my code to use pyomo parameters and sets and all that? Is there an easy way to patch this up? Thanks for any advice.

Miles




Gabriel Hackebeil

unread,
May 4, 2017, 3:08:59 PM5/4/17
to Pyomo Forum
The objective should not be a float. It should be an expression that you generate by using Pyomo variables in algebraic operations. In the example code you posted, you should be using model.x[i] instead model.x[i].value. We pass this expression to the solver when you solve the model.

A common misconception is that the “rule” functions associated with objectives and constraints are callbacks, but they are not. The use of rule functions has to do with delaying construction of these objects until data is provided.

Gabe

--
You received this message because you are subscribed to the Google Groups "Pyomo Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyomo-forum...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Miles Abarr

unread,
May 4, 2017, 3:52:39 PM5/4/17
to Pyomo Forum
Ok, I had tried that originally, and in that case it does not run and gives me the following error messages:

Traceback (most recent call last):
ERROR
: Rule failed when generating expression for objective objective:
 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
 
File "C:\Users\miles\Anaconda2\lib\site-packages\IPython\core\interactiveshell.py", line 2881, in run_code
ERROR
: Constructing component 'objective' from data=None failed:
 
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
   
exec(code_obj, self.user_global_ns, self.user_ns)
 
File "<ipython-input-4-de50b021a625>", line 1, in <module>
    FCC
.minimize_T_hot()
 
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 443, in minimize_T_hot
    model
.objective = po.Objective(rule=objective_function, sense=po.minimize)
 
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\block.py", line 484, in __setattr__
   
self.add_component(name, val)
 
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\block.py", line 890, in add_component
    val
.construct(data)
 
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\objective.py", line 307, in construct
    tmp
= _init_rule(_self_parent)
 
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 439, in objective_function
   
self.calculate_pinch()
 
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 183, in calculate_pinch
   
self.dH, self.T_hot, self.T_cold = pinch_composite(self.hot_list, self.cold_list)
 
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 90, in pinch_composite
    dH_seg
= (stream.mdot * np.abs(stream.state.h[1:] - stream.state.h[0:-1]))
 
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\numvalue.py", line 467, in __mul__
   
return generate_expression(_mul,self,other)
 
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\expr_coopr3.py", line 1244, in generate_expression
   
if ans._coef == 0:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()


To help debug, let me clarify the following line (where the error occurs):

dH_seg = (stream.mdot * np.abs(stream.state.h[1:] - stream.state.h[0:-1]))

Here, I am using stream.mdot, which is a pyomo object of class: <pyomo.core.base.expr_coopr3._ProductExpression at 0xd6a62d0>, which is obtained from constant multiplications and additions of model.x[i]. The stream.state.h's are each 1D numpy arrays. 

Miles

Gabriel Hackebeil

unread,
May 4, 2017, 3:57:34 PM5/4/17
to pyomo...@googlegroups.com
Pyomo expressions are not really compatible with Numpy array operations. If you cast the result of the np.abs(…) call to a float (convert it to a scalar), it should fix the problem.

Gabe

On May 4, 2017, at 3:52 PM, Miles Abarr <mi...@brightes.com> wrote:

Ok, I had tried that originally, and in that case it does not run and gives me the following error messages:

Traceback (most recent call last):
ERROR
: Rule failed when generating expression for objective objective:

 
ValueError: The truth value of an array with more than one element is ambiguous. Usea.any() or a.all()
  
File "C:\Users\miles\Anaconda2\lib\site-packages\IPython\core\interactiveshell.py",line 2881, in run_code
ERROR
: Constructing component 'objective' from data=None failed:
 
ValueError: The truth value of an array with more than one element is ambiguous. Usea.any() or a.all()

    
exec(code_obj, self.user_global_ns, self.user_ns)
  
File "<ipython-input-4-de50b021a625>", line 1, in <module>
    FCC
.minimize_T_hot()
  
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 443, inminimize_T_hot
    model
.objective = po.Objective(rule=objective_function, sense=po.minimize)

  
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\block.py", line 484,in __setattr__
    
self.add_component(name, val)
  
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\block.py", line 890,in add_component
    val
.construct(data)

  
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\objective.py", line 307, in construct
    tmp 
= _init_rule(_self_parent)
  
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 439, inobjective_function
    
self.calculate_pinch()
  
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 183, incalculate_pinch
    
self.dH, self.T_hot, self.T_cold = pinch_composite(self.hot_list, self.cold_list)
  
File "C:\Users\miles\Documents\GitHub\models2\core\pinch.py", line 90, inpinch_composite
    dH_seg 
= (stream.mdot * np.abs(stream.state.h[1:] - stream.state.h[0:-1]))
  
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\numvalue.py", line 467, in __mul__
    
return generate_expression(_mul,self,other)
  
File "C:\Users\miles\Anaconda2\lib\site-packages\pyomo\core\base\expr_coopr3.py", line 1244, in generate_expression
    
if ans._coef == 0:
ValueError: The truth value of an array with more than one element is ambiguous. Usea.any() or a.all()
Message has been deleted

Gabriel Hackebeil

unread,
May 4, 2017, 4:31:36 PM5/4/17
to pyomo...@googlegroups.com
You need to expand the array multiplication into a sum over scalar multiplications. Best practice is to just avoid using Numpy objects when building a Pyomo model because we don’t have any concept of array operations built into our expression system (yet).

 then do a minimum difference between the arrays

I don’t know how to interpret this. If you are saying your objective function is to minimize the difference between two arrays (assuming you are minimizing some kind of norm), then you would just expand that norm into a sum over (perhaps squared) differences.

Gabe

On May 4, 2017, at 4:09 PM, Miles Abarr <mi...@brightes.com> wrote:

Good to know. The problem is that I need to do multiplication of the Pyomo variable on some arrays, then do a minimum difference between the arrays. Is there a way to convert the numpy array into something Pyomo can work with? Thanks again for the help.

Miles

Miles Abarr

unread,
May 4, 2017, 7:41:01 PM5/4/17
to Pyomo Forum
What I mean is I need to take the difference between 2 arrays, and find the minimum value in that new difference array. I actually converted everything to list math only to find that I cant use Python's min() function in a Pyomo model. It is not obvious to me what the workaround for this might be. It seems to me like I might need to do a bunch of this math beforehand, then use Pyomo to select from those pre-calculated values.

Miles

Gabriel Hackebeil

unread,
May 4, 2017, 8:33:52 PM5/4/17
to pyomo...@googlegroups.com
If you are referring to arrays of (Pyomo) decision variables, and not just arrays of numbers, then you can not use the ‘min' function to build an objective or constraint expression. This is true of Pyomo as well as any other algebraic modeling tool for optimization, and I don’t know of any solver that would handle this kind of input.

You need to express this kind of operation using other modeling tricks that, sometimes, involve introducing additional variables and constraints. For instance, if you want to maximize the minimum over an array of decision variables, you could model it as

maximize z
subject to
z <= x(1)
z <= x(2)
z <= x(n)

Gabe
Reply all
Reply to author
Forward
0 new messages