0

I had read documentation and trying to understand how to work with scipy.optimize.minimize(), but my code just doesn't work, it keeps showing that"ValueError: The user-provided objective function must return a scalar value."

Here is my code:

PH = np.linspace(0, 14, 71)
ni_total = 0.1
citrate_total = 0.9
ammonia_total = 0.3

def concs(citrate_total,ni_total, ammonia_total, PH):
    h = 10 ** (-PH)
    def equations(p):
        cit3, nio2, nh4 = p
        Hcit = h*cit3*k4
        H2cit = h*Hcit*k3
        H3cit = h*H2cit*k2
        ni2pfree = (nio2*k1*(h**2))/(1+((nio2*k1*(h**2))/ni_total))
        NiH2cit = k7*ni2pfree*H2cit
        NiHcit = k6*ni2pfree*Hcit
        Nicit = k5*ni2pfree*cit3
        nh3 = k8*nh4/h
        nin4p2 = k9*(nh4**4)/(h**2)
        nin6p2 = k10*(nh4**6) /(h**4)
        return (citrate_total - Hcit - H2cit - H3cit - Nicit - NiHcit - NiH2cit - cit3,
                ni_total - Nicit - NiHcit - NiH2cit - ni2pfree - nin4p2- nin6p2- nio2,
                ammonia_total-nh3-4*nin4p2-6*nin6p2-nh4)
    initial_guess=[0.1,0.1,0.1]
    res = minimize(equations,initial_guess)
    cit3 = res.x[0]
    nio2 = res.x[1]
    nh4 = res.x[2]
    ni2pfree = (nio2 * k1 * (h ** 2)) / (1 + ((nio2 * k1 * (h ** 2)) / ni_total))
    Hcit = h * cit3 *k4
    H2cit = h * Hcit * k3
    H3cit = h * H2cit * k2
    NiH2cit = k7 * ni2pfree * H2cit
    NiHcit = k6 * ni2pfree * Hcit
    Nicit = k5 * ni2pfree * cit3
    nh3 = k8 * nh4 / h
    nin4p2 = k9 * (nh4 ** 4) / (h ** 2)
    nin6p2 = k10 * (nh4 ** 6) / (h ** 4)
    return [cit3, nio2, nh4, ni2pfree, Hcit, H2cit, H3cit, NiH2cit, NiHcit, Nicit,nh3,nin4p2,nin6p2]
  • You're returning a 3-tuple. You must return a single value. – Tim Roberts Aug 04 '22 at 20:54
  • Seems like you are trying to solve a system of equations. Either use `scipy.optimize.root` for this purpose or reformulate the root problem as a minimization problem that returns a **scalar** value, as your error message clearly tells you. – joni Aug 04 '22 at 21:09
  • Yes, using scipy.optimize.root does work, but how can I constrain the value of variables? – Robert_T119 Aug 05 '22 at 09:15

1 Answers1

0

The function scipy.optimize.minimize() takes in (among others) as arguments the objective fun and initial value x0. fun must return a single real number (also referred to as a scalar); not a list or a tuple.

In contrast, your function returns

def equations(p):
     # code 
     return (..., ..., ...)

Change it to

def equations(p):
     # code 
     return x

with the function value x of equations() that you actually want to minimize.

7shoe
  • 1,438
  • 1
  • 8
  • 12