[SciPy-User] Scipy.optimize.fmin_slsqp problem
josef.pktd at gmail.com
josef.pktd at gmail.com
Thu Jan 12 10:13:03 EST 2012
On Wed, Jan 11, 2012 at 12:01 PM, Hendrik <hendrik.venter1 at gmail.com> wrote:
> Hey Folks!! I'm new to the Forum world. I looked for a topic on
> optimization, but didn't see one, so sorry if I'm duplicating...
>
> I run Python 2.6.6.1
>
> I'm using scipy.optimize.fmin_slsqp to solve a non-linear function
> but it only returns the function value with the initial guess
> values... Can you please help???
>
> Below this message is my program... I'm struggling with this problem
> for over 3 months now, asking for advice with no success!!
>
> I want to minimize the function "changevars(self.gibbs)" within the
> constraints "changevars(self.atombalance)".
>
> The optimization program only returns the function value with the
> initial guess values... And i don't know why.
> When I run the program, I can see the minimum value graphically, but
> the optimization can't calculate it...
I have no idea what might be wrong, and I don't have an atomparser
available, so I cannot run the script.
What I would do to debug and see whether it's a coding problem or a
problem with slsqp is to convert the atombalance constraint into a
quadratic penalty (with a penalization factor that can be increased)
and see whether an approximate "unconstraint" solution can be found.
Josef
>
> Can you please help??
>
> Regards
>
> *************************************************************************************************************************************
> #!/usr/bin/env python
>
> # Calculate mixture equilibriums using minimisation of the Gibbs
> energy
>
> # 201110 Originally by Hendrik Venter
> # 201111 Significantly reworked by Carl Sandrock
>
> from __future__ import division
> import scipy.optimize
> import scipy.linalg
> import math
> import numpy
> import atomparser
> import sys
> import matplotlib.pyplot as pl
> from mpl_toolkits.mplot3d import axes3d
> from matplotlib import cm
>
> smallvalue = 1e-10
> fig = pl.figure()
> ax = fig.add_subplot(111, projection='3d')
>
> T = 298.15
> R = 8.314
> RT = R*T
> mustplot = 1 # 1 for Plotting, 0 for not plotting
>
>
> class compound:
> """ Basic container for compound properties """
> def __init__(self, name, DGf):
> self.name = name
> self.DGf = DGf
> self.parsed = atomparser.parseformula(name)
>
>
> class mixture:
> """ Container for mixture properties """
> def __init__(self, charge):
> """ Initialise mixture - charge contains tuples of
> (initialcharge, compound) """
> self.N, self.compounds = zip(*charge)
> self.N = numpy.array(self.N)
> self.compoundnames = [c.name for c in self.compounds]
> self.DGf = numpy.array([c.DGf for c in self.compounds])
> self.elements = reduce(set.union,
> (c.parsed.distinctelements()
> for c in self.compounds))
> self.S = numpy.array([c.parsed.counts(self.elements)
> for c in self.compounds]).T
> Srank = numpy.count_nonzero(numpy.linalg.svd(self.S,
> compute_uv=False) > smallvalue)
>
> # Calculating the Degrees of freedom
> self.DOF = self.S.shape[1] - Srank
> print 'Degrees of Freedom =', self.DOF
>
> # Coefficients of the Gibbs function
> Ncomps = len(self.compounds)
> # self.A = numpy.tile(numpy.repeat([-1, 1], [1, Ncomps-1]),
> [Ncomps, 1])
> # number of atoms of each element
> self.atoms = numpy.dot(self.S, self.N)
>
>
> def gibbs(self, N=None):
> """ Gibbs energy of mixture with N of each compound """
> if N is None: N = self.N
> # TODO: There is every chance that this function is not
> correct. It needs to be checked.
> #return sum(N*(self.DGf/(R*T) + numpy.log(numpy.dot(self.A,
> N))))
> logs = numpy.log(sum(N))
> return sum(N*(self.DGf/RT + numpy.log(N) - logs))
>
> def atombalance(self, N):
>
> """ Atom balance with N of each compound """
> #if N is None: N = self.N
> return numpy.dot(self.S, N) - self.atoms
>
>
> def conversion(self, conversionspec):
> """ Calculate the composition given a certain conversion.
> conversionspec is a list of 2-tuples containing a component
> index or name and a conversion """
> #TODO: A and B should only be calculated once
> #TODO: This does not take into account any existing products
> in the mixture
> #TODO: This works only for conversion specified in terms of
> reagents
> if len(conversionspec) < self.DOF:
> raise Exception("Not enough conversions specified.")
> C = numpy.zeros([len(conversionspec), self.S.shape[1]])
> Ic = C.copy()
> for i, (j, c) in enumerate(conversionspec):
> if type(j) is str:
> j = self.compoundnames.index(j)
> C[i, j] = 1-c
> Ic[i, j] = 1
> A = numpy.vstack([self.S, C])
> B = numpy.vstack([self.S, Ic])
> # A ni = B nf
> nf, _, _, _ = scipy.linalg.lstsq(B, numpy.dot(A, self.N))
> # assert residuals are neglegable
> nf[nf<0] = 0
> return nf
>
> def equilibrium(self, initialconversion):
> """ Return equilibrium composition as minimum of Gibbs Energy
> """
> # guess initial conditions
> N0 = self.conversion(initialconversion)
> logN0 = numpy.log(N0)
>
> # This decorator modifies a function to be defined in terms of
> new variables
> def changevars(f):
> def newf(newX):
> # print 'newX', newX
> # print 'X', numpy.exp(newX)
> r = f(numpy.exp(newX))
> # print 'f(X)', r
> return r
> return newf
>
> # Find optimal point in terms of a change of variables
> logN = scipy.optimize.fmin_slsqp(changevars(self.gibbs),
> logN0,
>
> f_eqcons=changevars(self.atombalance),
> acc = 1.0E-12)
> scipy.optimize.fmin
> N = numpy.exp(logN)
> print ''
> print 'Calculated Optimmum Values'
> print N
> print ''
> print 'Calculated Optimum Function value'
> print m.gibbs(N)
>
> return N
>
> # Here for a particular mixture:
> m = mixture([[1., compound('MgO', -568343.0)],
> [0.5, compound('Al2O3', -1152420.0)],
> [4., compound('H2O', -237141.0)],
> [0, compound('Mg(OH)2', -833644.0)],
> [0, compound('Al(OH)3', -1835750.0)]])
>
>
> # find Gibbs energy surface for many conversion possibilities
> Nsteps = 10
> convrange = numpy.linspace(0.001, 0.999, Nsteps)
> gibbssurface = numpy.zeros((Nsteps, Nsteps))
> for iMgO, xMgO in enumerate(convrange):
> for iAl2O3, xAl2O3 in enumerate(convrange):
> N = m.conversion([('MgO', xMgO),
> ('Al2O3', xAl2O3/50)])
> gibbssurface[iMgO, iAl2O3] = m.gibbs(N)
>
>
>
> # Try to find equilibrium
> # Initial conversion guess
> print ''
> print "***************Optimizing******************"
> X0 = [0.5, 0.5]
> conversionspec = zip(['MgO', 'Al2O3'], X0)
> # Solve to equilibrium
> N = m.equilibrium(conversionspec)
>
> print ''
> print '*************Final Values***************'
> for n, init, name in zip(N, m.N, m.compoundnames):
> print name, 'initial =', init, 'final =', n
>
>
> # Plot results
> if mustplot:
> Xaxis, Yaxis = numpy.meshgrid(convrange, convrange)
> Zaxis = gibbssurface
> surf = ax.plot_surface(Xaxis, Yaxis, Zaxis, rstride=1, cstride=1,
> cmap=cm.jet, linewidth=0, antialiased=False)
> fig.colorbar(surf, shrink=0.5, aspect=5)
> ax.set_xlabel('Conversion of MgO')
> ax.set_ylabel('Conversion of Al2O3')
> ax.set_zlabel('Gibbs free energy (G/RT)')
> pl.show()
>
> _______________________________________________
> SciPy-User mailing list
> SciPy-User at scipy.org
> http://mail.scipy.org/mailman/listinfo/scipy-user
More information about the SciPy-User
mailing list