def new_by_switch_atoms_on_substrate(ind_in: Individual): # returns individual made by switch of two random atoms on particular substrate struct = ind_in.get_relaxed_structure().copy() substrate = read_vasp("POSCAR.substrate") s = surface(substrate, (0, 0, 1), 1, vacuum=0., tol=1e-10) cell = s.get_cell() cell[2][2] = 25. s.set_cell(cell) z_max = -100. positions = s.get_positions() for pos in positions: z = pos[2] if z > z_max: z_max = z # print("z_max", z_max) chem_sym = struct.get_chemical_symbols() Nat = len(chem_sym) flag = 0 while flag == 0: indx1 = randrange(Nat) indx2 = randrange(Nat) z1 = struct.get_positions()[indx1][2] z2 = struct.get_positions()[indx2][2] # print(z1,z2) if indx2 != indx1 and chem_sym[indx1] != chem_sym[ indx2] and z1 > z_max and z2 > z_max: # print(indx1,indx2) chem_sym_new = swap_positions(chem_sym, indx1, indx2) struct.set_chemical_symbols(chem_sym_new) flag = 1 ind = Individual(struct, -1) return ind
def new_by_shift_coordinate(ind_in: Individual): # returns individual made by random change of one coordinate struct = ind_in.get_relaxed_structure().copy() Nat = len(struct.get_chemical_symbols()) positions = struct.get_scaled_positions() delta = uniform(-0.1, 0.1) indx_at = randrange(Nat) indx_coord = randrange(3) positions[indx_at][indx_coord] = positions[indx_at][indx_coord] + delta struct.set_scaled_positions(positions) ind = Individual(struct) return ind
def init_population_random_on_substrate(self): print("generating initial population on substrate randomly ...") population = [] i = 1 while i <= self.Npop: struct = random_structure_on_substrate(self.chem_form, self.amin, self.amax, self.dmin, self.model_file) individual = Individual(struct) individual.origin = "new ind. random on substrate from scratch" population.append(individual) i = i + 1 return population
def get_population_db(dbfile, ngen): population = [] conn = sqlite3.connect(dbfile) cur = conn.cursor() cur.execute("SELECT * FROM individuals WHERE ngen=?", [ngen]) rows = cur.fetchall() for row in rows: struct = pickle.loads(row[4]) ind = Individual(struct) population.append(ind) return population
def get_best_individual(population): e_tot_min = 0. for ind in population: try: e_tot = ind.e_tot struct = ind.get_relaxed_structure() except: e_tot = 1000. if e_tot < e_tot_min: struct_best = struct e_tot_min = e_tot print("e_tot_min: " + str(e_tot_min)) individual = Individual(struct_best) return individual
def new_by_switch_atoms(ind_in: Individual): # returns individual made by switch of two random atoms struct = ind_in.get_relaxed_structure().copy() chem_sym = struct.get_chemical_symbols() Nat = len(chem_sym) if Nat > 2: indx1 = randrange(Nat) flag = 0 while flag == 0: indx2 = randrange(Nat) if indx2 != indx1 and chem_sym[indx1] != chem_sym[indx2]: chem_sym_new = swap_positions(chem_sym, indx1, indx2) struct.set_chemical_symbols(chem_sym_new) flag = 1 ind = Individual(struct, -1) return ind
def new_by_shift_coordinates(ind_in: Individual): # returns individual made by random change of x,y coordinates by random delta struct = ind_in.get_relaxed_structure().copy() Nat = len(struct.get_chemical_symbols()) positions = struct.get_scaled_positions() delx = uniform(0., 0.2) dely = uniform(0., 0.2) indx1 = randrange(Nat) indx2 = indx1 while indx2 == indx1: indx2 = randrange(Nat) positions[indx1][0] = positions[indx1][0] + delx positions[indx1][1] = positions[indx1][1] + dely positions[indx2][0] = positions[indx2][0] - delx positions[indx2][1] = positions[indx2][1] - dely struct.set_scaled_positions(positions) ind = Individual(struct, -1) return ind
def init_population_random(self, model=1): # inits random population with model verification, returns list of individuals # verification regards "bad" struxtures print("generating initial population randomly ...") population = [] i = 1 while i <= self.Npop: if model == 0: struct = random_structure(self.chem_form, self.amin, self.amax, self.dmin) if model == 1: struct = random_structure_model(self.chem_form, self.amin, self.amax, self.dmin, self.model_file) individual = Individual(struct) individual.origin = "new ind. random from scratch" population.append(individual) i = i + 1 return population
def new_by_random_coordinates(ind_in: Individual): # returns individual made by changing all coordinates randomly (cell is intact) struct = ind_in.get_relaxed_structure().copy() Nat = len(struct.get_chemical_symbols()) flag = 0 while flag == 0: positions = [] # for i in range(Nat): pos = [uniform(0., 0.90), uniform(0., 0.90), uniform(-0.1, 0.1)] positions.append(pos) # struct.set_scaled_positions(positions) positions_ang = struct.get_positions() # print(positions_ang) flag = check_dist(Nat, positions_ang, dmin=1.4) # print(flag) # print(struct) ind = Individual(struct, -1) return ind
def init_population_random_group(self): # inits pyxtal random population with model verification, returns list of individuals print( "generating initial population randomly but using group theory ..." ) population = [] i = 1 while i <= self.Npop: struct = random_structure_group(self.chem_sym, self.stoichio, thickness=3.0, tol_factor=0.9, model_file=self.model_file, dmin=self.dmin, Natt=100) individual = Individual(struct) individual.origin = "new ind. random from scratch" population.append(individual) i = i + 1 return population
def get_c2db_prototypes(dbfile, prototype, stability=False, smagstate=False, sgap=0): # returns list of Individuals from c2db # Connect to the database - ase interface db = ase.db.connect(dbfile) # Connect to the database - sqlite3 interface conn = sqlite3.connect(dbfile) cur = conn.cursor() cur.execute('SELECT SQLITE_VERSION()') data = cur.fetchone() print("SQLite version: " + str(format(data))) # nstruct = 0 # magstate = 'FM' dyn_key = 'dynamic_stability_level' th_key = 'thermodynamic_stability_level' # gap_key = 'gap' # rows = db.select('magstate=FM') if prototype != "": query = 'class=' + prototype # print(query) rows = db.select(query) if prototype == "": # rows = db.select('calculator=gpaw') rows = db.select('gap>-1') print(rows) individuals = [] for row in rows: id = row.get("id") e_tot = row.get("energy") label = row.get('formula') gap = row.get('gap') #print(gap) magstate = row.get('magstate') magmom = row.get('magmom') positions = row.get('positions') cell = row.get('cell') hform = row.get('hform') e_tot = row.get('energy') # Stability info - not implemented is ase interface cur.execute( "SELECT * FROM number_key_values WHERE id=:id AND key=:dyn_key", { "id": id, "dyn_key": dyn_key }) data = cur.fetchone() if data is not None: stability_dyn = data[1] else: stability_dyn = 0. cur.execute( "SELECT * FROM number_key_values WHERE id=:id AND key=:th_key", { "id": id, "th_key": th_key }) data = cur.fetchone() if data is not None: stability_th = data[1] else: stability_th = 0. if stability == False: struct_ase = Atoms(label, positions=positions, cell=cell, pbc=np.array([True, True, True], dtype=bool)) Nat = len(struct_ase.get_chemical_symbols()) ind = Individual(struct_ase) ind.set_e_tot(e_tot / float(Nat)) ind.set_mmtot(magmom) ind.set_hform(hform) individuals.append(ind) if stability == True and smagstate == False and sgap == 0: if stability_th == 3.0: struct_ase = Atoms(label, positions=positions, cell=cell, pbc=np.array([True, True, True], dtype=bool)) Nat = len(struct_ase.get_chemical_symbols()) ind = Individual(struct_ase) ind.set_e_tot(e_tot / float(Nat)) ind.set_mmtot(magmom) ind.set_hform(hform) individuals.append(ind) if stability == True and smagstate == False and sgap > 0: if stability_th == 3.0 and gap > 0.: struct_ase = Atoms(label, positions=positions, cell=cell, pbc=np.array([True, True, True], dtype=bool)) Nat = len(struct_ase.get_chemical_symbols()) ind = Individual(struct_ase) ind.set_e_tot(e_tot / float(Nat)) ind.set_mmtot(magmom) ind.set_hform(hform) individuals.append(ind) if stability == True and smagstate == True and smagstate == "FM": if stability_dyn == 3.0 and stability_th == 3.0 and abs( float(magmom)) > 0.1: struct_ase = Atoms(label, positions=positions, cell=cell, pbc=np.array([True, True, True], dtype=bool)) Nat = len(struct_ase.get_chemical_symbols()) ind = Individual(struct_ase) ind.set_e_tot(e_tot / float(Nat)) ind.set_mmtot(magmom) ind.set_hform(hform) individuals.append(ind) return individuals
def new_by_switch_layers(ind_in: Individual): # returns individual made by switch of two random layers struct = ind_in.get_relaxed_structure().copy() write(filename="POSCAR.in.in", images=struct, format="espresso-in") layers = get_layers(struct) nlay = len(layers) if nlay > 1: # random indexes indx1 = randrange(nlay) flag = 0 while flag == 0: indx2 = randrange(nlay) if indx2 != indx1: flag = 1 layer1 = layers[indx1] layer2 = layers[indx2] print("switching layers " + str(indx1 + 1) + " and " + str(indx2 + 1)) pos = struct.get_positions() chem = struct.get_chemical_symbols() cell = struct.get_cell() new_pos = [] new_chem = [] # 1 - setting all other atoms n = len(chem) for i in range(n): if i not in layer1 and i not in layer2: # print(i) new_pos.append(pos[i]) new_chem.append(chem[i]) # 2 - calculate shift between layers z1 = [] z2 = [] for i in layer1: z = pos[i][2] z1.append(z) for i in layer2: z = pos[i][2] z2.append(z) min1 = max(z1) min2 = max(z2) zshift = min1 - min2 # 3 - setting layer1 and layer2 atoms with shift for i in range(n): if i in layer1: # print(i) if min1 > min2: pos[i][2] = pos[i][2] + zshift if min1 < min2: pos[i][2] = pos[i][2] - zshift new_pos.append(pos[i]) new_chem.append(chem[i]) if i in layer2: # print(i) if min1 > min2: pos[i][2] = pos[i][2] - zshift if min1 < min2: pos[i][2] = pos[i][2] + zshift new_pos.append(pos[i]) new_chem.append(chem[i]) st = "" for chem in new_chem: st = st + chem new_struct = Atoms(st) new_struct.set_cell(cell) new_pos2 = np.asarray(new_pos) new_struct.set_positions(new_pos2) ind = Individual(new_struct) write(filename="POSCAR.out.in", images=new_struct, format="espresso-in") else: ind = Individual(struct) print("warning: only one layer, no change in structure!") return ind
def generate_new_population_alg2_substrate(self, population): # generates new population using algorithm no. 2 print("") print("generating new population with softmutation ...") print("") new_population = [] population.sort() Npop = self.Npop adapt = AseAtomsAdaptor() model = MEGNetModel.from_file(self.model_file) for i in range(int(Npop / 4)): # 1/4 of population by atoms switch indx = randrange(Npop / 4) # +1 # using only best 25% of population print("-------------------------------") print("new ind. from no. " + str(indx) + " by atoms switch") individual = new_by_switch_atoms_on_substrate(population[indx]) individual.origin = "new ind. from no. " + str( indx) + " by atoms switch" new_population.append(individual) for i in range(int(Npop / 4)): # 1/4 of population by kind of softmutation indx = randrange(Npop / 4) # +1 # using only best 25% of population print("-------------------------------") print("new ind. from no. " + str(indx) + " by softmutation") ind_in = population[indx] structure_ase = ind_in.get_relaxed_structure().copy() structure_pymatgen = adapt.get_structure(structure_ase) e_tot_in = model.predict_structure(structure_pymatgen) e_tot_min = e_tot_in flag = 0 for i in range(100): individual = new_by_shift_coordinate(population[indx]) structure_ase = individual.get_init_structure().copy() structure_pymatgen = adapt.get_structure(structure_ase) try: e_tot = model.predict_structure(structure_pymatgen) except: e_tot = 0. print("isolated molecule exception handled") if e_tot < e_tot_min: flag = 1 e_tot_min = e_tot ind_out = individual ind_out.origin = "new ind. from no. " + str( indx) + " by softmutation" if flag == 1: new_population.append(ind_out) print("softmutate energy gain: " + str(e_tot_min - e_tot_in)) if flag == 0: new_population.append(ind_in) for i in range(int((Npop / 2) - 1)): # 1/2 of population (minus one) by new random structures, pyxtal+model # indx = randrange(Npop/2)+1 print("-------------------------------") print("new ind. random from scratch") struct = random_structure_group(self.chem_sym, self.stoichio, thickness=3.0, tol_factor=0.9, model_file=self.model_file, dmin=self.dmin, Natt=RANDOM_ATTEMPTS) individual = Individual(struct) individual.origin = "new ind. random from scratch" new_population.append(individual) best_ind = get_best_individual( population) # last one is the best in the current population best_ind.origin = "kept best" new_population.append(best_ind) return new_population