def get_H(self,mvals=None,customdir=None): """Computes the objective function contribution and its gradient / Hessian. First the low-level 'get' method is called with the analytic gradient and Hessian both turned on. Then we loop through the fd1_pids and compute the corresponding elements of the gradient by finite difference, if the 'fdgrad' switch is turned on. This is followed by looping through the fd2_pids and computing the corresponding Hessian elements by finite difference. Forward finite difference is used throughout for the sake of speed. """ Ans = self.meta_get(mvals,1,1,customdir=customdir) if self.fdhess: for i in self.pgrad: if any([j in self.FF.plist[i] for j in self.fd1_pids]) or 'ALL' in self.fd1_pids: Ans['G'][i] = f1d2p(fdwrap_G(self,mvals,i),self.h,f0 = Ans['X']) for i in self.pgrad: if any([j in self.FF.plist[i] for j in self.fd2_pids]) or 'ALL' in self.fd2_pids: FDSlice = f1d2p(fdwrap_H(self,mvals,i),self.h,f0 = Ans['G']) Ans['H'][i,:] = FDSlice Ans['H'][:,i] = FDSlice elif self.fdhessdiag: for i in self.pgrad: if any([j in self.FF.plist[i] for j in self.fd2_pids]) or 'ALL' in self.fd2_pids: Ans['G'][i], Ans['H'][i,i] = f12d3p(fdwrap_G(self,mvals,i),self.h, f0 = Ans['X']) if Counter() == self.zerograd and self.zerograd >= 0: self.write_0grads(Ans) self.hct += 1 return Ans
def get_H(self,mvals=None): """Computes the objective function contribution and its gradient / Hessian. First the low-level 'get' method is called with the analytic gradient and Hessian both turned on. Then we loop through the fd1_pids and compute the corresponding elements of the gradient by finite difference, if the 'fdgrad' switch is turned on. This is followed by looping through the fd2_pids and computing the corresponding Hessian elements by finite difference. Forward finite difference is used throughout for the sake of speed. """ Ans = self.meta_get(mvals,1,1) if self.fdhess: for i in self.pgrad: if any([j in self.FF.plist[i] for j in self.fd1_pids]) or 'ALL' in self.fd1_pids: Ans['G'][i] = f1d2p(fdwrap_G(self,mvals,i),self.h,f0 = Ans['X']) for i in self.pgrad: if any([j in self.FF.plist[i] for j in self.fd2_pids]) or 'ALL' in self.fd2_pids: FDSlice = f1d2p(fdwrap_H(self,mvals,i),self.h,f0 = Ans['G']) Ans['H'][i,:] = FDSlice Ans['H'][:,i] = FDSlice elif self.fdhessdiag: for i in self.pgrad: if any([j in self.FF.plist[i] for j in self.fd2_pids]) or 'ALL' in self.fd2_pids: Ans['G'][i], Ans['H'][i,i] = f12d3p(fdwrap_G(self,mvals,i),self.h, f0 = Ans['X']) self.write_0grads(Ans) self.hct += 1 return Ans
def get_G(self,mvals=None): """Computes the objective function contribution and its gradient. First the low-level 'get' method is called with the analytic gradient switch turned on. Then we loop through the fd1_pids and compute the corresponding elements of the gradient by finite difference, if the 'fdgrad' switch is turned on. Alternately we can compute the gradient elements and diagonal Hessian elements at the same time using central difference if 'fdhessdiag' is turned on. In this function we also record which parameters cause a nonzero change in the objective function contribution. Parameters which do not change the objective function will not be differentiated in subsequent calculations. This is recorded in a text file in the targets directory. """ Ans = self.meta_get(mvals,1,0) for i in self.pgrad: if any([j in self.FF.plist[i] for j in self.fd1_pids]) or 'ALL' in self.fd1_pids: if self.fdhessdiag: Ans['G'][i], Ans['H'][i,i] = f12d3p(fdwrap_G(self,mvals,i),self.h,f0 = Ans['X']) elif self.fdgrad: Ans['G'][i] = f1d2p(fdwrap_G(self,mvals,i),self.h,f0 = Ans['X']) self.gct += 1 self.write_0grads(Ans) return Ans
def get_G(self,mvals=None): """Computes the objective function contribution and its gradient. First the low-level 'get' method is called with the analytic gradient switch turned on. Then we loop through the fd1_pids and compute the corresponding elements of the gradient by finite difference, if the 'fdgrad' switch is turned on. Alternately we can compute the gradient elements and diagonal Hessian elements at the same time using central difference if 'fdhessdiag' is turned on. """ Ans = self.sget(mvals,1,0) for i in range(self.FF.np): if any([j in self.FF.plist[i] for j in self.fd1_pids]) or 'ALL' in self.fd1_pids: if self.fdhessdiag: Ans['G'][i], Ans['H'][i,i] = f12d3p(fdwrap_G(self,mvals,i),self.h,f0 = Ans['X']) elif self.fdgrad: Ans['G'][i] = f1d2p(fdwrap_G(self,mvals,i),self.h,f0 = Ans['X']) self.gct += 1 return Ans
def get(self, mvals, AGrad=False, AHess=False): """ LPW 05-30-2012 This subroutine builds the objective function (and optionally its derivatives) from a general software. This subroutine interfaces with simulation software 'drivers'. The driver is expected to give exact values, fitting values, and weights. @param[in] mvals Mathematical parameter values @param[in] AGrad Switch to turn on analytic gradient @param[in] AHess Switch to turn on analytic Hessian @return Answer Contribution to the objective function """ global LAST_MVALS, CHECK_BASIS # print mvals # print LAST_MVALS # print mvals == LAST_MVALS if LAST_MVALS is None or not (mvals == LAST_MVALS).all(): CHECK_BASIS = False else: CHECK_BASIS = False Answer = {} Fac = 1000000 ## Dictionary for derivative terms dM = {} # Create the new force field!! NP = len(mvals) G = np.zeros(NP) H = np.zeros((NP, NP)) pvals = self.FF.make(mvals) if float('Inf') in pvals: return {'X': 1e10, 'G': G, 'H': H} Ans = self.driver() W = Ans[:, 2] M = Ans[:, 1] Q = Ans[:, 0] D = M - Q self.MAQ = np.mean(np.abs(Q)) ns = len(M) # Wrapper to the driver, which returns just the part that changes. def callM(mvals_): self.FF.make(mvals_) Ans2 = self.driver() M_ = Ans2[:, 1] D_ = M_ - Q return Ans2[:, 1] if AGrad: # Leaving comment here if we want to reintroduce second deriv someday. # dM[p,:], ddM[p,:] = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = M) xgrad = [] for p in self.pgrad: dM_arr = f1d2p(fdwrap(callM, mvals, p), h=self.h, f0=M) if np.max(np.abs(dM_arr)) == 0.0 and (not self.evaluated): logger.info( "\r Simulation %s will skip over parameter %i in subsequent steps\n" % (self.name, p)) xgrad.append(p) else: dM[p] = dM_arr.copy() for p in xgrad: self.pgrad.remove(p) Objective = np.dot(W, D**2) * Fac if AGrad: for p in self.pgrad: G[p] = 2 * np.dot(W, D * dM[p]) if not AHess: continue H[p, p] = 2 * np.dot(W, dM[p]**2) for q in range(p): if q not in self.pgrad: continue GNP = 2 * np.dot(W, dM[p] * dM[q]) H[q, p] = GNP H[p, q] = GNP G *= Fac H *= Fac Answer = {'X': Objective, 'G': G, 'H': H} if not in_fd(): self.D = D self.objective = Answer['X'] LAST_MVALS = mvals.copy() return Answer
def get(self, mvals, AGrad=False, AHess=False): """ LPW 05-30-2012 This subroutine builds the objective function (and optionally its derivatives) from a general software. This subroutine interfaces with simulation software 'drivers'. The driver is expected to give exact values, fitting values, and weights. @param[in] mvals Mathematical parameter values @param[in] AGrad Switch to turn on analytic gradient @param[in] AHess Switch to turn on analytic Hessian @return Answer Contribution to the objective function """ global LAST_MVALS, CHECK_BASIS # print mvals # print LAST_MVALS # print mvals == LAST_MVALS if LAST_MVALS is None or not (mvals == LAST_MVALS).all(): CHECK_BASIS = False else: CHECK_BASIS = False Answer = {} Fac = 1000000 ## Dictionary for derivative terms dM = {} # Create the new force field!! NP = len(mvals) G = np.zeros(NP) H = np.zeros((NP,NP)) pvals = self.FF.make(mvals) if float('Inf') in pvals: return {'X' : 1e10, 'G' : G, 'H' : H} Ans = self.driver() W = Ans[:,2] M = Ans[:,1] Q = Ans[:,0] D = M - Q self.MAQ = np.mean(np.abs(Q)) ns = len(M) # Wrapper to the driver, which returns just the part that changes. def callM(mvals_): self.FF.make(mvals_) Ans2 = self.driver() M_ = Ans2[:,1] D_ = M_ - Q return Ans2[:,1] if AGrad: # Leaving comment here if we want to reintroduce second deriv someday. # dM[p,:], ddM[p,:] = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = M) xgrad = [] for p in self.pgrad: dM_arr = f1d2p(fdwrap(callM, mvals, p), h = self.h, f0 = M) if np.max(np.abs(dM_arr)) == 0.0 and (not self.evaluated): logger.info("\r Simulation %s will skip over parameter %i in subsequent steps\n" % (self.name, p)) xgrad.append(p) else: dM[p] = dM_arr.copy() for p in xgrad: self.pgrad.remove(p) Objective = np.dot(W, D**2) * Fac if AGrad: for p in self.pgrad: G[p] = 2 * np.dot(W, D*dM[p]) if not AHess: continue H[p, p] = 2 * np.dot(W, dM[p]**2) for q in range(p): if q not in self.pgrad: continue GNP = 2 * np.dot(W, dM[p] * dM[q]) H[q,p] = GNP H[p,q] = GNP G *= Fac H *= Fac Answer = {'X':Objective, 'G':G, 'H':H} if not in_fd(): self.D = D self.objective = Answer['X'] LAST_MVALS = mvals.copy() return Answer
def get(self, mvals, AGrad=False, AHess=False): """ LPW 04-17-2013 This subroutine builds the objective function from Psi4. @param[in] mvals Mathematical parameter values @param[in] AGrad Switch to turn on analytic gradient @param[in] AHess Switch to turn on analytic Hessian @return Answer Contribution to the objective function """ Answer = {} Fac = 1000000 n = len(mvals) X = 0.0 G = np.zeros(n) H = np.zeros((n,n)) pvals = self.FF.make(mvals) self.tdir = os.getcwd() self.objd = OrderedDict() self.gradd = OrderedDict() self.hdiagd = OrderedDict() wq = getWorkQueue() def fdwrap2(func,mvals0,pidx,qidx,key=None,**kwargs): def func2(arg1,arg2): mvals = list(mvals0) mvals[pidx] += arg1 mvals[qidx] += arg2 logger.info("\rfdwrap2:" + func.__name__ + "[%i] = % .1e , [%i] = % .1e" % (pidx, arg1, qidx, arg2) + ' '*50) if key != None: return func(mvals,**kwargs)[key] else: return func(mvals,**kwargs) return func2 def f2d5p(f, h): fpp, fpm, fmp, fmm = [f(i*h,j*h) for i,j in [(1,1),(1,-1),(-1,1),(-1,-1)]] fpp = (fpp-fpm-fmp+fmm)/(4*h*h) return fpp def f2d4p(f, h, f0 = None): if f0 == None: fpp, fp0, f0p, f0 = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1),(0,0)]] else: fpp, fp0, f0p = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1)]] fpp = (fpp-fp0-f0p+f0)/(h*h) return fpp for d in self.objfiles: logger.info("\rNow working on" + str(d) + 50*' ' + '\r') if wq == None: x = self.driver(mvals, d) grad = np.zeros(n) hdiag = np.zeros(n) hess = np.zeros((n,n)) apath = os.path.join(self.tdir, d, "current") x = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor for p in range(self.FF.np): if self.callderivs[d][p]: def reader(mvals_,h): apath = os.path.join(self.tdir, d, str(p), str(h)) answer = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor return answer if AHess: if wq != None: apath = os.path.join(self.tdir, d, "current") x = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor grad[p], hdiag[p] = f12d3p(fdwrap(reader, mvals, p, h=self.h), h = self.h, f0 = x) else: grad[p], hdiag[p] = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x) hess[p,p] = hdiag[p] elif AGrad: if self.bidirect: if wq != None: apath = os.path.join(self.tdir, d, "current") x = float(open(os.path.join(apath,'objective.out')).readlines()[0].split()[1])*self.factor grad[p], _ = f12d3p(fdwrap(reader, mvals, p, h=self.h), h = self.h, f0 = x) else: grad[p], _ = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x) else: if wq != None: # Since the calculations are submitted as 3-point finite difference, this part of the code # actually only reads from half of the completed calculations. grad[p] = f1d2p(fdwrap(reader, mvals, p, h=self.h), h = self.h, f0 = x) else: grad[p] = f1d2p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x) self.objd[d] = x self.gradd[d] = grad self.hdiagd[d] = hdiag X += x G += grad #H += np.diag(hdiag) H += hess if not in_fd(): self.objective = X self.objvals = self.objd # print self.objd # print self.gradd # print self.hdiagd if float('Inf') in pvals: return {'X' : 1e10, 'G' : G, 'H' : H} return {'X' : X, 'G' : G, 'H' : H}
def submit_jobs(self, mvals, AGrad=True, AHess=True): # This routine is called by Objective.stage() will run before "get". # It submits the jobs to the Work Queue and the stage() function will wait for jobs to complete. # self.tdir = os.getcwd() wq = getWorkQueue() if wq == None: return def submit_psi(this_apath, mname, these_mvals): """ Create a grid file and a psi4 input file in the absolute path and submit it to the work queue. """ cwd = os.getcwd() if not os.path.exists(this_apath) : os.makedirs(this_apath) os.chdir(this_apath) self.FF.make(these_mvals) o = wopen('objective.dat') for line in self.objfiles[d]: s = line.split() if len(s) > 2 and s[0] == 'path' and s[1] == '=': print >> o, "path = '%s'" % os.getcwd() elif len(s) > 2 and s[0] == 'set' and s[1] == 'objective_path': print >> o, "opath = '%s'" % os.getcwd() print >> o, "set objective_path $opath" else: print >> o, line, o.close() os.system("rm -f objective.out") if wq == None: logger.info("There is no Work Queue!!!\n") sys.exit() else: input_files = [(os.path.join(this_apath, i), i) for i in glob.glob("*")] # input_files += [(os.path.join(self.tgtdir,d,"build.dat"), "build.dat")] input_files += [(os.path.join(os.path.split(__file__)[0],"data","run_psi_rdvr3_objective.sh"), "run_psi_rdvr3_objective.sh")] logger.info("\r") queue_up_src_dest(wq,"sh run_psi_rdvr3_objective.sh %s &> run_psi_rdvr3_objective.log" % mname, input_files=input_files, output_files=[(os.path.join(this_apath, i),i) for i in ["run_psi_rdvr3_objective.log", "output.dat"]], verbose=False) os.chdir(cwd) for d in self.objfiles: logger.info("\rNow working on" + str(d) + 50*' ' + '\r') odir = os.path.join(os.getcwd(),d) #if os.path.exists(odir): # shutil.rmtree(odir) if not os.path.exists(odir): os.makedirs(odir) apath = os.path.join(odir, "current") submit_psi(apath, d, mvals) for p in range(self.FF.np): def subjob(mvals_,h): apath = os.path.join(odir, str(p), str(h)) submit_psi(apath, d, mvals_) #logger.info("Will set up a job for %s, parameter %i\n" % (d, p)) return 0.0 if self.callderivs[d][p]: if AHess: f12d3p(fdwrap(subjob, mvals, p, h=self.h), h = self.h, f0 = 0.0) elif AGrad: if self.bidirect: f12d3p(fdwrap(subjob, mvals, p, h=self.h), h = self.h, f0 = 0.0) else: f1d2p(fdwrap(subjob, mvals, p, h=self.h), h = self.h, f0 = 0.0)
def get(self, mvals, AGrad=False, AHess=False): """ LPW 04-17-2013 This subroutine builds the objective function from Psi4. @param[in] mvals Mathematical parameter values @param[in] AGrad Switch to turn on analytic gradient @param[in] AHess Switch to turn on analytic Hessian @return Answer Contribution to the objective function """ Answer = {} Fac = 1000000 n = len(mvals) X = 0.0 G = np.zeros(n) H = np.zeros((n, n)) pvals = self.FF.make(mvals) self.tdir = os.getcwd() self.objd = OrderedDict() self.gradd = OrderedDict() self.hdiagd = OrderedDict() wq = getWorkQueue() def fdwrap2(func, mvals0, pidx, qidx, key=None, **kwargs): def func2(arg1, arg2): mvals = list(mvals0) mvals[pidx] += arg1 mvals[qidx] += arg2 logger.info("\rfdwrap2:" + func.__name__ + "[%i] = % .1e , [%i] = % .1e" % (pidx, arg1, qidx, arg2) + ' ' * 50) if key is not None: return func(mvals, **kwargs)[key] else: return func(mvals, **kwargs) return func2 def f2d5p(f, h): fpp, fpm, fmp, fmm = [ f(i * h, j * h) for i, j in [(1, 1), (1, -1), (-1, 1), (-1, -1)] ] fpp = (fpp - fpm - fmp + fmm) / (4 * h * h) return fpp def f2d4p(f, h, f0=None): if f0 is None: fpp, fp0, f0p, f0 = [ f(i * h, j * h) for i, j in [(1, 1), (1, 0), (0, 1), (0, 0)] ] else: fpp, fp0, f0p = [ f(i * h, j * h) for i, j in [(1, 1), (1, 0), (0, 1)] ] fpp = (fpp - fp0 - f0p + f0) / (h * h) return fpp for d in self.objfiles: logger.info("\rNow working on" + str(d) + 50 * ' ' + '\r') if wq is None: x = self.driver(mvals, d) grad = np.zeros(n) hdiag = np.zeros(n) hess = np.zeros((n, n)) apath = os.path.join(self.tdir, d, "current") x = float( open(os.path.join( apath, 'objective.out')).readlines()[0].split()[1]) * self.factor for p in range(self.FF.np): if self.callderivs[d][p]: def reader(mvals_, h): apath = os.path.join(self.tdir, d, str(p), str(h)) answer = float( open(os.path.join(apath, 'objective.out')). readlines()[0].split()[1]) * self.factor return answer if AHess: if wq is not None: apath = os.path.join(self.tdir, d, "current") x = float( open(os.path.join(apath, 'objective.out')). readlines()[0].split()[1]) * self.factor grad[p], hdiag[p] = f12d3p(fdwrap(reader, mvals, p, h=self.h), h=self.h, f0=x) else: grad[p], hdiag[p] = f12d3p(fdwrap(self.driver, mvals, p, d=d), h=self.h, f0=x) hess[p, p] = hdiag[p] elif AGrad: if self.bidirect: if wq is not None: apath = os.path.join(self.tdir, d, "current") x = float( open(os.path.join(apath, 'objective.out')). readlines()[0].split()[1]) * self.factor grad[p], _ = f12d3p(fdwrap(reader, mvals, p, h=self.h), h=self.h, f0=x) else: grad[p], _ = f12d3p(fdwrap(self.driver, mvals, p, d=d), h=self.h, f0=x) else: if wq is not None: # Since the calculations are submitted as 3-point finite difference, this part of the code # actually only reads from half of the completed calculations. grad[p] = f1d2p(fdwrap(reader, mvals, p, h=self.h), h=self.h, f0=x) else: grad[p] = f1d2p(fdwrap(self.driver, mvals, p, d=d), h=self.h, f0=x) self.objd[d] = x self.gradd[d] = grad self.hdiagd[d] = hdiag X += x G += grad #H += np.diag(hdiag) H += hess if not in_fd(): self.objective = X self.objvals = self.objd # print self.objd # print self.gradd # print self.hdiagd if float('Inf') in pvals: return {'X': 1e10, 'G': G, 'H': H} return {'X': X, 'G': G, 'H': H}
def submit_jobs(self, mvals, AGrad=True, AHess=True): # This routine is called by Objective.stage() will run before "get". # It submits the jobs to the Work Queue and the stage() function will wait for jobs to complete. # self.tdir = os.getcwd() wq = getWorkQueue() if wq is None: return def submit_psi(this_apath, dname, these_mvals): """ Create a grid file and a psi4 input file in the absolute path and submit it to the work queue. """ cwd = os.getcwd() if not os.path.exists(this_apath): os.makedirs(this_apath) os.chdir(this_apath) self.FF.make(these_mvals) o = wopen('objective.dat') for line in self.objfiles[d]: s = line.split() if len(s) > 2 and s[0] == 'path' and s[1] == '=': print("path = '%s'" % os.getcwd(), file=o) elif len(s) > 2 and s[0] == 'set' and s[1] == 'objective_path': print("opath = '%s'" % os.getcwd(), file=o) print("set objective_path $opath", file=o) else: print(line, end=' ', file=o) o.close() os.system("rm -f objective.out") if wq is None: logger.info("There is no Work Queue!!!\n") sys.exit() else: input_files = [(os.path.join(this_apath, i), i) for i in glob.glob("*")] input_files += [(os.path.join(self.root, self.tgtdir, dname, "build.dat"), "build.dat")] input_files += [(os.path.join( os.path.split(__file__)[0], "data", "run_psi_rdvr3_objective.sh"), "run_psi_rdvr3_objective.sh")] logger.info("\r") queue_up_src_dest( wq, "sh run_psi_rdvr3_objective.sh -c %s &> run_psi_rdvr3_objective.log" % os.path.join(self.root, self.tgtdir, dname), input_files=input_files, output_files=[ (os.path.join(this_apath, i), i) for i in ["run_psi_rdvr3_objective.log", "output.dat"] ], verbose=False) os.chdir(cwd) for d in self.objfiles: logger.info("\rNow working on" + str(d) + 50 * ' ' + '\r') odir = os.path.join(os.getcwd(), d) #if os.path.exists(odir): # shutil.rmtree(odir) if not os.path.exists(odir): os.makedirs(odir) apath = os.path.join(odir, "current") submit_psi(apath, d, mvals) for p in range(self.FF.np): def subjob(mvals_, h): apath = os.path.join(odir, str(p), str(h)) submit_psi(apath, d, mvals_) #logger.info("Will set up a job for %s, parameter %i\n" % (d, p)) return 0.0 if self.callderivs[d][p]: if AHess: f12d3p(fdwrap(subjob, mvals, p, h=self.h), h=self.h, f0=0.0) elif AGrad: if self.bidirect: f12d3p(fdwrap(subjob, mvals, p, h=self.h), h=self.h, f0=0.0) else: f1d2p(fdwrap(subjob, mvals, p, h=self.h), h=self.h, f0=0.0)
def get(self, mvals, AGrad=False, AHess=False): """ LPW 04-17-2013 This subroutine builds the objective function from Psi4. @param[in] mvals Mathematical parameter values @param[in] AGrad Switch to turn on analytic gradient @param[in] AHess Switch to turn on analytic Hessian @return Answer Contribution to the objective function """ Answer = {} Fac = 1000000 n = len(mvals) X = 0.0 G = np.zeros(n,dtype=float) H = np.zeros((n,n),dtype=float) pvals = self.FF.make(mvals) self.tdir = os.getcwd() self.objd = OrderedDict() self.gradd = OrderedDict() self.hdiagd = OrderedDict() bidirect = False def fdwrap2(func,mvals0,pidx,qidx,key=None,**kwargs): def func2(arg1,arg2): mvals = list(mvals0) mvals[pidx] += arg1 mvals[qidx] += arg2 print "\rfdwrap2:", func.__name__, "[%i] = % .1e , [%i] = % .1e" % (pidx, arg1, qidx, arg2), ' '*50, if key != None: return func(mvals,**kwargs)[key] else: return func(mvals,**kwargs) return func2 def f2d5p(f, h): fpp, fpm, fmp, fmm = [f(i*h,j*h) for i,j in [(1,1),(1,-1),(-1,1),(-1,-1)]] fpp = (fpp-fpm-fmp+fmm)/(4*h*h) return fpp def f2d4p(f, h, f0 = None): if f0 == None: fpp, fp0, f0p, f0 = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1),(0,0)]] else: fpp, fp0, f0p = [f(i*h,j*h) for i,j in [(1,1),(1,0),(0,1)]] fpp = (fpp-fp0-f0p+f0)/(h*h) return fpp for d in self.objfiles: print "\rNow working on", d, 50*' ','\r', x = self.driver(mvals, d) grad = np.zeros(n,dtype=float) hdiag = np.zeros(n,dtype=float) hess = np.zeros((n,n),dtype=float) for p in range(self.FF.np): if self.callderivs[d][p]: if AHess: grad[p], hdiag[p] = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x) hess[p,p] = hdiag[p] # for q in range(p): # if self.callderivs[d][q]: # if bidirect: # hessentry = f2d5p(fdwrap2(self.driver, mvals, p, q, d=d), h = self.h) # else: # hessentry = f2d4p(fdwrap2(self.driver, mvals, p, q, d=d), h = self.h, f0 = x) # hess[p,q] = hessentry # hess[q,p] = hessentry elif AGrad: if bidirect: grad[p], _ = f12d3p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x) else: grad[p] = f1d2p(fdwrap(self.driver, mvals, p, d=d), h = self.h, f0 = x) self.objd[d] = x self.gradd[d] = grad self.hdiagd[d] = hdiag X += x G += grad #H += np.diag(hdiag) H += hess if not in_fd(): self.objective = X self.objvals = self.objd # print self.objd # print self.gradd # print self.hdiagd if float('Inf') in pvals: return {'X' : 1e10, 'G' : G, 'H' : H} return {'X' : X, 'G' : G, 'H' : H}
def get(self, mvals, AGrad=False, AHess=False): """ LPW 05-30-2012 This subroutine builds the objective function (and optionally its derivatives) from a general software. This subroutine interfaces with simulation software 'drivers'. The driver is expected to give exact values, fitting values, and weights. @param[in] mvals Mathematical parameter values @param[in] AGrad Switch to turn on analytic gradient @param[in] AHess Switch to turn on analytic Hessian @return Answer Contribution to the objective function """ global LAST_MVALS, CHECK_BASIS # print mvals # print LAST_MVALS # print mvals == LAST_MVALS if LAST_MVALS == None or not (mvals == LAST_MVALS).all(): CHECK_BASIS = False else: CHECK_BASIS = False Answer = {} Fac = 1000000 ## Dictionary for derivative terms dM = {} # Create the new force field!! np = len(mvals) G = zeros(np, dtype=float) H = zeros((np, np), dtype=float) pvals = self.FF.make(mvals) if float("Inf") in pvals: return {"X": 1e10, "G": G, "H": H} Ans = self.driver() W = Ans[:, 2] M = Ans[:, 1] Q = Ans[:, 0] D = M - Q self.MAQ = mean(abs(Q)) ns = len(M) # Wrapper to the driver, which returns just the part that changes. def callM(mvals_): self.FF.make(mvals_) Ans2 = self.driver() M_ = Ans2[:, 1] D_ = M_ - Q return Ans2[:, 1] if AGrad: # Leaving comment here if we want to reintroduce second deriv someday. # dM[p,:], ddM[p,:] = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = M) for p in range(np): if self.call_derivatives[p] == False: continue dM_arr = f1d2p(fdwrap(callM, mvals, p), h=self.h, f0=M) if max(abs(dM_arr)) == 0.0 and Counter() == 0: print "\r Simulation %s will skip over parameter %i in subsequent steps" % (self.name, p) self.call_derivatives[p] = False else: dM[p] = dM_arr.copy() Objective = dot(W, D ** 2) * Fac if AGrad: for p in range(np): if self.call_derivatives[p] == False: continue G[p] = 2 * dot(W, D * dM[p]) if not AHess: continue H[p, p] = 2 * dot(W, dM[p] ** 2) for q in range(p): if self.call_derivatives[q] == False: continue GNP = 2 * dot(W, dM[p] * dM[q]) H[q, p] = GNP H[p, q] = GNP G *= Fac H *= Fac Answer = {"X": Objective, "G": G, "H": H} if not in_fd(): self.D = D self.objective = Answer["X"] LAST_MVALS = mvals.copy() return Answer