def save_muairss_batch(args, global_params): structures_path = args.structures all_files = glob.glob(os.path.join(structures_path, "*")) structure_files = [ path for path in all_files if not os.path.splitext(path)[1] == '.yaml' ] global_params['out_folder'] = safe_create_folder( global_params['out_folder']) print("Beginning creation of {} structures".format(len(structure_files))) for path in structure_files: name = parse_structure_name(path) parameter_file = os.path.join(structures_path, "{}.yaml".format(name)) if not os.path.isfile(parameter_file): parameter_file = None struct = io.read(path) params = dict(global_params) # Copy params['name'] = name if parameter_file is not None: params = load_input_file(parameter_file, MuAirssSchema, merge=params) params['out_folder'] = params['name'] print("Making {} ---------------------".format(name)) save_muairss_collection(struct, params, batch_path=global_params['out_folder']) print("Done!")
def save_muairss_collection(struct, params, batch_path=""): """Generate input files for a single structure and configuration file""" dc = generate_muairss_collection(struct, params) # Just to keep track, add the parameters used to the collection dc.info["muairss_params"] = dict(params) # Output folder out_path = safe_create_folder(os.path.join(batch_path, params["out_folder"])) if not out_path: raise RuntimeError("Could not create folder {0}") io_formats = { "castep": ReadWriteCastep, "dftb+": ReadWriteDFTB, "uep": ReadWriteUEP, } calcs = [s.strip().lower() for s in params["calculator"].split(",")] if "all" in calcs: calcs = io_formats.keys() # Save LICENSE file for DFTB+ parameters if "dftb+" in calcs: from pymuonsuite.data.dftb_pars import get_license with open(os.path.join(out_path, "dftb.LICENSE"), "w") as f: f.write(get_license()) for cname in calcs: rw = io_formats[cname](params, script=params.get("script_file")) calc_path = os.path.join(out_path, cname) dc.save_tree( calc_path, rw.write, name_root=params["name"], opt_args={"calc_type": "GEOM_OPT"}, safety_check=2, ) # Do we also save a collective structure? allf = params["allpos_filename"] if allf is not None: alls = struct.copy() csp = struct.get_chemical_symbols() for atoms in dc: # We rely on the fact the muon is always put at the end mu = atoms[-1] alls.append(mu) csp += [params["mu_symbol"]] alls.set_array("castep_custom_species", np.array(csp)) with silence_stdio(True, True): io.write(allf, alls)
def save_muairss_collection(struct, params, batch_path=''): """Generate input files for a single structure and configuration file""" dc = generate_muairss_collection(struct, params) # Just to keep track, add the parameters used to the collection dc.info['muairss_params'] = dict(params) # Output folder out_path = os.path.join(batch_path, params['out_folder']) if not safe_create_folder(out_path): raise RuntimeError('Could not create folder {0}') # Now save in the appropriate format save_formats = { 'castep': castep_write_input, 'dftb+': dftb_write_input, 'uep': uep_write_input } # Which calculators? calcs = [s.strip().lower() for s in params['calculator'].split(',')] if 'all' in calcs: calcs = save_formats.keys() # Make the actual calculators make_calcs = { 'castep': create_muairss_castep_calculator, 'dftb+': create_muairss_dftb_calculator, 'uep': create_muairss_uep_calculator } calcs = { c: make_calcs[c](struct, params=params, calc=struct.calc) for c in calcs } # Save LICENSE file for DFTB+ parameters if 'dftb+' in calcs: from pymuonsuite.data.dftb_pars import get_license with open(os.path.join(out_path, 'dftb.LICENSE'), 'w') as f: f.write(get_license()) for cname, calc in calcs.items(): calc_path = os.path.join(out_path, cname) dc.save_tree(calc_path, save_formats[cname], name_root=params['name'], opt_args={ 'calc': calc, 'script': params['script_file'] }, safety_check=2)
def muairss_batch_io(args, global_params, save=False): structures_path = args.structures all_files = glob.glob(os.path.join(structures_path, "*")) structure_files = [ path for path in all_files if not os.path.splitext(path)[1] == ".yaml" ] if save: global_params["out_folder"] = safe_create_folder(global_params["out_folder"]) print( "Beginning {0} of {1} structures".format( "creation" if save else "loading", len(structure_files) ) ) bpath = global_params["out_folder"] loaded = {} for path in structure_files: name = parse_structure_name(path) parameter_file = os.path.join(structures_path, "{}.yaml".format(name)) if not os.path.isfile(parameter_file): parameter_file = None with silence_stdio(): struct = io.read(path) params = dict(global_params) # Copy params["name"] = name if parameter_file is not None: params = load_input_file(parameter_file, MuAirssSchema, merge=params) params["out_folder"] = params["name"] if save: print("Making {} ---------------------".format(name)) save_muairss_collection(struct, params, batch_path=bpath) else: print("Loading {} ---------------------".format(name)) coll = load_muairss_collection(struct, params, batch_path=bpath) loaded[name] = {"struct": struct, "collection": coll} print("Done!") if not save: return loaded
def write_cluster_report(args, params, clusters): if params['clustering_method'] == 'hier': clustinfo = """ Clustering method: Hierarchical t = {t} """.format(t=params['clustering_hier_t']) elif params['clustering_method'] == 'kmeans': clustinfo = """ Clustering method: k-Means k = {k} """.format(k=params['clustering_kmeans_k']) with open(params['name'] + '_clusters.txt', 'w') as f: f.write(""" **************************** | | | MUAIRSS | | Clustering report | | | **************************** Name: {name} Date: {date} Structure file(s): {structs} Parameter file: {param} {clustinfo} ******************* """.format(name=params['name'], date=datetime.now(), structs=args.structures, param=args.parameter_file, clustinfo=clustinfo)) for name, cdata in clusters.items(): f.write('Clusters for {0}:\n'.format(name)) if params['clustering_save_min'] is not None or \ params['clustering_save_type'] is not None: if params['clustering_save_folder'] is not None: clustering_save_path = safe_create_folder( params['clustering_save_folder']) else: clustering_save_path = safe_create_folder( '{0}_clusters'.format(params['name'])) if not clustering_save_path: raise RuntimeError('Could not create folder {0}') for calc, clusts in cdata.items(): # Computer readable fdat = open( params['name'] + '_{0}_{1}_clusters.dat'.format(name, calc), 'w') f.write('CALCULATOR: {0}\n'.format(calc)) (cinds, cgroups), ccolls, gvecs = clusts f.write('\t{0} clusters found\n'.format(max(cinds))) min_energy_structs = [] for i, g in enumerate(cgroups): f.write('\n\n\t-----------\n\tCluster ' '{0}\n\t-----------\n'.format(i + 1)) f.write('\tStructures: {0}\n'.format(len(g))) coll = ccolls[i + 1] E = gvecs[g, 0] Emin = np.amin(E) Eavg = np.average(E) Estd = np.std(E) f.write('\n\tEnergy (eV):\n') f.write('\tMinimum\t\tAverage\t\tStDev\n') f.write('\t{0:.2f}\t\t{1:.2f}\t\t{2:.2f}\n'.format( Emin, Eavg, Estd)) fdat.write('\t'.join( map(str, [ i + 1, len(g), Emin, Eavg, Estd, coll[np.argmin( E)].structures[0].positions[-1][0], coll[np.argmin(E)].structures[0].positions[-1][1], coll[np.argmin(E)].structures[0].positions[-1][2] ])) + '\n') f.write('\n\tMinimum energy structure: {0}\n'.format( coll[np.argmin(E)].structures[0].info['name'])) # Save minimum energy structure if params['clustering_save_type'] == 'structures' or \ params['clustering_save_min']: # For backwards-compatability with old pymuonsuite # versions if params['clustering_save_min']: if params['clustering_save_format'] is None: params['clustering_save_format'] = 'cif' try: calc_path = os.path.join(clustering_save_path, calc) if not os.path.exists(calc_path): os.mkdir(calc_path) fname = ('{0}_{1}_min_cluster_' '{2}.{3}'.format( params['name'], calc, i + 1, params['clustering_save_format'])) with silence_stdio(): io.write(os.path.join(calc_path, fname), coll[np.argmin(E)].structures[0]) except (io.formats.UnknownFileTypeError) as e: print("ERROR: File format '{0}' is not " "recognised. Modify 'clustering_save_format'" " and try again.".format(e)) return except ValueError as e: print("ERROR: {0}. Modify 'clustering_save_format'" "and try again.".format(e)) return min_energy_structs.append(coll[np.argmin(E)].structures[0]) f.write('\n\n\tStructure list:') for j, s in enumerate(coll): if j % 4 == 0: f.write('\n\t') f.write('{0}\t'.format(s.info['name'])) fdat.close() if params['clustering_save_type'] == 'input': calc_path = os.path.join(clustering_save_path, calc) sname = "{0}_min_cluster".format(params['name']) io_formats = { 'castep': ReadWriteCastep, 'dftb+': ReadWriteDFTB, } try: write_method = io_formats[ params['clustering_save_format']](params).write except KeyError as e: print("ERROR: Calculator type {0} is not " "recognised. Modify 'clustering_save_format'" " to be one of: {1}".format( e, list(io_formats.keys()))) return if params['clustering_save_format'] == 'dftb+': from pymuonsuite.data.dftb_pars import get_license with open( os.path.join(clustering_save_path, 'dftb.LICENSE'), 'w') as license_file: license_file.write(get_license()) min_energy_structs = AtomsCollection(min_energy_structs) # here we remove the structure's name so the original # numbering of the structs is removed: for i, a in enumerate(min_energy_structs): min_energy_structs.structures[i].info.pop('name', None) min_energy_structs.save_tree( calc_path, write_method, name_root=sname, opt_args={'calc_type': 'GEOM_OPT'}, safety_check=2) # Print distance matrix f.write('\n\n\t----------\n\n\tSimilarity (ranked):\n') centers = np.array( [np.average(gvecs[g], axis=0) for g in cgroups]) dmat = np.linalg.norm(centers[:, None] - centers[None, :], axis=-1) inds = np.triu_indices(len(cgroups), k=1) for i in np.argsort(dmat[inds]): c1 = inds[0][i] c2 = inds[1][i] d = dmat[c1, c2] f.write('\t{0} <--> {1} (distance = {2:.3f})\n'.format( c1 + 1, c2 + 1, d)) f.write('\n--------------------------\n\n') f.write('\n==========================\n\n')