Example #1
0
    def Run(self):
        """ Call the appropriate optimizer.  This is the method we might want to call from an executable. """

        xk = self.OptTab[self.jobtype]()
        
        ## Sometimes the optimizer doesn't return anything (i.e. in the case of a single point calculation)
        ## In these situations, don't do anything
        if xk == None: return

        ## Check derivatives by finite difference after the optimization is over (for good measure)
        check_after = False
        if check_after:
            self.mvals0 = xk.copy()
            self.FDCheckG()

        ## Print out final answer
        final_print = True
        if final_print:
            bar = printcool("Final optimization parameters:\n Paste to input file to restart",bold=True,color=4)
            print "read_mvals"
            self.FF.print_map(xk)
            print "/read_mvals"
            bar = printcool("Final physical parameters:",bold=True,color=4)
            self.FF.print_map(self.FF.create_pvals(xk))
            print bar
            self.FF.make(xk,False,'result')
            print
            print "The final force field has been printed to the 'result' directory."
            #bar = printcool("\x1b[1;45;93mCongratulations, ForceBalance has finished\x1b[0m\n\x1b[1;45;93mGive yourself a pat on the back!\x1b[0m")
            bar = printcool("Congratulations, ForceBalance has finished\nGive yourself a pat on the back!",ansi="1;44;93")

        ## Write out stuff to checkpoint file
        self.writechk()

        return xk
Example #2
0
    def FDCheckH(self):
        """ Finite-difference checker for the objective function Hessian.

        For each element in the Hessian, use a five-point stencil in both
        parameter indices to compute a finite-difference derivative, and
        compare it to the analytic result.

        This is meant to be a foolproof checker, so it is pretty slow.  We
        could write a faster checker if we assumed we had accurate first
        derivatives, but it's better to not make that assumption.

        The second derivative is computed by double-wrapping the objective
        function via the 'wrap2' function.

        """
        Adata        = self.Objective.Full(self.mvals0,Order=2)['H']
        Fdata        = np.zeros((self.FF.np,self.FF.np),dtype=float)
        printcool("Checking second derivatives by finite difference!\n%-8s%-20s%-20s%13s%13s%13s%13s" \
                  % ("Index", "Parameter1 ID", "Parameter2 ID", "Analytic","Numerical","Difference","Fractional"),bold=1,color=5)

        # Whee, our double-wrapped finite difference second derivative!
        def wrap2(mvals0,pidxi,pidxj):
            def func1(arg):
                mvals = list(mvals0)
                mvals[pidxj] += arg
                return f1d5p(fdwrap(self.Objective.Full,mvals,pidxi,'X',Order=0),self.h)
            return func1
        
        for i in range(self.FF.np):
            for j in range(i,self.FF.np):
                Fdata[i,j] = f1d5p(wrap2(self.mvals0,i,j),self.h)
                Denom = max(abs(Adata[i,j]),abs(Fdata[i,j]))
                Denom = Denom > 1e-8 and Denom or 1e-8
                D = Adata[i,j] - Fdata[i,j]
                Q = (Adata[i,j] - Fdata[i,j])/Denom
                cD = abs(D) > 0.5 and "\x1b[1;91m" or (abs(D) > 1e-2 and "\x1b[91m" or (abs(D) > 1e-5 and "\x1b[93m" or "\x1b[92m"))
                cQ = abs(Q) > 0.5 and "\x1b[1;91m" or (abs(Q) > 1e-2 and "\x1b[91m" or (abs(Q) > 1e-5 and "\x1b[93m" or "\x1b[92m"))
                print "\r    %-8i%-20s%-20s% 13.4e% 13.4e%s% 13.4e%s% 13.4e\x1b[0m" \
                      % (i, self.FF.plist[i][:20], self.FF.plist[j][:20], Adata[i,j], Fdata[i,j], cD, D, cQ, Q)
Example #3
0
    def FDCheckG(self):
        """ Finite-difference checker for the objective function gradient.

        For each element in the gradient, use a five-point finite difference
        stencil to compute a finite-difference derivative, and compare it to
        the analytic result.

        """

        Adata        = self.Objective.Full(self.mvals0,Order=1)['G']
        Fdata        = np.zeros(self.FF.np,dtype=float)
        printcool("Checking first derivatives by finite difference!\n%-8s%-20s%13s%13s%13s%13s" \
                  % ("Index", "Parameter ID","Analytic","Numerical","Difference","Fractional"),bold=1,color=5)
        for i in range(self.FF.np):
            Fdata[i] = f1d7p(fdwrap(self.Objective.Full,self.mvals0,i,'X',Order=0),self.h)
            Denom = max(abs(Adata[i]),abs(Fdata[i]))
            Denom = Denom > 1e-8 and Denom or 1e-8
            D = Adata[i] - Fdata[i]
            Q = (Adata[i] - Fdata[i])/Denom
            cD = abs(D) > 0.5 and "\x1b[1;91m" or (abs(D) > 1e-2 and "\x1b[91m" or (abs(D) > 1e-5 and "\x1b[93m" or "\x1b[92m"))
            cQ = abs(Q) > 0.5 and "\x1b[1;91m" or (abs(Q) > 1e-2 and "\x1b[91m" or (abs(Q) > 1e-5 and "\x1b[93m" or "\x1b[92m"))
            print "\r    %-8i%-20s% 13.4e% 13.4e%s% 13.4e%s% 13.4e\x1b[0m" \
                  % (i, self.FF.plist[i][:20], Adata[i], Fdata[i], cD, D, cQ, Q)
Example #4
0
def parse_inputs(input_file=None):
    """ Parse through the input file and read all user-supplied options.

    This is usually the first thing that happens when an executable script is called.
    Our parser first loads the default options, and then updates these options as it
    encounters keywords.

    Each keyword corresponds to a variable type; each variable type (e.g. string,
    integer, float, boolean) is treated differently.  For more elaborate inputs,
    there is a 'section' variable type.

    There is only one set of general options, but multiple sets of target options.
    Each target has its own section delimited by the \em $target keyword,
    and we build a list of target options.  

    @param[in]  input_file The name of the input file.
    @return     options    General options.
    @return     tgt_opts   List of fitting target options.
    
    @todo Implement internal coordinates.
    @todo Implement sampling correction.
    @todo Implement charge groups.
    """
    
    logger.info("Reading options from file: %s\n" % input_file)
    section = "NONE"
    # First load in all of the default options.
    options = deepcopy(gen_opts_defaults) # deepcopy to make sure options doesn't make changes to gen_opts_defaults
    options['root'] = os.getcwd()
    options['input_file'] = input_file
    tgt_opts = []
    this_tgt_opt = deepcopy(tgt_opts_defaults)
    # Give back a bunch of default options if input file isn't specified.
    if input_file == None:
        return (options, [this_tgt_opt])
    fobj = open(input_file)
    for line in fobj:
        try:
            # Anything after "#" is a comment
            line = line.split("#")[0].strip()
            s = line.split()
            # Skip over blank lines
            if len(s) == 0:
                continue
            key = s[0].lower()
            if key in bkwd: # Do option replacement for backward compatibility.
                key = bkwd[key]
            # If line starts with a $, this signifies that we're in a new section.
            if re.match('^\$',line):
                newsection = re.sub('^\$','',line).upper()
                if section in ["SIMULATION","TARGET"] and newsection in mainsections:
                    tgt_opts.append(this_tgt_opt)
                    this_tgt_opt = deepcopy(tgt_opts_defaults)
                if newsection == "END": newsection = "NONE"
                section = newsection
            elif section in ["OPTIONS","SIMULATION","TARGET"]:
                ## Depending on which section we are in, we choose the correct type dictionary
                ## and add stuff to 'options' and 'this_tgt_opt'
                (this_opt, opts_types) = (options, gen_opts_types) if section == "OPTIONS" else (this_tgt_opt, tgt_opts_types)
                ## Note that "None" is a special keyword!  The variable will ACTUALLY be set to None.
                if len(s) > 1 and s[1].upper() == "NONE":
                    this_opt[key] = None
                elif key in opts_types['strings']:
                    this_opt[key] = s[1]
                elif key in opts_types['allcaps']:
                    this_opt[key] = s[1].upper()
                elif key in opts_types['lists']:
                    for word in s[1:]:
                        this_opt.setdefault(key,[]).append(word)
                elif key in opts_types['ints']:
                    if isfloat(s[1]):
                        this_opt[key] = int(float(s[1]))
                    else:
                        this_opt[key] = int(s[1])
                elif key in opts_types['bools']:
                    if len(s) == 1:
                        this_opt[key] = True
                    elif s[1].upper() in ["0", "NO", "FALSE", "OFF"]:
                        this_opt[key] = False
                    elif isfloat(s[1]) and int(float(s[1])) == 0:
                        this_opt[key] = False
                    elif s[1].upper() in ["1", "YES", "TRUE", "ON"]:
                        this_opt[key] = True
                    elif isfloat(s[1]) and int(float(s[1])) == 1:
                        this_opt[key] = True
                    else:
                        raise RuntimeError('%s is a true/false option but you provided %s; to enable, provide ["1", "yes", "true", "on" or <no value>].  To disable, provide ["0", "no", "false", or "off"].' % (key, s[1]))
                elif key in opts_types['floats']:
                    this_opt[key] = float(s[1])
                elif key in opts_types['sections']:
                    this_opt[key] = ParsTab[key](fobj)
                else:
                    logger.error("Unrecognized keyword: --- \x1b[1;91m%s\x1b[0m --- in %s section\n" \
                          % (key, section))
                    logger.error("Perhaps this option actually belongs in %s section?\n" \
                          % (section == "OPTIONS" and "a TARGET" or "the OPTIONS"))
                    raise RuntimeError
            elif section == "NONE" and len(s) > 0:
                logger.error("Encountered a non-comment line outside of a section\n")
                raise RuntimeError
            elif section not in mainsections:
                logger.error("Unrecognized section: %s\n" % section)
                raise RuntimeError
        except:
            # traceback.print_exc()
            logger.exception("Failed to read in this line! Check your input file.\n")
            logger.exception('\x1b[91m' + line + '\x1b[0m\n')
            raise RuntimeError
    if section == "SIMULATION" or section == "TARGET":
        tgt_opts.append(this_tgt_opt)
    if not options['verbose_options']:
        printcool("Options at their default values are not printed\n Use 'verbose_options True' to Enable", color=5)
    return options, tgt_opts
Example #5
0
def parse_inputs(input_file=None):
    """ Parse through the input file and read all user-supplied options.

    This is usually the first thing that happens when an executable script is called.
    Our parser first loads the default options, and then updates these options as it
    encounters keywords.

    Each keyword corresponds to a variable type; each variable type (e.g. string,
    integer, float, boolean) is treated differently.  For more elaborate inputs,
    there is a 'section' variable type.

    There is only one set of general options, but multiple sets of target options.
    Each target has its own section delimited by the \em $target keyword,
    and we build a list of target options.  

    @param[in]  input_file The name of the input file.
    @return     options    General options.
    @return     tgt_opts   List of fitting target options.
    
    @todo Implement internal coordinates.
    @todo Implement sampling correction.
    @todo Implement charge groups.
    """
    
    logger.info("Reading options from file: %s\n" % input_file)
    section = "NONE"
    # First load in all of the default options.
    options = deepcopy(gen_opts_defaults) # deepcopy to make sure options doesn't make changes to gen_opts_defaults
    options['root'] = os.getcwd()
    options['input_file'] = input_file
    tgt_opts = []
    this_tgt_opt = deepcopy(tgt_opts_defaults)
    # Give back a bunch of default options if input file isn't specified.
    if input_file == None:
        return (options, [this_tgt_opt])
    fobj = open(input_file)
    for line in fobj:
        try:
            # Anything after "#" is a comment
            line = line.split("#")[0].strip()
            s = line.split()
            # Skip over blank lines
            if len(s) == 0:
                continue
            key = s[0].lower()
            if key in bkwd: # Do option replacement for backward compatibility.
                key = bkwd[key]
            # If line starts with a $, this signifies that we're in a new section.
            if re.match('^\$',line):
                newsection = re.sub('^\$','',line).upper()
                if section in ["SIMULATION","TARGET"] and newsection in mainsections:
                    tgt_opts.append(this_tgt_opt)
                    this_tgt_opt = deepcopy(tgt_opts_defaults)
                if newsection == "END": newsection = "NONE"
                section = newsection
            elif section in ["OPTIONS","SIMULATION","TARGET"]:
                ## Depending on which section we are in, we choose the correct type dictionary
                ## and add stuff to 'options' and 'this_tgt_opt'
                (this_opt, opts_types) = (options, gen_opts_types) if section == "OPTIONS" else (this_tgt_opt, tgt_opts_types)
                ## Note that "None" is a special keyword!  The variable will ACTUALLY be set to None.
                if len(s) > 1 and s[1].upper() == "NONE":
                    this_opt[key] = None
                elif key in opts_types['strings']:
                    this_opt[key] = s[1]
                elif key in opts_types['allcaps']:
                    this_opt[key] = s[1].upper()
                elif key in opts_types['lists']:
                    for word in s[1:]:
                        this_opt.setdefault(key,[]).append(word)
                elif key in opts_types['ints']:
                    if isfloat(s[1]):
                        this_opt[key] = int(float(s[1]))
                    else:
                        this_opt[key] = int(s[1])
                elif key in opts_types['bools']:
                    if len(s) == 1:
                        this_opt[key] = True
                    elif s[1].upper() in ["0", "NO", "FALSE", "OFF"]:
                        this_opt[key] = False
                    elif isfloat(s[1]) and int(float(s[1])) == 0:
                        this_opt[key] = False
                    elif s[1].upper() in ["1", "YES", "TRUE", "ON"]:
                        this_opt[key] = True
                    elif isfloat(s[1]) and int(float(s[1])) == 1:
                        this_opt[key] = True
                    else:
                        logger.error('%s is a true/false option but you provided %s; to enable, provide ["1", "yes", "true", "on" or <no value>].  To disable, provide ["0", "no", "false", or "off"].\n' % (key, s[1]))
                        raise RuntimeError
                elif key in opts_types['floats']:
                    this_opt[key] = float(s[1])
                elif key in opts_types['sections']:
                    this_opt[key] = ParsTab[key](fobj)
                else:
                    logger.error("Unrecognized keyword: --- \x1b[1;91m%s\x1b[0m --- in %s section\n" \
                          % (key, section))
                    logger.error("Perhaps this option actually belongs in %s section?\n" \
                          % (section == "OPTIONS" and "a TARGET" or "the OPTIONS"))
                    raise RuntimeError
            elif section == "NONE" and len(s) > 0:
                logger.error("Encountered a non-comment line outside of a section\n")
                raise RuntimeError
            elif section not in mainsections:
                logger.error("Unrecognized section: %s\n" % section)
                raise RuntimeError
        except:
            # traceback.print_exc()
            logger.exception("Failed to read in this line! Check your input file.\n")
            logger.exception('\x1b[91m' + line + '\x1b[0m\n')
            raise RuntimeError
    if section == "SIMULATION" or section == "TARGET":
        tgt_opts.append(this_tgt_opt)
    if not options['verbose_options']:
        printcool("Options at their default values are not printed\n Use 'verbose_options True' to Enable", color=5)
    # Expand target options (i.e. create multiple tgt_opts dictionaries if multiple target names are specified)
    tgt_opts_x = []
    for topt in tgt_opts:
        for name in topt['name']:
            toptx = deepcopy(topt)
            toptx['name'] = name
            tgt_opts_x.append(toptx)
    return options, tgt_opts_x
Example #6
0
    def ScipyOptimizer(self,Algorithm="None"):
        """ Driver for SciPy optimizations.

        Using any of the SciPy optimizers requires that SciPy is installed.
        This method first defines several wrappers around the objective function that the SciPy
        optimizers can use.  Then it calls the algorith mitself.

        @param[in] Algorithm The optimization algorithm to use, for example 'powell', 'simplex' or 'anneal'

        """
        from scipy import optimize
        def xwrap(func,verbose=True):
            def my_func(mvals):
                if verbose: print
                Answer = func(mvals,Order=0,verbose=verbose)['X']
                dx = (my_func.x_best - Answer) if my_func.x_best != None else 0.0
                if Answer < my_func.x_best or my_func.x_best == None:
                    color = "\x1b[92m"
                    my_func.x_best = Answer
                else:
                    color = "\x1b[91m"
                if verbose:
                    if self.print_vals:
                        print "k=", ' '.join(["% .4f" % i for i in mvals])
                    print "X2= %s%12.3e\x1b[0m d(X2)= %12.3e" % (color,Answer,dx)
                if Answer != Answer:
                    return 1e10
                else:
                    return Answer
            my_func.x_best = None
            return my_func
        def gwrap(func,verbose=True):
            def my_gfunc(mvals):
                if verbose: print
                Output = func(mvals,Order=1,verbose=verbose)
                Answer = Output['G']
                Objective = Output['X']
                dx = (my_gfunc.x_best - Objective) if my_gfunc.x_best != None else 0.0
                if Objective < my_gfunc.x_best or my_gfunc.x_best == None:
                    color = "\x1b[92m"
                    my_gfunc.x_best = Objective
                else:
                    color = "\x1b[91m"
                if verbose:
                    if self.print_vals:
                        print "k=", ' '.join(["% .4f" % i for i in mvals])
                    print "|Grad|= %12.3e X2= %s%12.3e\x1b[0m d(X2)= %12.3e" % (norm(Answer),color,Objective,dx)
                    print
                return Answer
            my_gfunc.x_best = None
            return my_gfunc
        if Algorithm == "powell":
            printcool("Minimizing Objective Function using Powell's Method" , ansi=1, bold=1)
            return optimize.fmin_powell(xwrap(self.Objective.Full),self.mvals0,ftol=self.conv_obj,xtol=self.conv_stp,maxiter=self.maxstep)
        elif Algorithm == "simplex":
            printcool("Minimizing Objective Function using Simplex Method" , ansi=1, bold=1)
            return optimize.fmin(xwrap(self.Objective.Full),self.mvals0,ftol=self.conv_obj,xtol=self.conv_stp,maxiter=self.maxstep,maxfun=self.maxstep*10)
        elif Algorithm == "anneal":
            printcool("Minimizing Objective Function using Simulated Annealing" , ansi=1, bold=1)
            return optimize.anneal(xwrap(self.Objective.Full),self.mvals0,lower=-1*self.trust0*np.ones(self.np),upper=self.trust0*np.ones(self.np),schedule='boltzmann')
        elif Algorithm == "cg":
            printcool("Minimizing Objective Function using Conjugate Gradient" , ansi=1, bold=1)
            return optimize.fmin_cg(xwrap(self.Objective.Full,verbose=False),self.mvals0,fprime=gwrap(self.Objective.Full),gtol=self.conv_grd)
Example #7
0
    def MainOptimizer(self,b_BFGS=0):
        """ The main ForceBalance adaptive trust-radius pseudo-Newton optimizer.  Tried and true in many situations. :)

        Usually this function is called with the BFGS or NewtonRaphson
        method.  The NewtonRaphson method is consistently the best
        method I have, because I always provide at least an
        approximate Hessian to the objective function.  The BFGS
        method is vestigial and currently does not work.

        BFGS is a pseudo-Newton method in the sense that it builds an
        approximate Hessian matrix from the gradient information in previous
        steps; Newton-Raphson requires the actual Hessian matrix.
        However, the algorithms are similar in that they both compute the
        step by inverting the Hessian and multiplying by the gradient.

        The method adaptively changes the step size.  If the step is
        sufficiently good (i.e. the objective function goes down by a
        large fraction of the predicted decrease), then the step size
        is increased; if the step is bad, then it rejects the step and
        tries again.

        The optimization is terminated after either a function value or
        step size tolerance is reached.

        @param[in] b_BFGS Switch to use BFGS (True) or Newton-Raphson (False)

        """
        if any(['liquid' in tgt.name.lower() for tgt in self.Objective.Targets]) and self.conv_obj < 1e-3:
            warn_press_key("Condensed phase targets detected - may not converge with current choice of convergence_objective (%.e)\nRecommended range is 1e-2 - 1e-1 for this option." % self.conv_obj)
        # Parameters for the adaptive trust radius
        a = self.adapt_fac  # Default value is 0.5, decrease to make more conservative.  Zero to turn off all adaptive.
        b = self.adapt_damp # Default value is 0.5, increase to make more conservative
        printcool( "Main Optimizer\n%s Mode%s" % ("BFGS" if b_BFGS else "Newton-Raphson", " (Static Radius)" if a == 0.0 else " (Adaptive Radius)"), ansi=1, bold=1)
        # First, set a bunch of starting values
        Ord         = 1 if b_BFGS else 2
        #Ord         = 2
        global ITERATION_NUMBER
        ITERATION_NUMBER = 0
        global GOODSTEP
        Best_Step = 1
        if all(i in self.chk for i in ['xk','X','G','H','ehist','x_best','xk_prev','trust']):
            print "Reading initial objective, gradient, Hessian from checkpoint file"
            xk, X, G, H, ehist     = self.chk['xk'], self.chk['X'], self.chk['G'], self.chk['H'], self.chk['ehist']
            X_best, xk_prev, trust = self.chk['x_best'], self.chk['xk_prev'], self.chk['trust']
        else:
            xk       = self.mvals0.copy()
            print
            data     = self.Objective.Full(xk,Ord,verbose=True)
            X, G, H  = data['X'], data['G'], data['H']
            ehist    = np.array([X])
            xk_prev  = xk.copy()
            trust    = abs(self.trust0)
            X_best   = X

        X_prev   = X
        G_prev   = G.copy()
        H_stor   = H.copy()
        ndx    = 0.0
        color  = "\x1b[1m"
        nxk = norm(xk)
        ngr = norm(G)

        Quality  = 0.0
        restep = False
        GOODSTEP = 1
        Ord         = 1 if b_BFGS else 2

        while 1: # Loop until convergence is reached.
            ## Put data into the checkpoint file
            self.chk = {'xk': xk, 'X' : X, 'G' : G, 'H': H, 'ehist': ehist,
                        'x_best': X_best,'xk_prev': xk_prev, 'trust': trust}
            if self.wchk_step:
                self.writechk()
            stdfront = len(ehist) > self.hist and np.std(np.sort(ehist)[:self.hist]) or (len(ehist) > 0 and np.std(ehist) or 0.0)
            stdfront *= 2
            print "%6s%12s%12s%12s%14s%12s%12s" % ("Step", "  |k|  ","  |dk|  "," |grad| ","    -=X2=-  ","Delta(X2)", "StepQual")
            print "%6i%12.3e%12.3e%12.3e%s%14.5e\x1b[0m%12.3e% 11.3f\n" % (ITERATION_NUMBER, nxk, ndx, ngr, color, X, stdfront, Quality)
            # Check the convergence criteria
            if ngr < self.conv_grd:
                print "Convergence criterion reached for gradient norm (%.2e)" % self.conv_grd
                break
            if ITERATION_NUMBER == self.maxstep:
                print "Maximum number of optimization steps reached (%i)" % ITERATION_NUMBER
                break
            if ndx < self.conv_stp and ITERATION_NUMBER > 0 and not restep:
                print "Convergence criterion reached in step size (%.2e)" % self.conv_stp
                break
            if stdfront < self.conv_obj and len(ehist) > self.hist and not restep: # Factor of two is so [0,1] stdev is normalized to 1
                print "Convergence criterion reached for objective function (%.2e)" % self.conv_obj
                break
            if self.print_grad:
                bar = printcool("Total Gradient",color=4)
                self.FF.print_map(vals=G,precision=8)
                print bar
            if self.print_hess:
                bar = printcool("Total Hessian",color=4)
                pmat2d(H,precision=8)
                print bar
            for key, val in self.Objective.ObjDict.items():
                if Best_Step:
                    self.Objective.ObjDict_Last[key] = val
            restep = False
            dx, dX_expect, bump = self.step(xk, data, trust)
            old_pk = self.FF.create_pvals(xk)
            old_xk = xk.copy()
            # Increment the iteration counter.
            ITERATION_NUMBER += 1
            # Take a step in the parameter space.
            xk += dx
            if self.print_vals:
                pk = self.FF.create_pvals(xk)
                dp = pk - old_pk
                bar = printcool("Mathematical Parameters (Current + Step = Next)",color=5)
                self.FF.print_map(vals=["% .4e %s %.4e = % .4e" % (old_xk[i], '+' if dx[i] >= 0 else '-', abs(dx[i]), xk[i]) for i in range(len(xk))])
                print bar
                bar = printcool("Physical Parameters (Current + Step = Next)",color=5)
                self.FF.print_map(vals=["% .4e %s %.4e = % .4e" % (old_pk[i], '+' if dp[i] >= 0 else '-', abs(dp[i]), pk[i]) for i in range(len(pk))])
                print bar
            # Evaluate the objective function and its derivatives.
            data        = self.Objective.Full(xk,Ord,verbose=True)
            X, G, H = data['X'], data['G'], data['H']
            ndx = norm(dx)
            nxk = norm(xk)
            ngr = norm(G)
            drc = abs(flat(dx)).argmax()

            dX_actual = X - X_prev
            try:
                Quality = dX_actual / dX_expect
            except:
                print "Warning: Step size of zero detected (i.e. wrong direction).  Try reducing the finite_difference_h parameter"
                Quality = 1.0 # This is a step length of zero.

            if Quality <= 0.25 and X < (X_prev + self.err_tol) and self.trust0 > 0:
                # If the step quality is bad, then we should decrease the trust radius.
                trust = max(ndx*(1./(1+a)), self.mintrust)
                print "Low quality step, reducing trust radius to % .4e" % trust
            if Quality >= 0.75 and bump and self.trust0 > 0:
                # If the step quality is good, then we should increase the trust radius.
                # The 'a' factor is how much we should grow or shrink the trust radius each step
                # and the 'b' factor determines how closely we are tied down to the original value.
                # Recommend values 0.5 and 0.5
                trust += a*trust*np.exp(-b*(trust/self.trust0 - 1))
            if X > (X_prev + self.err_tol):
                Best_Step = 0
                # Toggle switch for rejection (experimenting with no rejection)
                Rejects = True
                GOODSTEP = 0
                Reevaluate = True
                trust = max(ndx*(1./(1+a)), self.mintrust)
                print "Rejecting step and reducing trust radius to % .4e" % trust
                if Rejects:
                    xk = xk_prev.copy()
                    if Reevaluate:
                        restep = True
                        color = "\x1b[91m"
                        print "%6s%12s%12s%12s%14s%12s%12s" % ("Step", "  |k|  ","  |dk|  "," |grad| ","    -=X2=-  ","Delta(X2)", "StepQual")
                        print "%6i%12.3e%12.3e%12.3e%s%14.5e\x1b[0m%12.3e% 11.3f\n" % (ITERATION_NUMBER, nxk, ndx, ngr, color, X, stdfront, Quality)
                        printcool("Objective function rises!\nRe-evaluating at the previous point..",color=1)
                        ITERATION_NUMBER += 1
                        data        = self.Objective.Full(xk,Ord,verbose=True)
                        GOODSTEP = 1
                        X, G, H = data['X'], data['G'], data['H']
                        X_prev = X
                        dx *= 0
                        ndx = norm(dx)
                        nxk = norm(xk)
                        ngr = norm(G)
                        Quality = 0.0
                        color = "\x1b[0m"
                    else:
                        color = "\x1b[91m"
                        G = G_prev.copy()
                        H = H_stor.copy()
                        data = deepcopy(datastor)
                    continue
            else:
                GOODSTEP = 1
                if X > X_best:
                    Best_Step = 0
                    color = "\x1b[95m"
                else:
                    Best_Step = 1
                    color = "\x1b[92m"
                    X_best = X
                ehist = np.append(ehist, X)
            # Hessian update for BFGS.
            if b_BFGS:
                Hnew = H_stor.copy()
                Dx   = col(xk - xk_prev)
                Dy   = col(G  - G_prev)
                Mat1 = (Dy*Dy.T)/(Dy.T*Dx)[0,0]
                Mat2 = ((Hnew*Dx)*(Hnew*Dx).T)/(Dx.T*Hnew*Dx)[0,0]
                Hnew += Mat1-Mat2
                H = Hnew.copy()
                data['H'] = H.copy()

            datastor= deepcopy(data)
            G_prev  = G.copy()
            H_stor  = H.copy()
            xk_prev = xk.copy()
            X_prev  = X
            if len(self.FF.parmdestroy_this) > 0:
                self.FF.parmdestroy_save.append(self.FF.parmdestroy_this)
                self.FF.linedestroy_save.append(self.FF.linedestroy_this)
        
        bar = printcool("Final objective function value\nFull: % .6e  Un-penalized: % .6e" % (data['X'],data['X0']), '@', bold=True, color=2)
        return xk