Hi, I’m planning to write a corresponding ASL structural adapter function for a C++ function I’ve written as an external function. Then I compile it into a .dll file, call it via ExternalFunction in Pyomo and solve it with IPOPT.
I’m now experiencing the following error message from IPOPT. It may seem a bit confusing.
Ipopt 3.14.13: ERROR: Solver (ipopt) returned non-zero return code (3221226505)
ERROR: See the solver log above for diagnostic information.
Error during solving: Solver (ipopt) did not exit normally
Here is the C++ function.
double Srk::CalcMassEntropyLiquidMixture(
std::vector<double> &molefraction,
double &temperature,
double &pressure)
Here’s the adapter function I write that corresponds to the ASL structure.
real calc_mass_entropy_liquid_mixture(arglist *al) {
/*
*I have no idea how to get the variable of vector type from
*arglist, so I ask GPT for help. It seems that it doesn't work.
*/
if (al->n != 3) {
al->Errmsg = (char *) "calc_mass_entropy_liquid_mixture expects 3 arguments";
return 0.0;
}
std::vector<double> molefraction(al->ra[al->at[0]], al->ra[al->at[0]] + al->nr[al->at[0]]); //This may be incorrect, I think.
double temperature = al->ra[al->at[1]];
double pressure = al->ra[al->at[2]];
double entropy = Srk::CalcMassEntropyLiquidMixture(molefraction, temperature, pressure);
return entropy; // return answer
}
void funcadd(AmplExports *ae){
int t = FUNCADD_REAL_VALUED;
addfunc("calc_mass_entropy_liquid_mixture", (rfunc)calc_mass_entropy_liquid_mixture, t, 3, NULL);
}
Here’s the pyomo part.
def create_model():
m = pyo.ConcreteModel()
m.name = 'Example 1: Eason'
m.z = pyo.Var(range(3), domain=pyo.Reals, initialize=2.)
m.x = pyo.Var(range(3), initialize=2.)
m.temperature = pyo.Var(initialize=260.0)
m.pressure = pyo.Var(initialize=1823850)
m.x[0] = 0.3
m.x[1] = 0.3
m.x[2] = 0.4
m.ext_fcn = pyo.ExternalFunction(library='myfunctions.dll', function='calc_mass_entropy_liquid_mixture') #Here calls the imported function
m.obj = pyo.Objective(
expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6) #
m.c1 = pyo.Constraint(
expr=100 + m.ext_fcn(m.x, m.temperature, m.pressure) == 2*pyo.sqrt(2.0)) #it becomes a part of the constraints here
m.c2 = pyo.Constraint(expr=m.z[2]**4 * m.z[1]**2 + m.z[1] == 8+pyo.sqrt(2.0))
return m
model = create_model()
solver = pyo.SolverFactory('ipopt')
try:
result = solver.solve(model, tee=True)
print("Solver status:", result.solver.status)
print("Solver termination condition:", result.solver.termination_condition)
except Exception as e:
print("Error during solving:", e)
My questions are:
-
Now that one of the arguments of my function is in the form of a one-dimensional vector, how can I get the variable of vector type from *arglist?
-
Can I leave out the derivative and Hessian for this function and let IPOPT get them by approximating it itself?