def access_geometry(self, t, p=None, s=None, f=None): """ Access the equilibrium geometry of the corresponding configuration. Parameters: ---------- - t (float): Temperature (compulsory) - p (array): Pressure (optional) - s (array): Strain (optional) - f (array): Electric Field (optional) Return: ---------- - A Geometry object for the corresponding configuration. """ # folder and file naming folder, sim_name = self.get_location(t, p, s, f) reference_file = os.path.join(folder, sim_name + "_FINAL.REF") restart_file = os.path.join(folder, sim_name + "_EQUILIBRIUM.restart") geo = Geometry(self.supercell, self.model["species"], self.model["nats"]) geo.load_reference(reference_file) geo.load_restart(restart_file) return geo
sim = MCSimulation() sim.setup("srtio3", "srtio3_full_lat.xml", SUPERCELL, SPECIES, NATS, temp=TEMPERATURES, strain=STRAINS, stress=STRESSES, field=FIELDS, output_folder="output") A, B, Ox, Oy, Oz = LABELS # create an example starting geometry start_geom = Geometry(SUPERCELL, SPECIES, NATS) for x in range(SUPERCELL[0]): for y in range(SUPERCELL[1]): for z in range(SUPERCELL[2]): start_geom.displacements[x, y, z, B, :] = [0., 0., 0.2] # test independent simulation run sim.change_output_folder("independent_output") sim.independent_launch(start_geo=start_geom) # test sequential simulation run sim.change_output_folder("sequential_output") sim.sequential_launch_by_temperature(start_geo=start_geom) # test sequential simulation run (reverse order)
(0, 1, 2, 3, 4, 5, 6, 7, 8), # z axis rotation # octahedral deformations (1, 2, 4, 5), # x axis only (0, 2, 3, 5), # y axis only (0, 1, 3, 4), # z axis only ] run = False # run the hessian calculation? (LONG) pretty = True # print the pretty vectors or the original ones ortho_check = False # print orthogonality check # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # ~~~~~~~~~~~~~~~~~~~~~~~ code starts here ~~~~~~~~~~~~~~~~~~~~~~~~ # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # geo = Geometry(SUPERCELL, SPECIES, NATS) # calculate or load the hessian if run == True: hessian = finite_hessian("srtio3_full_lat.xml", geo, MASSES) with open("hessian.pickle", "wb") as f: pickle.dump(hessian, f) else: with open("hessian.pickle", "rb") as f: hessian = pickle.load(f) # create mass matrix M = [] for m in MASSES: for _ in range(3): M.append(m)
def sequential_launch_by_temperature(self, start_geo=None, inverse_order=False): """ Simulation run where the equilibrium geometry of the simulation for the previous temperature is used as starting geometry of the next one. Parameters: ---------- - start_geo (RestartGenerator): starting geometry of the first temperature. """ # check if setup() has been run if self.SETUP != True: raise ezSCUP.exceptions.MissingSetup( "Run MCSimulation.setup() before launching any simulation.") # check if somulation has already been carried out if self.DONE == True: return 0 print("\n ~ Sequential simulation run by temperature engaged. ~ ") # checks restart file matches loaded geometry if start_geo != None and isinstance(start_geo, Geometry): print("\nApplying starting geometry...") if not np.all(self.generator.supercell == start_geo.supercell): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.nats != None and (start_geo.nats != self.model["nats"]): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.species != None and (set( self.model["species"]) != set(self.model["species"])): raise ezSCUP.exceptions.GeometryNotMatching() # get a copy of the model file copy(self.model["file"], "param_file.xml") # parser to get equilibrium geometry parser = MCSimulationParser(output_folder=self.output_folder) # adjust temperature ordering if inverse_order: temp_sequence = list(reversed(list(self.temp))) else: temp_sequence = list(self.temp) # simulation counters total_counter = 0 # total number of simulations nsims = self.temp.size * len(self.strain) * len(self.field) * len( self.stress) # starting time of the simulation process main_start_time = time.time() print("\nStarting calculations...\n") for p in self.stress: stress_counter = [np.array_equal(p, x) for x in self.stress].index(True) for s in self.strain: strain_counter = [np.array_equal(s, x) for x in self.strain].index(True) for f in self.field: field_counter = [np.array_equal(f, x) for x in self.field].index(True) # set starting geometry if start_geo != None and isinstance(start_geo, Geometry): self.generator.displacements = start_geo.displacements tcount = 0 for t in temp_sequence: temp_counter = np.where(self.temp == t)[0][0] # update simulation counter total_counter += 1 tcount += 1 # starting time of the current configuration conf_start_time = time.time() print("##############################") print("Configuration " + str(total_counter) + " out of " + str(nsims)) print("Temperature:", str(t), "K") print("Stress:", str(p), "GPa") print("Strain:", str(s), r"% change") print("Electric Field:", str(f), "V/m") print("##############################") # file base name sim_name = self.name + "T{:d}".format(int(t)) self.sim.settings["system_name"].value = sim_name # configuration name conf_name = "c{:02d}{:02d}{:02d}{:02d}".format( temp_counter, stress_counter, strain_counter, field_counter) # subfolder name subfolder_name = self.name + "." + conf_name # modify target temperature self.sim.settings["mc_temperature"].value = t if self.stress != None: # modify target stress, if needed self.sim.settings["external_stress"] = [p] if self.strain != None: # set target strain, if needed self.generator.strains = s if self.field != None: # modify target field, if needed self.sim.settings["static_electric_field"] = [f] # define human output filename output = sim_name + ".out" # create restart file self.sim.settings["geometry_restart"] = FDFSetting( sim_name + ".restart") self.generator.write_restart(sim_name + ".restart") # simulate the current configuration self.sim.launch(output_file=output) # move all the output to its corresponding folder configuration_folder = os.path.join( self.main_output_folder, subfolder_name) os.makedirs(configuration_folder) files = os.listdir(self.current_path) for fi in files: if sim_name in fi: move(fi, configuration_folder) # finish time of the current conf conf_finish_time = time.time() conf_time = conf_finish_time - conf_start_time print( "\nConfiguration finished! (time elapsed: {:.3f}s)" .format(conf_time)) # calculate equilibrium geometry print("Calculating equilibrium geometry...") partials = parser.find_partials( t, p=p, s=s, f=f, min_step=self.mc_equilibration_steps) aux_geo = Geometry(self.supercell, self.model["species"], self.model["nats"]) aux_geo.load_equilibrium_displacements(partials) aux_geo.write_restart( os.path.join(configuration_folder, sim_name + "_EQUILIBRIUM.restart")) # grab final geometry for next run if needed if tcount < len(temp_sequence): geo = parser.access_geometry(t, p=p, s=s, f=f) self.generator.displacements = geo.displacements print("All files stored in output/" + subfolder_name + " succesfully.\n") # remove the copy of the model os.remove("param_file.xml") self.generator.reset_geom() main_finished_time = time.time() main_time = main_finished_time - main_start_time print("Simulation process complete!") print("Total simulation time: {:.3f}s".format(main_time))
def setup(self, system_name, model, supercell, temp, stress=None, strain=None, field=None, output_folder="output"): # TODO PARAMETER FILE, SPECIES, NATS """ Sets up everything Parameters: ---------- - fdf (string): common fdf base file for all simulations. - temp (list): list of temperatures, required. - stress (list): list of stress vectors, if needed. - strain (list): list of strain vectors, if needed. - field (list): list of field vectors, if needed. """ # first and foremost, check if a valid # ScaleUP executable has been configured. if cfg.SCUP_EXEC == None or not os.path.exists(cfg.SCUP_EXEC): print(""" WARNING: No valid executable detected A path for a valid ScaleUP executable must be provided before any simulations are carried out. In order to do this, include the lines import ezSCUP.settings as cfg cfg.SCUP_EXEC=[path_to_exec] at the beginning of your script. """) raise ezSCUP.exceptions.NoSCUPExecutableDetected self.name = system_name self.model = model self.supercell = supercell self.sim = MC_SCUPHandler(self.name, "param_file.xml", cfg.SCUP_EXEC) self.output_folder = output_folder # current output folder self.temp = np.array(temp) # temperature vector, required if stress == None: # stress vector, optional self.stress = [np.zeros(6)] else: self.stress = [np.array(p, dtype=np.float64) for p in stress] if strain == None: # strain vector list, optional self.strain = [np.zeros(6)] else: self.strain = [np.array(s, dtype=np.float64) for s in strain] if field == None: # electric field vector list, optional self.field = [np.zeros(3)] else: self.field = [np.array(f, dtype=np.float64) for f in field] # get the current path self.current_path = os.getcwd() # create output directory try: self.main_output_folder = os.path.join(self.current_path, self.output_folder) os.makedirs(self.main_output_folder) self.DONE = False except FileExistsError: # check whether directory already exists if cfg.OVERWRITE: print(""" Found already existing output folder named "{}", all its contents are now lost. Reason: OVERWRITE set to True.""".format(self.output_folder)) rmtree(self.main_output_folder) os.makedirs(self.main_output_folder) self.DONE = False print("") pass else: print(""" Found already existing output folder named "{}", skipping simulation process. Reason: OVERWRITE set to False.""".format(self.output_folder)) self.SETUP = True self.DONE = True return 0 # adjust the supercell as needed self.sim.settings["supercell"] = [list(self.supercell)] # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # record current settings from ezSCUP.settings # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # self.mc_steps = int(cfg.MC_STEPS) self.mc_step_interval = int(cfg.MC_STEP_INTERVAL) self.mc_equilibration_steps = int(cfg.MC_EQUILIBRATION_STEPS) self.mc_max_jump = float(cfg.MC_MAX_JUMP) self.lat_output_interval = int(cfg.LATTICE_OUTPUT_INTERVAL) self.fixed_strain_components = cfg.FIXED_STRAIN_COMPONENTS self.mc_annealing_rate = cfg.MC_ANNEALING_RATE # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # setup restart file generator self.generator = Geometry(self.supercell, model["species"], model["nats"]) # print common simulation settings if cfg.PRINT_CONF_SETTINGS: print("Starting FDF settings:") self.sim.print() print("") # save simulation setup file print("Saving simulation setup file... ") setup = { "name": self.name, "model": self.model, "supercell": self.supercell, "temp": self.temp, "strain": self.strain, "stress": self.stress, "field": self.field, "mc_steps": self.mc_steps, "mc_step_interval": self.mc_step_interval, "mc_equilibration_steps": self.mc_equilibration_steps, "mc_annealing_rate": self.mc_annealing_rate, "mc_max_jump": self.mc_max_jump, "lat_output_interval": self.lat_output_interval, "fixed_strain_components": self.fixed_strain_components, } simulation_setup_file = os.path.join(self.main_output_folder, cfg.SIMULATION_SETUP_FILE) with open(simulation_setup_file, "wb") as f: pickle.dump(setup, f) print("\nSimulation run has been properly configured.") print("You may now proceed to launch it.") self.SETUP = True # simulation run setup nicely pass
class MCSimulation: """ Executes Monte Carlo simulations with the given parameters. # BASIC USAGE # Creates an output folder in the current directory. All the simulation data for each configuration is conveniently stored in subfolders within it: output / [scale-up system_name].c[n] where n is the configuration number. That is, an 8 digit integer that specifies the index for each parameter in the given simulation, with two digits each in the following order: n = [temp][stress][strain][field] for example, in a simulation with temp=[20,40,60,80] all confs simulated at 40K will be stored in folders named output / [scale-up system_name].c01****** and so on. The information about the parameters for the simulation run is stored in the file: output / simulation.info # formated as a pickle file In order to access all the simulation output for any given configuration, refer to the class MCSimulationParser in this same module. # SIMULATION PARAMETER SPECIFICATION # - Temperature (temp): List of temperatures, in K i.e:temp = np.linspace(20,100,5) temp = [27, 45, 36] - External Stress (stress): List of stress vectors in Voigt notation, in GPa i.e:stress = [ [10., 0., 0., 0., 0., 0.], [0., 10., 0., 0., 0., 0.], [0., 0., 10., 0., 0., 0.] ] # 10 GPa strains in each direction - Strains (strain): List of strain vectors in Voigt notation, in percentual change i.e:strain = [ [+0.02, +0.02, 0., 0., 0., 0.], [+0.00, +0.00, 0., 0., 0., 0.], [-0.02, -0.02, 0., 0., 0., 0.] ] # +-2% and 0% cell strain in the x and y direction - Static Electric Field (field): List of electric field vectors, in V/m i.e:field = [ [1e9, 0., 0.] ] # 1e9 V/m = 1V/nm in the x direction Attributes: ---------- - fdf (string): base fdf file name - name (string): default fdf's system_name - temp (array): temperature vectors (K) - stress (array): stress vectors (Gpa) - strain (array): strain vectors (% change) - field (array): electric field vectors (V/m) """ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # def setup(self, system_name, model, supercell, temp, stress=None, strain=None, field=None, output_folder="output"): # TODO PARAMETER FILE, SPECIES, NATS """ Sets up everything Parameters: ---------- - fdf (string): common fdf base file for all simulations. - temp (list): list of temperatures, required. - stress (list): list of stress vectors, if needed. - strain (list): list of strain vectors, if needed. - field (list): list of field vectors, if needed. """ # first and foremost, check if a valid # ScaleUP executable has been configured. if cfg.SCUP_EXEC == None or not os.path.exists(cfg.SCUP_EXEC): print(""" WARNING: No valid executable detected A path for a valid ScaleUP executable must be provided before any simulations are carried out. In order to do this, include the lines import ezSCUP.settings as cfg cfg.SCUP_EXEC=[path_to_exec] at the beginning of your script. """) raise ezSCUP.exceptions.NoSCUPExecutableDetected self.name = system_name self.model = model self.supercell = supercell self.sim = MC_SCUPHandler(self.name, "param_file.xml", cfg.SCUP_EXEC) self.output_folder = output_folder # current output folder self.temp = np.array(temp) # temperature vector, required if stress == None: # stress vector, optional self.stress = [np.zeros(6)] else: self.stress = [np.array(p, dtype=np.float64) for p in stress] if strain == None: # strain vector list, optional self.strain = [np.zeros(6)] else: self.strain = [np.array(s, dtype=np.float64) for s in strain] if field == None: # electric field vector list, optional self.field = [np.zeros(3)] else: self.field = [np.array(f, dtype=np.float64) for f in field] # get the current path self.current_path = os.getcwd() # create output directory try: self.main_output_folder = os.path.join(self.current_path, self.output_folder) os.makedirs(self.main_output_folder) self.DONE = False except FileExistsError: # check whether directory already exists if cfg.OVERWRITE: print(""" Found already existing output folder named "{}", all its contents are now lost. Reason: OVERWRITE set to True.""".format(self.output_folder)) rmtree(self.main_output_folder) os.makedirs(self.main_output_folder) self.DONE = False print("") pass else: print(""" Found already existing output folder named "{}", skipping simulation process. Reason: OVERWRITE set to False.""".format(self.output_folder)) self.SETUP = True self.DONE = True return 0 # adjust the supercell as needed self.sim.settings["supercell"] = [list(self.supercell)] # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # record current settings from ezSCUP.settings # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # self.mc_steps = int(cfg.MC_STEPS) self.mc_step_interval = int(cfg.MC_STEP_INTERVAL) self.mc_equilibration_steps = int(cfg.MC_EQUILIBRATION_STEPS) self.mc_max_jump = float(cfg.MC_MAX_JUMP) self.lat_output_interval = int(cfg.LATTICE_OUTPUT_INTERVAL) self.fixed_strain_components = cfg.FIXED_STRAIN_COMPONENTS self.mc_annealing_rate = cfg.MC_ANNEALING_RATE # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # setup restart file generator self.generator = Geometry(self.supercell, model["species"], model["nats"]) # print common simulation settings if cfg.PRINT_CONF_SETTINGS: print("Starting FDF settings:") self.sim.print() print("") # save simulation setup file print("Saving simulation setup file... ") setup = { "name": self.name, "model": self.model, "supercell": self.supercell, "temp": self.temp, "strain": self.strain, "stress": self.stress, "field": self.field, "mc_steps": self.mc_steps, "mc_step_interval": self.mc_step_interval, "mc_equilibration_steps": self.mc_equilibration_steps, "mc_annealing_rate": self.mc_annealing_rate, "mc_max_jump": self.mc_max_jump, "lat_output_interval": self.lat_output_interval, "fixed_strain_components": self.fixed_strain_components, } simulation_setup_file = os.path.join(self.main_output_folder, cfg.SIMULATION_SETUP_FILE) with open(simulation_setup_file, "wb") as f: pickle.dump(setup, f) print("\nSimulation run has been properly configured.") print("You may now proceed to launch it.") self.SETUP = True # simulation run setup nicely pass # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # def change_output_folder(self, new_output_folder): # get the current path self.current_path = os.getcwd() previous = self.output_folder # create output directory print("\nCreating new output folder...") try: main_output_folder = os.path.join(self.current_path, new_output_folder) os.makedirs(main_output_folder) self.output_folder = new_output_folder self.main_output_folder = main_output_folder self.DONE = False except FileExistsError: # check whether directory already exists if cfg.OVERWRITE: print(""" Found already existing output folder named "{}", all its contents are now lost. Reason: OVERWRITE set to True.""".format(self.output_folder)) rmtree(main_output_folder) os.makedirs(main_output_folder) self.output_folder = new_output_folder self.main_output_folder = main_output_folder self.DONE = False print("") pass else: print(""" Found already existing output folder named "{}", aborting folder swap. Reason: OVERWRITE set to False.""".format(self.output_folder)) raise ezSCUP.exceptions.PreviouslyUsedOutputFolder() # save simulation setup file print("Saving simulation setup file... ") setup = { "name": self.name, "model": self.model, "supercell": self.supercell, "temp": self.temp, "strain": self.strain, "stress": self.stress, "field": self.field, "mc_steps": self.mc_steps, "mc_step_interval": self.mc_step_interval, "mc_equilibration_steps": self.mc_equilibration_steps, "mc_annealing_rate": self.mc_annealing_rate, "mc_max_jump": self.mc_max_jump, "lat_output_interval": self.lat_output_interval, "fixed_strain_components": self.fixed_strain_components, } simulation_setup_file = os.path.join(self.main_output_folder, cfg.SIMULATION_SETUP_FILE) with open(simulation_setup_file, "wb") as f: pickle.dump(setup, f) print('\nOutput folder swapped from "{}" to "{}".'.format( previous, self.output_folder)) pass # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # def independent_launch(self, start_geo=None): """ Start a simulation run with all the possible combinations of the given parameter grid. Parameters: ---------- - start_geo (Geometry): starting geometry of every simulation. """ # check if setup() has been run if self.SETUP != True: raise ezSCUP.exceptions.MissingSetup( "Run MCSimulation.setup() before launching any simulation.") # check if somulation has already been carried out if self.DONE == True: return 0 print("\n ~ Independent simulation run engaged. ~") # checks restart file matches loaded geometry if start_geo != None and isinstance(start_geo, Geometry): print("\nApplying starting geometry...") if not np.all(self.generator.supercell == start_geo.supercell): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.nats != None and (start_geo.nats != self.model["nats"]): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.species != None and (set( self.model["species"]) != set(self.model["species"])): raise ezSCUP.exceptions.GeometryNotMatching() self.generator.displacements = start_geo.displacements # get a copy of the model file copy(self.model["file"], "param_file.xml") # parser to get partials parser = MCSimulationParser(output_folder=self.output_folder) # simulation counters total_counter = 0 # total number of simulations nsims = self.temp.size * len(self.strain) * len(self.field) * len( self.stress) # starting time of the simulation process main_start_time = time.time() print("\nStarting calculations...\n") for t in self.temp: temp_counter = np.where(self.temp == t)[0][0] for p in self.stress: stress_counter = [np.array_equal(p, x) for x in self.stress].index(True) for s in self.strain: strain_counter = [ np.array_equal(s, x) for x in self.strain ].index(True) for f in self.field: field_counter = [ np.array_equal(f, x) for x in self.field ].index(True) # update simulation counter total_counter += 1 # starting time of the current configuration conf_start_time = time.time() print("##############################") print("Configuration " + str(total_counter) + " out of " + str(nsims)) print("Temperature:", str(t), "K") print("Stress:", str(p), "GPa") print("Strain:", str(s), r"% change") print("Electric Field:", str(f), "V/m") print("##############################") # file base name sim_name = self.name + "T{:d}".format(int(t)) self.sim.settings["system_name"].value = sim_name # configuration name conf_name = "c{:02d}{:02d}{:02d}{:02d}".format( temp_counter, stress_counter, strain_counter, field_counter) # subfolder name subfolder_name = self.name + "." + conf_name # modify target temperature self.sim.settings["mc_temperature"].value = t if self.stress != None: # modify target stress, if needed self.sim.settings["external_stress"] = [p] else: p = np.zeros(6) if self.strain != None: # set target strain, if needed self.generator.strains = s else: s = np.zeros(6) if self.field != None: # modify target field, if needed self.sim.settings["static_electric_field"] = [f] else: f = np.zeros(3) # define human output filename output = sim_name + ".out" # create restart file self.sim.settings["geometry_restart"] = FDFSetting( sim_name + ".restart") self.generator.write_restart(sim_name + ".restart") # simulate the current configuration self.sim.launch(output_file=output) # move all the output to its corresponding folder configuration_folder = os.path.join( self.main_output_folder, subfolder_name) os.makedirs(configuration_folder) files = os.listdir(self.current_path) for fi in files: if sim_name in fi: move(fi, configuration_folder) # finish time of the current conf conf_finish_time = time.time() conf_time = conf_finish_time - conf_start_time print( "\nConfiguration finished! (time elapsed: {:.3f}s)" .format(conf_time)) # calculate equilibrium geometry print("Calculating equilibrium geometry...") partials = parser.find_partials( t, p=p, s=s, f=f, min_step=self.mc_equilibration_steps) aux_geo = Geometry(self.supercell, self.model["species"], self.model["nats"]) aux_geo.load_equilibrium_displacements(partials) aux_geo.write_restart( os.path.join(configuration_folder, sim_name + "_EQUILIBRIUM.restart")) print("All files stored in output/" + subfolder_name + " succesfully.\n") self.generator.reset_geom() # remove the copy of the model os.remove("param_file.xml") main_finished_time = time.time() main_time = main_finished_time - main_start_time print("Simulation process complete!") print("Total simulation time: {:.3f}s".format(main_time)) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # def sequential_launch_by_temperature(self, start_geo=None, inverse_order=False): """ Simulation run where the equilibrium geometry of the simulation for the previous temperature is used as starting geometry of the next one. Parameters: ---------- - start_geo (RestartGenerator): starting geometry of the first temperature. """ # check if setup() has been run if self.SETUP != True: raise ezSCUP.exceptions.MissingSetup( "Run MCSimulation.setup() before launching any simulation.") # check if somulation has already been carried out if self.DONE == True: return 0 print("\n ~ Sequential simulation run by temperature engaged. ~ ") # checks restart file matches loaded geometry if start_geo != None and isinstance(start_geo, Geometry): print("\nApplying starting geometry...") if not np.all(self.generator.supercell == start_geo.supercell): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.nats != None and (start_geo.nats != self.model["nats"]): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.species != None and (set( self.model["species"]) != set(self.model["species"])): raise ezSCUP.exceptions.GeometryNotMatching() # get a copy of the model file copy(self.model["file"], "param_file.xml") # parser to get equilibrium geometry parser = MCSimulationParser(output_folder=self.output_folder) # adjust temperature ordering if inverse_order: temp_sequence = list(reversed(list(self.temp))) else: temp_sequence = list(self.temp) # simulation counters total_counter = 0 # total number of simulations nsims = self.temp.size * len(self.strain) * len(self.field) * len( self.stress) # starting time of the simulation process main_start_time = time.time() print("\nStarting calculations...\n") for p in self.stress: stress_counter = [np.array_equal(p, x) for x in self.stress].index(True) for s in self.strain: strain_counter = [np.array_equal(s, x) for x in self.strain].index(True) for f in self.field: field_counter = [np.array_equal(f, x) for x in self.field].index(True) # set starting geometry if start_geo != None and isinstance(start_geo, Geometry): self.generator.displacements = start_geo.displacements tcount = 0 for t in temp_sequence: temp_counter = np.where(self.temp == t)[0][0] # update simulation counter total_counter += 1 tcount += 1 # starting time of the current configuration conf_start_time = time.time() print("##############################") print("Configuration " + str(total_counter) + " out of " + str(nsims)) print("Temperature:", str(t), "K") print("Stress:", str(p), "GPa") print("Strain:", str(s), r"% change") print("Electric Field:", str(f), "V/m") print("##############################") # file base name sim_name = self.name + "T{:d}".format(int(t)) self.sim.settings["system_name"].value = sim_name # configuration name conf_name = "c{:02d}{:02d}{:02d}{:02d}".format( temp_counter, stress_counter, strain_counter, field_counter) # subfolder name subfolder_name = self.name + "." + conf_name # modify target temperature self.sim.settings["mc_temperature"].value = t if self.stress != None: # modify target stress, if needed self.sim.settings["external_stress"] = [p] if self.strain != None: # set target strain, if needed self.generator.strains = s if self.field != None: # modify target field, if needed self.sim.settings["static_electric_field"] = [f] # define human output filename output = sim_name + ".out" # create restart file self.sim.settings["geometry_restart"] = FDFSetting( sim_name + ".restart") self.generator.write_restart(sim_name + ".restart") # simulate the current configuration self.sim.launch(output_file=output) # move all the output to its corresponding folder configuration_folder = os.path.join( self.main_output_folder, subfolder_name) os.makedirs(configuration_folder) files = os.listdir(self.current_path) for fi in files: if sim_name in fi: move(fi, configuration_folder) # finish time of the current conf conf_finish_time = time.time() conf_time = conf_finish_time - conf_start_time print( "\nConfiguration finished! (time elapsed: {:.3f}s)" .format(conf_time)) # calculate equilibrium geometry print("Calculating equilibrium geometry...") partials = parser.find_partials( t, p=p, s=s, f=f, min_step=self.mc_equilibration_steps) aux_geo = Geometry(self.supercell, self.model["species"], self.model["nats"]) aux_geo.load_equilibrium_displacements(partials) aux_geo.write_restart( os.path.join(configuration_folder, sim_name + "_EQUILIBRIUM.restart")) # grab final geometry for next run if needed if tcount < len(temp_sequence): geo = parser.access_geometry(t, p=p, s=s, f=f) self.generator.displacements = geo.displacements print("All files stored in output/" + subfolder_name + " succesfully.\n") # remove the copy of the model os.remove("param_file.xml") self.generator.reset_geom() main_finished_time = time.time() main_time = main_finished_time - main_start_time print("Simulation process complete!") print("Total simulation time: {:.3f}s".format(main_time)) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # def sequential_launch_by_strain(self, start_geo=None, inverse_order=False): """ Simulation run where the equilibrium geometry of the simulation for the previous temperature is used as starting geometry of the next one. Parameters: ---------- - start_geo (RestartGenerator): starting geometry of the first temperature. """ # check if setup() has been run if self.SETUP != True: raise ezSCUP.exceptions.MissingSetup( "Run MCSimulation.setup() before launching any simulation.") # check if simulation has already been carried out if self.DONE == True: return 0 print("\n ~ Sequential simulation run by strain engaged. ~ ") # checks restart file matches loaded geometry if start_geo != None and isinstance(start_geo, Geometry): print("\nApplying starting geometry...") if not np.all(self.generator.supercell == start_geo.supercell): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.nats != None and (start_geo.nats != self.model["nats"]): raise ezSCUP.exceptions.GeometryNotMatching() if self.generator.species != None and (set( self.model["species"]) != set(self.model["species"])): raise ezSCUP.exceptions.GeometryNotMatching() # get a copy of the model file copy(self.model["file"], "param_file.xml") # parser to get equilibrium geometry parser = MCSimulationParser(output_folder=self.output_folder) # adjust strain ordering if inverse_order: strain_sequence = list(reversed(list(self.strain))) else: strain_sequence = list(self.strain) # simulation counters total_counter = 0 # total number of simulations nsims = self.temp.size * len(self.strain) * len(self.field) * len( self.stress) # starting time of the simulation process main_start_time = time.time() print("\nStarting calculations...\n") for t in self.temp: temp_counter = np.where(self.temp == t)[0][0] for p in self.stress: stress_counter = [np.array_equal(p, x) for x in self.stress].index(True) for f in self.field: field_counter = [np.array_equal(f, x) for x in self.field].index(True) # set starting geometry if start_geo != None and isinstance(start_geo, Geometry): self.generator.displacements = start_geo.displacements scount = 0 for s in strain_sequence: strain_counter = [ np.array_equal(s, x) for x in self.strain ].index(True) # update simulation counter total_counter += 1 scount += 1 # starting time of the current configuration conf_start_time = time.time() print("##############################") print("Configuration " + str(total_counter) + " out of " + str(nsims)) print("Temperature:", str(t), "K") print("Stress:", str(p), "GPa") print("Strain:", str(s), r"% change") print("Electric Field:", str(f), "V/m") print("##############################") # file base name sim_name = self.name + "T{:d}".format(int(t)) self.sim.settings["system_name"].value = sim_name # configuration name conf_name = "c{:02d}{:02d}{:02d}{:02d}".format( temp_counter, stress_counter, strain_counter, field_counter) # subfolder name subfolder_name = self.name + "." + conf_name # modify target temperature self.sim.settings["mc_temperature"].value = t if self.stress != None: # modify target stress, if needed self.sim.settings["external_stress"] = [p] if self.strain != None: # set target strain, if needed self.generator.strains = s if self.field != None: # modify target field, if needed self.sim.settings["static_electric_field"] = [f] # define human output filename output = sim_name + ".out" # create restart file self.sim.settings["geometry_restart"] = FDFSetting( sim_name + ".restart") self.generator.write_restart(sim_name + ".restart") # simulate the current configuration self.sim.launch(output_file=output) # move all the output to its corresponding folder configuration_folder = os.path.join( self.main_output_folder, subfolder_name) os.makedirs(configuration_folder) files = os.listdir(self.current_path) for fi in files: if sim_name in fi: move(fi, configuration_folder) # finish time of the current conf conf_finish_time = time.time() conf_time = conf_finish_time - conf_start_time print( "\nConfiguration finished! (time elapsed: {:.3f}s)" .format(conf_time)) # calculate equilibrium geometry print("Calculating equilibrium geometry...") partials = parser.find_partials( t, p=p, s=s, f=f, min_step=self.mc_equilibration_steps) aux_geo = Geometry(self.supercell, self.model["species"], self.model["nats"]) aux_geo.load_equilibrium_displacements(partials) aux_geo.write_restart( os.path.join(configuration_folder, sim_name + "_EQUILIBRIUM.restart")) # grab final geometry for next run if needed if scount < len(strain_sequence): geo = parser.access_geometry(t, p=p, s=s, f=f) self.generator.displacements = geo.displacements print("All files stored in output/" + subfolder_name + " succesfully.\n") # remove the copy of the model os.remove("param_file.xml") self.generator.reset_geom() main_finished_time = time.time() main_time = main_finished_time - main_start_time print("Simulation process complete!") print("Total simulation time: {:.3f}s".format(main_time))