示例#1
0
 def calculate_phonons(self):
     self.ctx.inputs.crystal.structure = self.ctx.optimise.outputs.output_structure
     self.ctx.inputs.crystal.parameters = get_data_class('dict')(dict=self.ctx.crystal_parameters.phonons)
     self.ctx.inputs.crystal.options = get_data_class('dict')(
         dict=self.construct_metadata(PHONON_LABEL))
     crystal_run = self.submit(BaseCrystalWorkChain, **self.ctx.inputs.crystal)
     return self.to_context(phonons=crystal_run)
示例#2
0
    def define(cls, spec):
        super(BasePropertiesWorkChain, cls).define(spec)

        # define inputs
        spec.input('code', valid_type=Code)
        spec.input('wavefunction',
                   valid_type=get_data_class('singlefile'),
                   required=True)
        spec.input('parameters',
                   valid_type=get_data_class('dict'),
                   required=True)
        spec.input('options',
                   valid_type=get_data_class('dict'),
                   required=True,
                   help="Calculation options")

        # define workchain routine
        spec.outline(cls.init_calculation, cls.run_calculation,
                     cls.retrieve_results)

        # define outputs
        spec.output('output_bands',
                    valid_type=get_data_class('array.bands'),
                    required=False)
        spec.output('output_dos',
                    valid_type=get_data_class('array'),
                    required=False)
示例#3
0
    def calculate_elastic_constants(self):
        if self.ctx.need_elastic_constants:
            # run elastic calc with optimised structure
            self.ctx.inputs.crystal.structure = self.ctx.optimise.outputs.output_structure
            options = self.construct_metadata(ELASTIC_LABEL)
            if "oxidation_states" in self.ctx.optimise.outputs:
                options["use_oxidation_states"] = self.ctx.optimise.outputs.oxidation_states.get_dict()
            self.ctx.inputs.crystal.parameters = get_data_class('dict')(
                dict=self.ctx.crystal_parameters.elastic_constants)
            self.ctx.inputs.crystal.options = get_data_class('dict')(dict=options)
            crystal_run = self.submit(BaseCrystalWorkChain, **self.ctx.inputs.crystal)
            return self.to_context(elastic_constants=crystal_run)

        else:
            self.logger.warning("Skipping elastic constants calculation")
示例#4
0
def listfamilies(element, list_pks, with_description):
    """List available families of CRYSTAL Basis Set files."""

    basis_family_cls = get_data_class('crystal_dft.basis_family')
    bases, groups = basis_family_cls.get_families(filter_elements=element)
    table = [['Family', 'Num Basis Sets']]
    if with_description:
        table[0].append('Description')
    if list_pks:
        table[0].append('Pks')
    for basis in bases:
        row = [basis.name, '--']
        if with_description:
            row.append('Predefined')
        if list_pks:
            row.append('')
        table.append(row)
    for group in groups:
        row = [group.label, len(group.nodes)]
        if with_description:
            row.append(group.description)
        if list_pks:
            row.append(",".join([str(n.pk) for n in group.nodes]))
        table.append(row)
    if len(table) > 1:
        click.echo(tabulate.tabulate(table, headers='firstrow'))
        click.echo()
    elif element:
        click.echo(
            'No Basis Set family contains all given elements and symbols.')
    else:
        click.echo('No Basis Set family available.')
示例#5
0
def createpredefined():
    """Create predefined basis families"""
    basis_family_cls = get_data_class('crystal_dft.basis_family')
    with cli_spinner():
        created = basis_family_cls.create_predefined()
    msg = 'Created {} predefined basis families'.format(len(created))
    if created:
        msg += ':\n{}'.format(', '.join(created))
    click.echo(msg)
示例#6
0
    def define(cls, spec):
        super(RunCryWorkChain, cls).define(spec)

        # define inputs
        spec.input('crystal_code', valid_type=Code)
        spec.input('properties_code', valid_type=Code)
        spec.expose_inputs(BaseCrystalWorkChain, include=['structure', 'basis_family'])
        spec.input('crystal_parameters', valid_type=get_data_class('parameter'), required=True)
        spec.input('properties_parameters', valid_type=get_data_class('parameter'), required=True)
        spec.input('options', valid_type=get_data_class('parameter'), required=True, help="Calculation options")

        # define workchain routine
        spec.outline(cls.init_inputs,
                     cls.run_crystal_calc,
                     cls.run_properties_calc,
                     cls.retrieve_results)

        # define outputs
        spec.expose_outputs(BaseCrystalWorkChain)
        spec.expose_outputs(BasePropertiesWorkChain)
示例#7
0
def uploadfamily(path, ext, name, description):
    """Upload a family of CRYSTAL Basis Set files."""
    basis_family_cls = get_data_class('crystal_dft.basis_family')
    with cli_spinner():
        nfiles, created, uploaded = basis_family_cls.upload(
            name,
            path,
            extension=".{}".format(ext),
            description=description
            )

    msg = 'Basis set files found: {}, out of them uploaded: {}'.format(nfiles, len(uploaded))
    if uploaded:
        msg += ' (for elements: {})'.format(', '.join(sorted(list(uploaded))))
    msg += ' to {}basis family {}'.format('newly created ' if created else '', name)
    click.echo(msg)
示例#8
0
    def get_geometry(self):
        """ Getting geometry from MPDS database
        """
        key = os.getenv('MPDS_KEY')
        client = MPDSDataRetrieval(api_key=key, verbose=False)
        query_dict = self.inputs.mpds_query.get_dict()

        # Add direct structures submitting support: FIXME
        assert query_dict or self.inputs.struct_in
        if not query_dict:
            return self.inputs.struct_in

        # insert props: atomic structure to query. Might check if it's already set to smth
        query_dict['props'] = 'atomic structure'
        try:
            answer = client.get_data(
                query_dict,
                fields={'S': [
                    'cell_abc',
                    'sg_n',
                    'basis_noneq',
                    'els_noneq'
                ]}
            )
        except APIError as ex:
            if ex.code == 429:
                self.logger.warning("Too many parallel MPDS requests, chilling")
                time.sleep(random.choice([2 * 2**m for m in range(5)]))
                return self.get_geometry()
            else: raise

        structs = [client.compile_crystal(line, flavor='ase') for line in answer]
        structs = list(filter(None, structs))
        if not structs:
            raise APIError('No crystal structures returned')
        minimal_struct = min([len(s) for s in structs])

        # get structures with minimal number of atoms and find the one with median cell vectors
        cells = np.array([s.get_cell().reshape(9) for s in structs if len(s) == minimal_struct])
        median_cell = np.median(cells, axis=0)
        median_idx = int(np.argmin(np.sum((cells - median_cell) ** 2, axis=1) ** 0.5))
        return get_data_class('structure')(ase=structs[median_idx])
示例#9
0
    def _set_default_parameters(self, parameters):
        """Set defaults to calculation parameters"""
        parameters_dict = parameters.get_dict()
        from aiida_crystal_dft.io.f9 import Fort9
        with self.inputs.wavefunction.open() as f:
            file_name = f.name
        wf = Fort9(file_name)
        if 'band' in parameters_dict:

            # automatic generation of k-point path
            if 'bands' not in parameters_dict['band']:
                self.logger.info(
                    'Proceeding with automatic generation of k-points path')
                structure = wf.get_structure()
                shrink, points, path = get_shrink_kpoints_path(structure)
                parameters_dict['band']['shrink'] = shrink
                parameters_dict['band']['bands'] = path

            # automatic generation of first and last band
            if 'first' not in parameters_dict['band']:
                parameters_dict['band']['first'] = 1
            if 'last' not in parameters_dict['band']:
                parameters_dict['band']['last'] = wf.get_ao_number()

        if 'dos' in parameters_dict:
            # automatic generation of projections in case no projections are given
            # TODO: explicit asking for automatic projections
            if ('projections_atoms' not in parameters_dict['dos']
                    and 'projections_orbitals' not in parameters_dict['dos']):
                self.logger.info(
                    'Proceeding with automatic generation of dos atomic projections'
                )
                parameters_dict['dos'][
                    'projections_atoms'] = get_dos_projections_atoms(
                        wf.get_atomic_numbers())

            # automatic generation of first and last band
            if 'first' not in parameters_dict['dos']:
                parameters_dict['dos']['first'] = 1
            if 'last' not in parameters_dict['dos']:
                parameters_dict['dos']['last'] = wf.get_ao_number()
        return get_data_class('dict')(dict=parameters_dict)
示例#10
0
    def define(cls, spec):
        super(MPDSCrystalWorkchain, cls).define(spec)

        # define code inputs
        spec.input('crystal_code', valid_type=Code, required=True)
        spec.input('properties_code', valid_type=Code, required=False)

        # MPDS phase id
        spec.input('mpds_query', valid_type=get_data_class('dict'), required=True)
        # Add direct structures submitting support: FIXME
        spec.input('struct_in', valid_type=get_data_class('structure'), required=False)

        # Basis set
        spec.expose_inputs(BaseCrystalWorkChain, include=['basis_family'])

        # Parameters (include OPTGEOM, FREQCALC and ELASTCON)
        spec.input('crystal_parameters', valid_type=get_data_class('dict'), required=True)
        spec.input('properties_parameters', valid_type=get_data_class('dict'), required=False)
        spec.input('options', valid_type=get_data_class('dict'), required=True, help="Calculation options")

        # define workchain routine
        spec.outline(cls.init_inputs,
                     cls.validate_inputs,
                     cls.optimize_geometry,
                     if_(cls.needs_phonons)(
                         cls.calculate_phonons),
                     cls.calculate_elastic_constants,
                     # correctly finalized
                     if_(cls.correctly_finalized("elastic_constants"))(
                         cls.print_exit_status),
                     if_(cls.needs_properties_run)(
                         cls.run_properties_calc),
                     cls.retrieve_results)

        # define outputs
        spec.output('phonons_parameters', valid_type=get_data_class('dict'), required=False)
        spec.output('elastic_parameters', valid_type=get_data_class('dict'), required=False)
        spec.expose_outputs(BaseCrystalWorkChain)
        spec.expose_outputs(BasePropertiesWorkChain)
示例#11
0
 def run_properties_calc(self):
     self.ctx.inputs.properties.wavefunction = self.ctx.optimise.outputs.output_wavefunction
     self.ctx.inputs.properties.options = get_data_class('dict')(
         dict=self.construct_metadata(PROPERTIES_LABEL))
     properties_run = self.submit(BasePropertiesWorkChain, **self.ctx.inputs.properties)
     return self.to_context(properties=properties_run)
示例#12
0
 def optimize_geometry(self):
     self.ctx.inputs.crystal.parameters = get_data_class('dict')(dict=self.ctx.crystal_parameters.optimise)
     self.ctx.inputs.crystal.options = get_data_class('dict')(dict=self.construct_metadata(GEOMETRY_LABEL))
     crystal_run = self.submit(BaseCrystalWorkChain, **self.ctx.inputs.crystal)
     return self.to_context(optimise=crystal_run)
示例#13
0
    def define(cls, spec):
        super(BaseCrystalWorkChain, cls).define(spec)

        # define inputs
        spec.input('code', valid_type=Code)
        spec.input('structure',
                   valid_type=get_data_class('structure'),
                   required=True)
        spec.input('parameters',
                   valid_type=get_data_class('dict'),
                   required=True)
        spec.input('basis_family',
                   valid_type=get_data_class('crystal_dft.basis_family'),
                   required=True)
        spec.input('clean_workdir',
                   valid_type=get_data_class('bool'),
                   required=False,
                   default=lambda: get_data_node('bool', False))
        spec.input('options',
                   valid_type=get_data_class('dict'),
                   required=True,
                   help="Calculation options")

        # define workchain routine
        spec.outline(
            cls.init_inputs,
            while_(not_(cls._converged))(
                cls.init_calculation,
                cls.run_calculation,
            ), cls.retrieve_results, cls.finalize)

        # define outputs
        spec.output('output_structure',
                    valid_type=get_data_class('structure'),
                    required=False)
        spec.output('primitive_structure',
                    valid_type=get_data_class('structure'),
                    required=False)
        spec.output('output_parameters',
                    valid_type=get_data_class('dict'),
                    required=False)
        spec.output('output_wavefunction',
                    valid_type=get_data_class('singlefile'),
                    required=False)
        spec.output('output_trajectory',
                    valid_type=get_data_class('array.trajectory'),
                    required=False)
        spec.output('oxidation_states',
                    valid_type=get_data_class('dict'),
                    required=False)

        # define error codes
        spec.exit_code(300, 'ERROR_CRYSTAL', message='CRYSTAL error')
        spec.exit_code(400, 'ERROR_UNKNOWN', message='Unknown error')