Exemplo n.º 1
0
 def symmetry(self, symprec=1e-3):
     """ Compute space group with spglib. """
     from matador.utils.cell_utils import doc2spg
     import spglib as spg
     print('Refining symmetries...')
     if self.mode == 'display':
         print_warning('{}'.format('At symprec: ' + str(symprec)))
         print_warning("{:^36}{:^16}{:^16}".format('text_id', 'new sg', 'old sg'))
     for _, doc in enumerate(self.cursor):
         try:
             spg_cell = doc2spg(doc)
             sg = spg.get_spacegroup(spg_cell, symprec=symprec).split(' ')[0]
             if sg != doc['space_group']:
                 self.changed_count += 1
                 self.diff_cursor.append(doc)
                 if self.mode == 'display':
                     print_notify("{:^36}{:^16}{:^16}"
                                  .format(doc['text_id'][0]+' '+doc['text_id'][1], sg, doc['space_group']))
                 doc['space_group'] = sg
             else:
                 if self.mode == 'display':
                     print("{:^36}{:^16}{:^16}"
                           .format(doc['text_id'][0]+' '+doc['text_id'][1], sg, doc['space_group']))
         except Exception:
             self.failed_count += 1
             if self.args.get('debug'):
                 print_exc()
                 print_failure('Failed for' + ' '.join(doc['text_id']))
Exemplo n.º 2
0
    def spawn(self, join=False):
        """ Spawn processes to perform calculations.

        Keyword arguments:
            join (bool): whether or not to attach to ComputeTask
                process. Useful for testing.

        """
        procs = []
        error_queue = mp.Queue()
        for proc_id in range(self.nprocesses):
            procs.append(
                mp.Process(target=self.perform_new_calculations,
                           args=(random.sample(self.file_lists['res'],
                                               len(self.file_lists['res'])),
                                 error_queue, proc_id)))
        for proc in procs:
            proc.start()
            if join:
                proc.join()

        errors = []
        failed_seeds = []

        # wait for each proc to write to error queue
        try:
            for _, proc in enumerate(procs):
                result = error_queue.get()
                if isinstance(result[1], Exception):
                    errors.append(result)
                    failed_seeds.append(result[2])

            if errors:
                error_message = ''
                for error in errors:
                    error_message += 'Process {} raised error(s): {}. '.format(
                        error[0], error[1])
                    if len({type(error[1]) for error in errors}) == 1:
                        raise errors[0][1]
                    raise type(errors[0][1])(error_message)
                raise BundledErrors(error_message)
        # the only errors that reach here are fatal, e.g. WalltimeError, CriticalError, InputError, KeyboardInterrupt
        except RuntimeError as err:
            result = [proc.join(timeout=2) for proc in procs]
            result = [proc.terminate() for proc in procs if proc.is_alive()]
            print_failure('Fatal error(s) reported:')
            print_warning(err)
            raise err

        print('Nothing left to do.')
Exemplo n.º 3
0
    def wrapped_plot_function(*args, **kwargs):
        """ Wrap and return the plotting function. """
        saving = False
        result = None

        # if we're going to be saving a figure, switch to Agg to avoid X-forwarding
        try:
            for arg in args:
                if arg.savefig:
                    import matplotlib
                    # don't warn as backend might have been set externally by e.g. Jupyter
                    matplotlib.use('Agg', force=False)
                    saving = True
                    break
        except AttributeError:
            pass
        if not saving:
            if any(kwargs.get(ext) for ext in SAVE_EXTS):
                import matplotlib
                matplotlib.use('Agg', force=False)
                saving = True

        settings = load_custom_settings(kwargs.get('config_fname'), quiet=True, no_quickstart=True)
        try:
            style = settings.get('plotting', {}).get('default_style')
            if kwargs.get('style'):
                style = kwargs['style']
            if style is not None and not isinstance(style, list):
                style = [style]
            if style is None:
                style = ['matador']
            if 'matador' in style:
                for ind, styles in enumerate(style):
                    if styles == 'matador':
                        style[ind] = MATADOR_STYLE

            # now actually call the function
            set_style(style)
            result = function(*args, **kwargs)

        except Exception as exc:
            if 'TclError' not in type(exc).__name__:
                raise exc

            print_failure('Caught exception: {}'.format(type(exc).__name__))
            print_warning('Error message was: {}'.format(exc))
            print_warning('This is probably an X-forwarding error')
            print_failure('Skipping plot...')

        return result
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    def make_recipe(self, structure, sg):
        """ Construct PDF with diffpy. """

        # construct a PDFContribution object
        pdf = PDFContribution("Contribution")
        # read experimental data
        try:
            pdf.loadData(self.input_file)
        except:
            print_failure('Failed to parse ' + self.input_file +
                          '. Exiting...')
            exit()

        print('Constructing PDF object for', structure.title)

        pdf.setCalculationRange(self.xmin, self.xmax, self.dx)
        pdf.addStructure("Contribution", structure)

        # create FitRecipe to calculate PDF with chosen fit variable
        fit = FitRecipe()
        fit.addContribution(pdf)
        # configure variables and add to recipe
        if sg != 'xxx' and sg is not None:
            print(sg)
            spacegroup_params = constrainAsSpaceGroup(pdf.Contribution.phase,
                                                      sg)
        else:
            cart_lat = abc2cart([[
                structure.lattice.a, structure.lattice.b, structure.lattice.c
            ],
                                 [
                                     structure.lattice.alpha,
                                     structure.lattice.beta,
                                     structure.lattice.gamma
                                 ]])
            positions_frac = structure.xyz
            atomic_numbers = []
            for atom in structure.element:
                atomic_numbers.append(get_atomic_number(atom))
            cell = (cart_lat, positions_frac, atomic_numbers)
            sg = int(
                spg.get_spacegroup(cell, symprec=1e-2).split(' ')[1].replace(
                    '(', '').replace(')', ''))
            spacegroup_params = constrainAsSpaceGroup(pdf.Contribution.phase,
                                                      sg)
        # print('Space group parameters:')
        # print(', '.join([param.name for param in spacegroup_params]))
        # iterate through spacegroup params and activate them
        for param in spacegroup_params.latpars:
            fit.addVar(param)
        for param in spacegroup_params.xyzpars:
            fit.addVar(param, fixed=True)
        # these next parameters are taken from Martin's PDFht.py,
        # though I have a feeling that was not their origin...
        # set initial ADP parameters
        for param in spacegroup_params.adppars:
            fit.addVar(param, value=0.03, fixed=True)
        # overall scale of PDF and delta2 parameter for correlated motion - from PDFht.py
        fit.addVar(pdf.scale, 1, fixed=True)
        fit.restrain(pdf.scale, lb=0, ub=0.1, scaled=True)
        fit.addVar(pdf.Contribution.delta2, 5, fixed=True)
        fit.restrain(pdf.Contribution.delta2, lb=1, ub=10, scaled=True)
        # fix Qdamp based on information about "our beamline": yep, no idea
        fit.addVar(pdf.qdamp, 0.03, fixed=True)
        fit.restrain(pdf.qdamp, lb=0, ub=0.1, scaled=True)

        return fit