def SinglePointEnergies(traj, label='aimd', xcf='VDW', xca='DRSLL', basistype='DZP', EngTole=0.0000001, frame=50, cpu=4, dE=0.2, d2E=0.1, select=False): ''' get single point energy and labeling data ''' images = Trajectory(traj) tframe = len(images) E, E_, dEs = [], [], [] if tframe > frame: if frame > 1: ind_ = list(np.linspace(0, tframe - 1, num=frame, dtype=np.int32)) else: ind_ = [tframe - 1] else: ind_ = [i for i in range(tframe)] if len(ind_) > 1 and 0 in ind_: ind_.pop(0) his = TrajectoryWriter(label + '.traj', mode='w') energies = [] d2Es = [] dE_ = 0.0 d2E_ = 0.0 for i, atoms in enumerate(images): energy = atoms.get_potential_energy() extreme_point = False if i > 0: if i < (tframe - 1): deltEl = energy - energies[-1] deltEr = images[i + 1].get_potential_energy() - energy dE_ = abs(deltEl) d2E_ = abs(deltEr - deltEl) else: deltEl = energy - energies[-1] deltEr = deltEl dE_ = abs(deltEl) if (deltEr > 0.0 and deltEl < 0.0) or (deltEr < 0.0 and deltEl > 0.0) or dE_ < 0.00001: extreme_point = True if select: if dE_ > dE or extreme_point: if i not in ind_: if i - 1 not in ind_: ind_.append(i) dEs.append(dE_) d2Es.append(d2E_) energies.append(energy) ide = np.argmax(dEs) id2e = np.argmax(d2Es) if (ide not in ind_) and (ide + 1 not in ind_) and (ide - 1 not in ind_): ind_.append(ide) if id2e not in ind_ and (id2e + 1 not in ind_) and (id2e - 1 not in ind_): ind_.append(id2e) ind_.sort() LabelDataLog = ' AtomicConfigure E(ML) E(DFT) Diff dE d2E \n' LabelDataLog += ' --------------------------------------------------------\n' for i in ind_: atoms = images[i] e_ = atoms.get_potential_energy() dE_ = dEs[i] d2E_ = d2Es[i] atoms_ = single_point(atoms, xcf=xcf, xca=xca, basistype=basistype, cpu=cpu) e = atoms_.get_potential_energy() E.append(e) E_.append(e_) diff_ = abs(e - e_) LabelDataLog += ' {:3d} {:9.5f} {:9.5f} {:6.6f} {:5.4f} {:5.4f}\n'.format( i, e_, e, diff_, dE_, d2E_) with open('SinglePointEnergies.log', 'a') as fs: fs.write( '%d MLP: %9.5f DFT: %9.5f Diff: %6.6f dE: %5.4f d2E: %5.4f\n' % (i, e_, e, diff_, dE_, d2E_)) if diff_ > EngTole: # or i==ind_[-1] his.write(atoms=atoms_) his.close() images = None dEmax = dEs[ide] d2Emax = d2Es[id2e] return E, E_, dEmax, d2Emax, LabelDataLog
def dh(traj='siesta.traj', batch_size=1, nn=True, frame=7): ffield = 'ffield.json' if nn else 'ffield' images = Trajectory(traj) atoms = images[frame] his = TrajectoryWriter('tmp.traj', mode='w') his.write(atoms=atoms) his.close() from irff.irff import IRFF ir = IRFF(atoms=atoms, libfile=ffield, nn=nn, bo_layer=[9, 2]) ir.get_potential_energy(atoms) from irff.reax import ReaxFF rn = ReaxFF(libfile=ffield, direcs={'tmp': 'tmp.traj'}, dft='siesta', opt=[], optword='nocoul', batch_size=batch_size, atomic=True, clip_op=False, InitCheck=False, nn=nn, pkl=False, to_train=False) molecules = rn.initialize() rn.session(learning_rate=1.0e-10, method='AdamOptimizer') mol = 'tmp' hblab = rn.lk.hblab hbs = [] for hb in ir.hbs: hbs.append(list(hb)) eh_ = rn.get_value(rn.EHB) # eh = ir.ehb.numpy() rhb_ = rn.get_value(rn.rhb) # rhb = ir.rhb.numpy() frhb_ = rn.get_value(rn.frhb) # frhb = ir.frhb.numpy() sin4_ = rn.get_value(rn.sin4) # sin4 = ir.sin4.numpy() # exphb1_= rn.get_value(rn.exphb1) # exphb2_= rn.get_value(rn.exphb2) # exphb1 = ir.exphb1.numpy() # exphb2 = ir.exphb2.numpy() # hbsum_ = rn.get_value(rn.hbsum) # hbsum = ir.hbsum.numpy() for hb in rn.hbs: for a_ in range(rn.nhb[hb]): a = hblab[hb][a_][1:] i, j, k = a if a in hbs: ai = hbs.index(a) # if eh_[hb][a_][0]<-0.000001: print( '- %2d%s-%2d%s-%2d%s:' % (i, ir.atom_name[i], j, ir.atom_name[j], k, ir.atom_name[k]), 'ehb: %10.8f' % (eh_[hb][a_][0]), 'rhb: %10.8f' % (rhb_[hb][a_][0]), 'frhb: %10.8f' % (frhb_[hb][a_][0]), 'sin4: %10.8f' % (sin4_[hb][a_][0]))
def _find_one_transition_path(self, path_length=1000, trajfile="default.traj", target="both", nsteps=None): """ Finds a transition path by running random samples :param int path_length: Number of MC sweep in path :param str trajfile: Trajectory file where path will be stored :param str target: Target basins (reactant, product or both) :param nsteps: Number of MC steps in one sweep :type nsteps: int or None """ supported_targets = ["reactant", "product", "both"] if target not in supported_targets: raise ValueError("Target has to be one of {}" "".format(supported_targets)) # Check if a snapshot tracker is attached traj = TrajectoryWriter(trajfile, mode="w") result = {} symbs = [] unique_symbols = [] for atom in self.atoms: if atom.symbol not in unique_symbols: unique_symbols.append(atom.symbol) output_every_sec = 30 now = time.time() energies = [] result = {} sizes = [] for sweep in range(int(path_length)): self.network.reset() if time.time() - now > output_every_sec: self.log("Sweep {} of {}".format(sweep, path_length)) now = time.time() self.sweep(nsteps=nsteps) # Explicitly enforce a construction of the network self.network(None) energies.append(self.current_energy) symbs.append([atom.symbol for atom in self.atoms]) atoms = self.network.get_atoms_with_largest_cluster( prohibited_symbols=unique_symbols) sizes.append(self.network.max_size) self._add_info_to_atoms(atoms) calc = SinglePointCalculator(atoms, energy=self.current_energy) atoms.set_calculator(calc) if atoms is None: traj.write(self.atoms) else: traj.write(atoms) if target == "reactant": if self.is_product(): # Terminate before the desired path length is reached result["type"] = "product" result["symbols"] = symbs result["energy"] = energies result["sizes"] = sizes return result elif target == "product": if self.is_reactant(): result["type"] = "reactant" result["symbols"] = symbs result["energy"] = energies result["sizes"] = sizes # Terminate before the desired path length is reached return result traj.close() if self.is_reactant(): result["type"] = "reactant" elif self.is_product(): result["type"] = "product" else: stat = self.network.get_statistics() max_size = stat["max_size"] msg = "State did not end up in product or reactant region. " msg += "Increase the number of sweeps.\n" msg += "Max. cluster size {}.".format(max_size) msg += "Max cluster size reactants {}".format( self.max_size_reactant) msg += "Min cluster size products {}".format(self.min_size_product) raise DidNotReachProductOrReactantError(msg) result["symbols"] = symbs result["energy"] = energies result["sizes"] = sizes return result
def da(traj='opt.traj', batch_size=50, ef=3, nn=True, frame=44): ffield = 'ffield.json' if nn else 'ffield' images = Trajectory(traj) atoms = images[frame] his = TrajectoryWriter('tmp.traj', mode='w') his.write(atoms=atoms) # his.write(atoms=images[frame+1]) his.close() ir = IRFF(atoms=atoms, libfile=ffield, nn=nn, autograd=False) ir.calculate(atoms) rn = MPNN(libfile=ffield, direcs={'tmp': 'tmp.traj'}, dft='siesta', opt=[], optword='nocoul', batch_size=batch_size, atomic=True, clip_op=False, InitCheck=False, nn=nn, bo_layer=[9, 2], EnergyFunction=ef, pkl=False) molecules = rn.initialize() rn.session(learning_rate=1.0e-10, method='AdamOptimizer') mol = 'tmp' anglab = rn.lk.anglab angs = [] for ang in ir.angs: angs.append(list(ang)) ea_ = rn.get_value(rn.EANG) ea = ir.eang.numpy() f7_ = rn.get_value(rn.f_7) f7 = ir.f_7.numpy() f8_ = rn.get_value(rn.f_8) f8 = ir.f_8.numpy() expang_ = rn.get_value(rn.expang) expang = ir.expang.numpy() theta_ = rn.get_value(rn.theta) theta = ir.theta.numpy() theta0_ = rn.get_value(rn.theta0) theta0 = ir.thet0.numpy() sbo3_ = rn.get_value(rn.SBO3) sbo3 = ir.SBO3.numpy() fa = open('ang.txt', 'w') for ang in rn.angs: for a_ in range(rn.nang[ang]): a = anglab[ang][a_][1:] if a not in angs: a.reverse() i, j, k = a if a in angs: ai = angs.index(a) print( ' * %2d%s-%2d%s-%2d%s:' % (i, ir.atom_name[i], j, ir.atom_name[j], k, ir.atom_name[k]), #'eang: %10.8f %10.8f' %(ea_[ang][a_][0],ea[ai]), 'f7: %10.8f %10.8f' % (f7_[ang][a_][0], f7[ai]), 'f8: %10.8f %10.8f' % (f8_[ang][a_][0], f8[ai]), 'expang: %10.8f %10.8f' % (expang_[ang][a_][0], expang[ai]), 'theta: %10.8f %10.8f' % (theta_[ang][a_][0], theta[ai]), # 'sbo3: %10.8f %10.8f' %(sbo3_[ang][a_][0],sbo3[ai]), 'theta0: %10.8f %10.8f' % (theta0_[ang][a_][0], theta0[ai]), file=fa) else: print( ' * %2d%s-%2d%s-%2d%s:' % (i, ir.atom_name[i], j, ir.atom_name[j], k, ir.atom_name[k]), #'eang: %10.8f' %(ea_[ang][a_][0]), 'f7: %10.8f' % (f7_[ang][a_][0]), 'f8: %10.8f' % (f8_[ang][a_][0]), 'expang: %10.8f' % (expang_[ang][a_][0]), 'expang: %10.8f' % (expang_[ang][a_][0]), 'theta: %10.8f' % (theta_[ang][a_][0]), # 'sbo3: %10.8f' %(sbo3_[ang][a_][0]), 'theta0: %10.8f' % (theta0_[ang][a_][0])) fa.close() epen = rn.get_value(rn.epen) eang = rn.get_value(rn.eang) print(' * penalty energy:', ir.Epen.numpy(), epen[mol][0]) print(' * angel energy:', ir.Eang.numpy(), eang[mol][0])
def dt(traj='siesta.traj', batch_size=1, nn=True, frame=0): ffield = 'ffield.json' if nn else 'ffield' images = Trajectory(traj) atoms = images[frame] his = TrajectoryWriter('tmp.traj', mode='w') his.write(atoms=atoms) his.close() from irff.irff import IRFF ir = IRFF(atoms=atoms, libfile=ffield, nn=nn) ir.get_potential_energy(atoms) eb = ir.Ebond.numpy() et = ir.etor.numpy() ef = ir.efcon.numpy() f10 = ir.f_10.numpy() f11 = ir.f_11.numpy() sijk = ir.s_ijk.numpy() sjkl = ir.s_jkl.numpy() f = ir.fijkl.numpy() v1 = ir.v1.numpy() v2 = ir.v2.numpy() v3 = ir.v3.numpy() expv2 = ir.expv2.numpy() boij = ir.botij.numpy() bojk = ir.botjk.numpy() bokl = ir.botkl.numpy() cosw = ir.cos_w.numpy() cos2w = ir.cos2w.numpy() w = ir.w.numpy() Etor = ir.Etor.numpy() del IRFF from irff.reax import ReaxFF rn = ReaxFF(libfile=ffield, direcs={'tmp': 'tmp.traj'}, dft='siesta', opt=[], optword='nocoul', batch_size=batch_size, atomic=True, clip_op=False, InitCheck=False, nn=nn, bo_layer=[9, 2], pkl=False, to_train=False) molecules = rn.initialize() # rn.calculate(rn.p,rn.m) rn.session(learning_rate=3.0 - 4, method='AdamOptimizer') mol = 'tmp' torlab = rn.lk.torlab tors = [] for tor in ir.tors: tors.append(list(tor)) print(tor) eb_ = rn.get_value(rn.ebond[mol]) et_ = rn.get_value(rn.ETOR) ef_ = rn.get_value(rn.Efcon) f10_ = rn.get_value(rn.f_10) f11_ = rn.get_value(rn.f_11) sijk_ = rn.get_value(rn.s_ijk) sjkl_ = rn.get_value(rn.s_jkl) f_ = rn.get_value(rn.fijkl) boij_ = rn.get_value(rn.BOtij) bojk_ = rn.get_value(rn.BOtjk) bokl_ = rn.get_value(rn.BOtkl) v1_ = rn.get_value(rn.v1) v2_ = rn.get_value(rn.v2) v3_ = rn.get_value(rn.v3) expv2_ = rn.get_value(rn.expv2) cosw_ = rn.get_value(rn.cos_w) cos2w_ = rn.get_value(rn.cos2w) w_ = rn.get_value(rn.w) for tor in rn.tors: for a_ in range(rn.ntor[tor]): a = torlab[tor][a_][1:] if a not in tors: a.reverse() i, j, k, l = a if a in tors: ai = tors.index(a) # if abs(et_[tor][a_][0]-et[ai])>0.0001: print( '- %2d%s-%2d%s-%2d%s-%2d%s:' % (i, ir.atom_name[i], j, ir.atom_name[j], k, ir.atom_name[k], l, ir.atom_name[l]), 'etor: %10.8f %10.8f' % (et_[tor][a_][0], et[ai]), 'sijk: %10.8f %10.8f' % (sijk_[tor][a_][0], sijk[ai]), 'sjkl: %10.8f %10.8f' % (sjkl_[tor][a_][0], sjkl[ai]), 'boij: %10.8f %10.8f' % (boij_[tor][a_][0], boij[ai]), 'bojk: %10.8f %10.8f' % (bojk_[tor][a_][0], bojk[ai]), 'bokl: %10.8f %10.8f' % (bokl_[tor][a_][0], bokl[ai]), 'fijkl: %10.8f %10.8f' % (f_[tor][a_][0], f[ai]), 'v1: %10.8f %10.8f' % (v1_[tor][a_][0], v1[ai]), 'v2: %10.8f %10.8f' % (v2_[tor][a_][0], v2[ai]), 'v3: %10.8f %10.8f' % (v3_[tor][a_][0], v3[ai]), 'expv2: %10.8f %10.8f' % (expv2_[tor][a_][0], expv2[ai]), 'ptor1: %10.8f %10.8f' % (rn.p_['tor1_' + tor], ir.P['tor1'][ai]), # 'cosw: %10.8f %10.8f' %(cosw_[tor][a_][0],cosw[ai]), # 'cos2w: %10.8f %10.8f' %(cos2w_[tor][a_][0],cos2w[ai]), # 'v1: %10.8f %10.8f' %(0.5*rn.p_['V1_'+tor]*(1.0+cosw_[tor][a_][0]), # 0.5*ir.P['V1'][ai]*(1.0+cosw[ai])), # 'w: %10.8f %10.8f' %(w_[tor][a_][0],w[ai]), # 'efcon: %10.8f %10.8f' %(ef_[tor][a_][0],ef[ai]), # 'f_10: %10.8f %10.8f' %(f10_[tor][a_][0],f10[ai]), # 'f_11: %10.8f %10.8f' %(f11_[tor][a_][0],f11[ai]), ) Etor_ = rn.get_value(rn.etor) print('\n- torsion energy:', Etor, Etor_[mol][0], end='\n') print('\n- Bond energy:', eb, eb_, end='\n') del ReaxFF
def dl(traj='siesta.traj', batch_size=1, nn=False, frame=0): ffield = 'ffield.json' if nn else 'ffield' images = Trajectory(traj) atoms = images[frame] his = TrajectoryWriter('tmp.traj', mode='w') his.write(atoms=atoms) his.close() ir = IRFF(atoms=atoms, libfile=ffield, nn=False, bo_layer=[8, 4]) ir.get_potential_energy(atoms) el = ir.elone.numpy() Dle = ir.Delta_e.numpy() Dlp = ir.Delta_lp.numpy() de = ir.DE.numpy() nlp = ir.nlp.numpy() elp = ir.explp.numpy() eu = ir.eunder.numpy() eu1 = ir.eu1.numpy() eu2 = ir.eu2.numpy() eu3 = ir.expeu3.numpy() rn = ReaxFF(libfile=ffield, direcs={'tmp': 'tmp.traj'}, dft='siesta', opt=[], optword='nocoul', batch_size=batch_size, atomic=True, clip_op=False, InitCheck=False, nn=nn, pkl=False, to_train=False) molecules = rn.initialize() rn.session(learning_rate=1.0e-10, method='AdamOptimizer') mol = 'tmp' el_ = rn.get_value(rn.EL) Dle_ = rn.get_value(rn.Delta_e) Dlp_ = rn.get_value(rn.Delta_lp) de_ = rn.get_value(rn.DE) nlp_ = rn.get_value(rn.nlp) elp_ = rn.get_value(rn.explp) eu_ = rn.get_value(rn.EUN) eu1_ = rn.get_value(rn.eu1) eu2_ = rn.get_value(rn.eu2) eu3_ = rn.get_value(rn.expeu3) alab = rn.lk.atlab bosi = ir.bosi.numpy() for i in range(ir.natom): a = ir.atom_name[i] al = [mol, i] na = alab[a].index(al) print( '- %d %s:' % (i, ir.atom_name[i]), 'elone: %10.8f %10.8f' % (el_[a][na], el[i]), # 'Delta_e: %10.8f %10.8f' %(Dle_[a][na],Dle[i]), # 'Delta_lp: %10.8f %10.8f' %(Dlp_[a][na],Dlp[i]), # 'nlp: %10.8f %10.8f' %(nlp_[a][na],nlp[i]), 'eunder: %10.8f %10.8f' % (eu_[a][na], eu[i]), # 'eu1: %10.8f %10.8f' %(eu1_[a][na],eu1[i]), 'eu2: %10.8f %10.8f' % (eu2_[a][na], eu2[i]), 'eu3: %10.8f %10.8f' % (eu3_[a][na], eu3[i])) print('\n- under energy:', ir.Eunder.numpy(), rn.eunder[mol].numpy()[0], end='\n')
#!/usr/bin/env python from irff.nwchem import decompostion from ase.io.trajectory import Trajectory, TrajectoryWriter from ase.calculators.singlepoint import SinglePointCalculator import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # decompostion(gen='rdx.gen',ncpu=12) images1 = Trajectory('stretch0.traj') images2 = Trajectory('stretch.traj') traj = TrajectoryWriter('decompostion.traj', mode='w') rs, es = [], [] for image in images1: vr = image.positions[3] - image.positions[18] vr2 = np.square(vr) r = np.sqrt(np.sum(vr2)) rs.append(r) e = image.get_potential_energy() es.append(e) #calc = SinglePointCalculator(A,energy=e) #image.set_calculator(calc) traj.write(atoms=image) for image in images2: vr = image.positions[3] - image.positions[18]
def static_compress(): traj = TrajectoryWriter('pre_opt.traj', mode='w') atoms = read('nm.gen') cell = atoms.get_cell() atoms_ = atoms.copy() configs = [] GPa = 1.60217662 * 1.0e2 s = 1.0 i = 0 ir = IRFF(atoms=atoms_, libfile='ffield.json', nn=True) v_, p = [], [] v0 = atoms.get_volume() while s > 0.66: print(' * lattice step:', i) f = s**(1.0 / 3.0) cell_ = cell.copy() cell_ = cell * f ir.CalStress = False atoms_.set_cell(cell_) atoms_ = opt(atoms=atoms_, fmax=0.02, step=120, optimizer=FIRE) configs.append(atoms_) traj.write(atoms=atoms_) ir.CalStress = True ir.calculate(atoms=atoms_) stress = ir.results['stress'] nonzero = 0 stre_ = 0.0 for _ in range(3): if abs(stress[_]) > 0.0000001: nonzero += 1 stre_ += -stress[_] pressure = stre_ * GPa / nonzero p.append(pressure) v = atoms_.get_volume() v_.append(v / v0) print(' * V/V0', v_[-1], v, pressure) s = s * 0.98 i += 1 fig, ax = plt.subplots() plt.ylabel(r'$Pressure$ ($GPa$)') plt.xlabel(r'$V/V_0$') plt.plot(v_, p, label=r'$IRFF-MPNN$', color='blue', marker='o', markerfacecolor='none', markeredgewidth=1, ms=5, alpha=0.8, linewidth=1, linestyle='-') plt.legend(loc='best', edgecolor='yellowgreen') plt.savefig('pv.pdf') plt.close()
def get_siesta_cart(self, label='siesta'): fin = open('in.fdf', 'r') lines = fin.readlines() fin.close() # getting informations from input file for i, line in enumerate(lines): l = line.split() if len(l) > 0: if l[0] == 'NumberOfSpecies': ns = int(l[1]) if l[0] == 'NumberOfAtoms': self.natom = int(l[1]) if l[0] == '%block': if l[1] == 'ChemicalSpeciesLabel': spl = i + 1 if l[1] == 'AtomicCoordinatesAndAtomicSpecies': atml = i + 1 sp = [] for isp in range(ns): l = lines[spl + isp].split() sp.append(l[2]) for na in range(self.natom): l = lines[atml + na].split() self.atom_name.append(sp[int(l[3]) - 1]) fe = open(label + '.MD_CAR', 'r') lines = fe.readlines() fe.close() nl = len(lines) if nl - (self.natom + 7) * self.nframe != 0: fra = (nl - (self.natom + 7) * self.nframe) / (self.natom + 7) print('- %d frames more than expected, error case ... ... ...' % fra) exit() lsp = lines[5].split() nsp = [int(l) for l in lsp] xs = [] if self.traj: his = TrajectoryWriter(self.structure + '.traj', mode='w') for nf in range(self.nframe): block = self.natom + 7 nl = block * nf la = lines[nl + 2].split() lb = lines[nl + 3].split() lc = lines[nl + 4].split() a = [float(la[0]), float(la[1]), float(la[2])] b = [float(lb[0]), float(lb[1]), float(lb[2])] c = [float(lc[0]), float(lc[1]), float(lc[2])] x = [] il = 0 for i, s in enumerate(nsp): for ns in range(s): l = lines[nl + 7 + il].split() xd = [float(l[0]), float(l[1]), float(l[2])] x1 = xd[0] * a[0] + xd[1] * b[0] + xd[2] * c[0] x2 = xd[0] * a[1] + xd[1] * b[1] + xd[2] * c[1] x3 = xd[0] * a[2] + xd[1] * b[2] + xd[2] * c[2] x.append([x1, x2, x3]) il += 1 xs.append(x) if self.traj: A = Atoms(self.atom_name, x, cell=[a, b, c], pbc=[True, True, True]) his.write(atoms=A) self.cell = np.array([a, b, c]) if self.traj: his.close() return xs
def cluster_GA( nPool, eleNames, eleNums, eleRadii, generations, calc, filename, log_file, CXPB=0.5, singleTypeCluster=False, use_dask=False, use_vasp=False, al_method=None, al_learner_params=None, train_config=None, optimizer=BFGS, use_vasp_inter=False, restart=False, gen_num=None, ): """ DEAP Implementation of the GIGA Geneting Algorithm for nanoclusters nPool : Total number of clusters present in the initial pool eleNames : List of element symbols present in the cluster eleNums : List of the number of atoms of each element present in the cluster eleRadii : List of radii of each element present in the cluster generations : Total number of generations to run the genetic algorithm calc : The calculator used to perform relaxations (must be an ase calculator object) filename : Name of the file to be used to generate ase traj and db files log_file : Name of the log file CXPB : probability of a crossover operation in a given generation singleTypeCluster : Default = False, set to True if only 1 element is present in cluster use_Dask : Default = False, set to True if using dask (Refer examples on using dask) use_vasp : Default = False, set to True if using inbuilt vasp optimizer to run GA code (not supported with active learning) al_method : Default = None, accepts values 'online' or 'offline' al_learner_params : Default = None, refer examples or https://github.com/ulissigroup/al_mlp for sample set up trainer_config : Default = None, refer examples or https://github.com/ulissigroup/al_mlp for sample set up optimizer : Default = BFGS, ase optimizer to be used use_vasp_inter : Default = False, whether to use vasp interactive mode or not """ def calculate(atoms): """ Support function to assign the type of minimization to e performed (pure vasp, using ase optimizer or using active learning) """ if al_method is not None: atoms_min, parent_calls = minimize_al( atoms, calc, eleNames, al_learner_params, train_config, dataset_parent, optimizer, al_method, ) else: if use_vasp == True: atoms_min = minimize_vasp(atoms, calc) else: atoms_min = minimize(atoms, calc, optimizer, use_vasp_inter) return atoms_min, parent_calls if al_method is not None: al_method = al_method.lower() # Creating DEAP types creator.create("FitnessMax", base.Fitness, weights=(1.0, )) creator.create("Individual", list, fitness=creator.FitnessMax) # Registration of the evolutionary tools in the toolbox toolbox = base.Toolbox() toolbox.register("poolfill", fillPool, eleNames, eleNums, eleRadii, calc) toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.poolfill, 1) toolbox.register("evaluate", fitness_func) toolbox.register("population", tools.initRepeat, list, toolbox.individual) # Registering mutations and crossover operators toolbox.register("mate", mate) toolbox.register("mutate_homotop", homotop) toolbox.register("mutate_rattle", rattle_mut) toolbox.register("mutate_rotate", rotate_mut) toolbox.register("mutate_twist", twist) toolbox.register("mutate_tunnel", tunnel) toolbox.register("mutate_partialinv", partialInversion) toolbox.register("mutate_skin", skin) toolbox.register("mutate_changecore", changeCore) # Registering selection operator toolbox.register("select", tools.selTournament) #Initialize the parent dataset dataset_parent = [] # Creating a list of cluster atom objects from population if not restart: population = toolbox.population(n=nPool) pop_list = [] for individual in population: pop_list.append(individual[0]) write('init_pop_before_relax.traj', pop_list) if use_dask == True: # distribute and run the calculations (requires dask and needs to be set up correctly) clus_bag = db.from_sequence(pop_list, partition_size=1) clus_bag_computed = clus_bag.map(calculate) lst_clus_min = clus_bag_computed.compute() else: lst_clus_min = list(map(calculate, pop_list)) for i, p in enumerate(population): p[0] = lst_clus_min[i][0] init_pop_list_after_relax = [] for individual in population: init_pop_list_after_relax.append(individual[0]) write('init_pop_after_relax.traj', init_pop_list_after_relax) with open(log_file, "a+") as fh: fh.write( f'Total clusters in the intital pool after relaxationi: {len(population)}' "\n") #parent_calls list if online learner total_parent_calls = [] parent_calls_initial_pool = [] for i in range(len(lst_clus_min)): parent_calls_initial_pool.append(lst_clus_min[i][1]) total_parent_calls.extend(parent_calls_initial_pool) with open(log_file, "a+") as fh: fh.write( f'parent calls after initial pool relaxation: {parent_calls_initial_pool}' '\n') fh.write( f'Total parent calls after initial pool relaxation: {sum(parent_calls_initial_pool)}' '\n') # Fitnesses (or Energy) values of the initial random population fitnesses = list(map(toolbox.evaluate, population)) for ind, fit in zip(population, fitnesses): ind.fitness.values = fit #Removing bad geometries population_filter = [] for i, p in enumerate(population): if checkBonded(p[0]) == True: if checkOverlap(p[0]) == False: population_filter.append(p) population = copy.deepcopy(population_filter) init_pop_list_after_filter = [] for individual in population: init_pop_list_after_filter.append(individual[0]) write('init_pop_after_filter.traj', init_pop_list_after_filter) with open(log_file, "a+") as fh: fh.write( f'Total clusters in the intital pool after filtering: {len(population)}' "\n") fitnesses_init_pool = list(map(toolbox.evaluate, population)) with open(log_file, "a+") as fh: fh.write("Energies (fitnesses) of the initial pool" "\n") for value in fitnesses_init_pool: fh.write("{} \n".format(value[0])) # Evolution of the Genetic Algorithm with open(log_file, "a+") as fh: fh.write("\n") fh.write("Starting Evolution" "\n") g = 0 # Generation counter init_pop_db = ase.db.connect("init_pop_{}.db".format(filename)) for cl in population: write_to_db(init_pop_db, cl[0]) bi = [] else: population = toolbox.population(n=nPool) restart_gen = 'best_n_clus_after_gen' + str(gen_num) + '.traj' restart_traj = Trajectory(restart_gen) for i, p in enumerate(population): p[0] = restart_traj[i] # Fitnesses (or Energy) values of the restart population from the gen_num fitnesses = list(map(toolbox.evaluate, population)) for ind, fit in zip(population, fitnesses): ind.fitness.values = fit fitnesses_restart_pool = list(map(toolbox.evaluate, population)) # Restarting the Evolution of the Genetic Algorithm from Restart Trajectory with open(log_file, "a+") as fh: fh.write("\n") fh.write("Restarting Evolution" "\n") fh.write("Energies (fitnesses) of the Restarted pool" "\n") for value in fitnesses_restart_pool: fh.write("{} \n".format(value[0])) fh.write("\n") g = gen_num # Generation counter -Restart gen number #parent_calls list if online learner total_parent_calls = [] bi = [] old_final_pop_db = "./final_pop_{}.db".format(filename) copy_final_pop_db = "final_pop_{}_{}.db".format(filename, gen_num) if os.path.exists(old_final_pop_db): subprocess.call( ['mv', old_final_pop_db, 'old_' + copy_final_pop_db]) ##### Evolution of Generations ###### while g < generations: mutType = None muttype_list = [] g = g + 1 with open(log_file, "a+") as fh: fh.write("{} {} \n".format("Generation", g)) cm_pop = [] if random.random() < CXPB: # Crossover Operation mutType = "crossover" with open(log_file, "a+") as fh: fh.write("{} {} \n".format("mutType", mutType)) # Crossover operation step. # The child clusters will be checked for bonding and similarity # between other child clusters. loop_count = 0 while ( loop_count != 200 ): # Perform 200 possible crossovers or until unique crossovers match pool size clusters = toolbox.select(population, 2, 1) muttype_list.append(mutType) parent1 = copy.deepcopy(clusters[0]) parent2 = copy.deepcopy(clusters[1]) fit1 = clusters[0].fitness.values (f1, ) = fit1 fit2 = clusters[1].fitness.values (f2, ) = fit2 child_clus = toolbox.mate(parent1[0], parent2[0], f1, f2) parent1[0] = child_clus diff_list = [] if checkBonded(parent1[0]) == True: if loop_count == 0: cm_pop.append(parent1) else: for c, cluster in enumerate(cm_pop): diff = checkSimilar(cluster[0], parent1[0]) diff_list.append(diff) if all(diff_list) == True: cm_pop.append(parent1) loop_count = loop_count + 1 if len(cm_pop) == nPool: break else: # Mutation Operation mutType = "mutations" with open(log_file, "a+") as fh: fh.write("{} {} \n".format("mutType", mutType)) # Mutation opeation step # Each cluster in the population will undergo a randomly chosen mutation step # Mutated new clusters will be checked for bonding and similarity with other new clusters for m, mut in enumerate(population): mutant = copy.deepcopy(mut) if singleTypeCluster: mutType = random.choice([ "rattle", "rotate", "twist", "partialinv", "tunnel", "skin", "changecore", ]) else: mutType = random.choice([ "rattle", "rotate", "homotop", "twist", "partialinv", "tunnel", "skin", "changecore", ]) muttype_list.append(mutType) if mutType == "homotop": mutant[0] = toolbox.mutate_homotop(mutant[0]) if mutType == "rattle": mutant[0] = toolbox.mutate_rattle(mutant[0]) if mutType == "rotate": mutant[0] = toolbox.mutate_rotate(mutant[0]) if mutType == "twist": mutant[0] = toolbox.mutate_twist(mutant[0]) if mutType == "tunnel": mutant[0] = toolbox.mutate_tunnel(mutant[0]) if mutType == "partialinv": mutant[0] = toolbox.mutate_partialinv(mutant[0]) if mutType == "skin": mutant[0] = toolbox.mutate_skin(mutant[0]) if mutType == "changecore": mutant[0] = toolbox.mutate_changecore(mutant[0]) diff_list = [] if checkBonded(mutant[0]) == True: for c, cluster in enumerate(cm_pop): diff = checkSimilar(cluster[0], mutant[0]) diff_list.append(diff) if all(diff_list) == True: cm_pop.append(mutant) with open(log_file, "a+") as fh: fh.write("{} {} \n".format("mutType_list", muttype_list)) mut_new_lst = [] for mut in cm_pop: mut_new_lst.append(mut[0]) write('mut_before_relax_gen' + str(g) + '.traj', mut_new_lst) # DASK Parallel relaxation of the crossover child/mutated clusters if use_dask == True: mut_bag = db.from_sequence(mut_new_lst, partition_size=1) mut_bag_computed = mut_bag.map(calculate) mut_new_lst_min = mut_bag_computed.compute() else: mut_new_lst_min = list(map(calculate, mut_new_lst)) for i, mm in enumerate(cm_pop): mm[0] = mut_new_lst_min[i][0] mut_list_after_relax = [] for individual in cm_pop: mut_list_after_relax.append(individual[0]) write('mut_after_relax_gen' + str(g) + '.traj', mut_list_after_relax) with open(log_file, "a+") as fh: fh.write( f'Total clusters relaxed in Generation {g}: {len(cm_pop)}' "\n") #parent calls list if online learner parent_calls_mut_list = [] for i in range(len(mut_new_lst_min)): parent_calls_mut_list.append(mut_new_lst_min[i][1]) total_parent_calls.extend(parent_calls_mut_list) with open(log_file, "a+") as fh: fh.write( f'Parent calls list after relaxtions in this generation: {parent_calls_mut_list} ' '\n') fh.write( f'Total Parent calls specific to this generation: {sum(parent_calls_mut_list)} ' '\n') fh.write( f'Total Parent calls up to this generation: {sum(total_parent_calls)} ' '\n') fitnesses_mut = list(map(toolbox.evaluate, cm_pop)) for ind, fit in zip(cm_pop, fitnesses_mut): ind.fitness.values = fit new_population = copy.deepcopy(population) # Relaxed clusters will be checked for bonded and similarity with the other # clusters in the population. If dissimilar, they will be added to the new population. for cm1, cmut1 in enumerate(cm_pop): new_diff_list = [] if checkBonded(cmut1[0]) == True: if checkOverlap(cmut1[0]) == False: for c2, cluster1 in enumerate(population): diff = checkSimilar(cluster1[0], cmut1[0]) new_diff_list.append(diff) if all(new_diff_list) == True: new_population.append(cmut1) else: pass mut_list_after_filter = [] for individual in new_population: mut_list_after_filter.append(individual[0]) write('mut_after_filter_gen' + str(g) + '.traj', mut_list_after_filter) with open(log_file, "a+") as fh: fh.write( f'Total clusters flitered out in Generation {g}: {len(cm_pop) + len(population) - len(new_population)}' "\n") fh.write( f'Total clusters in the pool after filtering in Generation {g}: {len(new_population)}' "\n") fitnesses_pool = list(map(toolbox.evaluate, new_population)) with open(log_file, "a+") as fh: fh.write( "Energies (fitnesses) of the present pool before best 10 are selected" "\n") for value in fitnesses_pool: fh.write("{} \n".format(value[0])) # Selecting the lowest energy npool clusters from the new_population len_new_pop = len(new_population) if len_new_pop > nPool: best_n_clus = tools.selWorst(new_population, nPool) else: best_n_clus = new_population best_n_clus_list = [] for individual in best_n_clus: best_n_clus_list.append(individual[0]) write('best_n_clus_after_gen' + str(g) + '.traj', best_n_clus_list) population = best_n_clus best_clus = tools.selWorst(population, 1)[0] with open(log_file, "a+") as fh: fh.write("{} {} \n".format("Lowest energy for this generation is", best_clus.fitness.values[0])) fh.write("\n Best cluster in this generation: \n") for atom in best_clus[0]: fh.write("{} {:12.8f} {:12.8f} {:12.8f} \n".format( atom.symbol, atom.x, atom.y, atom.z)) fh.write("\n") bi.append(best_clus[0]) if g == 1: writer = TrajectoryWriter(filename + "_best.traj", mode="w", atoms=best_clus[0]) writer.write() else: writer = TrajectoryWriter(filename + "_best.traj", mode="a", atoms=best_clus[0]) writer.write() final_pop_db = ase.db.connect("final_pop_{}.db".format(filename)) for clus in population: write_to_db(final_pop_db, clus[0]) with open(log_file, "a+") as fh: fh.write("Global Minimum after {} Generations \n".format(g)) for atom in best_clus[0]: fh.write("{} {:12.8f} {:12.8f} {:12.8f} \n".format( atom.symbol, atom.x, atom.y, atom.z)) # Return the list of best clusters in every generations and the overall best cluster return bi, best_clus[0]