11# from mace.calculators import mace_mp
22# from ase.calculators.vasp import Vasp
33from chgnet .model import CHGNetCalculator
4+ from ase .calculators .singlepoint import SinglePointCalculator
45from raffle .generator import raffle_generator
56from ase import build , Atoms
6- from ase .optimize import BFGS , FIRE
7+ from ase .optimize import FIRE
78from ase .io import write
89from ase .visualize import view
910import numpy as np
@@ -31,17 +32,10 @@ def runInParallel(*fns):
3132 print (results )
3233
3334
34- def process_structure_with_queue (i , structure , num_old , calc_params , optimise_structure , iteration , queue ):
35- # Perform the computation
36- result = process_structure (i , structure , num_old , calc_params , optimise_structure , iteration )
37- queue .put (result ) # Report completion
38-
39- def process_structure (i , atoms , num_structures_old , calc_params , optimise_structure , iteration ):
40- if i < num_structures_old :
41- return
35+ def process_structure (i , atoms , calc_params , optimise_structure , calc ):
36+ # Check if the structure has already been processed
4237
4338 # calc = Vasp(**calc_params, label=f"struct{i}", directory=f"iteration{iteration}/struct{i}/", txt=f"stdout{i}.o")
44- inew = i - num_structures_old
4539 atoms .calc = calc
4640 # positions_initial = atoms.get_positions()
4741
@@ -51,7 +45,7 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
5145
5246 # Optimise the structure if requested
5347 if optimise_structure :
54- optimizer = FIRE (atoms , trajectory = f"traje{ inew } .traj" , logfile = f"optimisation{ inew } .log" )
48+ optimizer = FIRE (atoms , trajectory = f"traje{ i } .traj" , logfile = f"optimisation{ i } .log" )
5549 try :
5650 optimizer .run (fmax = 0.05 , steps = 100 )
5751 except Exception as e :
@@ -72,7 +66,7 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
7266 print (f"Distance too small: { atoms .get_all_distances (mic = True ).min ()} " )
7367 return None , None , None
7468
75- if abs (energy_rlxd - energy_unrlxd ) > 10 .0 :
69+ if abs (energy_rlxd - energy_unrlxd ) > 5 .0 :
7670 print (f"Energy difference too large: { energy_rlxd } vs { energy_unrlxd } " )
7771 return None , None , None
7872
@@ -137,9 +131,17 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
137131 """
138132 #void_val; rand_val; walk_val; grow_val; min_val
139133 ##############[ V, R, W, G, M]
140- method_val = [85.0 , 15.0 , 0.0 , 0.0 , 0.0 ] #change
141-
142-
134+ method_dicts = [
135+ {"void" : 1.0 , "rand" : 0.0 , "walk" : 0.0 , "grow" : 0.0 , "min" : 0.0 },
136+ {"void" : 0.0 , "rand" : 1.0 , "walk" : 0.0 , "grow" : 0.0 , "min" : 0.0 },
137+ {"void" : 0.0 , "rand" : 0.0 , "walk" : 1.0 , "grow" : 0.0 , "min" : 0.0 },
138+ {"void" : 0.0 , "rand" : 0.0 , "walk" : 0.0 , "grow" : 1.0 , "min" : 0.0 },
139+ {"void" : 0.0 , "rand" : 0.0 , "walk" : 0.0 , "grow" : 0.0 , "min" : 1.0 },
140+ {"void" : 85.0 , "rand" : 15.0 , "walk" : 0.0 , "grow" : 0.0 , "min" : 0.0 },
141+ {"void" : 0.0 , "rand" : 15.0 , "walk" : 85.0 , "grow" : 0.0 , "min" : 0.0 },
142+ {"void" : 0.0 , "rand" : 15.0 , "walk" : 0.0 , "grow" : 85.0 , "min" : 0.0 },
143+ {"void" : 0.0 , "rand" : 15.0 , "walk" : 0.0 , "grow" : 0.0 , "min" : 85.0 },
144+ ]
143145
144146 hosts = []
145147 for crystal_structure in crystal_structures :
@@ -166,8 +168,26 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
166168 density = 1.61 # u/A^3
167169 # num_atoms = 7
168170
169- for seed in range (1 ):
170- print (f"Seed: { seed } " )
171+ # get the current directory
172+ cwd = os .getcwd ()
173+ print (f"Current working directory: { cwd } " )
174+
175+ seed = 0
176+ for methods in method_dicts :
177+ # move to the cwd
178+ os .chdir (cwd )
179+ print (f"Changed directory to { cwd } " )
180+
181+ # print the methods
182+ print (f"Method: { methods } " )
183+
184+ # make method directory
185+ method_dir = f"method_v{ methods ['void' ]} _r{ methods ['rand' ]} _w{ methods ['walk' ]} _g{ methods ['grow' ]} _m{ methods ['min' ]} /"
186+ if not os .path .exists (method_dir ):
187+ os .makedirs (method_dir )
188+ os .chdir (method_dir )
189+ print (f"Changed directory to { method_dir } " )
190+
171191 energies_rlxd_filename = f"energies_rlxd_seed{ seed } .txt"
172192 energies_unrlxd_filename = f"energies_unrlxd_seed{ seed } .txt"
173193 generator = raffle_generator ()
@@ -198,11 +218,17 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
198218 else :
199219 open (energies_unrlxd_filename , "w" ).close ()
200220
221+ # delete .traj files if they exist
222+ if os .path .exists (f"unrlxd_structures_seed{ seed } .xyz" ):
223+ os .remove (f"unrlxd_structures_seed{ seed } .xyz" )
224+ if os .path .exists (f"rlxd_structures_seed{ seed } .xyz" ):
225+ os .remove (f"rlxd_structures_seed{ seed } .xyz" )
201226
202- num_structures_old = 0
227+ num_structures_tot = 0
203228 unrlxd_structures = []
204229 rlxd_structures = []
205- iter2 = 0
230+ iter2 = - 1
231+ generator .init_seed (put = seed )
206232 for iter in range (10 ):
207233 for host in hosts :
208234 generator .set_host (host )
@@ -215,17 +241,16 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
215241 print (f"Volume: { volume } " )
216242 print (f"Number of atoms: { num_atoms } " )
217243
218- generator .generate (
244+ generated_structures = generator .generate (
219245 num_structures = 5 ,
220246 stoichiometry = { 'Al' : num_atoms },
221- seed = seed * 1000 + iter ,
222- method_ratio = {"void" : method_val [0 ], "rand" : method_val [1 ], "walk" : method_val [2 ], "grow" : method_val [3 ], "min" : method_val [4 ]},
247+ method_ratio = methods ,
223248 verbose = 0 ,
249+ calc = calc ,
224250 )
225251
226252 # print the number of structures generated
227253 print ("Total number of structures generated: " , generator .num_structures )
228- generated_structures = generator .get_structures (calc )
229254 num_structures_new = len (generated_structures )
230255
231256 # check if directory iteration[iter] exists, if not create it
@@ -235,51 +260,63 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
235260 generator .print_settings (iterdir + "generator_settings.txt" )
236261
237262 # set up list of energies
238- energy_unrlxd = np .zeros (num_structures_new - num_structures_old )
239- energy_rlxd = np .zeros (num_structures_new - num_structures_old )
240- for i in range (num_structures_new - num_structures_old ):
241- write (iterdir + f"POSCAR_unrlxd_{ i } " , generated_structures [num_structures_old + i ])
242- print (f"Structure { i } energy per atom: { generated_structures [num_structures_old + i ].get_potential_energy () / len (generated_structures [num_structures_old + i ])} " )
243- unrlxd_structures .append (deepcopy (generated_structures [num_structures_old + i ]))
244-
263+ for i in reversed (range (len (generated_structures ))):
264+ if generated_structures [i ] is None :
265+ print (f"Structure { i } is None, skipping" )
266+ del generated_structures [i ]
267+ continue
268+ write (iterdir + f"POSCAR_unrlxd_{ i } " , generated_structures [i ])
269+ print (f"Structure { i } energy per atom: { generated_structures [i ].get_potential_energy () / len (generated_structures [i ])} " )
270+
271+
245272 # Start parallel execution
246273 print ("Starting parallel execution" )
247274 results = Parallel (n_jobs = 5 )(
248- delayed (process_structure )(i , deepcopy ( generated_structures [i ]), num_structures_old , calc_params , optimise_structure , iteration = seed )
249- for i in range (num_structures_old , num_structures_new )
275+ delayed (process_structure )(i , generated_structures [i ]. copy ( ), calc_params , optimise_structure , calc = calc )
276+ for i in range (len ( generated_structures ) )
250277 )
251278
252279 # Wait for all futures to complete
280+ energies_unrlxd = []
281+ energies_rlxd = []
253282 for j , result in enumerate (results ):
254- generated_structures [j + num_structures_old ], energy_unrlxd [j ], energy_rlxd [j ] = result
255- rlxd_structures .append (deepcopy (generated_structures [j + num_structures_old ]))
283+ rlxd_generated_structure , energy_unrlxd , energy_rlxd = result
284+ if rlxd_generated_structure is None :
285+ print ("Structure failed the checks" )
286+ continue
287+ else :
288+ unrlxd_structures .append (generated_structures [j ].copy ())
289+ unrlxd_structures [- 1 ].calc = SinglePointCalculator (
290+ generated_structures [j ],
291+ energy = generated_structures [j ].get_potential_energy (),
292+ forces = generated_structures [j ].get_forces ()
293+ )
294+ rlxd_structures .append (rlxd_generated_structure .copy ())
295+ rlxd_structures [- 1 ].calc = SinglePointCalculator (
296+ rlxd_generated_structure ,
297+ energy = rlxd_generated_structure .get_potential_energy (),
298+ forces = rlxd_generated_structure .get_forces ()
299+ )
300+ energies_unrlxd .append (energy_unrlxd )
301+ energies_rlxd .append (energy_rlxd )
256302 print ("All futures completed" )
303+ num_structures_new = len (energies_unrlxd )
257304
258- # Remove structures that failed the checks
259- for j , atoms in reversed (list (enumerate (generated_structures ))):
260- if atoms is None :
261- energy_unrlxd = np .delete (energy_unrlxd , j - num_structures_old )
262- energy_rlxd = np .delete (energy_rlxd , j - num_structures_old )
263- del generated_structures [j ]
264- # del unrlxd_structures[j]
265- del rlxd_structures [j ]
266- generator .remove_structure (j )
267- num_structures_new = len (generated_structures )
268305
269306 # write the structures to files
270- for i in range (num_structures_new - num_structures_old ):
271- write (iterdir + f"POSCAR_{ i } " , generated_structures [ num_structures_old + i ])
272- print (f"Structure { i } energy per atom: { energy_rlxd [i ]} " )
307+ for i in range (num_structures_new ):
308+ write (iterdir + f"POSCAR_{ i } " , rlxd_structures [ num_structures_tot + i ])
309+ print (f"Structure { i } energy per atom: { energies_rlxd [i ]} " )
273310 # append energy per atom to the 'energies_unrlxd_filename' file
274311 with open (energies_unrlxd_filename , "a" ) as energy_file :
275- energy_file .write (f"{ i + num_structures_old } { energy_unrlxd [i ]} \n " )
312+ energy_file .write (f"{ i + num_structures_tot } { energies_unrlxd [i ]} \n " )
276313 # append energy per atom to the 'energies_rlxd_filename' file
277314 with open (energies_rlxd_filename , "a" ) as energy_file :
278- energy_file .write (f"{ i + num_structures_old } { energy_rlxd [i ]} \n " )
315+ energy_file .write (f"{ i + num_structures_tot } { energies_rlxd [i ]} \n " )
279316
280317 # update the distribution functions
281318 print ("Updating distributions" )
282- generator .distributions .update (generated_structures [ num_structures_old :], from_host = False , deallocate_systems = False )
319+ generator .distributions .update (rlxd_structures [ num_structures_tot :], from_host = False , deallocate_systems = False )
283320
284321 # print the new distribution functions to a file
285322 print ("Printing distributions" )
@@ -289,8 +326,12 @@ def process_structure(i, atoms, num_structures_old, calc_params, optimise_struct
289326 generator .distributions .write_4body (iterdir + "df4.txt" )
290327 generator .distributions .deallocate_systems ()
291328
329+ write (f"unrlxd_structures_seed{ seed } .xyz" , unrlxd_structures [num_structures_tot :], append = True )
330+ write (f"rlxd_structures_seed{ seed } .xyz" , rlxd_structures [num_structures_tot :], append = True )
331+
292332 # update the number of structures generated
293- num_structures_old = num_structures_new
333+ num_structures_tot += num_structures_new
334+
294335
295336 generator .distributions .write_gdfs (f"gdfs_seed{ seed } .txt" )
296337
0 commit comments