def diff_hulls(client, collections, **args): """ Helper function to diff hulls from cmd-line args. Parameters: client (MongoClient): connection to database collections (dict of Collection): dict of collections to query Keyword arguments: args: dict, command-line arguments to select hulls. """ from matador.query import DBQuery from matador.hull import QueryConvexHull diff_args = args['compare'] del args['compare'] args['no_plot'] = True if args.get('verbosity') in [0, None] and not args.get('debug'): args['quiet'] = True diff_args = sorted(diff_args) args['time'] = diff_args[0] print('Calculating hull {} days ago...'.format(args['time'])) query_old = DBQuery(client, collections, **args) hull_old = QueryConvexHull(query_old, **args) if len(diff_args) == 1 or isinstance(diff_args, str): args['time'] = '0' else: args['time'] = diff_args[1] if args['time'] == '0': print('... to compare with up-to-date hull.') else: print('... to compare with hull {} days ago.'.format(args['time'])) query_new = DBQuery(client, collections, **args) hull_new = QueryConvexHull(query_new, **args) HullDiff(hull_old, hull_new, **args)
def import_res(): """ Import from res files, returning data to be checked. """ # import from combined res/cell/param files os.chdir(REAL_PATH + "/data/res_files") sys.argv = ["matador", "import", "--force", "--db", DB_NAME] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] if DEBUG: sys.argv += ["--debug"] matador.cli.cli.main(no_quickstart=True) query_1 = DBQuery(db=DB_NAME, config=CONFIG_FNAME, details=True, source=True) query_2 = DBQuery(db=DB_NAME, composition="KSnP", config=CONFIG_FNAME, details=True, source=True) files_to_delete = glob.glob("*spatula*") for f in files_to_delete: os.remove(f) os.chdir(OUTPUT_DIR) return query_1, query_2
def pseudoternary_hull(): """ Import some other res files ready to make a hull. """ os.chdir(REAL_PATH + "/data/hull-LLZO") sys.argv = ["matador", "import", "--force", "--db", DB_NAME] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] if DEBUG: sys.argv += ["--debug"] matador.cli.cli.main(no_quickstart=True) query = DBQuery( db=DB_NAME, subcmd="hull", composition="La2O3:Li2O:ZrO2", config=CONFIG_FNAME, details=True, source=True, no_plot=True, ) hull = QueryConvexHull(query=query) os.chdir(OUTPUT_DIR) return query, hull
def test_binary_from_fake_query(self): cursor, s = res2dict(REAL_PATH + "data/hull-KP-KSnP_pub/*.res") print() print(80 * "-") self.assertEqual( len(cursor), 295, "Error with test res files, please check installation...") hull = QueryConvexHull(cursor=cursor, elements=["KP"], no_plot=True) self.assertEqual(len(hull.cursor), 295) self.assertEqual(len(hull.hull_cursor), 7) fake_query = DBQuery.__new__(DBQuery) fake_query.cursor = hull.cursor for ind, doc in enumerate(fake_query.cursor): fake_query.cursor[ind]["_id"] = None fake_query.cursor[ind]["text_id"] = [doc["source"][0], "."] del fake_query.cursor[ind]["hull_distance"] del fake_query.cursor[ind]["concentration"] fake_query._non_elemental = False fake_query._create_hull = True fake_query.args = dict() fake_query.args["intersection"] = False fake_query.args["subcmd"] = "hull" fake_query.args["composition"] = ["KP"] hull = QueryConvexHull(query=fake_query, chempots=[-791.456765, -219.58161025], no_plot=True) # now need to include custom chempots in counts self.assertEqual(len(hull.cursor), 297) self.assertEqual(len(hull.hull_cursor), 9)
def test_pseudoternary_from_fake_query(self): cursor, s = res2dict(REAL_PATH + "data/hull-LLZO/*.res") print() print(80 * "-") self.assertEqual( len(cursor), 12, "Error with test res files, please check installation...") hull = QueryConvexHull(cursor=cursor, elements=["La2O3", "ZrO2", "Li2O"], no_plot=True) self.assertEqual(len(hull.cursor), 7) fake_query = DBQuery.__new__(DBQuery) fake_query.cursor = hull.cursor for ind, doc in enumerate(fake_query.cursor): fake_query.cursor[ind]["_id"] = None fake_query.cursor[ind]["text_id"] = [doc["source"][0], "."] fake_query._non_elemental = True fake_query._create_hull = True fake_query.args = dict() fake_query.args["intersection"] = True fake_query.args["subcmd"] = "hull" fake_query.args["composition"] = ["La2O3:ZrO2:Li2O"] hull = QueryConvexHull( query=fake_query, hull_cutoff=0.01, chempots=[26200.3194 / 40, -8715.94784 / 12, -3392.59361 / 12], no_plot=True, ) self.assertEqual(len(hull.cursor), 10) self.assertEqual(len(hull.hull_cursor), 9)
def changes(): """ Test matador changes functionality by undoing the second change (i.e. the res import). """ sys.argv = ["matador", "changes", "--db", DB_NAME, "-c", "2", "--undo"] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) query_1 = DBQuery(db=DB_NAME, config=CONFIG_FNAME) query_2 = DBQuery(db=DB_NAME, composition="KSnP", config=CONFIG_FNAME) changes_count = MONGO_CLIENT.crystals["__changelog_" + DB_NAME].count_documents({}) return query_1, query_2, changes_count
def id_query(): """ Test a simple ID query, and that nothing is found... """ sys.argv = ["matador", "query", "--db", DB_NAME, "-i", "testing testing"] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) query = DBQuery(db=DB_NAME, config=CONFIG_FNAME, id="testing testing") return query
def import_castep(extra_flags=None): """ Import from castep files, returning data to be checked. """ # import from CASTEP files only os.chdir(REAL_PATH + "/data/castep_files") sys.argv = ["matador", "import", "--force", "--db", DB_NAME] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] if DEBUG: sys.argv += ["--debug"] matador.cli.cli.main(no_quickstart=True) query = DBQuery(db=DB_NAME, config=CONFIG_FNAME, details=True, source=True) files_to_delete = glob.glob("*spatula*") for f in files_to_delete: os.remove(f) os.chdir(OUTPUT_DIR) return query
def __init__(self, *args, **kwargs): """ Initialise the query with command line arguments and return results. """ # read args self.kwargs = kwargs self.args = vars(args[0]) self.args['no_quickstart'] = self.kwargs.get('no_quickstart') self.argstr = kwargs.get('argstr') file_exts = ['cell', 'res', 'pdb', 'markdown', 'latex', 'param', 'xsf'] self.export = any([self.args.get(ext) for ext in file_exts]) self.subcommand = self.args.pop("subcmd") if self.subcommand != 'import': self.settings = load_custom_settings( config_fname=self.args.get('config'), debug=self.args.get('debug'), no_quickstart=self.args.get('no_quickstart')) result = make_connection_to_collection( self.args.get('db'), check_collection=(self.subcommand != "stats"), mongo_settings=self.settings) self.client, self.db, self.collections = result if self.subcommand == 'stats': self.stats() try: if self.subcommand == 'import': from matador.db import Spatula self.importer = Spatula(self.args) if self.subcommand == 'query': self.query = DBQuery(self.client, self.collections, **self.args) self.cursor = self.query.cursor if self.subcommand == 'swaps': from matador.swaps import AtomicSwapper self.query = DBQuery(self.client, self.collections, **self.args) if self.args.get('hull_cutoff') is not None: self.hull = QueryConvexHull(query=self.query, **self.args) self.swapper = AtomicSwapper(self.hull.hull_cursor, **self.args) else: self.swapper = AtomicSwapper(self.query.cursor, **self.args) self.cursor = self.swapper.cursor if self.subcommand == 'refine': from matador.db import Refiner self.query = DBQuery(self.client, self.collections, **self.args) if self.args.get('hull_cutoff') is not None: self.hull = QueryConvexHull(self.query, **self.args) self.refiner = Refiner(self.hull.cursor, self.query.repo, **self.args) else: self.refiner = Refiner(self.query.cursor, self.query.repo, **self.args) self.cursor = self.refiner.cursor if self.subcommand == 'hull' or self.subcommand == 'voltage': self.hull = QueryConvexHull(**self.args, voltage=self.subcommand == 'voltage', client=self.client, collections=self.collections) self.cursor = self.hull.hull_cursor if self.subcommand == 'changes': from matador.db import DatabaseChanges if len(self.collections) != 1: raise SystemExit( 'Cannot view changes of more than one collection at once.' ) if self.args.get('undo'): action = 'undo' else: action = 'view' changeset = self.args.get('changeset') if changeset is None: changeset = 0 DatabaseChanges([key for key in self.collections][0], changeset_ind=changeset, action=action, mongo_settings=self.settings, override=kwargs.get('no_quickstart')) if self.subcommand == 'hulldiff': from matador.hull.hull_diff import diff_hulls if self.args.get('compare') is None: raise SystemExit( 'Please specify which hulls to query with --compare.') diff_hulls(self.client, self.collections, **self.args) if self.export and self.cursor: from matador.export import query2files if self.args.get('write_n') is not None: self.cursor = [ doc for doc in self.cursor if len(doc['stoichiometry']) == self.args.get('write_n') ] if not self.cursor: print_failure('No structures left to export.') query2files(self.cursor, **self.args, argstr=self.argstr, subcmd=self.subcommand, hash_dupe=True) if self.args.get('view'): from matador.utils.viz_utils import viz if self.args.get('top') is None: self.top = len(self.cursor) else: self.top = self.args.get('top') if len(self.cursor[:self.top]) > 10: from time import sleep print_warning( 'WARNING: opening {} files with ase-gui...'.format( len(self.cursor))) print_warning( 'Please kill script within 3 seconds if undesired...') sleep(3) if len(self.cursor[:self.top]) > 20: print_failure( 'You will literally be opening that many windows, ' + 'I\'ll give you another 5 seconds to reconsider...') sleep(5) print_notify('It\'s your funeral...') sleep(1) for doc in self.cursor[:self.top]: viz(doc) if self.subcommand != 'import': self.client.close() except (RuntimeError, SystemExit, KeyboardInterrupt) as oops: if isinstance(oops, RuntimeError): print_failure(oops) elif isinstance(oops, SystemExit): print_warning(oops) try: self.client.close() except AttributeError: pass raise oops
def __init__(self, query=None, cursor=None, elements=None, species=None, voltage=False, volume=False, subcmd=None, plot_kwargs=None, lazy=False, energy_key='enthalpy_per_atom', client=None, collections=None, db=None, **kwargs): """ Initialise the class from either a DBQuery or a cursor (list of matador dicts) and construct the appropriate phase diagram. Keyword arguments: query (matador.query.DBQuery): object containing structures, cursor (list(dict)): alternatively specify list of matador documents. species (list(str)): list of elements/chempots to use, used to provide a useful order, voltage (bool): whether or nto to compute voltages relative for insertion of first entry in species, volume (bool): whether or not to compute volume expansion relative to first entry in species, energy_key (str): key under which the desired energy *per atom* is stored. lazy (bool): if True, do not create hull until `self.create_hull()` is called chempots (list(float)): list of chemical potential values to use. elements (list(str)): deprecated form `species`. kwargs (dict): mostly CLI arguments, see matador hull --help for full options. plot_kwargs (dict): arguments to pass to plot_hull function client (pymongo.MongoClient): optional client to pass to DBQuery. collections (dict of pymongo.collections.Collection): optional dict of collections to pass to DBQuery. db (str): db name to connect to in DBQuery. """ self.args = dict() if query is not None: self.args.update(query.args) self.args.update(kwargs) if subcmd is not None: warnings.warn("subcmd will soon be deprecated, please pass the equivalent flag as a kwarg (e.g. voltage=True)") if subcmd == 'voltage': voltage = True self.args['subcmd'] = subcmd if plot_kwargs is None: plot_kwargs = {} self.args['plot_kwargs'] = plot_kwargs self.from_cursor = False self.plot_params = False self.compute_voltages = voltage self.compute_volumes = volume if query is None and cursor is None: # if no query or cursor passed, push all kwargs to new query from matador.query import DBQuery kwargs.pop('intersection', None) query = DBQuery( subcmd='hull', intersection=True, client=client, collections=collections, **kwargs ) self._query = query if self._query is not None: # this isn't strictly necessary but it maintains the sanctity of the query results self.cursor = list(deepcopy(query.cursor)) self.args['use_source'] = False if self._query.args['subcmd'] not in ['hull', 'voltage', 'hulldiff']: print_warning('Query was not prepared with subcmd=hull, so cannot guarantee consistent formation energies.') else: self.cursor = list(cursor) self.from_cursor = True self.args['use_source'] = True # set up attributes for later self.structures = None self.convex_hull = None self.chempot_cursor = None self.hull_cursor = None self.phase_diagram = None self.hull_dist = None self.species = None self.voltage_data: List[VoltageProfile] = [] self.volume_data = defaultdict(list) self.elements = [] self.num_elements = 0 self.species = self._get_species(species, elements) self._dimension = len(self.species) # tracker for whether per_b fields have been setup self._per_b_done = False self.energy_key = energy_key if not self.energy_key.endswith('_per_atom'): warnings.warn('Appending per_atom to energy_key {}'.format(self.energy_key)) self.energy_key += '_per_atom' self._extensive_energy_key = self.energy_key.split('_per_atom')[0] if self.args.get('hull_cutoff') is not None: self.hull_cutoff = float(self.args['hull_cutoff']) else: self.hull_cutoff = 0.0 if self.cursor is None: raise RuntimeError('Failed to find structures to create hull!') self._non_elemental = False assert isinstance(self.species, list) for _species in self.species: if len(parse_element_string(_species, stoich=True)) > 1: self._non_elemental = True if not lazy: self.create_hull()
def refine(): """ Test various matador refine tasks. """ sys.argv = [ "matador", "refine", "--db", DB_NAME, "--task", "sym", "--mode", "overwrite", ] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) sys.argv = [ "matador", "refine", "--db", DB_NAME, "--task", "source", "--mode", "set", ] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) sys.argv = [ "matador", "refine", "--db", DB_NAME, "--task", "doi", "--mode", "set", "--new_doi", "10/12345", ] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) sys.argv = [ "matador", "refine", "--db", DB_NAME, "--task", "tag", "--mode", "overwrite", "--new_tag", "integration_test", ] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) sys.argv = [ "matador", "refine", "--db", DB_NAME, "--task", "pspot", "--mode", "overwrite", ] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) sys.argv = [ "matador", "refine", "--db", DB_NAME, "--task", "raw", "--mode", "overwrite", ] if CONFIG_FNAME is not None: sys.argv += ["--config", CONFIG_FNAME] matador.cli.cli.main(no_quickstart=True) query = DBQuery(db=DB_NAME, config=CONFIG_FNAME) return query
vornet = VoronoiNetwork(filename='Vropple.res') if debug: print(vornet.struc) vornet.computeVorNet() doc['voronoi_nodes'] = vornet.getNodeFracPos() doc['voronoi_face_midpoints'] = vornet.getFracFaceMidpoints() doc['voronoi_edge_midpoints'] = vornet.getFracEdgeMidpoints() if isfile('Vropple.res'): remove('Vropple.res') return doc['voronoi_nodes'] except: if isfile('Vropple.res'): remove('Vropple.res') return False if __name__ == '__main__': from matador.query import DBQuery from matador.hull import QueryConvexHull # test with LiAs query = DBQuery(composition=['LiAs'], subcmd='hull') hull = QueryConvexHull(query, no_plot=True, hull_cutoff=0) hull_cursor = hull.hull_cursor most_lithiated = hull_cursor[-2] most_lithiated_substruc = get_voronoi_substructure(most_lithiated) other_substruc = [] for doc in hull_cursor: other_substruc.append(get_voronoi_substructure(doc)) print(other_substruc) print(most_lithiated_substruc)
#!/usr/bin/env python """ This example runs directly from a matador DBQuery. """ from matador.query import DBQuery from matador.hull import QueryConvexHull from matador.fingerprints.similarity import get_uniq_cursor from ilustrado.ilustrado import ArtificialSelector # prepare best structures from hull as gene pool query = DBQuery(composition=['KPSn'], db=['KP'], cutoff=[300, 301], intersection=True, kpoint_tolerance=0.03, subcmd='hull', biggest=True) hull = QueryConvexHull(query, intersection=True, subcmd='hull', no_plot=True, kpoint_tolerance=0.03, summary=True, hull_cutoff=7.5e-2) print('Filtering down to only ternary phases... {}'.format( len(hull.hull_cursor))) hull.hull_cursor = [ doc for doc in hull.hull_cursor if len(doc['stoichiometry']) == 3 ] print('Filtering unique structures... {}'.format(len(hull.hull_cursor))) uniq_list, _, _, _ = list(get_uniq_cursor(hull.hull_cursor[1:-1], debug=False)) cursor = [hull.hull_cursor[1:-1][ind] for ind in uniq_list]