def main(*args): """Main function for running calculation""" #Read in parameters from input file with open(args[0]) as f: input_dict = iprPy.calculation_read_input(__calc_type__, f, *args[1:]) #Read in potential potential = lmp.Potential(input_dict['potential'], input_dict['potential_dir']) #Get axes info axes = np.array([input_dict['x-axis'], input_dict['y-axis'], input_dict['z-axis']]) #Perform crss calculation results_dict = crss(input_dict['lammps_command'], input_dict['initial_system'], potential, input_dict['symbols'], input_dict['C'], mpi_command=input_dict['mpi_command'], chi=input_dict['chi_angle'], sigma=input_dict['sigma'], tau_1=input_dict['tau_1'], tau_2=input_dict['tau_2'], press=input_dict['press'], rss_steps=input_dict['rss_steps'], axes=axes) #Save data model of results results = iprPy.calculation_data_model(__calc_type__, input_dict, results_dict) with open('results.json', 'w') as f: results.json(fp=f, indent=4)
def isymbolscombos(prototype, potential): symbols = lmp.Potential(potential.content).symbols natypes = prototype.todict()['natypes'] for ivals in iterbox(len(symbols), natypes): yield list(np.asarray(symbols)[ivals])
def interpret(self, input_dict): """ Interprets calculation parameters. Parameters ---------- input_dict : dict Dictionary containing input parameter key-value pairs. """ # Set default keynames keymap = self.keymap # Extract input values and assign default values potential_file = input_dict[keymap['potential_file']] potential_dir = input_dict.get(keymap['potential_dir'], '') potential_content = input_dict.get(keymap['potential_content'], None) # Use potential_content instead of potential_file if given if potential_content is not None: potential_file = potential_content # Save processed terms input_dict[keymap['potential_dir']] = potential_dir input_dict[keymap['potential']] = lmp.Potential( potential_file, potential_dir)
def load_parameters(self, input_dict): """ Interprets calculation parameters. Parameters ---------- input_dict : dict Dictionary containing input parameter key-value pairs. """ # Set default keynames keymap = self.keymap # Extract input values and assign default values potential_file = input_dict[keymap['potential_file']] potential_kim_id = input_dict.get(keymap['potential_kim_id'], None) potential_kim_potid = input_dict.get(keymap['potential_kim_potid'], None) potential_dir = input_dict.get(keymap['potential_dir'], None) potential_content = input_dict.get(keymap['potential_content'], None) # Use potential_content instead of potential_file if given if potential_content is not None: potential_file = potential_content # Read potential self.potential = lmp.Potential(potential_file, pot_dir=potential_dir, kim_id=potential_kim_id, potid=potential_kim_potid)
def interpret_input(input_dict): with open(input_dict['potential_file']) as f: input_dict['potential'] = lmp.Potential(f, os.path.abspath(input_dict['potential_dir'])) iprPy.input.system_family(input_dict) iprPy.input.ucell(input_dict) iprPy.input.initialsystem(input_dict)
def main(*args): """Main function for running calculation""" #Read in parameters from input file with open(args[0]) as f: input_dict = iprPy.calculation_read_input(__calc_type__, f, *args[1:]) #Read in potential potential = lmp.Potential(input_dict['potential'], input_dict['potential_dir']) #Save data model of results results = iprPy.calculation_data_model(__calc_type__, input_dict, results_dict) with open('results.json', 'w') as f: results.json(fp=f, indent=4)
def lammps_potential(input_dict, **kwargs): """ Interprets calculation parameters associated with a potential-LAMMPS record. The input_dict keys used by this function (which can be renamed using the function's keyword arguments): - **'potential_file'** the potential-LAMMPS model to load. - **'potential_dir'** the directory containing all of the potential's artifacts. - **'potential_content'** alternate file or content to load instead of specified potential_file. This is used by prepare functions. - **'potential'** the atomman.lammps.Potential object created. Parameters ---------- input_dict : dict Dictionary containing input parameter key-value pairs. potential_file : str Replacement parameter key name for 'potential_file'. potential_dir : str Replacement parameter key name for 'potential_dir'. potential : str Replacement parameter key name for 'potential'. """ # Set default keynames keynames = [ 'potential_file', 'potential_dir', 'potential_content', 'potential' ] for keyname in keynames: kwargs[keyname] = kwargs.get(keyname, keyname) # Extract input values and assign default values potential_file = input_dict[kwargs['potential_file']] potential_dir = input_dict.get(kwargs['potential_dir'], '') potential_content = input_dict.get(kwargs['potential_content'], None) # Use potential_content instead of potential_file if given if potential_content is not None: potential_file = potential_content # Save processed terms input_dict[kwargs['potential_dir']] = potential_dir input_dict[kwargs['potential']] = lmp.Potential(potential_file, potential_dir)
def main(*args): """Main function for running calculation""" # Read input file in as dictionary with open(args[0]) as f: input_dict = iprPy.input.parse(f, allsingular=True) # Interpret and process input parameters process_input(input_dict, *args[1:]) #Read in potential potential = lmp.Potential(input_dict['potential'], input_dict['potential_dir']) #Get axes info axes = np.array( [input_dict['x-axis'], input_dict['y-axis'], input_dict['z-axis']]) # Perform crss calculation results_dict = crss(input_dict['lammps_command'], input_dict['initial_system'], potential, input_dict['C'], mpi_command=input_dict['mpi_command'], chi=input_dict['chi_angle'], sigma=input_dict['sigma'], tau_1=input_dict['tau_1'], tau_2=input_dict['tau_2'], press=input_dict['press'], rss_steps=input_dict['rss_steps'], axes=axes) # Build and save data model of results record = iprPy.load_record(record_style) record.buildcontent(input_dict, results_dict) with open('results.json', 'w') as f: record.content.json(fp=f, indent=4)
def relaxed(database_name, crystal_match_file, all_crystals_file, unique_crystals_file): # !!!!!!!!!!!!!!!!!!!!!!!!!!!!! Load records !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # database = load_database(database_name) # Load potential_LAMMPS records pot_records = database.get_records_df(style='potential_LAMMPS') print(f'{len(pot_records)} potential records found', flush=True) # Load crystal_prototype records proto_records = database.get_records_df(style='crystal_prototype') print(f'{len(proto_records)} prototype records found', flush=True) # Load reference_crystal records ref_records = database.get_records_df(style='reference_crystal') print(f'{len(ref_records)} reference records found', flush=True) # Get key lists for relax_* calculations raw_df = database.get_records_df(style='calculation_relax_box', full=False, flat=True) print(f'{len(raw_df)} calculation_relax_box records found', flush=True) try: box_keys = raw_df.key.tolist() except: box_keys = [] raw_df = database.get_records_df(style='calculation_relax_static', full=False, flat=True) print(f'{len(raw_df)} calculation_relax_static records found', flush=True) try: static_keys = raw_df.key.tolist() except: static_keys = [] raw_df = database.get_records_df(style='calculation_relax_dynamic', full=False, flat=True) print(f'{len(raw_df)} calculation_relax_dynamic records found', flush=True) try: dynamic_keys = raw_df.key.tolist() except: dynamic_keys = [] print() # Get space group results spg_records = database.get_records_df(style='calculation_crystal_space_group', full=True, flat=False, status='finished') print(f'{len(spg_records)} calculation_crystal_space_group records found', flush=True) if len(spg_records) == 0: print('Stopping as no calculations to process') return # Separate records by branch prototype_records = spg_records[spg_records.branch == 'prototype'] reference_records = spg_records[spg_records.branch == 'reference'] family_records = spg_records[(spg_records.branch == 'prototype') |(spg_records.branch == 'reference')] print(f' -{len(prototype_records)} are for prototypes', flush=True) print(f' -{len(reference_records)} are for references', flush=True) calc_records = spg_records[spg_records.branch == 'relax'].reset_index(drop=True) print(f' -{len(calc_records)} are for calculations', flush=True) print() if len(calc_records) == 0: print('Stopping as no calculations to process') return if len(family_records) == 0: print('Stopping as prototype/reference records needed') return # !!!!!!!!!!!!!!!!!!!!!!!!!! Load saved results !!!!!!!!!!!!!!!!!!!!!!!!!!!!! # try: ref_proto_match = pd.read_csv(crystal_match_file) except: columns = ['reference', 'prototype', 'composition'] ref_proto_match = pd.DataFrame(columns=columns) print(f'{len(ref_proto_match)} references matched to prototypes', flush=True) try: results = pd.read_csv(all_crystals_file) except: columns = ['calc_key', 'potential_LAMMPS_key', 'potential_LAMMPS_id', 'potential_key', 'potential_id', 'composition', 'prototype', 'family', 'method', 'transformed', 'E_coh', 'a', 'b', 'c', 'alpha', 'beta', 'gamma'] results = pd.DataFrame(columns=columns) print(f'{len(results)} previous results found', flush=True) try: unique = pd.read_csv(unique_crystals_file) except: columns = ['calc_key', 'potential_LAMMPS_key', 'potential_LAMMPS_id', 'potential_key', 'potential_id', 'composition', 'prototype', 'family', 'method', 'transformed', 'E_coh', 'a', 'b', 'c', 'alpha', 'beta', 'gamma'] unique = pd.DataFrame(columns=columns) print(f'{len(unique)} previous unique results found', flush=True) print() # !!!!!!!!!!!!!!!!!!!!!!!!! Process new results !!!!!!!!!!!!!!!!!!!!!!!!!!!!! # newresults = [] old_keys = results.calc_key.values for series in calc_records.itertuples(): if series.key in old_keys: continue results_dict = {} # Copy over values in series results_dict['calc_key'] = series.key results_dict['composition'] = series.composition results_dict['family'] = series.family results_dict['a'] = series.ucell.box.a results_dict['b'] = series.ucell.box.b results_dict['c'] = series.ucell.box.c results_dict['alpha'] = series.ucell.box.alpha results_dict['beta'] = series.ucell.box.beta results_dict['gamma'] = series.ucell.box.gamma # Identify prototype try: results_dict['prototype'] = ref_proto_match[ref_proto_match.reference==series.family].prototype.values[0] except: results_dict['prototype'] = series.family else: if pd.isnull(results_dict['prototype']): results_dict['prototype'] = series.family # Check if structure has transformed relative to reference family_series = family_records[family_records.family == series.family].iloc[0] results_dict['transformed'] = (not (family_series.spacegroup_number == series.spacegroup_number and family_series.pearson_symbol == series.pearson_symbol)) # Extract info from parent calculations for parent in database.get_parent_records(name=series.key): parent_dict = parent.todict() if parent_dict['key'] in box_keys: results_dict['method'] = 'box' results_dict['E_coh'] = parent_dict['E_cohesive'] results_dict['potential_LAMMPS_key'] = parent_dict['potential_LAMMPS_key'] continue elif parent_dict['key'] in dynamic_keys: results_dict['method'] = 'dynamic' continue elif parent_dict['key'] in static_keys: results_dict['method'] = 'static' results_dict['E_coh'] = parent_dict['E_cohesive'] results_dict['potential_LAMMPS_key'] = parent_dict['potential_LAMMPS_key'] pot_record = pot_records[pot_records.key == results_dict['potential_LAMMPS_key']].iloc[0] results_dict['potential_id'] = pot_record.pot_id results_dict['potential_key'] = pot_record.pot_key results_dict['potential_LAMMPS_id'] = pot_record.id newresults.append(results_dict) print(f'{len(newresults)} new results added') if len(newresults) > 0: results = results.append(newresults, ignore_index=True) results.to_csv(all_crystals_file, index=False) # !!!!!!!!!!!!!!!!!!!!!!!!! Find unique results !!!!!!!!!!!!!!!!!!!!!!!!!!!!! # new_unique = pd.DataFrame(columns=results.columns) # Loop over all potential implementations for implememtation_key in np.unique(results.potential_LAMMPS_key): imp_results = results[results.potential_LAMMPS_key == implememtation_key] # Loop over all compositions for composition in np.unique(results.composition): comp_unique = unique[unique.composition == composition].reset_index(drop=True) comp_results = imp_results[imp_results.composition == composition] # Loop over all prototypes for prototype in np.unique(comp_results.prototype): proto_results = comp_results[comp_results.prototype == prototype] # Loop over calculation methods from most robust to least for method in ['dynamic', 'static', 'box']: # First try matching results where prototype == family for i, series in proto_results[(proto_results.prototype == proto_results.family) &(proto_results.method == method) &(~proto_results.transformed)].iterrows(): try: matches = comp_unique[(np.isclose(comp_unique.E_coh, series.E_coh)) &(np.isclose(comp_unique.a, series.a)) &(np.isclose(comp_unique.b, series.b)) &(np.isclose(comp_unique.c, series.c)) &(np.isclose(comp_unique.alpha, series.alpha)) &(np.isclose(comp_unique.beta, series.beta)) &(np.isclose(comp_unique.gamma, series.gamma))] except: matches = [] if len(matches) == 0: comp_unique = comp_unique.append(series) new_unique = new_unique.append(series) # Next try matching results where prototype != family for i, series in proto_results[(proto_results.prototype != proto_results.family) &(proto_results.method == method) &(~proto_results.transformed)].iterrows(): try: matches = comp_unique[(np.isclose(comp_unique.E_coh, series.E_coh)) &(np.isclose(comp_unique.a, series.a)) &(np.isclose(comp_unique.b, series.b)) &(np.isclose(comp_unique.c, series.c)) &(np.isclose(comp_unique.alpha, series.alpha)) &(np.isclose(comp_unique.beta, series.beta)) &(np.isclose(comp_unique.gamma, series.gamma))] except: matches = [] if len(matches) == 0: comp_unique = comp_unique.append(series) new_unique = new_unique.append(series) print(f'{len(new_unique)} new unique results added') if len(new_unique) > 0: unique = unique.append(new_unique) unique.to_csv(unique_crystals_file, index=False) # !!!!!!!!!!!!!!!!!!! Generate relaxed_crystal records !!!!!!!!!!!!!!!!!!!!!! # for row in new_unique.itertuples(): crystal_terms = {} crystal_terms['key'] = str(uuid.uuid4()) crystal_terms['method'] = row.method crystal_terms['family'] = row.family crystal_terms['length_unit'] = 'angstrom' pot_record = database.get_record(name = pot_records[pot_records.key == row.potential_LAMMPS_key].id) crystal_terms['potential'] = lmp.Potential(pot_record.content) c_record = calc_records[calc_records.key == row.calc_key].iloc[0] # Use spg crystals for ref and α-As if (row.prototype[:3] == 'mp-' or row.prototype[:4] == 'mvc-' or row.prototype[:5] == 'oqmd-' or row.prototype == 'A7--alpha-As'): crystal_terms['ucell'] = c_record.ucell # Use scaled prototype crystals for the rest else: p_record = proto_records[proto_records.id == row.prototype].iloc[0] crystal_terms['ucell'] = p_record.ucell crystal_terms['ucell'].symbols = c_record.symbols crystal_terms['ucell'].box_set(a=row.a, b=row.b, c=row.c, alpha=row.alpha, beta=row.beta, gamma=row.gamma, scale=True) relaxrecord = load_record('relaxed_crystal') relaxrecord.buildcontent('b', crystal_terms) relaxrecord.name = crystal_terms['key'] database.add_record(relaxrecord)
def prepare(inline_terms, global_variables): """This is the prepare method for the calculation""" working_dir = os.getcwd() #Read in the calc_template calc_template = __calc_name__ + '.template' with open(os.path.join(__calc_dir__, 'calc_files', calc_template)) as f: template = f.read() #Identify the contents of calc_files calc_files = os.listdir(os.path.join(__calc_dir__, 'calc_files')) calc_files.remove(calc_template) #prepare_variables -- keywords used by this prepare function and the associated value lists given in inline_terms and global_variables #calculation_variables -- keywords in the calculation's template file. Empty and singular values filled in here, iterated values later prepare_variables, calculation_variables = __initial_setup( inline_terms, global_variables) #Loop over all potentials for potential_file, potential_dir in zip( prepare_variables.aslist('potential_file'), prepare_variables.aslist('potential_dir')): #Loop over all load systems for load, load_options, load_elements, box_parameters, elastic_constants_model in zip( prepare_variables.aslist('load'), prepare_variables.aslist('load_options'), prepare_variables.aslist('load_elements'), prepare_variables.aslist('box_parameters'), prepare_variables.aslist('elastic_constants_model')): #Loop over all size_mults for size_mults in prepare_variables.aslist('size_mults'): #Loop over all dislocation data models for dislocation_model in global_variables.aslist( 'dislocation_model'): #Add iterated values to calculation_variables calculation_variables['potential_file'] = potential_file calculation_variables['potential_dir'] = potential_dir calculation_variables['load'] = load calculation_variables['load_options'] = load_options calculation_variables['box_parameters'] = box_parameters calculation_variables['size_mults'] = size_mults calculation_variables['symbols'] = '' calculation_variables[ 'dislocation_model'] = dislocation_model calculation_variables[ 'elastic_constants_model'] = elastic_constants_model #Fill in template using calculation_variables values, and build input_dict calc_in = fill_template(template, calculation_variables, '<', '>') input_dict = read_input(calc_in) #Extract info from input dict potential = lmp.Potential(input_dict['potential']) system_family = input_dict['system_family'] dislocation_id = input_dict['dislocation_model'][ 'dislocation-monopole-parameters']['dislocation']['id'] #Check if disl_model's system_family matches the load_file's system_family if system_family != input_dict['dislocation_model'][ 'dislocation-monopole-parameters']['system-family']: continue #Loop over all symbols combinations for symbols in atomman_input.yield_symbols( load, load_options, load_elements, global_variables, potential): #Define directory path for the record record_dir = os.path.join( calculation_variables['lib_directory'], str(potential), '-'.join(symbols), system_family, __calc_type__) #record_dir = os.path.join(calculation_variables['lib_directory'], str(potential), '-'.join(symbols), system_family, __calc_type__, dislocation_id) #Add symbols to input_dict and build incomplete record input_dict['symbols'] = list(symbols) record = data_model(input_dict) #Check if record already exists if __is_new_record(record_dir, record): UUID = str(uuid.uuid4()) calculation_variables['symbols'] = ' '.join( symbols) #Create calculation run folder sim_dir = os.path.join( calculation_variables['run_directory'], UUID) os.makedirs(sim_dir) #Copy calc_files to run folder for fname in calc_files: shutil.copy( os.path.join(__calc_dir__, 'calc_files', fname), sim_dir) #Copy potential and load files to run directory and shorten paths if calculation_variables['copy_files']: #Divy up the load information load_terms = load.split() load_style = load_terms[0] load_file = ' '.join(load_terms[1:]) #Copy loose files shutil.copy(potential_file, sim_dir) shutil.copy(load_file, sim_dir) shutil.copy(dislocation_model, sim_dir) #Copy potential_dir and contents to run folder os.mkdir( os.path.join( sim_dir, os.path.basename(potential_dir))) for fname in glob.iglob( os.path.join(potential_dir, '*')): shutil.copy( fname, os.path.join( sim_dir, os.path.basename(potential_dir))) #Shorten file paths to be relative calculation_variables[ 'potential_file'] = os.path.basename( potential_file) calculation_variables[ 'potential_dir'] = os.path.basename( potential_dir) calculation_variables['load'] = ' '.join( [load_style, os.path.basename(load_file)]) calculation_variables[ 'dislocation_model'] = os.path.basename( dislocation_model) #Create calculation input file by filling in template with calculation_variables terms os.chdir(sim_dir) calc_in = fill_template(template, calculation_variables, '<', '>') input_dict = read_input(calc_in, UUID) with open(__calc_name__ + '.in', 'w') as f: f.write('\n'.join(calc_in)) os.chdir(working_dir) #Save the record to the library with open(os.path.join(record_dir, UUID + '.json'), 'w') as f: record.json(fp=f, indent=2)
def prepare(terms, variable): """This is the prepare method for the calculation""" working_dir = os.getcwd() #Identify the necessary run files in the calculation directory calc_template = os.path.join(__calc_dir__, __calc_name__ + '.template') calc_py = os.path.join(__calc_dir__, __calc_name__ + '.py') min_template = os.path.join(__calc_dir__, 'min.template') #Read in the calc_template with open(calc_template) as f: template = f.read() #Interpret and check terms and variables run_directory, lib_directory, v_dict = __initial_setup(terms, variable) #Loop over all potentials for potential_file, potential_dir in zip(variable.aslist('potential_file'), variable.aslist('potential_dir')): #Load potential with open(potential_file) as f: potential = lmp.Potential(f) #Pass potential's file and directory info to v_dict v_dict['potential_file'] = os.path.basename(potential_file) v_dict['potential_dir'] = os.path.basename(potential_dir) #Loop over all systems for load, load_options, load_elements, box_parameters in zip( variable.aslist('load'), variable.aslist('load_options'), variable.aslist('load_elements'), variable.aslist('box_parameters')): #Divy up the load information load_terms = load.split() load_style = load_terms[0] load_file = ' '.join(load_terms[1:]) load_base = os.path.basename(load_file) #Check for system_model fields from previous simulations if load_style == 'system_model': with open(load_file) as f: model = DM(f) #Skip if load relaxed with a different potential try: pot_key = model.find('potential')['key'] if pot_key != potential.uuid: continue except: pass #Get or make the load artifact family name try: system_family = model.find( 'system-info')['artifact']['family'] except: system_family = os.path.splitext(load_base)[0] else: system_family = os.path.splitext(load_base)[0] #Loop over all point defect data models for ptd_model in variable.aslist('ptd_model'): #Check if ptd_model's system_family matches the load_file's system_family with open(ptd_model) as f: ptd = DM(f) if system_family != ptd['point-defect']['system-family']: continue #Pass system's file, options and box parameters to v_dict v_dict['load'] = ' '.join([load_terms[0], load_base]) v_dict['load_options'] = load_options v_dict['box_parameters'] = box_parameters #Pass defect model to v_dict ptd_file = os.path.basename(ptd_model) v_dict['ptd_model'] = ptd_file v_dict['ptd_name'] = ptd['point-defect']['identifier']['name'] #Loop over all symbols combinations for symbols in atomman_input.yield_symbols( load, load_options, load_elements, variable, potential): #Pass symbols to v_dict v_dict['symbols'] = ' '.join(symbols) #Define directory path for the record record_dir = os.path.join(lib_directory, str(potential), '-'.join(symbols), system_family, __calc_type__) #Loop over all size_mults for size_mults in variable.aslist('size_mults'): v_dict['size_mults'] = size_mults #Check if record already exists if __is_new_record(record_dir, v_dict): UUID = str(uuid.uuid4()) #Create calculation run folder sim_dir = os.path.join(run_directory, UUID) os.makedirs(sim_dir) #Copy files to run folder shutil.copy(calc_py, sim_dir) shutil.copy(min_template, sim_dir) shutil.copy(potential_file, sim_dir) shutil.copy(load_file, sim_dir) shutil.copy(ptd_model, sim_dir) #Copy potential_dir and contents to run folder os.mkdir( os.path.join(sim_dir, os.path.basename(potential_dir))) for fname in glob.iglob( os.path.join(potential_dir, '*')): shutil.copy( fname, os.path.join( sim_dir, os.path.basename(potential_dir))) #Create calculation input file by filling in template with v_dict terms os.chdir(sim_dir) calc_in = fill_template(template, v_dict, '<', '>') input_dict = calc.input(calc_in, UUID) with open(__calc_name__ + '.in', 'w') as f: f.write('\n'.join(calc_in)) os.chdir(working_dir) #Save the incomplete record model = calc.data_model(input_dict) with open(os.path.join(record_dir, UUID + '.json'), 'w') as f: model.json(fp=f, indent=2)
def main(*args): calculation = iprPy.Calculation(__calc_style__) with open(args[0]) as f: prepare_dict = read_input(f) #open database dbase = iprPy.database_fromdict(prepare_dict) #Build record_df record_df = build_record_df(dbase, __record_style__) #Loop over all potentials for pot_record in iprPy.prepare.ipotentials( dbase, element=prepare_dict['potential_element'], name=prepare_dict['potential_name'], pair_style=prepare_dict['potential_pair_style']): potential = lmp.Potential(pot_record.content) pot_tar = dbase.get_tar(pot_record) #Loop over all prototypes for proto_record in iprPy.prepare.iprototypes( dbase, natypes=prepare_dict['prototype_natypes'], name=prepare_dict['prototype_name'], spacegroup=prepare_dict['prototype_spacegroup'], crystalfamily=prepare_dict['prototype_crystalfamily'], pearson=prepare_dict['prototype_Pearsonsymbol']): #Iterate over all combinations of potentials, prototypes and symbols for symbols in iprPy.prepare.isymbolscombos( proto_record, pot_record): #Create calc_key calc_key = str(uuid.uuid4()) #Define values for calc_*.in file calc_dict = {} calc_dict['lammps_command'] = prepare_dict['lammps_command'] calc_dict['mpi_command'] = prepare_dict['mpi_command'] calc_dict['potential_file'] = pot_record.name + '.xml' calc_dict['potential_dir'] = pot_record.name calc_dict[ 'load'] = 'system_model ' + proto_record.name + '.xml' calc_dict['load_options'] = '' calc_dict['symbols'] = ' '.join(symbols) calc_dict['box_parameters'] = '' calc_dict['x_axis'] = '' calc_dict['y_axis'] = '' calc_dict['z_axis'] = '' calc_dict['atomshift'] = '' calc_dict['sizemults'] = prepare_dict['sizemults'] calc_dict['length_unit'] = prepare_dict['length_unit'] calc_dict['pressure_unit'] = prepare_dict['pressure_unit'] calc_dict['energy_unit'] = prepare_dict['energy_unit'] calc_dict['force_unit'] = prepare_dict['force_unit'] calc_dict['minimum_r'] = prepare_dict['minimum_r'] calc_dict['maximum_r'] = prepare_dict['maximum_r'] calc_dict['number_of_steps_r'] = prepare_dict[ 'number_of_steps_r'] #Build inputfile by filling in calculation's template inputfile = iprPy.tools.filltemplate(calculation.template, calc_dict, '<', '>') #Read inputfile to build input_dict input_dict = calculation.read_input(inputfile, calc_key) #Define additional input_dict terms input_dict['potential'] = potential input_dict['load_file'] = proto_record.content iprPy.input.system_family(input_dict) #Build incomplete record new_record = iprPy.Record( name=calc_key, content=calculation.data_model(input_dict).xml(), style=__record_style__) #Check if record is new if is_new(record_df, new_record): #Add record to database dbase.add_record(record=new_record) #Generate calculation folder calc_directory = os.path.join( prepare_dict['run_directory'], calc_key) os.makedirs(calc_directory) #Save inputfile to calculation folder with open( os.path.join(calc_directory, 'calc_' + __calc_style__ + '.in'), 'w') as f: f.write(inputfile) #Add calculation files to calculation folder for calc_file in calculation.files: shutil.copy(calc_file, calc_directory) #Add potential record file to calculation folder with open( os.path.join(calc_directory, pot_record.name + '.xml'), 'w') as f: f.write(pot_record.content) #Extract potential's tar files to calculation folder pot_tar.extractall(calc_directory) #Add prototype record file to calculation folder with open( os.path.join(calc_directory, proto_record.name + '.xml'), 'w') as f: f.write(proto_record.content)
def atomicreference(database, keys, lib_directory=None, elements=None, **kwargs): # Get potentials if 'potential_file' in keys: potential_kwargs = {} for key in list(kwargs.keys()): if key[:10] == 'potential_': potential_kwargs[key[10:]] = kwargs.pop(key) pot_inputs = interatomicpotential(database, **potential_kwargs) potentials = {} potsymbols = {} for i in range(len(pot_inputs['potential_dir'])): potentials[pot_inputs['potential_dir'][i]] = pot_inputs['potential_content'][i] potsymbols[pot_inputs['potential_dir'][i]] = lmp.Potential(pot_inputs['potential_content'][i]).symbols else: potentials = {'empty': ''} potsymbols = None if lib_directory is None: lib_directory = os.path.join(os.path.dirname(rootdir), 'library') if elements is not None: elements = aslist(elements) allelements = set() for i in range(len(elements)): e = elements[i].split() allelements.update(e) e.sort() elements[i] = '-'.join(e) if potsymbols is None: if elements is not None: potsymbols = {'empty': list(allelements)} else: potsymbols = {'empty': ['*']} inputs = {} for key in keys: inputs[key] = [] # Get reference file names for searching names = aslist(kwargs.get('name', '*')) for potential_name in potentials: potential_content = potentials[potential_name] allsymbols = potsymbols[potential_name] allsymbols.sort() for symbols in subsets(allsymbols): symbol_str = '-'.join(symbols) if elements is not None and symbol_str != '*' and symbol_str not in elements: continue for name in names: for fname in glob.iglob(os.path.join(lib_directory, 'ref', symbol_str, name)): load_file = os.path.basename(fname) load_name, load_ext = os.path.splitext(load_file) with open(fname) as f: load_content = f.read() load_style = load_ext[1:] if load_style in ['xml', 'json']: load_style = 'system_model' elif load_style == 'dump': load_style = 'atom_dump' elif load_style == 'dat': load_style = 'atom_data' for key in keys: if key == 'potential_file': inputs['potential_file'].append(potential_name + '.json') elif key == 'potential_content': inputs['potential_content'].append(potential_content) elif key == 'potential_dir': inputs['potential_dir'].append(potential_name) elif key == 'load_file': inputs['load_file'].append(load_file) elif key == 'load_content': inputs['load_content'].append('file ' + os.path.abspath(fname)) elif key == 'load_style': inputs['load_style'].append(load_style) elif key == 'family': inputs['family'].append(load_name) else: inputs[key].append('') return inputs
def bain_run_calcs(input_dict, __calc_type__, step): #-------------------SETS UP THE SYSTEM-------------------- #Read in potential potential = lmp.Potential( input_dict['potential'], input_dict['potential_dir']) #reads the potential filename system = input_dict['initial_system'] #if initial step, set up system to find difference in cohesive energy. this step is skipped when a and c values change. if step == 'initial': a_scale = 1 c_scale = 1 elif step == 'bain': a_scale = input_dict['bain_a_scale'] c_scale = input_dict['bain_c_scale'] #scale box and atoms simultaneously system.box_set(a=a_scale * system.box.a, b=a_scale * system.box.b, c=c_scale * system.box.c, scale=True) #ensure all atoms are within the box system.wrap() #-------------------RUN LAMMPS AND SAVE RESULTS------------------ #use above information to generate system_info and pair_info for LAMMPS system_info = am.lammps.atom_data.dump('bain.dat', system, units=potential.units, atom_style=potential.atom_style) pair_info = potential.pair_info( input_dict['symbols'] ) #pulls the potential info when given which element the calculation is running on #write the LAMMPS input script with open('bain.in', 'w') as f: f.write( bain_relax_script('min.template', system_info, pair_info, etol=input_dict['energy_tolerance'], ftol=input_dict['force_tolerance'], maxiter=input_dict['maximum_iterations'], maxeval=input_dict['maximum_evaluations'])) #run LAMMPS output = lmp.run(input_dict['lammps_command'], 'bain.in', input_dict['mpi_command']) atom_last = 'atom.%i' % output.finds('Step')[ -1] #prints number of iterations (?) #save results into results_dict if step == 'initial': try: os.rename(atom_last, 'initial.dump') except: os.remove('initial.dump') os.rename(atom_last, 'initial.dump') os.remove('atom.0') d_system = lmp.atom_dump.load('initial.dump') elif step == 'bain': try: os.rename(atom_last, 'bain.dump') except: os.remove('bain.dump') os.rename(atom_last, 'bain.dump') os.remove('atom.0') d_system = lmp.atom_dump.load('bain.dump') results_dict = {} results_dict['potential_energy'] = float(output.finds('PotEng')[-1]) #return values return results_dict['potential_energy']
def main(*args): calculation = iprPy.Calculation(__calc_style__) with open(args[0]) as f: prepare_dict = read_input(f) #open database dbase = iprPy.database_fromdict(prepare_dict) #Build record_df record_df = build_record_df(dbase, __record_style__) #Build potential dictionaries (single dbase access) pot_record_dict = {} pot_tar_dict = {} for pot_record in dbase.iget_records(style='LAMMPS-potential'): pot_record_dict[pot_record.name] = pot_record #Load E_vs_r_scan records for parent_record in iprPy.prepare.icalculations( dbase, record_style='calculation-cohesive-energy-relation', symbol=prepare_dict['symbol_name'], prototype=prepare_dict['prototype_name'], potential=prepare_dict['potential_name']): parent_dict = parent_record.todict() #Load potential pot_record = pot_record_dict[parent_dict['potential_id']] potential = lmp.Potential(pot_record.content) #Get pot_tar from dbase only once per potential if parent_dict['potential_id'] in pot_tar_dict: pot_tar = pot_tar_dict[parent_dict['potential_id']] else: pot_tar = dbase.get_tar(pot_record) pot_tar_dict[parent_dict['potential_id']] = pot_tar #Loop over number_min_states for i in xrange(parent_dict['number_min_states']): if i == 0: load_options = 'key minimum-atomic-system' else: load_options = 'key minimum-atomic-system index ' + str(i) #Loop over strainrange values for strain in iprPy.tools.iaslist(prepare_dict['strainrange']): #Create calc_key calc_key = str(uuid.uuid4()) #Define values for calc_*.in file calc_dict = {} calc_dict['lammps_command'] = prepare_dict['lammps_command'] calc_dict['mpi_command'] = prepare_dict['mpi_command'] calc_dict['potential_file'] = pot_record.name + '.xml' calc_dict['potential_dir'] = pot_record.name calc_dict[ 'load'] = 'system_model ' + parent_record.name + '.xml' calc_dict['load_options'] = load_options calc_dict['symbols'] = '' calc_dict['box_parameters'] = '' calc_dict['x_axis'] = '' calc_dict['y_axis'] = '' calc_dict['z_axis'] = '' calc_dict['atomshift'] = '' calc_dict['sizemults'] = prepare_dict['sizemults'] calc_dict['length_unit'] = prepare_dict['length_unit'] calc_dict['pressure_unit'] = prepare_dict['pressure_unit'] calc_dict['energy_unit'] = prepare_dict['energy_unit'] calc_dict['force_unit'] = prepare_dict['force_unit'] calc_dict['strainrange'] = strain calc_dict['energytolerance'] = prepare_dict['energytolerance'] calc_dict['forcetolerance'] = prepare_dict['forcetolerance'] calc_dict['maxiterations'] = prepare_dict['maxiterations'] calc_dict['maxevaluations'] = prepare_dict['maxevaluations'] calc_dict['maxatommotion'] = prepare_dict['maxatommotion'] #Build inputfile by filling in calculation's template inputfile = iprPy.tools.filltemplate(calculation.template, calc_dict, '<', '>') #Read inputfile to build input_dict input_dict = calculation.read_input(inputfile, calc_key) #Define additional input_dict terms input_dict['potential'] = potential input_dict['load_file'] = parent_record.content iprPy.input.system_family(input_dict) #Build incomplete record new_record = iprPy.Record( name=calc_key, content=calculation.data_model(input_dict).xml(), style=__record_style__) #Check if record is new if is_new(record_df, new_record): #Add record to database dbase.add_record(record=new_record) #Generate calculation folder calc_directory = os.path.join( prepare_dict['run_directory'], calc_key) os.makedirs(calc_directory) #Save inputfile to calculation folder with open( os.path.join(calc_directory, 'calc_' + __calc_style__ + '.in'), 'w') as f: f.write(inputfile) #Add calculation files to calculation folder for calc_file in calculation.files: shutil.copy(calc_file, calc_directory) #Add potential record file to calculation folder with open( os.path.join(calc_directory, pot_record.name + '.xml'), 'w') as f: f.write(pot_record.content) #Extract potential's tar files to calculation folder pot_tar.extractall(calc_directory) #Add parent record file to calculation folder with open( os.path.join(calc_directory, parent_record.name + '.xml'), 'w') as f: f.write(parent_record.content)
def crystalprototype(database, keys, record='crystal_prototype', query=None, **kwargs): # Get potentials if 'potential_file' in keys: potential_kwargs = {} for key in list(kwargs.keys()): if key[:10] == 'potential_': potential_kwargs[key[10:]] = kwargs.pop(key) pot_inputs = interatomicpotential(database, **potential_kwargs) potentials = {} potsymbols = {} for i in range(len(pot_inputs['potential_dir'])): potentials[pot_inputs['potential_dir'] [i]] = pot_inputs['potential_content'][i] potsymbols[pot_inputs['potential_dir'][i]] = lmp.Potential( pot_inputs['potential_content'][i]).symbols else: potentials = {'empty': ''} potsymbols = {'empty': None} prototypes, prototype_df = database.get_records(style=record, return_df=True, query=query, **kwargs) inputs = {} for key in keys: inputs[key] = [] for i, prototype_info in prototype_df.iterrows(): prototype = prototypes[i] natypes = prototype_info.natypes for potential_name in potentials: potential_content = potentials[potential_name] allsymbols = potsymbols[potential_name] for symbols in itersymbols(allsymbols, natypes): for key in keys: if key == 'potential_file': inputs['potential_file'].append(potential_name + '.json') elif key == 'potential_content': inputs['potential_content'].append(potential_content) elif key == 'potential_dir': inputs['potential_dir'].append(potential_name) elif key == 'load_file': inputs['load_file'].append(prototype.name + '.json') elif key == 'load_content': inputs['load_content'].append('record ' + prototype.name) elif key == 'load_style': inputs['load_style'].append('system_model') elif key == 'family': inputs['family'].append(prototype.name) elif key == 'symbols': inputs['symbols'].append(' '.join(symbols).strip()) else: inputs[key].append('') return inputs
def relaxed(database_name, crystal_match_file, all_crystals_file, unique_crystals_file): # !!!!!!!!!!!!!!!!!!!!!!!!!!!!! Load records !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # database = load_database(database_name) # Load potential_LAMMPS records pot_records = database.get_records_df(style='potential_LAMMPS') print(f'{len(pot_records)} potential records found', flush=True) # Load crystal_prototype records proto_records = database.get_records_df(style='crystal_prototype') print(f'{len(proto_records)} prototype records found', flush=True) # Load reference_crystal records ref_records = database.get_records_df(style='reference_crystal') print(f'{len(ref_records)} reference records found', flush=True) # Load relax_box records raw_df = database.get_records_df(style='calculation_relax_box', full=True, flat=True) print(f'{len(raw_df)} calculation_relax_box records found', flush=True) if len(raw_df) > 0: box_df = raw_df[raw_df.branch == 'main'].reset_index(drop=True) box_df['method'] = 'box' print(f" - {len(box_df)} are branch main", flush=True) else: box_df = pd.DataFrame() # Load relax_static records raw_df = database.get_records_df(style='calculation_relax_static', full=True, flat=True) print(f'{len(raw_df)} calculation_relax_static records found', flush=True) if len(raw_df) > 0: static_df = raw_df[raw_df.branch == 'main'].reset_index(drop=True) static_df['method'] = 'static' print(f" - {len(static_df)} are branch main", flush=True) dynamic_df = raw_df[raw_df.branch == 'from_dynamic'].reset_index( drop=True) dynamic_df['method'] = 'dynamic' print(f" - {len(dynamic_df)} are branch from_dynamic", flush=True) else: static_df = pd.DataFrame() dynamic_df = pd.DataFrame() parent_df = pd.concat([box_df, static_df, dynamic_df], ignore_index=True, sort=False) # Get space group results spg_records = database.get_records_df( style='calculation_crystal_space_group', full=True, flat=False, status='finished') print(f'{len(spg_records)} calculation_crystal_space_group records found', flush=True) if len(spg_records) > 0: # Separate records using branch prototype_records = spg_records[spg_records.branch == 'prototype'] print(f' - {len(prototype_records)} are for prototypes', flush=True) reference_records = spg_records[spg_records.branch == 'reference'] print(f' - {len(reference_records)} are for references', flush=True) family_records = spg_records[(spg_records.branch == 'prototype') | (spg_records.branch == 'reference')] calc_records = spg_records[spg_records.branch == 'relax'].reset_index( drop=True) print(f' - {len(calc_records)} are for calculations', flush=True) else: print('Stopping as no calculations to process') if len(calc_records) == 0: print('Stopping as no calculations to process') if len(family_records) == 0: print('Stopping as prototype/reference records needed') # Get existing relaxed_records relaxed_records = database.get_records_df(style='relaxed_crystal', full=True, flat=False) print(len(relaxed_records), 'relaxed records found') print( f' - {len(relaxed_records[relaxed_records.standing=="good"])} good and unique' ) # !!!!!!!!!!!!!!!!!!!!!!!!!! Load saved results !!!!!!!!!!!!!!!!!!!!!!!!!!!!! # # Load crystal_match_file try: ref_proto_match = pd.read_csv(crystal_match_file) except: columns = ['reference', 'prototype', 'composition'] ref_proto_match = pd.DataFrame(columns=columns) print(f'{len(ref_proto_match)} references matched to prototypes', flush=True) # !!!!!!!!!!!!!!! Merge DataFrames and extract results !!!!!!!!!!!!!!!!!!!!! # # Get parent keys (relax_*) for space_group calculations def get_parent(series): return series.load_file.split('/')[0] calc_records['parent'] = calc_records.apply(get_parent, axis=1) # Merge calc_records, family_records and ref_proto_match merged_df = pd.merge(pd.merge(pd.merge(calc_records, parent_df, left_on='parent', right_on='key', suffixes=('', '_parent'), validate='one_to_one'), family_records, on='family', suffixes=('', '_family'), validate="many_to_one"), ref_proto_match, how='left', left_on='family', right_on='reference', suffixes=('', '_ref')) # Direct copy values from merged_df to results results = {} results['calc_key'] = merged_df.key results['potential_LAMMPS_key'] = merged_df.potential_LAMMPS_key results['potential_LAMMPS_id'] = merged_df.potential_LAMMPS_id results['potential_key'] = merged_df.potential_key results['potential_id'] = merged_df.potential_id results['composition'] = merged_df.composition results['family'] = merged_df.family results['method'] = merged_df.method results['parent_key'] = merged_df.parent results['E_coh'] = merged_df.E_cohesive results['prototype'] = merged_df.prototype results['ucell'] = merged_df.ucell results['ucell_family'] = merged_df.ucell_family # Identify transformed structures by comparing spacegroup info before/after relax def get_transformed(series): return ( not (series.spacegroup_number_family == series.spacegroup_number and series.pearson_symbol_family == series.pearson_symbol)) results['transformed'] = merged_df.apply(get_transformed, axis=1) # Set prototype as prototype (if given) or family def get_prototype(series): # Identify prototype if pd.isnull(series.prototype): return series.family else: return series.prototype results['prototype'] = merged_df.apply(get_prototype, axis=1) # Extract lattice constants from ucell def get_a(series): return series.ucell.box.a def get_b(series): return series.ucell.box.b def get_c(series): return series.ucell.box.c def get_alpha(series): return series.ucell.box.alpha def get_beta(series): return series.ucell.box.beta def get_gamma(series): return series.ucell.box.gamma results['a'] = merged_df.apply(get_a, axis=1) results['b'] = merged_df.apply(get_b, axis=1) results['c'] = merged_df.apply(get_c, axis=1) results['alpha'] = merged_df.apply(get_alpha, axis=1) results['beta'] = merged_df.apply(get_beta, axis=1) results['gamma'] = merged_df.apply(get_gamma, axis=1) # Create results DataFrame and save to all_crystals_file results_keys = [ 'calc_key', 'potential_LAMMPS_key', 'potential_LAMMPS_id', 'potential_key', 'potential_id', 'composition', 'prototype', 'family', 'parent_key', 'method', 'transformed', 'E_coh', 'a', 'b', 'c', 'alpha', 'beta', 'gamma', 'ucell', 'ucell_family' ] sort_keys = [ 'potential_LAMMPS_id', 'composition', 'prototype', 'family', 'E_coh' ] results = pd.DataFrame(results, columns=results_keys).sort_values(sort_keys) results[results_keys[:-2]].to_csv(all_crystals_file, index=False) print(all_crystals_file, 'updated') # !!!!!!!!!!!!!!!! Add new records to relaxed_crystal !!!!!!!!!!!!!!! # results = results[~results.transformed] print(len(results), 'results remained untransformed') results['added'] = results.calc_key.isin(relaxed_records.parent_key) def set_parent_type(series): if series.family[0] == 'm' or series.family[0] == 'o': return 'reference' else: return 'prototype' results['parent_type'] = results.apply(set_parent_type, axis=1) def set_method_int(series): if series.method == 'dynamic': return 1 elif series.method == 'static': return 2 else: return 3 results['method_int'] = results.apply(set_method_int, axis=1) newresults = results[~results['added']] print(f' - {len(newresults)} new results to add') # Loop over all new records for i, series in newresults.sort_values(['method_int', 'parent_type']).iterrows(): oldresults = results[results.added] # Create new record key = str(uuid.uuid4()) record = load_record('relaxed_crystal', name=key) # Set simple properties input_dict = {} input_dict['key'] = key input_dict['method'] = series.method input_dict['family'] = series.family input_dict['parent_key'] = series.calc_key input_dict['length_unit'] = 'angstrom' # Set potential potential_record = database.get_record(style='potential_LAMMPS', key=series.potential_LAMMPS_key) input_dict['potential'] = lmp.Potential(potential_record.content) # Set ucell # Use spg crystals for ref and α-As if (series.prototype[:3] == 'mp-' or series.prototype[:4] == 'mvc-' or series.prototype[:5] == 'oqmd-' or series.prototype == 'A7--alpha-As'): ucell = series.ucell # Use scaled prototype crystals for the rest else: ucell = series.ucell_family ucell.symbols = series.ucell.symbols ucell.box_set(vects=series.ucell.box.vects, scale=True) input_dict['ucell'] = ucell # Check for existing duplicates matches = ( (series.potential_LAMMPS_key == oldresults.potential_LAMMPS_key) & (series.composition == oldresults.composition) & np.isclose(series.E_coh, oldresults.E_coh) & np.isclose(series.a, oldresults.a) & np.isclose(series.b, oldresults.b) & np.isclose(series.c, oldresults.c) & np.isclose(series.alpha, oldresults.alpha) & np.isclose(series.beta, oldresults.beta) & np.isclose(series.gamma, oldresults.gamma)) # Set standing if series.E_coh < -1e-5 and matches.sum() == 0: input_dict['standing'] = 'good' else: input_dict['standing'] = 'bad' # Build content and upload record.buildcontent('noscript', input_dict) database.add_record(record=record) relaxed_records = database.get_records_df(style='relaxed_crystal', full=True, flat=False) print(len(relaxed_records), 'relaxed records found') print( f' - {len(relaxed_records[relaxed_records.standing=="good"])} good and unique' ) unique_results = pd.merge(results, relaxed_records, left_on='calc_key', right_on='parent_key', suffixes=('', '_dup'), validate='one_to_one') unique_results = unique_results[unique_results.standing == 'good'].sort_values(sort_keys) unique_results[results_keys[:-2]].to_csv(unique_crystals_file, index=False) print(unique_crystals_file, 'updated')
import pandas import shutil import atomman.lammps as lmp config_lst, file_name_lst, name_lst, species_lst = [], [], [], [] potential_folder = 'NISTiprpy' pyiron_pot_path = 'pyiron-resources/lammps/potentials/' prev_data_frame = pandas.read_csv(os.path.join(pyiron_pot_path, 'potentials_lammps.csv')) for f in os.listdir(potential_folder): if '.json' in f: with open(os.path.join(potential_folder, f), 'r') as potfile: pot_json = potfile.readlines() try: pot_json_str = ''.join(pot_json) potential = lmp.Potential(pot_json_str) if potential.id not in prev_data_frame['Name']: potential.load(pot_json_str, pot_dir=potential_folder) config_lst.append([l + '\n' for l in potential.pair_info().replace('NISTiprpy/', '').split('\n') if any([s in l for s in ['pair_style', 'pair_coeff']])]) species_lst.append(potential.symbols) pot_spec_folder = os.path.join(potential_folder, os.path.splitext(f)[0]) file_name_lst.append([os.path.join(pot_spec_folder, pot) for pot in os.listdir(pot_spec_folder)]) name_lst.append(potential.id) print(f, ' added') except json.decoder.JSONDecodeError: print(f, ' failed') model_lst = ['NISTiprpy'] * len(name_lst) new_data_frame = pandas.DataFrame({'Config': config_lst,
def create_relaxed_crystal_records(database_name, results=None, all_crystals_file=None): """ Generates new relaxed_crystal records based on the untransformed listings from the compiled relaxation results. Parameters ---------- database_name : str The name of the database to access. results : pandas.DataFrame, optional The compiled relaxation results. Either but not both of results and all_crystals_file must be given. all_crystals_file : str, optional The file path to the csv file where the compiled relaxation results are saved. Either but not both of results and all_crystals_file must be given. """ # Access the database database = load_database(database_name) # Load results from all_crystals_file if needed if results is None: if all_crystals_file is not None: results = pd.read_csv(all_crystals_file) else: raise TypeError('results or all_crystals_file must be given') elif all_crystals_file is not None: raise TypeError('results and all_crystals_file cannot both be given') # Filter out the transformed results results = results[~results.transformed] print(len(results), 'untransformed crystals found in the compiled relaxation results') # Load existing relaxed_crystal records from the database relaxed_records = database.get_records_df(style='relaxed_crystal', full=True, flat=False) print(len(relaxed_records), 'relaxed_crystal records found in the database') # Identify new results using parent_key (i.e. one relaxed_crystal per parent) newresults = results[~results.calc_key.isin(relaxed_records.parent_key)] print(f' - {len(newresults)} new results to add') # Load potential_LAMMPS records potential_records, potential_records_df = database.get_records( style='potential_LAMMPS', return_df=True) # Loop over all new records for i in newresults.index: series = newresults.loc[i] # Create new record key = str(uuid.uuid4()) record = load_record('relaxed_crystal', name=key) # Set simple properties input_dict = {} input_dict['key'] = key input_dict['method'] = series.method input_dict['family'] = series.family input_dict['parent_key'] = series.calc_key input_dict['length_unit'] = 'angstrom' input_dict['energy_unit'] = 'eV' input_dict['E_coh'] = series.E_coh # Set potential try: potential_record = potential_records[ potential_records_df[potential_records_df.key == series.potential_LAMMPS_key].index[0]] except: print( f'potential {series.potential_LAMMPS_id}({series.potential_LAMMPS_key}) not found for calculation {series.calc_key}' ) continue input_dict['potential'] = lmp.Potential(potential_record.content) # Set ucell # Use spg crystals for ref and α-As if (series.prototype[:3] == 'mp-' or series.prototype[:4] == 'mvc-' or series.prototype[:5] == 'oqmd-' or series.prototype == 'A7--alpha-As'): ucell = series.ucell # Use scaled prototype crystals for the rest else: ucell = series.ucell_family ucell.symbols = series.ucell.symbols ucell.box_set(vects=series.ucell.box.vects, scale=True) input_dict['ucell'] = ucell # Set standing as bad for structures with positive or near-zero energies if series.E_coh < -1e-5: input_dict['standing'] = 'good' else: input_dict['standing'] = 'bad' # Build content and upload record.buildcontent(input_dict) database.add_record(record=record)