Esempio n. 1
0
    def inspect_and_update_stage(self):
        """Update geometry, parent folder and the new &MOTION settings."""
        last_stage = self.ctx.stages[-1]

        if 'output_structure' in last_stage.outputs:
            self.ctx.structure = last_stage.outputs.output_structure
            self.report('Structure updated for next stage')
        else:
            self.report(
                'New structure NOT found and NOT updated for next stage')

        self.ctx.parent_calc_folder = last_stage.outputs.remote_folder
        last_stage.outputs.output_parameters.label = '{}_{}_valid'.format(
            self.ctx.stage_tag, self.ctx.settings_tag)

        self.ctx.stage_idx += 1
        next_stage_tag = 'stage_{}'.format(self.ctx.stage_idx)

        if next_stage_tag in self.ctx.protocol:
            self.ctx.stage_tag = next_stage_tag
            self.ctx.next_stage_exists = True
            dict_merge(self.ctx.cp2k_param,
                       self.ctx.protocol[self.ctx.stage_tag])
        else:
            self.ctx.next_stage_exists = False
            self.report("All stages computed, finishing...")
Esempio n. 2
0
    def run_isotherms(self):
        """Compute isotherms at different temperatures."""

        self.ctx.ntemp = len(self.inputs.parameters['temperature_list'])

        # create inputs: exposed are code and metadata
        inputs = self.exposed_inputs(IsothermWorkChain)
        inputs['geometric'] = self.ctx.geom
        if 'block' in self.ctx.geom_only.outputs:
            inputs['raspa_base']['raspa']["block_pocket"] = {
                "block_file": self.ctx.geom_only.outputs.block
            }

        # Update the parameters with only one temperature and submit
        for i in range(self.ctx.ntemp):
            self.ctx.parameters_singletemp = get_parameters_singletemp(
                i, self.inputs.parameters)

            dict_merge(
                inputs, {
                    'metadata': {
                        'label': "Isotherm_{}".format(i),
                        'call_link_label': 'run_isotherm_{}'.format(i),
                    },
                    'parameters': self.ctx.parameters_singletemp
                })

            running = self.submit(IsothermWorkChain, **inputs)
            self.to_context(**{'isotherm_{}'.format(i): running})
Esempio n. 3
0
    def run_zeopp(self):
        """Perform Zeo++ block and VOLPO calculations."""

        # Skip zeopp calculation if the geometric properties are already provided by IsothermMultiTemp
        if self.ctx.multitemp_mode == 'run_single_temp':
            return None

        # create inputs: exposed are code and metadata
        inputs = self.exposed_inputs(ZeoppCalculation, 'zeopp')

        # Set inputs for zeopp
        dict_merge(
            inputs, {
                'metadata': {
                    'label': "ZeoppVolpoBlock",
                    'call_link_label': 'run_zeopp_block_and_volpo',
                },
                'structure': self.inputs.structure,
                'atomic_radii': get_atomic_radii(self.ctx.parameters),
                'parameters': get_zeopp_parameters(self.ctx.molecule, self.ctx.parameters)
            })

        running = self.submit(ZeoppCalculation, **inputs)
        self.report("Running zeo++ block and volpo for {} Calculation<{}>".format(self.ctx.molecule['name'],
                                                                                  running.id))
        return ToContext(zeopp=running)
Esempio n. 4
0
    def run_geo_opt(self):
        """Prepare inputs, submit and direct output to context."""

        self.ctx.base_inp = AttributeDict(
            self.exposed_inputs(Cp2kBaseWorkChain, 'cp2k_base'))
        self.ctx.base_inp['cp2k']['structure'] = self.ctx.system

        # Overwrite the generated input with the custom cp2k/parameters, update metadata and submit
        if 'parameters' in self.exposed_inputs(Cp2kBaseWorkChain,
                                               'cp2k_base')['cp2k']:
            dict_merge(
                self.ctx.cp2k_param,
                self.exposed_inputs(
                    Cp2kBaseWorkChain,
                    'cp2k_base')['cp2k']['parameters'].get_dict())
        self.ctx.base_inp['cp2k']['parameters'] = Dict(
            dict=self.ctx.cp2k_param)
        self.ctx.base_inp['metadata'].update({
            'label':
            'geo_opt_molecule',
            'call_link_label':
            'run_geo_opt_molecule'
        })
        self.ctx.base_inp['cp2k']['metadata'].update({'label': 'GEO_OPT'})
        self.ctx.base_inp['cp2k']['metadata']['options'][
            'parser_name'] = 'lsmo.cp2k_advanced_parser'
        running_base = self.submit(Cp2kBaseWorkChain, **self.ctx.base_inp)
        self.report("Optimize molecule position in the structure.")
        return ToContext(stages=append_(running_base))
Esempio n. 5
0
    def run_stage(self):
        """Check for restart, prepare input, submit and direct output to context."""

        # Update structure
        self.ctx.base_inp['cp2k']['structure'] = self.ctx.structure

        # Check if it is needed to restart the calculation and provide the parent folder and new structure
        if self.ctx.parent_calc_folder:
            self.ctx.base_inp['cp2k'][
                'parent_calc_folder'] = self.ctx.parent_calc_folder
            self.ctx.cp2k_param['FORCE_EVAL']['DFT']['SCF'][
                'SCF_GUESS'] = 'RESTART'
            self.ctx.cp2k_param['FORCE_EVAL']['DFT'][
                'WFN_RESTART_FILE_NAME'] = './parent_calc/aiida-RESTART.wfn'
        else:
            self.ctx.cp2k_param['FORCE_EVAL']['DFT']['SCF'][
                'SCF_GUESS'] = 'ATOMIC'

        # Overwrite the generated input with the custom cp2k/parameters
        if 'parameters' in self.exposed_inputs(Cp2kBaseWorkChain,
                                               'cp2k_base')['cp2k']:
            dict_merge(
                self.ctx.cp2k_param,
                AttributeDict(
                    self.exposed_inputs(
                        Cp2kBaseWorkChain,
                        'cp2k_base')['cp2k']['parameters'].get_dict()))
        self.ctx.base_inp['cp2k']['parameters'] = Dict(
            dict=self.ctx.cp2k_param).store()

        # Update labels
        self.ctx.base_inp['metadata'].update({
            'label':
            '{}_{}'.format(self.ctx.stage_tag, self.ctx.settings_tag),
            'call_link_label':
            'run_{}_{}'.format(self.ctx.stage_tag, self.ctx.settings_tag),
        })
        self.ctx.base_inp['cp2k']['metadata'].update({
            'label':
            self.ctx.base_inp['cp2k']['parameters'].get_dict()['GLOBAL']
            ['RUN_TYPE']
        })

        running_base = self.submit(Cp2kBaseWorkChain, **self.ctx.base_inp)
        self.report("submitted Cp2kBaseWorkChain for {}/{}".format(
            self.ctx.stage_tag, self.ctx.settings_tag))
        return ToContext(stages=append_(running_base))
Esempio n. 6
0
    def run_geometric(self):
        """Perform Zeo++ block and VOLPO calculation with IsothermWC."""

        # create inputs: exposed are code and metadata
        inputs = self.exposed_inputs(IsothermWorkChain)

        # Set inputs for zeopp
        dict_merge(
            inputs, {
                'metadata': {
                    'label': "IsothermGeometric",
                    'call_link_label': 'run_geometric',
                },
            })

        running = self.submit(IsothermWorkChain, **inputs)
        self.report("Computing common gemetric properties")
        return ToContext(geom_only=running)
Esempio n. 7
0
    def inspect_and_update_settings_stage0(self):  # pylint: disable=inconsistent-return-statements
        """Inspect the stage0/settings_{idx} calculation and check if it is
        needed to update the settings and resubmint the calculation."""
        self.ctx.settings_ok = True

        # Settings/structure are bad: there are problems in parsing the output file
        # and, most probably, the calculation didn't even start the scf cycles
        if 'output_parameters' in self.ctx.stages[-1].outputs:
            cp2k_out = self.ctx.stages[-1].outputs.output_parameters
        else:
            self.report('ERROR_PARSING_OUTPUT')
            return self.exit_codes.ERROR_PARSING_OUTPUT  # pylint: disable=no-member

        # Settings are bad: the SCF did not converge in the final step
        if not cp2k_out["motion_step_info"]["scf_converged"][-1]:
            self.report("BAD SETTINGS: the SCF did not converge")
            self.ctx.settings_ok = False
            self.ctx.settings_idx += 1
        else:
            # SCF converged, but the computed bandgap needs to be checked
            self.report("Bandgaps spin1/spin2: {:.3f} and {:.3f} ev".format(
                cp2k_out["bandgap_spin1_au"] * HARTREE2EV,
                cp2k_out["bandgap_spin2_au"] * HARTREE2EV))
            bandgap_thr_ev = self.ctx.protocol['bandgap_thr_ev']
            if ot_has_small_bandgap(self.ctx.cp2k_param, cp2k_out,
                                    bandgap_thr_ev):
                self.report("BAD SETTINGS: band gap is < {:.3f} eV".format(
                    bandgap_thr_ev))
                self.ctx.settings_ok = False
                self.ctx.settings_idx += 1

        # Update the settings tag, check if it is available and overwrite
        if not self.ctx.settings_ok:
            cp2k_out.label = '{}_{}_discard'.format(self.ctx.stage_tag,
                                                    self.ctx.settings_tag)
            next_settings_tag = 'settings_{}'.format(self.ctx.settings_idx)
            if next_settings_tag in self.ctx.protocol:
                self.ctx.settings_tag = next_settings_tag
                dict_merge(self.ctx.cp2k_param,
                           self.ctx.protocol[self.ctx.settings_tag])
            else:
                return self.exit_codes.ERROR_NO_MORE_SETTINGS  # pylint: disable=no-member
Esempio n. 8
0
    def run_isotherms(self):
        """Run Isotherm work chain for CO2 and N2."""

        inputs = self.exposed_inputs(IsothermWorkChain)
        self.report(
            "Run Isotherm work chain for CO2 and N2, in CifData<{}> (label: {} )"
            .format(self.inputs.structure.pk, self.inputs.structure.label))

        for mol in ['co2', 'n2']:

            dict_merge(
                inputs, {
                    'metadata': {
                        'call_link_label': 'run_isotherm_for_{}'.format(mol),
                    },
                    'molecule': Str(mol),
                    'parameters': self.inputs.parameters
                })

            running = self.submit(IsothermWorkChain, **inputs)
            self.to_context(**{'isotherm_{}'.format(mol): running})
Esempio n. 9
0
    def run_bsse(self):
        """Update parameters and run BSSE calculation. BSSE assumes that the molecule has no charge and unit
        multiplicity: this can be customized from builder.cp2k_base.cp2k.parameters.
        """

        self.ctx.cp2k_param['GLOBAL']['RUN_TYPE'] = 'BSSE'
        dict_merge(
            self.ctx.cp2k_param,
            get_bsse_section(natoms_a=self.ctx.natoms_structure,
                             natoms_b=self.ctx.natoms_molecule,
                             mult_a=self.ctx.cp2k_param['FORCE_EVAL']['DFT']
                             ['MULTIPLICITY'],
                             mult_b=1,
                             charge_a=0,
                             charge_b=0))

        # Overwrite the generated input with the custom cp2k/parameters, update structure and metadata, and submit
        if 'parameters' in self.exposed_inputs(Cp2kBaseWorkChain,
                                               'cp2k_base')['cp2k']:
            dict_merge(
                self.ctx.cp2k_param,
                self.exposed_inputs(
                    Cp2kBaseWorkChain,
                    'cp2k_base')['cp2k']['parameters'].get_dict())
        self.ctx.base_inp['cp2k']['parameters'] = Dict(
            dict=self.ctx.cp2k_param)
        self.ctx.base_inp['cp2k']['structure'] = self.ctx.stages[
            -1].outputs.output_structure
        self.ctx.base_inp['metadata'].update({
            'label': 'bsse',
            'call_link_label': 'run_bsse'
        })
        self.ctx.base_inp['cp2k']['metadata'].update({'label': 'BSSE'})
        self.ctx.base_inp['cp2k']['metadata']['options'][
            'parser_name'] = 'lsmo.cp2k_bsse_parser'
        running_base = self.submit(Cp2kBaseWorkChain, **self.ctx.base_inp)
        self.report(
            "Run BSSE calculation to compute corrected binding energy.")

        return ToContext(stages=append_(running_base))
Esempio n. 10
0
    def setup_multistage(self):
        """Setup initial parameters."""

        # Store the workchain inputs in context (to be modified later)
        self.ctx.base_inp = AttributeDict(
            self.exposed_inputs(Cp2kBaseWorkChain, 'cp2k_base'))

        # Check if an input parent_calc_folder is provided
        if 'parent_calc_folder' in self.inputs:
            self.ctx.parent_calc_folder = self.inputs.parent_calc_folder
        else:
            self.ctx.parent_calc_folder = None

        # Read yaml file selected as SinglefileData or chosen with the tag, and overwrite with custom modifications
        if 'protocol_yaml' in self.inputs:
            self.ctx.protocol = yaml.safe_load(
                self.inputs.protocol_yaml.open())
        else:
            thisdir = os.path.dirname(os.path.abspath(__file__))
            yamlfullpath = os.path.join(
                thisdir, 'cp2k_multistage_protocols',
                self.inputs.protocol_tag.value + '.yaml')
            with open(yamlfullpath, 'r') as stream:
                self.ctx.protocol = yaml.safe_load(stream)
        dict_merge(self.ctx.protocol, self.inputs.protocol_modify.get_dict())

        # Initialize
        self.ctx.settings_ok = False
        self.ctx.stage_idx = 0
        self.ctx.stage_tag = 'stage_{}'.format(self.ctx.stage_idx)
        self.ctx.settings_idx = 0
        self.ctx.settings_tag = 'settings_{}'.format(self.ctx.settings_idx)
        self.ctx.structure = self.inputs.structure

        # Resize the unit cell if min(perp_with) < inputs.min_cell_size
        self.ctx.resize = check_resize_unit_cell_legacy(
            self.ctx.structure, self.inputs.min_cell_size)  # Dict
        if self.ctx.resize['nx'] > 1 or self.ctx.resize[
                'ny'] > 1 or self.ctx.resize['nz'] > 1:
            resized_struct = resize_unit_cell(self.ctx.structure,
                                              self.ctx.resize)
            self.ctx.structure = resized_struct
            self.report(
                "Unit cell resized by {}x{}x{} (StructureData<{}>)".format(
                    self.ctx.resize['nx'], self.ctx.resize['ny'],
                    self.ctx.resize['nz'], resized_struct.pk))
        else:
            self.report("Unit cell was NOT resized")

        # Generate input parameters and store them
        self.ctx.cp2k_param = deepcopy(self.ctx.protocol['settings_0'])
        while self.inputs.starting_settings_idx > self.ctx.settings_idx:
            # overwrite untill the desired starting setting are obtained
            self.ctx.settings_idx += 1
            self.ctx.settings_tag = 'settings_{}'.format(self.ctx.settings_idx)
            if self.ctx.settings_tag in self.ctx.protocol:
                dict_merge(self.ctx.cp2k_param,
                           self.ctx.protocol[self.ctx.settings_tag])
            else:
                return self.exit_codes.ERROR_MISSING_INITIAL_SETTINGS  # pylint: disable=no-member
        kinds = get_kinds_section(self.ctx.structure, self.ctx.protocol)
        dict_merge(self.ctx.cp2k_param, kinds)
        multiplicity = get_input_multiplicity(self.ctx.structure,
                                              self.ctx.protocol)
        dict_merge(self.ctx.cp2k_param, multiplicity)
        dict_merge(self.ctx.cp2k_param, self.ctx.protocol['stage_0'])
Esempio n. 11
0
    def setup(self):
        """Setup initial parameters."""

        # Read yaml file selected as SinglefileData or chosen with the tag, and overwrite with custom modifications
        if 'protocol_yaml' in self.inputs:
            self.ctx.protocol = yaml.safe_load(
                self.inputs.protocol_yaml.open())
        else:
            thisdir = os.path.dirname(os.path.abspath(__file__))
            yamlfullpath = os.path.join(
                thisdir, 'cp2k_multistage_protocols',
                self.inputs.protocol_tag.value + '.yaml')
            with open(yamlfullpath, 'r') as stream:
                self.ctx.protocol = yaml.safe_load(stream)
        dict_merge(self.ctx.protocol, self.inputs.protocol_modify.get_dict())

        # Initialize
        self.ctx.settings_ok = False
        self.ctx.settings_idx = 0
        self.ctx.settings_tag = 'settings_{}'.format(self.ctx.settings_idx)

        self.ctx.system = aiida_structure_merge(self.inputs.structure,
                                                self.inputs.molecule)
        self.ctx.natoms_structure = len(self.inputs.structure.get_ase())
        self.ctx.natoms_molecule = len(self.inputs.molecule.get_ase())

        # Generate input parameters
        self.ctx.cp2k_param = deepcopy(self.ctx.protocol['settings_0'])
        while self.inputs.starting_settings_idx < self.ctx.settings_idx:
            # overwrite untill the desired starting setting are obtained
            self.ctx.settings_idx += 1
            self.ctx.settings_tag = 'settings_{}'.format(self.ctx.settings_idx)
            if self.ctx.settings_tag in self.ctx.protocol:
                dict_merge(self.ctx.cp2k_param,
                           self.ctx.protocol[self.ctx.settings_tag])
            else:
                return self.exit_codes.ERROR_MISSING_INITIAL_SETTINGS  # pylint: disable=no-member
        dict_merge(
            self.ctx.cp2k_param,
            get_kinds_with_ghost_section(self.ctx.system, self.ctx.protocol))
        dict_merge(self.ctx.cp2k_param,
                   get_input_multiplicity(self.ctx.system, self.ctx.protocol))
        dict_merge(
            self.ctx.cp2k_param,
            {
                'GLOBAL': {
                    'RUN_TYPE': 'GEO_OPT'
                },
                'FORCE_EVAL': {
                    'DFT': {
                        'SCF': {
                            'SCF_GUESS': 'ATOMIC'
                        }
                    }
                },
                'MOTION': {
                    'GEO_OPT': {
                        'MAX_ITER': 200
                    },  # Can be adjusted from builder.cp2k_base.cp2k.parameters
                    'CONSTRAINT': {
                        'FIXED_ATOMS': {
                            'LIST': "1..{}".format(self.ctx.natoms_structure)
                        }
                    }
                }
            })