Evaluating numerical value of variable at runtime

Dear GAMSPy Community,

I am new to GAMSPy and set-based declarative algebraic modeling in general so please forgive the potentially silly question. I would like to use GAMSPy in place of SciPy solvers like minimize(), which is not very robust and requires a good initial guess, to optimise thermodynamic cycles. In order to calculate the fluid properties at different stations around my cycle, I need to call the Python library CoolProp, whose methods naturally accept only numerical inputs, e.g. temperature and pressure. To use GAMSPy, I would have to evaluate my variables, i.e. extract their numerical values, during each iteration of the optimisation process.

I read the sections “External Equations” and “Extrinsic Functions” of the documentation, but before delving into this (I am not very familiar with C/FORTRAN) I was wondering whether there is an easier way of evaluating the variables at runtime (at the cost of performance, of course). To give you an idea of what I am after, below is a short code showing how I envisage to iterate the total-total pressure ratio pi_tt across a compressor to obtain a desired total-static pressure ratio pi_ts_req.

from gamspy import Container, Equation, Model, Variable, Parameter
from ... import model_meanline

inlet_stagnation_state = ...

def calculate_pi_ts(pi_tt):
    
    # Evaluate mean-line model
    outlet_static_state = \
        model_meanline(
            inlet_stagnation_state, #  constant input
            pi_tt, # THIS SHOULD BE A NUMERICAL VALUE BUT IS CURRENTLY A SYMBOLIC EXPRESSION
            ... #  other constant inputs
        )
    
    # Calculate total-static pressure ratio
    pi_ts = outlet_state.p/inlet_stagnation_state.p
    
    return pi_ts

m = Container()

pi_ts_req = Parameter(m, name="pi_ts_req", records=2.5)

pi_tt = Variable(m, name="pi_tt", type="positive")
var_obj = Variable(m, name="var_obj")

eq_obj = Equation(m, name="eq_obj", type="regular")
eq = Equation(m, name="eq", type="regular")

# Objective function
eequ[...] = calculate_pi_ts(pi_tt) - pi_ts_req == 0
eq_obj[...] = var_obj == 1

# Variable bounds
pi_tt.lo = pi_ts_req
pi_tt.up = 100
# Initial guess
pi_tt.l = pi_ts_req + 0.1

compressor_model = Model(
    m,
    name="compressor_model",
    equations=m.getEquations(),
    problem="nlp",
    sense="min",
    objective=var_obj,
)
compressor_model.solve()

Many thanks in advance for your help,
Nils

Update: in the API reference I found that Variable.toValue() is supposed to “[…] return symbol records as a Python float”. This indeed works after the model has been solved successfully, but when I type print(Variable.toValue()) inside the calculate_pi_ts() function in my initial post I get None. What is it that fundamentally prevents the conversion from symbolic expression to float under those conditions?

The reason why you get None when you type print(Variable.toValue()) inside the calculate_pi_ts() is that the model has not been solved yet by the time you call calculate_pi_ts. External equations are your best bet to achieve what you want. Here is an example that shows how to implement an external equation.