def Target_Terms(self, mvals, Order=0, verbose=False, customdir=None): ## This is the objective function; it's a dictionary containing the value, first and second derivatives Objective = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np,self.FF.np))} # Loop through the targets, stage the directories and submit the Work Queue processes. for Tgt in self.Targets: Tgt.stage(mvals, AGrad = Order >= 1, AHess = Order >= 2, customdir=customdir) if self.asynchronous: # Asynchronous evaluation of objective function and Work Queue tasks. # Create a list of the targets, and remove them from the list as they are finished. Need2Evaluate = self.Targets[:] # This ensures that the OrderedDict doesn't get out of order. for Tgt in self.Targets: self.ObjDict[Tgt.name] = None # Loop through the targets and compute the objective function for ones that are finished. while len(Need2Evaluate) > 0: for Tgt in Need2Evaluate: if Tgt.wq_complete(): # List of functions that I can call. Funcs = [Tgt.get_X, Tgt.get_G, Tgt.get_H] # Call the appropriate function Ans = Funcs[Order](mvals, customdir=customdir) # Print out the qualitative indicators if verbose: Tgt.meta_indicate(customdir=customdir) # Note that no matter which order of function we call, we still increment the objective / gradient / Hessian the same way. if not in_fd(): self.ObjDict[Tgt.name] = {'w' : Tgt.weight/self.WTot , 'x' : Ans['X']} for i in range(3): Objective[Letters[i]] += Ans[Letters[i]]*Tgt.weight/self.WTot Need2Evaluate.remove(Tgt) break else: pass else: wq = getWorkQueue() if wq != None: wq_wait(wq) for Tgt in self.Targets: # The first call is always done at the midpoint. Tgt.bSave = True # List of functions that I can call. Funcs = [Tgt.get_X, Tgt.get_G, Tgt.get_H] # Call the appropriate function Ans = Funcs[Order](mvals, customdir=customdir) # Print out the qualitative indicators if verbose: Tgt.meta_indicate(customdir=customdir) # Note that no matter which order of function we call, we still increment the objective / gradient / Hessian the same way. if not in_fd(): self.ObjDict[Tgt.name] = {'w' : Tgt.weight/self.WTot , 'x' : Ans['X']} for i in range(3): Objective[Letters[i]] += Ans[Letters[i]]*Tgt.weight/self.WTot # The target has evaluated at least once. for Tgt in self.Targets: Tgt.evaluated = True # Safeguard to make sure we don't have exact zeros on Hessian diagonal for i in range(self.FF.np): if Objective['H'][i,i] == 0.0: Objective['H'][i,i] = 1.0 return Objective
def Target_Terms(self, mvals, Order=0, verbose=False, customdir=None): ## This is the objective function; it's a dictionary containing the value, first and second derivatives Objective = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np,self.FF.np))} # Loop through the targets, stage the directories and submit the Work Queue processes. for Tgt in self.Targets: Tgt.stage(mvals, AGrad = Order >= 1, AHess = Order >= 2, customdir=customdir) if self.asynchronous: # Asynchronous evaluation of objective function and Work Queue tasks. # Create a list of the targets, and remove them from the list as they are finished. Need2Evaluate = self.Targets[:] # This ensures that the OrderedDict doesn't get out of order. for Tgt in self.Targets: self.ObjDict[Tgt.name] = None # Loop through the targets and compute the objective function for ones that are finished. while len(Need2Evaluate) > 0: for Tgt in Need2Evaluate: if Tgt.wq_complete(): # List of functions that I can call. Funcs = [Tgt.get_X, Tgt.get_G, Tgt.get_H] # Call the appropriate function Ans = Funcs[Order](mvals, customdir=customdir) # Print out the qualitative indicators if verbose: Tgt.meta_indicate(customdir=customdir) # Note that no matter which order of function we call, we still increment the objective / gradient / Hessian the same way. if not in_fd(): self.ObjDict[Tgt.name] = {'w' : Tgt.weight/self.WTot , 'x' : Ans['X']} for i in range(3): Objective[Letters[i]] += Ans[Letters[i]]*Tgt.weight/self.WTot Need2Evaluate.remove(Tgt) break else: pass else: wq = getWorkQueue() if wq is not None: wq_wait(wq) for Tgt in self.Targets: # The first call is always done at the midpoint. Tgt.bSave = True # List of functions that I can call. Funcs = [Tgt.get_X, Tgt.get_G, Tgt.get_H] # Call the appropriate function Ans = Funcs[Order](mvals, customdir=customdir) # Print out the qualitative indicators if verbose: Tgt.meta_indicate(customdir=customdir) # Note that no matter which order of function we call, we still increment the objective / gradient / Hessian the same way. if not in_fd(): self.ObjDict[Tgt.name] = {'w' : Tgt.weight/self.WTot , 'x' : Ans['X']} for i in range(3): Objective[Letters[i]] += Ans[Letters[i]]*Tgt.weight/self.WTot # The target has evaluated at least once. for Tgt in self.Targets: Tgt.evaluated = True # Safeguard to make sure we don't have exact zeros on Hessian diagonal for i in range(self.FF.np): if Objective['H'][i,i] == 0.0: Objective['H'][i,i] = 1.0 return Objective
def compute(mvals, p_idx=None): ''' Compute total objective value for each system ''' self.FF.make(mvals) v_obj_list = [] for sysname, sysopt in self.sys_opts.items(): # ref values of each type vref_bonds = self.internal_coordinates[sysname]['vref_bonds'] vref_angles = self.internal_coordinates[sysname]['vref_angles'] vref_dihedrals = self.internal_coordinates[sysname]['vref_dihedrals'] vref_impropers = self.internal_coordinates[sysname]['vref_impropers'] # counts of each type n_bonds = len(vref_bonds) n_angles = len(vref_angles) n_dihedrals = len(vref_dihedrals) n_impropers = len(vref_impropers) # use self.system_mval_masks to skip evaluations when computing gradients if enable_system_mval_mask and in_fd() and (p_idx is not None) and (self.system_mval_masks[sysname][p_idx] == False): v_obj_list += [0] * (n_bonds + n_angles + n_dihedrals + n_impropers) continue # read denominators from system options bond_denom = sysopt['bond_denom'] angle_denom = sysopt['angle_denom'] dihedral_denom = sysopt['dihedral_denom'] improper_denom = sysopt['improper_denom'] # inverse demon to be scaling factors, 0 for denom 0 scale_bond = 1.0 / bond_denom if bond_denom != 0 else 0.0 scale_angle = 1.0 / angle_denom if angle_denom != 0 else 0.0 scale_dihedral = 1.0 / dihedral_denom if dihedral_denom != 0 else 0.0 scale_improper = 1.0 / improper_denom if improper_denom != 0 else 0.0 # calculate new internal coordinates v_ic = self.system_driver(sysname) # objective contribution from bonds vtar_bonds = v_ic['bonds'] diff_bond = ((vref_bonds - vtar_bonds) * scale_bond).tolist() if n_bonds > 0 else [] # objective contribution from angles vtar_angles = v_ic['angles'] diff_angle = (periodic_diff(vref_angles, vtar_angles, 360) * scale_angle).tolist() if n_angles > 0 else [] # objective contribution from dihedrals vtar_dihedrals = v_ic['dihedrals'] diff_dihedral = (periodic_diff(vref_dihedrals, vtar_dihedrals, 360) * scale_dihedral).tolist() if n_dihedrals > 0 else [] # objective contribution from improper dihedrals vtar_impropers = v_ic['impropers'] diff_improper = (periodic_diff(vref_impropers, vtar_impropers, 360) * scale_improper).tolist() if n_impropers > 0 else [] # combine objective values into a big result list sys_obj_list = diff_bond + diff_angle + diff_dihedral + diff_improper # extend the result v_obj_list by individual terms in this system v_obj_list += sys_obj_list # save print string if not in_fd(): # For printing, we group the RMSD by type rmsd_bond = compute_rmsd(vref_bonds, vtar_bonds) rmsd_angle = compute_rmsd(vref_angles, vtar_angles, v_periodic=360) rmsd_dihedral = compute_rmsd(vref_dihedrals, vtar_dihedrals, v_periodic=360) rmsd_improper = compute_rmsd(vref_impropers, vtar_impropers, v_periodic=360) obj_total = sum(v**2 for v in sys_obj_list) self.PrintDict[sysname] = "% 9.3f % 7.2f % 9.3f % 7.2f % 9.3f % 7.2f % 9.3f % 7.2f %17.3f" % (rmsd_bond, \ bond_denom, rmsd_angle, angle_denom, rmsd_dihedral, dihedral_denom, rmsd_improper, improper_denom, obj_total) return np.array(v_obj_list, dtype=float)
def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] for sys_ in self.sys_opts: Energy_, RMSD_ = self.system_driver(sys_) #print "Setting %s to" % sys_, Energy_ exec("%s = Energy_" % sys_) in locals() RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_][ 'rmsd_weight'] if 'rmsd_weight' in self.sys_opts[ sys_] else 1.0 VectorD_.append(np.sqrt(w_) * RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_ * RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: Calculated_ = eval(self.inter_opts[inter_]['equation']) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.cauchy: Divisor_ = np.sqrt(Denom_**2 + Reference_**2) elif self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_ - Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_][ 'weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_) * DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % ( Calculated_, Reference_, Delta_, w_ * DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_), np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_), np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_)
def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] for sys_ in self.sys_opts: Energy_, RMSD_ = self.system_driver(sys_) # Energies are stored in a dictionary. EnergyDict[sys_] = Energy_ RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0 VectorD_.append(np.sqrt(w_)*RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: def encloseInDictionary(matchobj): return 'EnergyDict["' + matchobj.group(0)+'"]' # Here we need to evaluate a mathematical expression of the stored variables in EnergyDict. # We start by enclosing every variable in EnergyDict[""] and then calling eval on it. evalExpr = re.sub('[A-Za-z_][A-Za-z0-9_]*', encloseInDictionary, self.inter_opts[inter_]['equation']) Calculated_ = eval(evalExpr) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.cauchy: Divisor_ = np.sqrt(Denom_**2 + Reference_**2) elif self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_)*DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_)
def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] for sys_ in self.sys_opts: Energy_, RMSD_ = self.system_driver(sys_) # Energies are stored in a dictionary. EnergyDict[sys_] = Energy_ RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0 VectorD_.append(np.sqrt(w_)*RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: def encloseInDictionary(matchobj): return 'EnergyDict["' + matchobj.group(0)+'"]' # Here we need to evaluate a mathematical expression of the stored variables in EnergyDict. # We start by enclosing every variable in EnergyDict[""] and then calling eval on it. evalExpr = re.sub('[A-Za-z_][A-Za-z0-9_]*', encloseInDictionary, self.inter_opts[inter_]['equation']) Calculated_ = eval(evalExpr) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_)*DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_)
def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] for sys_ in self.sys_opts: Energy_, RMSD_ = self.system_driver(sys_) #print "Setting %s to" % sys_, Energy_ exec("%s = Energy_" % sys_) in locals() RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0 VectorD_.append(np.sqrt(w_)*RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: Calculated_ = eval(self.inter_opts[inter_]['equation']) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.cauchy: Divisor_ = np.sqrt(Denom_**2 + Reference_**2) elif self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_)*DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_)
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = { 'X': 0.0, 'G': np.zeros(self.FF.np), 'H': np.zeros((self.FF.np, self.FF.np)) } if self.hfemode.lower() == 'single' or self.hfemode.lower() == 'sp': D, dD = self.get_sp(mvals, AGrad, AHess) elif self.hfemode.lower() == 'ti2': D, dD = self.get_ti2(mvals, AGrad, AHess) elif self.hfemode.lower() in ['exp_gas', 'exp_liq', 'exp_both']: D, dD = self.get_exp(mvals, AGrad, AHess) Answer['X'] = np.dot(D, D) / self.denom**2 / (np.sum(self.whfe) if self.normalize else 1) for p in self.pgrad: Answer['G'][p] = 2 * np.dot(D, dD[p, :]) / self.denom**2 / (np.sum( self.whfe) if self.normalize else 1) for q in self.pgrad: Answer['H'][p, q] = 2 * np.dot( dD[p, :], dD[q, :]) / self.denom**2 / (np.sum( self.whfe) if self.normalize else 1) if not in_fd(): self.calc = self.hfe_dict if hasattr(self, 'hfe_err'): self.calc_err = self.hfe_err self.objective = Answer['X'] return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':zeros(self.FF.np, dtype=float), 'H':zeros((self.FF.np, self.FF.np), dtype=float)} def get_momvals(mvals_): self.FF.make(mvals_) moments = self.moments_driver() # Unpack from dictionary. return self.unpack_moments(moments) self.FF.make(mvals) ref_momvals = self.unpack_moments(self.ref_moments) calc_moments = self.moments_driver() calc_momvals = self.unpack_moments(calc_moments) D = calc_momvals - ref_momvals dV = zeros((self.FF.np,len(calc_momvals)),dtype=float) if AGrad or AHess: for p in range(self.FF.np): dV[p,:], _ = f12d3p(fdwrap(get_momvals, mvals, p), h = self.h, f0 = calc_momvals) Answer['X'] = dot(D,D) for p in range(self.FF.np): Answer['G'][p] = 2*dot(D, dV[p,:]) for q in range(self.FF.np): Answer['H'][p,q] = 2*dot(dV[p,:], dV[q,:]) if not in_fd(): self.FF.make(mvals) self.calc_moments = calc_moments self.objective = Answer['X'] return Answer
def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs) # The overlap metric may take into account some frequency differences dev = np.array([[(np.abs(i-j)/1000)/(1.0+np.abs(i-j)/1000) for j in self.ref_eigvals] for i in eigvals]) for i in range(dev.shape[0]): dev[i, :] /= max(dev[i, :]) if self.reassign in ['permute', 'overlap']: # In the matrix that we constructed, these are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers) if self.reassign == 'permute': a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) c2r = Assign(a) eigvals = eigvals[c2r] elif self.reassign == 'overlap': a = np.array([[(1.0-np.dot(v1.flatten(),v2.flatten())**2) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) a += dev c2r = np.argmin(a, axis=0) eigvals_p = [] for j in c2r: eigvals_p.append(eigvals[j]) eigvals = np.array(eigvals_p) if not in_fd(): if self.reassign == 'permute': eigvecs_nrm_mw = eigvecs_nrm_mw[c2r] elif self.reassign == 'overlap': self.c2r = c2r eigvecs_nrm_mw_p = [] for j in c2r: eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j]) eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p) self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)]) return eigvals
def driver(self): ## Actually run PSI4. if not in_fd() and CheckBasis(): logger.info("Now checking for linear dependencies.\n") _exec("cp %s %s.bak" % (self.GBSfnm, self.GBSfnm), print_command=False) ln0 = self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save) o = wopen(".lindep.dat") for line in open(self.DATfnm).readlines(): s = line.split("#")[0].split() if len(s) == 3 and s[0].lower() == 'basis' and s[1].lower() == 'file': print >> o, "basis file %s" % self.GBSfnm else: print >> o, line, o.close() _exec("mv .lindep.dat %s" % self.DATfnm, print_command=False) _exec("psi4 %s" % self.DATfnm, print_command=False) LI = GBS_Reader() LI_lines = {} ## Read in the commented linindep.gbs file and ensure that these same lines are commented in the new .gbs file for line in open('linindep.gbs'): LI.feed(line,linindep=True) key = '.'.join([str(i) for i in LI.element,LI.amom,LI.basis_number[LI.element],LI.contraction_number]) if LI.isdata: if key in LI_lines: logger.info("Duplicate key found:\n") logger.info("%s\n" % key) logger.info(str(LI_lines[key])) logger.info(line) warn_press_key("In %s, the LI_lines dictionary should not contain repeated keys!" % __file__) LI_lines[key] = (line, LI.destroy)
def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs) if self.reassign in ['permute', 'overlap']: a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) # In the matrix that we constructed, these are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers) if self.reassign == 'permute': c2r = Assign(a) eigvals = eigvals[c2r] elif self.reassign == 'overlap': c2r = np.argmin(a, axis=0) eigvals_p = [] for j in c2r: eigvals_p.append(eigvals[j]) eigvals = np.array(eigvals_p) if not in_fd(): if self.reassign == 'permute': eigvecs_nrm_mw = eigvecs_nrm_mw[c2r] elif self.reassign == 'overlap': self.c2r = c2r eigvecs_nrm_mw_p = [] for j in c2r: eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j]) eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p) self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)]) return eigvals
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':zeros(self.FF.np, dtype=float), 'H':zeros((self.FF.np, self.FF.np), dtype=float)} def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() # Put reference eigenvectors in the rows and calculated eigenvectors in the columns. # Square the dot product (pointing in opposite direction is still the same eigenvector) # Convert to integer for the "Assign" subroutine, subtract from a million. a = array([[int(1e6*(1.0-min(1.0,dot(v1.flatten(),v2.flatten())**2))) for v2 in self.ref_eigvecs] for v1 in eigvecs]) # In the matrix that we constructed, these are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers) c2r = Assign(a) return eigvals[c2r] calc_eigvals = get_eigvals(mvals) D = calc_eigvals - self.ref_eigvals dV = zeros((self.FF.np,len(calc_eigvals)),dtype=float) if AGrad or AHess: for p in range(self.FF.np): dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals) Answer['X'] = dot(D,D) / self.denom**2 for p in range(self.FF.np): Answer['G'][p] = 2*dot(D, dV[p,:]) / self.denom**2 for q in range(self.FF.np): Answer['H'][p,q] = 2*dot(dV[p,:], dV[q,:]) / self.denom**2 if not in_fd(): self.calc_eigvals = calc_eigvals self.objective = Answer['X'] return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} def get_momvals(mvals_): self.FF.make(mvals_) moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry) # Unpack from dictionary. return self.unpack_moments(moments) self.FF.make(mvals) ref_momvals = self.unpack_moments(self.ref_moments) calc_moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry) calc_momvals = self.unpack_moments(calc_moments) D = calc_momvals - ref_momvals dV = np.zeros((self.FF.np,len(calc_momvals))) if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(get_momvals, mvals, p), h = self.h, f0 = calc_momvals) Answer['X'] = np.dot(D,D) for p in self.pgrad: Answer['G'][p] = 2*np.dot(D, dV[p,:]) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) if not in_fd(): self.calc_moments = calc_moments self.objective = Answer['X'] return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} if not hasattr(self, 'ref_eigvecs_nrm'): self.ref_eigvecs_nrm, self.ref_eigvecs_nrm_mw = self.process_vectors(self.ref_eigvecs) def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs) # The overlap metric may take into account some frequency differences dev = np.array([[(np.abs(i-j)/1000)/(1.0+np.abs(i-j)/1000) for j in self.ref_eigvals] for i in eigvals]) for i in range(dev.shape[0]): dev[i, :] /= max(dev[i, :]) if self.reassign in ['permute', 'overlap']: # In the matrix that we constructed, these are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers) if self.reassign == 'permute': a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) row, c2r = optimize.linear_sum_assignment(a) # Commented out dependency on assignment code # c2r = Assign(a) eigvals = eigvals[c2r] elif self.reassign == 'overlap': a = np.array([[(1.0-np.dot(v1.flatten(),v2.flatten())**2) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) a += dev c2r = np.argmin(a, axis=0) eigvals_p = [] for j in c2r: eigvals_p.append(eigvals[j]) eigvals = np.array(eigvals_p) if not in_fd(): if self.reassign == 'permute': eigvecs_nrm_mw = eigvecs_nrm_mw[c2r] elif self.reassign == 'overlap': self.c2r = c2r eigvecs_nrm_mw_p = [] for j in c2r: eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j]) eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p) self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)]) return eigvals calc_eigvals = get_eigvals(mvals) D = calc_eigvals - self.ref_eigvals dV = np.zeros((self.FF.np,len(calc_eigvals))) if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals) Answer['X'] = np.dot(D,D) / self.denom**2 / (len(D) if self.normalize else 1) for p in self.pgrad: Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2 / (len(D) if self.normalize else 1) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2 / (len(D) if self.normalize else 1) if not in_fd(): self.calc_eigvals = calc_eigvals self.objective = Answer['X'] return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} def get_momvals(mvals_): self.FF.make(mvals_) moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry) # Unpack from dictionary. return self.unpack_moments(moments) self.FF.make(mvals) ref_momvals = self.unpack_moments(self.ref_moments) calc_moments = self.engine.multipole_moments(polarizability='polarizability' in self.ref_moments, optimize=self.optimize_geometry) calc_momvals = self.unpack_moments(calc_moments) D = calc_momvals - ref_momvals dV = np.zeros((self.FF.np,len(calc_momvals))) if AGrad or AHess: for p in range(self.FF.np): dV[p,:], _ = f12d3p(fdwrap(get_momvals, mvals, p), h = self.h, f0 = calc_momvals) Answer['X'] = np.dot(D,D) for p in range(self.FF.np): Answer['G'][p] = 2*np.dot(D, dV[p,:]) for q in range(self.FF.np): Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) if not in_fd(): self.calc_moments = calc_moments self.objective = Answer['X'] return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} if not hasattr(self, 'ref_eigvecs_nrm'): self.ref_eigvecs_nrm, self.ref_eigvecs_nrm_mw = self.process_vectors(self.ref_eigvecs) def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs) # The overlap metric may take into account some frequency differences dev = np.array([[(np.abs(i-j)/1000)/(1.0+np.abs(i-j)/1000) for j in self.ref_eigvals] for i in eigvals]) for i in range(dev.shape[0]): dev[i, :] /= max(dev[i, :]) if self.reassign in ['permute', 'overlap']: # In the matrix that we constructed, these are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers) if self.reassign == 'permute': a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) c2r = Assign(a) eigvals = eigvals[c2r] elif self.reassign == 'overlap': a = np.array([[(1.0-np.dot(v1.flatten(),v2.flatten())**2) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) a += dev c2r = np.argmin(a, axis=0) eigvals_p = [] for j in c2r: eigvals_p.append(eigvals[j]) eigvals = np.array(eigvals_p) if not in_fd(): if self.reassign == 'permute': eigvecs_nrm_mw = eigvecs_nrm_mw[c2r] elif self.reassign == 'overlap': self.c2r = c2r eigvecs_nrm_mw_p = [] for j in c2r: eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j]) eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p) self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)]) return eigvals calc_eigvals = get_eigvals(mvals) D = calc_eigvals - self.ref_eigvals dV = np.zeros((self.FF.np,len(calc_eigvals))) if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals) Answer['X'] = np.dot(D,D) / self.denom**2 / (len(D) if self.normalize else 1) for p in self.pgrad: Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2 / (len(D) if self.normalize else 1) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2 / (len(D) if self.normalize else 1) if not in_fd(): self.calc_eigvals = calc_eigvals self.objective = Answer['X'] return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() # The overlap metric may take into account some frequency differences. # Here, an element of dev is equal to 2/3 if (for example) the frequencies differ by 1000. dev = np.array([[(np.abs(i-j)/1000)/(1.0+np.abs(i-j)/1000) for j in eigvals] for i in self.ref_eigvals]) for i in range(dev.shape[0]): dev[i, :] /= max(dev[i, :]) if self.reassign in ['permute', 'overlap']: # The elements of "a" matrix are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers). # Highly similar eigenvectors are assigned small values because # the assignment problem is a cost minimization problem. a = np.array([[(1.0-vib_overlap(self.engine, v1, v2)) for v2 in eigvecs] for v1 in self.ref_eigvecs]) a += dev if self.reassign == 'permute': row, c2r = optimize.linear_sum_assignment(a) eigvals = eigvals[c2r] elif self.reassign == 'overlap': c2r = np.argmin(a, axis=0) eigvals_p = [] for j in c2r: eigvals_p.append(eigvals[j]) eigvals = np.array(eigvals_p) if not in_fd(): if self.reassign == 'permute': eigvecs = eigvecs[c2r] elif self.reassign == 'overlap': self.c2r = c2r eigvecs_p = [] for j in c2r: eigvecs_p.append(eigvecs[j]) eigvecs = np.array(eigvecs_p) self.overlaps = np.array([vib_overlap(self.engine, v1, v2) for v1, v2 in zip(self.ref_eigvecs, eigvecs)]) return eigvals calc_eigvals = get_eigvals(mvals) D = calc_eigvals - self.ref_eigvals dV = np.zeros((self.FF.np,len(calc_eigvals))) if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals) Answer['X'] = np.dot(D,D) / self.denom**2 / (len(D) if self.normalize else 1) for p in self.pgrad: Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2 / (len(D) if self.normalize else 1) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2 / (len(D) if self.normalize else 1) if not in_fd(): self.calc_eigvals = calc_eigvals self.objective = Answer['X'] return Answer
def meta_get(self, mvals, AGrad=False, AHess=False, customdir=None): """ Wrapper around the get function. Create the directory for the target, and then calls 'get'. If we are reading existing data, go into the appropriate read directory and call read() instead. The 'get' method should not worry about the directory that it's running in. """ ## Directory of the current iteration; if not None, then the simulation runs under ## temp/target_name/iteration_number ## The 'customdir' is customizable and can go below anything cwd = os.getcwd() absgetdir = os.path.join(self.root, self.tempdir) if Counter() is not None: # Not expecting more than ten thousand iterations if Counter() > 10000: logger.error( 'Cannot handle more than 10000 iterations due to current directory structure. Consider revising code.\n' ) raise RuntimeError iterdir = "iter_%04i" % Counter() absgetdir = os.path.join(absgetdir, iterdir) if customdir is not None: absgetdir = os.path.join(absgetdir, customdir) if not os.path.exists(absgetdir): os.makedirs(absgetdir) os.chdir(absgetdir) self.link_from_tempdir(absgetdir) self.rundir = absgetdir.replace(self.root + '/', '') ## Read existing information from disk (i.e. when recovering an aborted run) # Note that reading information is not supported for custom folders (e.g. microiterations during search) if self.rd is not None and ( not self.evaluated ) and self.read_objective and customdir is None: os.chdir(self.absrd()) logger.info("Reading objective function information from %s\n" % os.getcwd()) Answer = self.read(mvals, AGrad, AHess) os.chdir(absgetdir) else: ## Evaluate the objective function. Answer = self.get(mvals, AGrad, AHess) if self.write_objective: forcebalance.nifty.lp_dump(Answer, 'objective.p') ## Save the force field files to this directory, so that it ## reflects the objective function and properties that were ## printed out. if not in_fd(): self.FF.make(mvals) os.chdir(cwd) return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} # If the weight is zero, turn all derivatives off. if (self.weight == 0.0): AGrad = False AHess = False def callM(mvals_, dielectric=False): logger.info("\r") pvals = self.FF.make(mvals_) return self.engine.interaction_energy(self.select1, self.select2) logger.info("Executing\r") emm = callM(mvals) D = emm - self.eqm dV = np.zeros((self.FF.np,len(emm))) # Dump interaction energies to disk. np.savetxt('M.txt',emm) np.savetxt('Q.txt',self.eqm) # Do the finite difference derivative. if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = emm) # Create the force field one last time. pvals = self.FF.make(mvals) Answer['X'] = np.dot(self.prefactor*D/self.divisor,D/self.divisor) for p in self.pgrad: Answer['G'][p] = 2*np.dot(self.prefactor*D/self.divisor, dV[p,:]/self.divisor) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(self.prefactor*dV[p,:]/self.divisor, dV[q,:]/self.divisor) if not in_fd(): self.emm = emm self.objective = Answer['X'] ## QYD: try to clean up OpenMM engine.simulation objects to free up GPU memory try: if self.engine.name == 'openmm': if hasattr(self.engine, 'simulation'): del self.engine.simulation if hasattr(self.engine, 'A'): del self.engine.A if hasattr(self.engine, 'B'): del self.engine.B except: pass return Answer
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} if not hasattr(self, 'ref_eigvecs_nrm'): self.ref_eigvecs_nrm, self.ref_eigvecs_nrm_mw = self.process_vectors(self.ref_eigvecs) def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() eigvecs_nrm, eigvecs_nrm_mw = self.process_vectors(eigvecs) if self.reassign in ['permute', 'overlap']: a = np.array([[int(1e6*(1.0-np.dot(v1.flatten(),v2.flatten())**2)) for v2 in self.ref_eigvecs_nrm] for v1 in eigvecs_nrm_mw]) # In the matrix that we constructed, these are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers) if self.reassign == 'permute': c2r = Assign(a) eigvals = eigvals[c2r] elif self.reassign == 'overlap': c2r = np.argmin(a, axis=0) eigvals_p = [] for j in c2r: eigvals_p.append(eigvals[j]) eigvals = np.array(eigvals_p) if not in_fd(): if self.reassign == 'permute': eigvecs_nrm_mw = eigvecs_nrm_mw[c2r] elif self.reassign == 'overlap': self.c2r = c2r eigvecs_nrm_mw_p = [] for j in c2r: eigvecs_nrm_mw_p.append(eigvecs_nrm_mw[j]) eigvecs_nrm_mw = np.array(eigvecs_nrm_mw_p) self.overlaps = np.array([np.abs(np.dot(v1.flatten(),v2.flatten())) for v1, v2 in zip(self.ref_eigvecs_nrm, eigvecs_nrm_mw)]) return eigvals calc_eigvals = get_eigvals(mvals) D = calc_eigvals - self.ref_eigvals dV = np.zeros((self.FF.np,len(calc_eigvals))) if AGrad or AHess: for p in range(self.FF.np): dV[p,:], _ = f12d3p(fdwrap(get_eigvals, mvals, p), h = self.h, f0 = calc_eigvals) Answer['X'] = np.dot(D,D) / self.denom**2 for p in range(self.FF.np): Answer['G'][p] = 2*np.dot(D, dV[p,:]) / self.denom**2 for q in range(self.FF.np): Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) / self.denom**2 if not in_fd(): self.calc_eigvals = calc_eigvals self.objective = Answer['X'] return Answer
def meta_get(self, mvals, AGrad=False, AHess=False, customdir=None): """ Wrapper around the get function. Create the directory for the target, and then calls 'get'. If we are reading existing data, go into the appropriate read directory and call read() instead. The 'get' method should not worry about the directory that it's running in. """ ## Directory of the current iteration; if not None, then the simulation runs under ## temp/target_name/iteration_number ## The 'customdir' is customizable and can go below anything cwd = os.getcwd() absgetdir = os.path.join(self.root,self.tempdir) if Counter() is not None: # Not expecting more than ten thousand iterations if Counter() > 10000: logger.error('Cannot handle more than 10000 iterations due to current directory structure. Consider revising code.\n') raise RuntimeError iterdir = "iter_%04i" % Counter() absgetdir = os.path.join(absgetdir,iterdir) if customdir is not None: absgetdir = os.path.join(absgetdir,customdir) if not os.path.exists(absgetdir): os.makedirs(absgetdir) os.chdir(absgetdir) self.link_from_tempdir(absgetdir) self.rundir = absgetdir.replace(self.root+'/','') ## Read existing information from disk (i.e. when recovering an aborted run) # Note that reading information is not supported for custom folders (e.g. microiterations during search) if self.rd is not None and (not self.evaluated) and self.read_objective and customdir is None: os.chdir(self.absrd()) logger.info("Reading objective function information from %s\n" % os.getcwd()) Answer = self.read(mvals, AGrad, AHess) os.chdir(absgetdir) else: ## Evaluate the objective function. Answer = self.get(mvals, AGrad, AHess) if self.write_objective: forcebalance.nifty.lp_dump(Answer, 'objective.p') ## Save the force field files to this directory, so that it ## reflects the objective function and properties that were ## printed out. if not in_fd(): self.FF.make(mvals) os.chdir(cwd) return Answer
def Full(self, mvals, Order=0, verbose=False): Objective = self.Target_Terms(mvals, Order, verbose) ## Compute the penalty function. Extra = self.Penalty.compute(mvals,Objective) Objective['X0'] = Objective['X'] Objective['G0'] = Objective['G'].copy() Objective['H0'] = Objective['H'].copy() if not in_fd(): self.ObjDict['Regularization'] = {'w' : 1.0, 'x' : Extra[0]} if verbose: self.Indicate() for i in range(3): Objective[Letters[i]] += Extra[i] return Objective
def Full(self, mvals, Order=0, verbose=False): Objective = self.Target_Terms(mvals, Order, verbose) ## Compute the penalty function. Extra = self.Penalty.compute(mvals, Objective) Objective['X0'] = Objective['X'] Objective['G0'] = Objective['G'].copy() Objective['H0'] = Objective['H'].copy() if not in_fd(): self.ObjDict['Regularization'] = {'w': 1.0, 'x': Extra[0]} if verbose: self.Indicate() for i in range(3): Objective[Letters[i]] += Extra[i] return Objective
def stage(self, mvals, AGrad=False, AHess=False, use_iterdir=True, customdir=None, firstIteration=False): """ Stages the directory for the target, and then launches Work Queue processes if any. The 'get' method should not worry about the directory that it's running in. """ if self.sleepy > 0: logger.info("Sleeping for %i seconds as directed...\n" % self.sleepy) time.sleep(self.sleepy) ## Directory of the current iteration; if not None, then the simulation runs under ## temp/target_name/iteration_number ## The 'customdir' is customizable and can go below anything cwd = os.getcwd() absgetdir = os.path.join(self.root, self.tempdir) if use_iterdir and Counter() is not None: ## Not expecting more than ten thousand iterations iterdir = "iter_%04i" % Counter() absgetdir = os.path.join(absgetdir, iterdir) if customdir is not None: absgetdir = os.path.join(absgetdir, customdir) ## Go into the directory where get() will be executed. if not os.path.exists(absgetdir): os.makedirs(absgetdir) os.chdir(absgetdir) self.link_from_tempdir(absgetdir) ## Write mathematical parameters to file; will be used to checkpoint calculation. if not in_fd(): np.savetxt('mvals.txt', mvals) ## Read in file that specifies which derivatives may be skipped. if Counter() >= self.zerograd and self.zerograd >= 0: self.read_0grads() self.rundir = absgetdir.replace(self.root + '/', '') ## Submit jobs to the Work Queue. if self.rd is None or (not firstIteration): self.submit_jobs(mvals, AGrad, AHess) elif customdir is not None: # Allows us to submit micro-iteration jobs for remote targets self.submit_jobs(mvals, AGrad, AHess) os.chdir(cwd) return
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} if self.hfemode.lower() == 'single' or self.hfemode.lower() == 'sp': D, dD = self.get_sp(mvals, AGrad, AHess) elif self.hfemode.lower() == 'ti2': D, dD = self.get_ti2(mvals, AGrad, AHess) Answer['X'] = np.dot(D,D) / self.denom**2 / (np.sum(self.whfe) if self.normalize else 1) for p in self.pgrad: Answer['G'][p] = 2*np.dot(D, dD[p,:]) / self.denom**2 / (np.sum(self.whfe) if self.normalize else 1) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(dD[p,:], dD[q,:]) / self.denom**2 / (np.sum(self.whfe) if self.normalize else 1) if not in_fd(): self.calc = self.hfe_dict self.objective = Answer['X'] return Answer
def Full(self, vals, Order=0, verbose=False, customdir=None): Objective = self.Target_Terms(vals, Order, verbose, customdir) ## Compute the penalty function. if self.FF.use_pvals: Extra = self.Penalty.compute(self.FF.create_mvals(vals), Objective) else: Extra = self.Penalty.compute(vals, Objective) Objective['X0'] = Objective['X'] Objective['G0'] = Objective['G'].copy() Objective['H0'] = Objective['H'].copy() if not in_fd(): self.ObjDict['Regularization'] = {'w': 1.0, 'x': Extra[0]} if verbose: self.Indicate() for i in range(3): Objective[Letters[i]] += Extra[i] return Objective
def Full(self, vals, Order=0, verbose=False, customdir=None): Objective = self.Target_Terms(vals, Order, verbose, customdir) ## Compute the penalty function. if self.FF.use_pvals: Extra = self.Penalty.compute(self.FF.create_mvals(vals),Objective) else: Extra = self.Penalty.compute(vals,Objective) Objective['X0'] = Objective['X'] Objective['G0'] = Objective['G'].copy() Objective['H0'] = Objective['H'].copy() if not in_fd(): self.ObjDict['Regularization'] = {'w' : 1.0, 'x' : Extra[0]} if verbose: self.Indicate() for i in range(3): Objective[Letters[i]] += Extra[i] return Objective
def get_eigvals(mvals_): self.FF.make(mvals_) eigvals, eigvecs = self.vibration_driver() # The overlap metric may take into account some frequency differences. # Here, an element of dev is equal to 2/3 if (for example) the frequencies differ by 1000. dev = np.array([[ (np.abs(i - j) / 1000) / (1.0 + np.abs(i - j) / 1000) for j in eigvals ] for i in self.ref_eigvals]) for i in range(dev.shape[0]): dev[i, :] /= max(dev[i, :]) if self.reassign in ['permute', 'overlap']: # The elements of "a" matrix are the column numbers (reference mode numbers) # that are mapped to the row numbers (calculated mode numbers). # Highly similar eigenvectors are assigned small values because # the assignment problem is a cost minimization problem. a = np.array([[(1.0 - vib_overlap(self.engine, v1, v2)) for v2 in eigvecs] for v1 in self.ref_eigvecs]) a += dev if self.reassign == 'permute': row, c2r = optimize.linear_sum_assignment(a) eigvals = eigvals[c2r] elif self.reassign == 'overlap': c2r = np.argmin(a, axis=0) eigvals_p = [] for j in c2r: eigvals_p.append(eigvals[j]) eigvals = np.array(eigvals_p) if not in_fd(): if self.reassign == 'permute': eigvecs = eigvecs[c2r] elif self.reassign == 'overlap': self.c2r = c2r eigvecs_p = [] for j in c2r: eigvecs_p.append(eigvecs[j]) eigvecs = np.array(eigvecs_p) self.overlaps = np.array([ vib_overlap(self.engine, v1, v2) for v1, v2 in zip(self.ref_eigvecs, eigvecs) ]) return eigvals
def stage(self, mvals, AGrad=False, AHess=False, customdir=None, firstIteration=False): """ Stages the directory for the target, and then launches Work Queue processes if any. The 'get' method should not worry about the directory that it's running in. """ if self.sleepy > 0: logger.info("Sleeping for %i seconds as directed...\n" % self.sleepy) time.sleep(self.sleepy) ## Directory of the current iteration; if not None, then the simulation runs under ## temp/target_name/iteration_number ## The 'customdir' is customizable and can go below anything cwd = os.getcwd() absgetdir = os.path.join(self.root,self.tempdir) if Counter() is not None: ## Not expecting more than ten thousand iterations iterdir = "iter_%04i" % Counter() absgetdir = os.path.join(absgetdir,iterdir) if customdir is not None: absgetdir = os.path.join(absgetdir,customdir) ## Go into the directory where get() will be executed. if not os.path.exists(absgetdir): os.makedirs(absgetdir) os.chdir(absgetdir) self.link_from_tempdir(absgetdir) ## Write mathematical parameters to file; will be used to checkpoint calculation. if not in_fd(): np.savetxt('mvals.txt', mvals) ## Read in file that specifies which derivatives may be skipped. if Counter() >= self.zerograd and self.zerograd >= 0: self.read_0grads() self.rundir = absgetdir.replace(self.root+'/','') ## Submit jobs to the Work Queue. if self.rd is None or (not firstIteration): self.submit_jobs(mvals, AGrad, AHess) elif customdir is not None: # Allows us to submit micro-iteration jobs for remote targets self.submit_jobs(mvals, AGrad, AHess) os.chdir(cwd) return
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':zeros(self.FF.np, dtype=float), 'H':zeros((self.FF.np, self.FF.np), dtype=float)} # If the weight is zero, turn all derivatives off. if (self.weight == 0.0): AGrad = False AHess = False def callM(mvals_, dielectric=False): logger.info("\r") pvals = self.FF.make(mvals_) return self.interaction_driver_all(dielectric) logger.info("Executing\r") emm = callM(mvals) D = emm - self.eqm dV = zeros((self.FF.np,len(emm)),dtype=float) # Dump interaction energies to disk. savetxt('M.txt',emm) savetxt('Q.txt',self.eqm) # Do the finite difference derivative. if AGrad or AHess: for p in range(self.FF.np): dV[p,:], _ = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = emm) # Create the force field one last time. pvals = self.FF.make(mvals) Answer['X'] = dot(self.prefactor*D/self.divisor,D/self.divisor) for p in range(self.FF.np): Answer['G'][p] = 2*dot(self.prefactor*D/self.divisor, dV[p,:]/self.divisor) for q in range(self.FF.np): Answer['H'][p,q] = 2*dot(self.prefactor*dV[p,:]/self.divisor, dV[q,:]/self.divisor) if not in_fd(): self.emm = emm self.objective = Answer['X'] return Answer
def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] # The following code was odified by Chengwen Liu to accelarate the tinker analyze and optimize jobs def Energy_RMSD(systems): tinkerhome = os.environ["TINKERPATH"] f1 = open("runAna.sh", "w") f2 = open("runMin.sh", "w") i = 0 for sys_ in systems: opts = systems[sys_] optimize = (opts['optimize'] if 'optimize' in opts else False) if not optimize: if (i+1)%24 == 0: cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out \n"%(sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 else: cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out & \n"%(sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 f1.write(cmd) else: if (i+1)%24 == 0: cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out \n"%(sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 else: cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out & \n"%(sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 f2.write(cmd) f1.write("wait\n") f2.write("wait\n") f1.close() f2.close() os.system("sh runAna.sh") os.system("sh runMin.sh") for sys_ in systems: while not os.path.isfile(os.path.join(os.getcwd(), sys_ + ".out")): time.sleep(1.0) Es = {} RMSDs = {} for sys_ in systems: energ = 0.0 rmsd = 0.0 for line in open("%s.out"%sys_).readlines(): if "Total Potential Energy" in line: energ = float(line.split()[-2].replace('D','e')) Es[sys_] = energ RMSDs[sys_] = 0.0 if "Final Function Value :" in line: energ = float(line.split()[-1].replace('D','e')) Es[sys_] = energ M1 = Molecule("%s.xyz" % sys_, ftype="tinker") M2 = Molecule("%s.xyz_2" % sys_, ftype="tinker") M1 += M2 RMSDs[sys_] = M1.ref_rmsd(0)[1] return Es,RMSDs Es, RMSDs = Energy_RMSD(self.sys_opts) for sys_ in self.sys_opts: Energy_ = Es[sys_] RMSD_ = RMSDs[sys_] exec("%s = Energy_" % sys_) in locals() RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0 VectorD_.append(np.sqrt(w_)*RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: Calculated_ = eval(self.inter_opts[inter_]['equation']) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.cauchy: Divisor_ = np.sqrt(Denom_**2 + Reference_**2) elif self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_)*DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_)
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} def compute(mvals_): self.FF.make(mvals_) Xx, Gx, Hx, freqs, normal_modes, M_opt = self.hessian_driver() # convert into internal hessian Xx *= 1/ Bohr2nm Gx *= Bohr2nm/ Hartree2kJmol Hx *= Bohr2nm**2/ Hartree2kJmol Hq = self.IC.calcHess(Xx, Gx, Hx) compute.Hq_flat = Hq.flatten() compute.freqs = freqs compute.normal_modes = normal_modes compute.M_opt = M_opt diff = Hq - self.ref_Hq return (np.sqrt(self.wts)/self.denom) * (compute.Hq_flat - self.ref_Hq_flat) V = compute(mvals) Answer['X'] = np.dot(V,V) * len(compute.freqs) # HJ: len(compute.freqs) is multiplied to match the scale of X2 with vib freq target X2 # compute gradients and hessian dV = np.zeros((self.FF.np,len(V))) if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(compute, mvals, p), h = self.h, f0 = V) for p in self.pgrad: Answer['G'][p] = 2*np.dot(V, dV[p,:]) * len(compute.freqs) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) * len(compute.freqs) if not in_fd(): self.Hq_flat = compute.Hq_flat self.Hq = self.Hq_flat.reshape(self.ref_Hq.shape) self.objective = Answer['X'] self.FF.make(mvals) if self.writelevel > 0: # 1. write HessianCompare.txt hessian_comparison = np.array([ self.ref_Hq_flat, compute.Hq_flat, compute.Hq_flat - self.ref_Hq_flat, np.sqrt(self.wts)/self.denom ]).T np.savetxt("HessianCompare.txt", hessian_comparison, header="%11s %12s %12s %12s" % ("QMHessian", "MMHessian", "Delta(MM-QM)", "Weight"), fmt="% 12.6e") # 2. rearrange MM vibrational frequencies using overlap between normal modes in redundant internal coordinates ref_int_normal_modes = self.calc_int_normal_mode(self.ref_xyz, self.ref_eigvecs) int_normal_modes = self.calc_int_normal_mode(np.array(compute.M_opt.xyzs[0]), compute.normal_modes) a = np.array([[(1.0-np.abs(np.dot(v1/np.linalg.norm(v1),v2/np.linalg.norm(v2)))) for v2 in int_normal_modes] for v1 in ref_int_normal_modes]) row, c2r = optimize.linear_sum_assignment(a) # old arrangement method, which uses overlap between mass weighted vibrational modes in cartesian coordinates # a = np.array([[(1.0-self.vib_overlap(v1, v2)) for v2 in compute.normal_modes] for v1 in self.ref_eigvecs]) # row, c2r = optimize.linear_sum_assignment(a) freqs_rearr = compute.freqs[c2r] normal_modes_rearr = compute.normal_modes[c2r] # 3. Save rearranged frequencies and normal modes into a file for post-analysis with open('mm_vdata.txt', 'w') as outfile: outfile.writelines('%s\n' % line for line in compute.M_opt.write_xyz([0])) outfile.write('\n') for freq, normal_mode in zip(freqs_rearr, normal_modes_rearr): outfile.write(f'{freq}\n') for nx, ny, nz in normal_mode: outfile.write(f'{nx:13.4f} {ny:13.4f} {nz:13.4f}\n') outfile.write('\n') outfile.close() # 4. draw a scatter plot of vibrational frequencies and an overlap matrix of normal modes in cartessian coordinates draw_vibfreq_scatter_plot_n_overlap_matrix(self.name, self.engine, self.ref_eigvals, self.ref_eigvecs, freqs_rearr, normal_modes_rearr) return Answer
def driver(self): ## Actually run PSI4. if not in_fd() and CheckBasis(): logger.info("Now checking for linear dependencies.\n") _exec("cp %s %s.bak" % (self.GBSfnm, self.GBSfnm), print_command=False) ln0 = self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save) o = wopen(".lindep.dat") for line in open(self.DATfnm).readlines(): s = line.split("#")[0].split() if len(s) == 3 and s[0].lower() == 'basis' and s[1].lower() == 'file': print("basis file %s" % self.GBSfnm, file=o) else: print(line, end=' ', file=o) o.close() _exec("mv .lindep.dat %s" % self.DATfnm, print_command=False) _exec("psi4 %s" % self.DATfnm, print_command=False) LI = GBS_Reader() LI_lines = {} ## Read in the commented linindep.gbs file and ensure that these same lines are commented in the new .gbs file for line in open('linindep.gbs'): LI.feed(line,linindep=True) key = '.'.join([str(i) for i in (LI.element,LI.amom,LI.basis_number[LI.element],LI.contraction_number)]) if LI.isdata: if key in LI_lines: logger.info("Duplicate key found:\n") logger.info("%s\n" % key) logger.info(str(LI_lines[key])) logger.info(line) warn_press_key("In %s, the LI_lines dictionary should not contain repeated keys!" % __file__) LI_lines[key] = (line, LI.destroy) ## Now build a "Frankenstein" .gbs file composed of the original .gbs file but with data from the linindep.gbs file! FK = GBS_Reader() FK_lines = [] self.FF.linedestroy_this = [] self.FF.prmdestroy_this = [] for ln, line in enumerate(open(self.GBSfnm).readlines()): FK.feed(line) key = '.'.join([str(i) for i in (FK.element,FK.amom,FK.basis_number[FK.element],FK.contraction_number)]) if FK.isdata and key in LI_lines: if LI_lines[key][1]: logger.info("Destroying line %i (originally %i): " % (ln, ln0[ln])) logger.info(line) self.FF.linedestroy_this.append(ln) for p_destroy in [i for i, fld in enumerate(self.FF.pfields) if any([subfld[0] == self.GBSfnm and subfld[1] == ln0[ln] for subfld in fld])]: logger.info("Destroying parameter %i located at line %i (originally %i) with fields given by: %s" % (p_destroy, ln, ln0[ln], str(self.FF.pfields[p_destroy]))) self.FF.prmdestroy_this.append(p_destroy) FK_lines.append(LI_lines[key][0]) else: FK_lines.append(line) o = wopen('franken.gbs') for line in FK_lines: print(line, end=' ', file=o) o.close() _exec("cp %s.bak %s" % (self.GBSfnm, self.GBSfnm), print_command=False) if len(list(itertools.chain(*(self.FF.linedestroy_save + [self.FF.linedestroy_this])))) > 0: logger.info("All lines removed: " + self.FF.linedestroy_save + [self.FF.linedestroy_this] + '\n') logger.info("All prms removed: " + self.FF.prmdestroy_save + [self.FF.prmdestroy_this] + '\n') self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save + [self.FF.linedestroy_this]) _exec("psi4", print_command=False, outfnm="psi4.stdout") if not in_fd(): for line in open('psi4.stdout').readlines(): if "MP2 Energy:" in line: self.MP2_Energy = float(line.split()[-1]) elif "DF Energy:" in line: self.DF_Energy = float(line.split()[-1]) Ans = np.array([[float(i) for i in line.split()] for line in open("objective.dat").readlines()]) os.unlink("objective.dat") return Ans
def driver(self): ## Actually run PSI4. if not in_fd() and CheckBasis(): logger.info("Now checking for linear dependencies.\n") _exec("cp %s %s.bak" % (self.GBSfnm, self.GBSfnm), print_command=False) ln0 = self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save) o = wopen(".lindep.dat") for line in open(self.DATfnm).readlines(): s = line.split("#")[0].split() if len(s) == 3 and s[0].lower() == 'basis' and s[1].lower( ) == 'file': print("basis file %s" % self.GBSfnm, file=o) else: print(line, end=' ', file=o) o.close() _exec("mv .lindep.dat %s" % self.DATfnm, print_command=False) _exec("psi4 %s" % self.DATfnm, print_command=False) LI = GBS_Reader() LI_lines = {} ## Read in the commented linindep.gbs file and ensure that these same lines are commented in the new .gbs file for line in open('linindep.gbs'): LI.feed(line, linindep=True) key = '.'.join([ str(i) for i in (LI.element, LI.amom, LI.basis_number[LI.element], LI.contraction_number) ]) if LI.isdata: if key in LI_lines: logger.info("Duplicate key found:\n") logger.info("%s\n" % key) logger.info(str(LI_lines[key])) logger.info(line) warn_press_key( "In %s, the LI_lines dictionary should not contain repeated keys!" % __file__) LI_lines[key] = (line, LI.destroy) ## Now build a "Frankenstein" .gbs file composed of the original .gbs file but with data from the linindep.gbs file! FK = GBS_Reader() FK_lines = [] self.FF.linedestroy_this = [] self.FF.prmdestroy_this = [] for ln, line in enumerate(open(self.GBSfnm).readlines()): FK.feed(line) key = '.'.join([ str(i) for i in (FK.element, FK.amom, FK.basis_number[FK.element], FK.contraction_number) ]) if FK.isdata and key in LI_lines: if LI_lines[key][1]: logger.info("Destroying line %i (originally %i): " % (ln, ln0[ln])) logger.info(line) self.FF.linedestroy_this.append(ln) for p_destroy in [ i for i, fld in enumerate(self.FF.pfields) if any([ subfld[0] == self.GBSfnm and subfld[1] == ln0[ln] for subfld in fld ]) ]: logger.info( "Destroying parameter %i located at line %i (originally %i) with fields given by: %s" % (p_destroy, ln, ln0[ln], str(self.FF.pfields[p_destroy]))) self.FF.prmdestroy_this.append(p_destroy) FK_lines.append(LI_lines[key][0]) else: FK_lines.append(line) o = wopen('franken.gbs') for line in FK_lines: print(line, end=' ', file=o) o.close() _exec("cp %s.bak %s" % (self.GBSfnm, self.GBSfnm), print_command=False) if len( list( itertools.chain(*(self.FF.linedestroy_save + [self.FF.linedestroy_this])))) > 0: logger.info("All lines removed: " + self.FF.linedestroy_save + [self.FF.linedestroy_this] + '\n') logger.info("All prms removed: " + self.FF.prmdestroy_save + [self.FF.prmdestroy_this] + '\n') self.write_nested_destroy( self.GBSfnm, self.FF.linedestroy_save + [self.FF.linedestroy_this]) _exec("psi4", print_command=False, outfnm="psi4.stdout") if not in_fd(): for line in open('psi4.stdout').readlines(): if "MP2 Energy:" in line: self.MP2_Energy = float(line.split()[-1]) elif "DF Energy:" in line: self.DF_Energy = float(line.split()[-1]) Ans = np.array([[float(i) for i in line.split()] for line in open("objective.dat").readlines()]) os.unlink("objective.dat") return Ans
def get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = { 'X': 0.0, 'G': np.zeros(self.FF.np), 'H': np.zeros((self.FF.np, self.FF.np)) } # If the weight is zero, turn all derivatives off. if (self.weight == 0.0): AGrad = False AHess = False def callM(mvals_, dielectric=False): logger.info("\r") pvals = self.FF.make(mvals_) return self.engine.interaction_energy(self.select1, self.select2) logger.info("Executing\r") emm = callM(mvals) D = emm - self.eqm dV = np.zeros((self.FF.np, len(emm))) if self.writelevel > 0: # Dump interaction energies to disk. np.savetxt('M.txt', emm) np.savetxt('Q.txt', self.eqm) import pickle pickle.dump((self.name, self.label, self.prefactor, self.eqm, emm), open("qm_vs_mm.p", 'w')) # select the qm and mm data that has >0 weight to plot qm_data, mm_data = [], [] for i in range(len(self.eqm)): if self.prefactor[i] != 0: qm_data.append(self.eqm[i]) mm_data.append(emm[i]) plot_interaction_qm_vs_mm(qm_data, mm_data, title="Interaction Energy " + self.name) # Do the finite difference derivative. if AGrad or AHess: for p in self.pgrad: dV[p, :], _ = f12d3p(fdwrap(callM, mvals, p), h=self.h, f0=emm) # Create the force field one last time. pvals = self.FF.make(mvals) Answer['X'] = np.dot(self.prefactor * D / self.divisor, D / self.divisor) for p in self.pgrad: Answer['G'][p] = 2 * np.dot(self.prefactor * D / self.divisor, dV[p, :] / self.divisor) for q in self.pgrad: Answer['H'][p, q] = 2 * np.dot( self.prefactor * dV[p, :] / self.divisor, dV[q, :] / self.divisor) if not in_fd(): self.emm = emm self.objective = Answer['X'] ## QYD: try to clean up OpenMM engine.simulation objects to free up GPU memory try: if self.engine.name == 'openmm': if hasattr(self.engine, 'simulation'): del self.engine.simulation if hasattr(self.engine, 'A'): del self.engine.A if hasattr(self.engine, 'B'): del self.engine.B except: pass 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,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): Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} self.PrintDict = OrderedDict() self.RMSDDict = OrderedDict() #pool = Pool(processes=4) def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] for sys_ in self.sys_opts: Energy_, RMSD_ = self.system_driver(sys_) #print "Setting %s to" % sys_, Energy_ exec("%s = Energy_" % sys_) in locals() RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0 VectorD_.append(np.sqrt(w_)*RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: Calculated_ = eval(self.inter_opts[inter_]['equation']) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.cauchy: Divisor_ = np.sqrt(Denom_**2 + Reference_**2) elif self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_)*DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_) V = compute(mvals) dV = np.zeros((self.FF.np,len(V))) if AGrad or AHess: for p in range(self.FF.np): dV[p,:], _ = f12d3p(fdwrap(compute, mvals, p), h = self.h, f0 = V) Answer['X'] = np.dot(V,V) for p in range(self.FF.np): Answer['G'][p] = 2*np.dot(V, dV[p,:]) for q in range(self.FF.np): Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) if not in_fd(): self.objective = Answer['X'] self.FF.make(mvals) return Answer
def get(self, mvals, AGrad=False, AHess=False): Answer = { 'X': 0.0, 'G': np.zeros(self.FF.np), 'H': np.zeros((self.FF.np, self.FF.np)) } self.PrintDict = OrderedDict() self.RMSDDict = OrderedDict() EnergyDict = OrderedDict() #pool = Pool(processes=4) def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] for sys_ in self.sys_opts: Energy_, RMSD_ = self.system_driver(sys_) # Energies are stored in a dictionary. EnergyDict[sys_] = Energy_ RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_][ 'rmsd_weight'] if 'rmsd_weight' in self.sys_opts[ sys_] else 1.0 VectorD_.append(np.sqrt(w_) * RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_ * RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: def encloseInDictionary(matchobj): return 'EnergyDict["' + matchobj.group(0) + '"]' # Here we need to evaluate a mathematical expression of the stored variables in EnergyDict. # We start by enclosing every variable in EnergyDict[""] and then calling eval on it. evalExpr = re.sub('[A-Za-z_][A-Za-z0-9_]*', encloseInDictionary, self.inter_opts[inter_]['equation']) Calculated_ = eval(evalExpr) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.cauchy: Divisor_ = np.sqrt(Denom_**2 + Reference_**2) elif self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_ - Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_][ 'weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_) * DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % ( Calculated_, Reference_, Delta_, w_ * DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_), np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_), np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_) V = compute(mvals) dV = np.zeros((self.FF.np, len(V))) if AGrad or AHess: for p in self.pgrad: dV[p, :], _ = f12d3p(fdwrap(compute, mvals, p), h=self.h, f0=V) Answer['X'] = np.dot(V, V) for p in self.pgrad: Answer['G'][p] = 2 * np.dot(V, dV[p, :]) for q in self.pgrad: Answer['H'][p, q] = 2 * np.dot(dV[p, :], dV[q, :]) if not in_fd(): self.objective = Answer['X'] self.FF.make(mvals) 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 compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] # original code #for sys_ in self.sys_opts: # Energy_, RMSD_ = self.system_driver(sys_) # # Energies are stored in a dictionary. # EnergyDict[sys_] = Energy_ # RMSDNrm_ = RMSD_ / self.rmsd_denom # w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0 # VectorD_.append(np.sqrt(w_)*RMSDNrm_) # if not in_fd() and RMSD_ != 0.0: # self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2) # Added by Chengwen def Energy_RMSD(systems): tinkerhome = os.environ["TINKERPATH"] f1 = open("runAna.sh", "w") f2 = open("runMin.sh", "w") i = 0 for sys_ in systems: opts = systems[sys_] optimize = (opts['optimize'] if 'optimize' in opts else False) if not optimize: if (i + 1) % 24 == 0: cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out \n" % ( sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 else: cmd = "rm -f %s.out\n%s/analyze %s.xyz -k %s.key E > %s.out & \n" % ( sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 f1.write(cmd) else: if (i + 1) % 24 == 0: cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out \n" % ( sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 else: cmd = "rm -f %s.xyz_2 %s.out \n%s/optimize %s.xyz -k %s.key 0.0001 > %s.out & \n" % ( sys_, sys_, os.environ["TINKERPATH"], sys_, sys_, sys_) i += 1 f2.write(cmd) f1.write("wait\n") f2.write("wait\n") f1.close() f2.close() os.system("sh runAna.sh") os.system("sh runMin.sh") for sys_ in systems: while not os.path.isfile( os.path.join(os.getcwd(), sys_ + ".out")): time.sleep(1.0) Es = {} RMSDs = {} for sys_ in systems: energ = 0.0 rmsd = 0.0 for line in open("%s.out" % sys_).readlines(): if "Total Potential Energy" in line: energ = float(line.split()[-2].replace('D', 'e')) Es[sys_] = energ RMSDs[sys_] = 0.0 if "Final Function Value :" in line: energ = float(line.split()[-1].replace('D', 'e')) Es[sys_] = energ M1 = Molecule("%s.xyz" % sys_, ftype="tinker") M2 = Molecule("%s.xyz_2" % sys_, ftype="tinker") M1 += M2 RMSDs[sys_] = M1.ref_rmsd(0)[1] return Es, RMSDs Es, RMSDs = Energy_RMSD(self.sys_opts) for sys_ in self.sys_opts: Energy_ = Es[sys_] RMSD_ = RMSDs[sys_] EnergyDict[sys_] = Energy_ RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_][ 'rmsd_weight'] if 'rmsd_weight' in self.sys_opts[ sys_] else 1.0 VectorD_.append(np.sqrt(w_) * RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_ * RMSDNrm_**2) #====== Above ===== VectorE_ = [] for inter_ in self.inter_opts: def encloseInDictionary(matchobj): return 'EnergyDict["' + matchobj.group(0) + '"]' # Here we need to evaluate a mathematical expression of the stored variables in EnergyDict. # We start by enclosing every variable in EnergyDict[""] and then calling eval on it. evalExpr = re.sub('[A-Za-z_][A-Za-z0-9_]*', encloseInDictionary, self.inter_opts[inter_]['equation']) Calculated_ = eval(evalExpr) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_ - Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_][ 'weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_) * DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % ( Calculated_, Reference_, Delta_, w_ * DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_), np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_), np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_)
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=True, AHess=True): """Return the contribution to the total objective function. This is a weighted average of the calculated quantities. Parameters ---------- mvals : list Mathematical parameter values. AGrad : Boolean Switch to turn on analytic gradient. AHess : Boolean Switch to turn on analytic Hessian. Returns ------- Answer : dict Contribution to the objective function. `Answer` is a dict with keys `X` for the objective function, `G` for its gradient and `H` for its Hessian. """ Answer = {} Objective = 0.0 Gradient = np.zeros(self.FF.np) Hessian = np.zeros((self.FF.np, self.FF.np)) for pt in self.points: # Update data point with MD results self.retrieve(pt) obj = OrderedDict() reweighted = [] for q in self.quantities: # Returns dict with keys "X"=objective term value, "G"=the # gradient, "H"=the hessian, and "info"=printed info about points obj[q] = self.objective_term(q) # Apply weights for quantities (normalized) if obj[q]["X"] == 0: self.weights[q] = 0.0 # Store weights sorted in the order of self.quantities reweighted.append(self.weights[q]) # Normalize weights reweighted = np.array(reweighted) wtot = np.sum(reweighted) reweighted = reweighted/wtot if wtot > 0 else reweighted # Picks out the "X", "G" and "H" keys for the quantities sorted in the # order of self.quantities. Xs is N-array, Gs is NxM-array and Hs is # NxMxM-array, where N is number of quantities and M is number of # parameters. Xs = np.array([dic["X"] for dic in obj.values()]) Gs = np.array([dic["G"] for dic in obj.values()]) Hs = np.array([dic["H"] for dic in obj.values()]) # Target contribution is (normalized) weighted averages of the # individual quantity terms. Objective = np.average(Xs, weights=(None if np.all(reweighted == 0) else \ reweighted), axis=0) if AGrad: Gradient = np.average(Gs, weights=(None if np.all(reweighted == 0) else \ reweighted), axis=0) if AHess: Hessian = np.average(Hs, weights=(None if np.all(reweighted == 0) else \ reweighted), axis=0) if not in_fd(): # Store results to show with indicator() function self.Xp = {q : dic["X"] for (q, dic) in obj.items()} self.Wp = {q : reweighted[self.quantities.index(q)] for (q, dic) in obj.items()} self.Pp = {q : dic["info"] for (q, dic) in obj.items()} if AGrad: self.Gp = {q : dic["G"] for (q, dic) in obj.items()} self.Objective = Objective Answer = { "X": Objective, "G": Gradient, "H": Hessian } 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 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 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
def get(self, mvals, AGrad=False, AHess=False): Answer = { 'X': 0.0, 'G': np.zeros(self.FF.np), 'H': np.zeros((self.FF.np, self.FF.np)) } self.PrintDict = OrderedDict() def compute(mvals_, indicate=False): self.FF.make(mvals_) M_opts = None compute.emm = [] compute.rmsd = [] for i in range(self.ns): energy, rmsd, M_opt = self.engine.optimize(shot=i, align=False) # Create a molecule object to hold the MM-optimized structures compute.emm.append(energy) compute.rmsd.append(rmsd) if M_opts is None: M_opts = deepcopy(M_opt) else: M_opts += M_opt compute.emm = np.array(compute.emm) compute.emm -= compute.emm[self.smin] compute.rmsd = np.array(compute.rmsd) if indicate: if self.writelevel > 0: M_opts.write('mm_minimized.xyz') if self.ndim == 1: import matplotlib.pyplot as plt plt.switch_backend('agg') fig, ax = plt.subplots() dihedrals = np.array( [i[0] for i in self.metadata['torsion_grid_ids']]) dsort = np.argsort(dihedrals) ax.plot(dihedrals[dsort], self.eqm[dsort], label='QM') if hasattr(self, 'emm_orig'): ax.plot(dihedrals[dsort], compute.emm[dsort], label='MM Current') ax.plot(dihedrals[dsort], self.emm_orig[dsort], label='MM Initial') else: ax.plot(dihedrals[dsort], compute.emm[dsort], label='MM Initial') self.emm_orig = compute.emm.copy() ax.legend() ax.set_xlabel('Dihedral (degree)') ax.set_ylabel('Energy (kcal/mol)') fig.suptitle( 'Torsion profile: iteration %i\nSystem: %s' % (Counter(), self.name)) fig.savefig('plot_torsion.pdf') return (np.sqrt(self.wts) / self.energy_denom) * (compute.emm - self.eqm) compute.emm = None compute.rmsd = None V = compute(mvals, indicate=True) Answer['X'] = np.dot(V, V) # Energy RMSE e_rmse = np.sqrt(np.dot(self.wts, (compute.emm - self.eqm)**2)) self.PrintDict[ self. name] = '%10s %10s %6.3f - %-6.3f % 6.3f - %-6.3f %6.3f %7.4f % 7.4f' % ( ','.join([ '%i' % i for i in self.metadata['torsion_grid_ids'][self.smin] ]), ','.join([ '%i' % i for i in self.metadata['torsion_grid_ids'][ np.argmin(compute.emm)] ]), min(self.eqm), max(self.eqm), min(compute.emm), max(compute.emm), max(compute.rmsd), e_rmse, Answer['X']) # compute gradients and hessian dV = np.zeros((self.FF.np, len(V))) if AGrad or AHess: for p in self.pgrad: dV[p, :], _ = f12d3p(fdwrap(compute, mvals, p), h=self.h, f0=V) for p in self.pgrad: Answer['G'][p] = 2 * np.dot(V, dV[p, :]) for q in self.pgrad: Answer['H'][p, q] = 2 * np.dot(dV[p, :], dV[q, :]) if not in_fd(): self.objective = Answer['X'] self.FF.make(mvals) return Answer
FK_lines.append(LI_lines[key][0]) else: FK_lines.append(line) o = wopen('franken.gbs') for line in FK_lines: print >> o, line, o.close() _exec("cp %s.bak %s" % (self.GBSfnm, self.GBSfnm), print_command=False) if len(list(itertools.chain(*(self.FF.linedestroy_save + [self.FF.linedestroy_this])))) > 0: logger.info("All lines removed: " + self.FF.linedestroy_save + [self.FF.linedestroy_this] + '\n') logger.info("All prms removed: " + self.FF.prmdestroy_save + [self.FF.prmdestroy_this] + '\n') self.write_nested_destroy(self.GBSfnm, self.FF.linedestroy_save + [self.FF.linedestroy_this]) _exec("psi4", print_command=False, outfnm="psi4.stdout") if not in_fd(): for line in open('psi4.stdout').readlines(): if "MP2 Energy:" in line: self.MP2_Energy = float(line.split()[-1]) elif "DF Energy:" in line: self.DF_Energy = float(line.split()[-1]) Ans = np.array([[float(i) for i in line.split()] for line in open("objective.dat").readlines()]) os.unlink("objective.dat") return Ans class Grid_Reader(BaseReader): """Finite state machine for parsing DVR grid files. """ def __init__(self,fnm=None):
def get(self, mvals, AGrad=False, AHess=False): Answer = { 'X': 0.0, 'G': np.zeros(self.FF.np), 'H': np.zeros((self.FF.np, self.FF.np)) } self.PrintDict = OrderedDict() # enable self.system_mval_masks (supported by OptGeoTarget_SMIRNOFF) enable_system_mval_mask = hasattr(self, 'system_mval_masks') def compute(mvals, p_idx=None): ''' Compute total objective value for each system ''' self.FF.make(mvals) v_obj_list = [] for sysname, sysopt in self.sys_opts.items(): # ref values of each type vref_bonds = self.internal_coordinates[sysname]['vref_bonds'] vref_angles = self.internal_coordinates[sysname]['vref_angles'] vref_dihedrals = self.internal_coordinates[sysname][ 'vref_dihedrals'] vref_impropers = self.internal_coordinates[sysname][ 'vref_impropers'] # counts of each type n_bonds = len(vref_bonds) n_angles = len(vref_angles) n_dihedrals = len(vref_dihedrals) n_impropers = len(vref_impropers) # use self.system_mval_masks to skip evaluations when computing gradients if enable_system_mval_mask and in_fd() and ( p_idx is not None) and ( self.system_mval_masks[sysname][p_idx] == False): v_obj_list += [0] * (n_bonds + n_angles + n_dihedrals + n_impropers) continue # read denominators from system options bond_denom = sysopt['bond_denom'] angle_denom = sysopt['angle_denom'] dihedral_denom = sysopt['dihedral_denom'] improper_denom = sysopt['improper_denom'] # inverse demon to be scaling factors, 0 for denom 0 scale_bond = 1.0 / bond_denom if bond_denom != 0 else 0.0 scale_angle = 1.0 / angle_denom if angle_denom != 0 else 0.0 scale_dihedral = 1.0 / dihedral_denom if dihedral_denom != 0 else 0.0 scale_improper = 1.0 / improper_denom if improper_denom != 0 else 0.0 # calculate new internal coordinates v_ic = self.system_driver(sysname) # objective contribution from bonds vtar_bonds = v_ic['bonds'] diff_bond = ((vref_bonds - vtar_bonds) * scale_bond).tolist() if n_bonds > 0 else [] # objective contribution from angles vtar_angles = v_ic['angles'] diff_angle = (periodic_diff(vref_angles, vtar_angles, 360) * scale_angle).tolist() if n_angles > 0 else [] # objective contribution from dihedrals vtar_dihedrals = v_ic['dihedrals'] diff_dihedral = ( periodic_diff(vref_dihedrals, vtar_dihedrals, 360) * scale_dihedral).tolist() if n_dihedrals > 0 else [] # objective contribution from improper dihedrals vtar_impropers = v_ic['impropers'] diff_improper = ( periodic_diff(vref_impropers, vtar_impropers, 360) * scale_improper).tolist() if n_impropers > 0 else [] # combine objective values into a big result list sys_obj_list = diff_bond + diff_angle + diff_dihedral + diff_improper # extend the result v_obj_list by individual terms in this system v_obj_list += sys_obj_list # save print string if not in_fd(): # For printing, we group the RMSD by type rmsd_bond = compute_rmsd(vref_bonds, vtar_bonds) rmsd_angle = compute_rmsd(vref_angles, vtar_angles, v_periodic=360) rmsd_dihedral = compute_rmsd(vref_dihedrals, vtar_dihedrals, v_periodic=360) rmsd_improper = compute_rmsd(vref_impropers, vtar_impropers, v_periodic=360) obj_total = sum(v**2 for v in sys_obj_list) self.PrintDict[sysname] = "% 9.3f % 7.2f % 9.3f % 7.2f % 9.3f % 7.2f % 9.3f % 7.2f %17.3f" % (rmsd_bond, \ bond_denom, rmsd_angle, angle_denom, rmsd_dihedral, dihedral_denom, rmsd_improper, improper_denom, obj_total) return np.array(v_obj_list, dtype=float) V = compute(mvals) Answer['X'] = np.dot(V, V) # write objective decomposition if wanted if self.writelevel > 0: # recover mvals self.FF.make(mvals) with open('rmsd_decomposition.txt', 'w') as fout: for sysname in self.internal_coordinates: fout.write("\n[ %s ]\n" % sysname) fout.write('%-25s %15s %15s %15s\n' % ("Internal Coordinate", "Ref QM Value", "Cur MM Value", "Difference")) # reference data sys_data = self.internal_coordinates[sysname] sys_data['ic_bonds'] # compute all internal coordinate values again v_ic = self.system_driver(sysname) for p in ['bonds', 'angles', 'dihedrals', 'impropers']: fout.write('--- ' + p + ' ---\n') ic_list = sys_data['ic_' + p] ref_v = sys_data['vref_' + p] tar_v = v_ic[p] # print each value for ic, v1, v2 in zip(ic_list, ref_v, tar_v): diff = periodic_diff( v1, v2, v_periodic=360) if p != 'bonds' else v1 - v2 fout.write('%-25s %15.5f %15.5f %+15.3e\n' % (ic, v1, v2, diff)) # compute gradients and hessian dV = np.zeros((self.FF.np, len(V))) if AGrad or AHess: for p in self.pgrad: dV[p, :], _ = f12d3p(fdwrap(compute, mvals, p, p_idx=p), h=self.h, f0=V) for p in self.pgrad: Answer['G'][p] = 2 * np.dot(V, dV[p, :]) for q in self.pgrad: Answer['H'][p, q] = 2 * np.dot(dV[p, :], dV[q, :]) if not in_fd(): self.objective = Answer['X'] self.FF.make(mvals) 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 get(self, mvals, AGrad=False, AHess=False): """ Evaluate objective function. """ Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} # If the weight is zero, turn all derivatives off. if (self.weight == 0.0): AGrad = False AHess = False def callM(mvals_, dielectric=False): logger.info("\r") pvals = self.FF.make(mvals_) return self.engine.interaction_energy(self.select1, self.select2) logger.info("Executing\r") emm = callM(mvals) D = emm - self.eqm dV = np.zeros((self.FF.np,len(emm))) if self.writelevel > 0: # Dump interaction energies to disk. np.savetxt('M.txt',emm) np.savetxt('Q.txt',self.eqm) import pickle pickle.dump((self.name, self.label, self.prefactor, self.eqm, emm), open("qm_vs_mm.p",'w')) # select the qm and mm data that has >0 weight to plot qm_data, mm_data = [], [] for i in xrange(len(self.eqm)): if self.prefactor[i] != 0: qm_data.append(self.eqm[i]) mm_data.append(emm[i]) plot_interaction_qm_vs_mm(qm_data, mm_data, title="Interaction Energy "+self.name) # Do the finite difference derivative. if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(callM, mvals, p), h = self.h, f0 = emm) # Create the force field one last time. pvals = self.FF.make(mvals) Answer['X'] = np.dot(self.prefactor*D/self.divisor,D/self.divisor) for p in self.pgrad: Answer['G'][p] = 2*np.dot(self.prefactor*D/self.divisor, dV[p,:]/self.divisor) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(self.prefactor*dV[p,:]/self.divisor, dV[q,:]/self.divisor) if not in_fd(): self.emm = emm self.objective = Answer['X'] ## QYD: try to clean up OpenMM engine.simulation objects to free up GPU memory try: if self.engine.name == 'openmm': if hasattr(self.engine, 'simulation'): del self.engine.simulation if hasattr(self.engine, 'A'): del self.engine.A if hasattr(self.engine, 'B'): del self.engine.B except: pass return Answer
def get(self, mvals, AGrad=False, AHess=False): Answer = {'X':0.0, 'G':np.zeros(self.FF.np), 'H':np.zeros((self.FF.np, self.FF.np))} self.PrintDict = OrderedDict() self.RMSDDict = OrderedDict() EnergyDict = OrderedDict() #pool = Pool(processes=4) def compute(mvals_): # This function has automatically assigned variable names from the interaction master file # Thus, all variable names in here are protected using an underscore. self.FF.make(mvals_) VectorD_ = [] for sys_ in self.sys_opts: Energy_, RMSD_ = self.system_driver(sys_) # Energies are stored in a dictionary. EnergyDict[sys_] = Energy_ RMSDNrm_ = RMSD_ / self.rmsd_denom w_ = self.sys_opts[sys_]['rmsd_weight'] if 'rmsd_weight' in self.sys_opts[sys_] else 1.0 VectorD_.append(np.sqrt(w_)*RMSDNrm_) if not in_fd() and RMSD_ != 0.0: self.RMSDDict[sys_] = "% 9.3f % 12.5f" % (RMSD_, w_*RMSDNrm_**2) VectorE_ = [] for inter_ in self.inter_opts: def encloseInDictionary(matchobj): return 'EnergyDict["' + matchobj.group(0)+'"]' # Here we need to evaluate a mathematical expression of the stored variables in EnergyDict. # We start by enclosing every variable in EnergyDict[""] and then calling eval on it. evalExpr = re.sub('[A-Za-z_][A-Za-z0-9_]*', encloseInDictionary, self.inter_opts[inter_]['equation']) Calculated_ = eval(evalExpr) Reference_ = self.inter_opts[inter_]['reference_physical'] Delta_ = Calculated_ - Reference_ Denom_ = self.energy_denom if self.cauchy: Divisor_ = np.sqrt(Denom_**2 + Reference_**2) elif self.attenuate: if Reference_ < Denom_: Divisor_ = Denom_ else: Divisor_ = np.sqrt(Denom_**2 + (Reference_-Denom_)**2) else: Divisor_ = Denom_ DeltaNrm_ = Delta_ / Divisor_ w_ = self.inter_opts[inter_]['weight'] if 'weight' in self.inter_opts[inter_] else 1.0 VectorE_.append(np.sqrt(w_)*DeltaNrm_) if not in_fd(): self.PrintDict[inter_] = "% 9.3f % 9.3f % 9.3f % 12.5f" % (Calculated_, Reference_, Delta_, w_*DeltaNrm_**2) # print "%-20s" % inter_, "Calculated:", Calculated_, "Reference:", Reference_, "Delta:", Delta_, "DeltaNrm:", DeltaNrm_ # The return value is an array of normalized interaction energy differences. if not in_fd(): self.rmsd_part = np.dot(np.array(VectorD_),np.array(VectorD_)) if len(VectorE_) > 0: self.energy_part = np.dot(np.array(VectorE_),np.array(VectorE_)) else: self.energy_part = 0.0 if len(VectorE_) > 0 and len(VectorD_) > 0: return np.array(VectorD_ + VectorE_) elif len(VectorD_) > 0: return np.array(VectorD_) elif len(VectorE_) > 0: return np.array(VectorE_) V = compute(mvals) dV = np.zeros((self.FF.np,len(V))) if AGrad or AHess: for p in self.pgrad: dV[p,:], _ = f12d3p(fdwrap(compute, mvals, p), h = self.h, f0 = V) Answer['X'] = np.dot(V,V) for p in self.pgrad: Answer['G'][p] = 2*np.dot(V, dV[p,:]) for q in self.pgrad: Answer['H'][p,q] = 2*np.dot(dV[p,:], dV[q,:]) if not in_fd(): self.objective = Answer['X'] self.FF.make(mvals) return Answer