def test_find_last_submitted_calcjob(fixture_localhost, generate_calc_job_node,
                                     generate_work_chain_node):
    from aiida_fleur.tools.common_fleur_wf import find_last_submitted_calcjob
    from aiida.common.links import LinkType
    from aiida.common.exceptions import NotExistent

    node1 = generate_calc_job_node('fleur.fleur', fixture_localhost)
    node2 = generate_calc_job_node('fleur.fleur', fixture_localhost)
    node3 = generate_calc_job_node('fleur.fleur', fixture_localhost)

    node_main = generate_work_chain_node('fleur.base_relax', fixture_localhost)
    node_main.store()

    with pytest.raises(NotExistent):
        result = find_last_submitted_calcjob(node_main)

    node1.add_incoming(node_main,
                       link_type=LinkType.CALL_CALC,
                       link_label='CALL')
    node2.add_incoming(node_main,
                       link_type=LinkType.CALL_CALC,
                       link_label='CALL')
    node3.add_incoming(node_main,
                       link_type=LinkType.CALL_CALC,
                       link_label='CALL')

    node1.store()
    node2.store()
    node3.store()

    result = find_last_submitted_calcjob(node_main)

    assert result == node3.uuid
Exemple #2
0
    def return_results(self):
        """
        return the results of the calculations
        This should run through and produce output nodes even if everything failed,
        therefore it only uses results from context.
        """
        if self.ctx.last_base_wc:
            try:
                last_calc_uuid = find_last_submitted_calcjob(
                    self.ctx.last_base_wc)
            except NotExistent:
                last_calc_uuid = None
        else:
            last_calc_uuid = None

        try:  # if something failed, we still might be able to retrieve something
            last_calc_out = self.ctx.last_base_wc.outputs.output_parameters
            retrieved = self.ctx.last_base_wc.outputs.retrieved
            last_calc_out_dict = last_calc_out.get_dict()
        except (NotExistent, AttributeError):
            last_calc_out = None
            last_calc_out_dict = {}
            retrieved = None

        last_nmmp_distance = None
        if self.ctx.last_nmmp_distance > 0.0:
            last_nmmp_distance = self.ctx.last_nmmp_distance

        outputnode_dict = {}
        outputnode_dict['workflow_name'] = self.__class__.__name__
        outputnode_dict['workflow_version'] = self._workflowversion
        outputnode_dict['material'] = self.ctx.formula
        outputnode_dict['conv_mode'] = self.ctx.wf_dict.get('mode')
        outputnode_dict['loop_count'] = self.ctx.loop_count
        outputnode_dict['iterations_total'] = last_calc_out_dict.get(
            'number_of_iterations_total', None)
        outputnode_dict['distance_charge'] = self.ctx.last_charge_density
        outputnode_dict['distance_charge_all'] = self.ctx.distance
        outputnode_dict['total_energy'] = last_calc_out_dict.get(
            'energy_hartree', None)
        outputnode_dict['total_energy_all'] = self.ctx.total_energy
        outputnode_dict['force_diff_last'] = self.ctx.forcediff
        outputnode_dict['force_largest'] = last_calc_out_dict.get(
            'force_largest', None)
        outputnode_dict['distance_charge_units'] = 'me/bohr^3'
        outputnode_dict['total_energy_units'] = 'Htr'
        outputnode_dict['nmmp_distance'] = last_nmmp_distance
        outputnode_dict['nmmp_distance_all'] = self.ctx.nmmp_distance
        outputnode_dict['last_calc_uuid'] = last_calc_uuid
        outputnode_dict['total_wall_time'] = self.ctx.total_wall_time
        outputnode_dict['total_wall_time_units'] = 's'
        outputnode_dict['info'] = self.ctx.info
        outputnode_dict['warnings'] = self.ctx.warnings
        outputnode_dict['errors'] = self.ctx.errors

        if self.ctx.successful and self.ctx.reached_conv:
            if len(self.ctx.total_energy
                   ) <= 1:  # then len(self.ctx.all_forces) <= 1 too
                self.report(
                    'STATUS: Done, the convergence criteria are reached.\n'
                    'INFO: The charge density of the FLEUR calculation '
                    'converged after {} FLEUR runs, {} iterations and {} sec '
                    'walltime to {} "me/bohr^3" \n'
                    'INFO: Did not manage to get energy and largest force difference '
                    'between two last iterations, probably converged in a single iteration'
                    ''.format(
                        self.ctx.loop_count,
                        last_calc_out_dict.get('number_of_iterations_total',
                                               None), self.ctx.total_wall_time,
                        outputnode_dict['distance_charge']))
                if self.ctx.last_nmmp_distance > 0.0:
                    self.report(
                        'INFO: The LDA+U density matrix is converged to {} change '
                        'of all matrix elements'.format(
                            self.ctx.last_nmmp_distance))
            else:
                self.report(
                    'STATUS: Done, the convergence criteria are reached.\n'
                    'INFO: The charge density of the FLEUR calculation '
                    'converged after {} FLEUR runs, {} iterations and {} sec '
                    'walltime to {} "me/bohr^3" \n'
                    'INFO: The total energy difference of the last two iterations '
                    'is {} Htr and largest force difference is {} Htr/bohr'
                    ''.format(
                        self.ctx.loop_count,
                        last_calc_out_dict.get('number_of_iterations_total',
                                               None), self.ctx.total_wall_time,
                        outputnode_dict['distance_charge'],
                        self.ctx.energydiff, self.ctx.forcediff))
                if self.ctx.last_nmmp_distance > 0.0:
                    self.report(
                        'INFO: The LDA+U density matrix is converged to {} change '
                        'of all matrix elements'.format(
                            self.ctx.last_nmmp_distance))
        elif self.ctx.successful and not self.ctx.reached_conv:
            if len(self.ctx.total_energy
                   ) <= 1:  # then len(self.ctx.all_forces) <= 1 too
                self.report(
                    'STATUS/WARNING: Done, the maximum number of runs '
                    'was reached.\n INFO: The '
                    'charge density of the FLEUR calculation, '
                    'after {} FLEUR runs, {} iterations and {} sec '
                    'walltime is {} "me/bohr^3"\n'
                    'INFO: can not extract energy and largest force difference between'
                    ' two last iterations, probably converged in a single iteration'
                    ''.format(
                        self.ctx.loop_count,
                        last_calc_out_dict.get('number_of_iterations_total',
                                               None), self.ctx.total_wall_time,
                        outputnode_dict['distance_charge']))
            else:
                self.report(
                    'STATUS/WARNING: Done, the maximum number of runs '
                    'was reached.\n INFO: The '
                    'charge density of the FLEUR calculation, '
                    'after {} FLEUR runs, {} iterations and {} sec '
                    'walltime is {} "me/bohr^3"\n'
                    'INFO: The total energy difference of the last two iterations '
                    'is {} Htr and largest force difference is {} Htr/bohr\n'
                    ''.format(
                        self.ctx.loop_count,
                        last_calc_out_dict.get('number_of_iterations_total',
                                               None), self.ctx.total_wall_time,
                        outputnode_dict['distance_charge'],
                        self.ctx.energydiff, self.ctx.forcediff))
            if self.ctx.last_nmmp_distance > 0.0:
                self.report(
                    'INFO: The LDA+U density matrix is converged to {} change '
                    'of all matrix elements'.format(
                        self.ctx.last_nmmp_distance))
        else:  # Termination ok, but not converged yet...
            if self.ctx.abort:  # some error occurred, do not use the output.
                self.report('STATUS/ERROR: I abort, see logs and '
                            'errors/warning/hints in output_scf_wc_para')

        outputnode_t = Dict(dict=outputnode_dict)
        # this is unsafe so far, because last_calc_out could not exist...
        if last_calc_out:
            outdict = create_scf_result_node(outpara=outputnode_t,
                                             last_calc_out=last_calc_out,
                                             last_calc_retrieved=retrieved)
        else:
            outdict = create_scf_result_node(outpara=outputnode_t)

        # Now it always returns changed fleurinp that was actually used in the calculation
        if self.ctx.fleurinp is not None:
            outdict['fleurinp'] = self.ctx.fleurinp

        if last_calc_out:
            outdict['last_fleur_calc_output'] = last_calc_out

        #outdict['output_scf_wc_para'] = outputnode
        for link_name, node in outdict.items():
            self.out(link_name, node)

        if not self.ctx.reached_conv:
            return self.exit_codes.ERROR_DID_NOT_CONVERGE
Exemple #3
0
    def get_res(self):
        """
        Check how the last Fleur calculation went
        Parse some results.
        """
        self.report('INFO: get results FLEUR')

        mode = self.ctx.wf_dict.get('mode')
        if self.ctx.parse_last:
            last_base_wc = self.ctx.last_base_wc
            fleur_calcjob = load_node(
                find_last_submitted_calcjob(last_base_wc))
            walltime = last_base_wc.outputs.output_parameters.dict.walltime

            if isinstance(walltime, int):
                self.ctx.total_wall_time = self.ctx.total_wall_time + walltime
            with fleur_calcjob.outputs.retrieved.open(
                    fleur_calcjob.process_class._OUTXML_FILE_NAME,
                    'r') as outxmlfile:
                output_dict = outxml_parser(outxmlfile,
                                            minimal_mode=True,
                                            list_return=True,
                                            iteration_to_parse='all',
                                            ignore_validation=True)

            energies = output_dict.get('energy_hartree', [])
            if energies is not None:
                self.ctx.total_energy.extend(energies)

            if 'overall_density_convergence' in output_dict:
                distances = output_dict['overall_density_convergence']
            else:
                distances = output_dict.get('density_convergence', [])

            if distances is not None:
                self.ctx.distance.extend(distances)

            if 'ldau_info' in output_dict:
                nmmp_distances = output_dict['ldau_info'].get(
                    'nmmp_distances', [])

                if nmmp_distances is not None:
                    self.ctx.nmmp_distance.extend(nmmp_distances)

            if mode == 'force':
                forces = output_dict.get('force_atoms', [])
                if forces is not None:
                    for force_iter in forces:
                        self.ctx.all_forces.append(
                            [force for atom, force in force_iter])

        else:
            errormsg = 'ERROR: scf wc was not successful, check log for details'
            self.control_end_wc(errormsg)
            return self.exit_codes.ERROR_FLEUR_CALCULATION_FAILED

        if not self.ctx.distance:
            # if fleur relaxes an already converged crystal it stops directly
            if mode == 'force':
                self.report(
                    'INFO: System already force converged, could not extract distance.'
                )
                self.ctx.last_charge_density = None
            else:
                errormsg = 'ERROR: did not manage to extract charge density from the calculation'
                self.control_end_wc(errormsg)
                return self.exit_codes.ERROR_FLEUR_CALCULATION_FAILED
        else:
            self.ctx.last_charge_density = self.ctx.distance[-1]

        if self.ctx.nmmp_distance:
            self.ctx.last_nmmp_distance = max(self.ctx.nmmp_distance[-1])
Exemple #4
0
    def return_results(self):
        '''
        return the results of the calculations
        '''
        # TODO more here
        self.report('BandDOS workflow Done')
        self.report(
            f'A bandstructure was calculated and is found under pk={self.ctx.banddos_calc.pk}, '
            f'calculation {self.ctx.banddos_calc}')

        from aiida_fleur.tools.common_fleur_wf import find_last_submitted_calcjob
        if self.ctx.banddos_calc:
            try:
                last_calc_uuid = find_last_submitted_calcjob(
                    self.ctx.banddos_calc)
            except NotExistent:
                last_calc_uuid = None
        else:
            last_calc_uuid = None

        try:  # if something failed, we still might be able to retrieve something
            last_calc_out = self.ctx.banddos_calc.outputs.output_parameters
            retrieved = self.ctx.banddos_calc.outputs.retrieved
            if 'fleurinpdata' in self.ctx.banddos_calc.inputs:
                fleurinp = self.ctx.banddos_calc.inputs.fleurinpdata
            else:
                fleurinp = get_fleurinp_from_remote_data(
                    self.ctx.banddos_calc.inputs.parent_folder)
            last_calc_out_dict = last_calc_out.get_dict()
        except (NotExistent, AttributeError):
            last_calc_out = None
            last_calc_out_dict = {}
            retrieved = None
            fleurinp = None

        #check if band file exists: if not succesful = False
        #TODO be careful with general bands.X
        bandfiles = ['bands.1', 'bands.2', 'banddos.hdf']

        bandfile_res = []
        if retrieved:
            bandfile_res = retrieved.list_object_names()

        for name in bandfiles:
            if name in bandfile_res:
                self.ctx.successful = True
        if not self.ctx.successful:
            self.report(
                '!NO bandstructure file was found, something went wrong!')

        # # get efermi from last calculation
        scf_results = None
        efermi_scf = 0
        bandgap_scf = 0
        if 'remote' in self.inputs:
            for w in self.inputs.remote.get_incoming().all():
                if isinstance(w.node, CalcJobNode):
                    scf_results = load_node(w.node.pk).res
                    efermi_scf = scf_results.fermi_energy
                    bandgap_scf = scf_results.bandgap

        efermi_band = last_calc_out_dict.get('fermi_energy', None)
        bandgap_band = last_calc_out_dict.get('bandgap', None)

        diff_efermi = None
        if efermi_band is not None:
            diff_efermi = efermi_scf - efermi_band

        diff_bandgap = None
        if bandgap_band is not None:
            diff_bandgap = bandgap_scf - bandgap_band

        outputnode_dict = {}

        outputnode_dict['workflow_name'] = self.__class__.__name__
        outputnode_dict['Warnings'] = self.ctx.warnings
        outputnode_dict['successful'] = self.ctx.successful
        outputnode_dict['last_calc_uuid'] = last_calc_uuid
        outputnode_dict['last_calc_pk'] = self.ctx.banddos_calc.pk
        outputnode_dict['mode'] = self.ctx.wf_dict.get('mode')
        outputnode_dict['fermi_energy_band'] = efermi_band
        outputnode_dict['bandgap_band'] = bandgap_band
        outputnode_dict['fermi_energy_scf'] = efermi_scf
        outputnode_dict['bandgap_scf'] = bandgap_scf
        outputnode_dict['diff_efermi'] = diff_efermi
        outputnode_dict['diff_bandgap'] = diff_bandgap
        outputnode_dict['bandgap_units'] = 'eV'
        outputnode_dict['fermi_energy_units'] = 'Htr'

        outputnode_t = Dict(dict=outputnode_dict)
        if last_calc_out:
            outdict = create_band_result_node(outpara=outputnode_t,
                                              last_calc_out=last_calc_out,
                                              last_calc_retrieved=retrieved)

            if self.ctx.wf_dict.get(
                    'mode'
            ) == 'band' and fleurinp is not None and retrieved is not None:
                bands = create_aiida_bands_data(fleurinp=fleurinp,
                                                retrieved=retrieved)
                if isinstance(bands, BandsData):
                    outdict['output_banddos_wc_bands'] = bands
            elif self.ctx.wf_dict.get(
                    'mode') == 'dos' and retrieved is not None:
                dos = create_aiida_dos_data(retrieved=retrieved)
                if isinstance(dos, XyData):
                    outdict['output_banddos_wc_dos'] = dos

        else:
            outdict = create_band_result_node(outpara=outputnode_t)

        if retrieved:
            outdict['last_calc_retrieved'] = retrieved

        #TODO parse Bandstructure
        for link_name, node in outdict.items():
            self.out(link_name, node)
Exemple #5
0
    def get_res(self):
        """
        Check how the last Fleur calculation went
        Parse some results.
        """
        self.report('INFO: get results FLEUR')

        xpath_energy = '/fleurOutput/scfLoop/iteration/totalEnergy/@value'
        xpath_iter = '/fleurOutput/scfLoop/iteration'
        xpath_force = 'totalForcesOnRepresentativeAtoms/forceTotal'

        # be aware of magnetism
        xpath_distance = '/fleurOutput/scfLoop/iteration/densityConvergence/chargeDensity/@distance'
        overallchargedensity_xpath = ('/fleurOutput/scfLoop/iteration/densityConvergence/'
                                      'overallChargeDensity/@distance')

        mode = self.ctx.wf_dict.get('mode')
        if self.ctx.parse_last:
            last_base_wc = self.ctx.last_base_wc
            fleur_calcjob = load_node(find_last_submitted_calcjob(last_base_wc))
            walltime = last_base_wc.outputs.output_parameters.dict.walltime
            if isinstance(walltime, int):
                self.ctx.total_wall_time = self.ctx.total_wall_time + walltime
            with fleur_calcjob.outputs.retrieved.open(fleur_calcjob.process_class._OUTXML_FILE_NAME,
                                                      'r') as outxmlfile_opened:
                tree = etree.parse(outxmlfile_opened)
            root = tree.getroot()

            energies = eval_xpath2(root, xpath_energy)
            for energy in energies:
                self.ctx.total_energy.append(float(energy))

            overall_distances = eval_xpath2(root, overallchargedensity_xpath)
            if not overall_distances:
                distances = eval_xpath2(root, xpath_distance)
                for distance in distances:
                    self.ctx.distance.append(float(distance))
            else:
                for distance in overall_distances:
                    self.ctx.distance.append(float(distance))

            if mode == 'force':
                iter_all = eval_xpath2(root, xpath_iter)
                for iteration in iter_all:
                    forces = eval_xpath2(iteration, xpath_force)
                    forces_in_iter = []
                    for force in forces:
                        force_x = float(get_xml_attribute(force, 'F_x'))
                        force_y = float(get_xml_attribute(force, 'F_y'))
                        force_z = float(get_xml_attribute(force, 'F_z'))

                        forces_in_iter.append(force_x)
                        forces_in_iter.append(force_y)
                        forces_in_iter.append(force_z)

                    self.ctx.all_forces.append(forces_in_iter)
        else:
            errormsg = 'ERROR: scf wc was not successful, check log for details'
            self.control_end_wc(errormsg)
            return self.exit_codes.ERROR_FLEUR_CALCULATION_FAILED

        if not self.ctx.distance:
            # if fleur relaxes an already converged crystal it stops directly
            if mode == 'force':
                self.report('INFO: System already force converged, could not extract distance.')
                self.ctx.last_charge_density = None
            else:
                errormsg = 'ERROR: did not manage to extract charge density from the calculation'
                self.control_end_wc(errormsg)
                return self.exit_codes.ERROR_FLEUR_CALCULATION_FAILED
        else:
            self.ctx.last_charge_density = self.ctx.distance[-1]
Exemple #6
0
    def return_results(self):
        '''
        return the results of the calculations
        '''
        # TODO more here
        self.report('Band workflow Done')
        self.report('A bandstructure was calculated for fleurinpdata {} and is found under pk={}, '
                    'calculation {}'.format(self.ctx.fleurinp_scf, self.ctx.last_calc.pk, self.ctx.last_calc))

        from aiida_fleur.tools.common_fleur_wf import find_last_submitted_calcjob
        if self.ctx.last_calc:
            try:
                last_calc_uuid = find_last_submitted_calcjob(self.ctx.last_calc)
            except NotExistent:
                last_calc_uuid = None
        else:
            last_calc_uuid = None

        try:  # if something failed, we still might be able to retrieve something
            last_calc_out = self.ctx.last_calc.outputs.output_parameters
            retrieved = self.ctx.last_calc.outputs.retrieved
            last_calc_out_dict = last_calc_out.get_dict()
        except (NotExistent, AttributeError):
            last_calc_out = None
            last_calc_out_dict = {}
            retrieved = None

        #check if band file exists: if not succesful = False
        #TODO be careful with general bands.X
        # bandfilename = 'bands.1' # ['bands.1', 'bands.2', ...]

        # bandfile =retrieved.open(bandfilename).name

        # if os.path.isfile(bandfile):
        #     self.ctx.successful = True
        # else:
        #     bandfile = None
        #     self.report('!NO bandstructure file was found, something went wrong!')

        # # get efermi from last calculation
        scf_results = None
        efermi_scf = 0
        bandgap_scf = 0
        if 'remote' in self.inputs:
            for w in self.inputs.remote.get_incoming().all():
                if isinstance(w.node, CalcJobNode):
                    scf_results = load_node(w.node.pk).res
                    efermi_scf = scf_results.fermi_energy
                    bandgap_scf = scf_results.bandgap

        efermi_band = last_calc_out_dict.get('fermi_energy', None)
        bandgap_band = last_calc_out_dict.get('bandgap', None)

        diff_efermi = None
        if efermi_band is not None:
            diff_efermi = efermi_scf - efermi_band

        diff_bandgap = None
        if bandgap_band is not None:
            diff_bandgap = bandgap_scf - bandgap_band

        outputnode_dict = {}

        outputnode_dict['workflow_name'] = self.__class__.__name__
        outputnode_dict['Warnings'] = self.ctx.warnings
        outputnode_dict['successful'] = self.ctx.successful
        outputnode_dict['last_calc_uuid'] = last_calc_uuid
        outputnode_dict['last_calc_pk'] = self.ctx.last_calc.pk
        outputnode_dict['fermi_energy_band'] = efermi_band
        outputnode_dict['bandgap_band'] = bandgap_band
        outputnode_dict['fermi_energy_scf'] = efermi_scf
        outputnode_dict['bandgap_scf'] = bandgap_scf
        outputnode_dict['diff_efermi'] = diff_efermi
        outputnode_dict['diff_bandgap'] = diff_bandgap
        outputnode_dict['bandgap_units'] = 'eV'
        outputnode_dict['fermi_energy_units'] = 'Htr'
        # outputnode_dict['bandfile']           = bandfile

        outputnode_t = Dict(dict=outputnode_dict)
        if last_calc_out:
            outdict = create_band_result_node(outpara=outputnode_t,
                                              last_calc_out=last_calc_out,
                                              last_calc_retrieved=retrieved)
        else:
            outdict = create_band_result_node(outpara=outputnode_t)

        #TODO parse Bandstructure
        for link_name, node in six.iteritems(outdict):
            self.out(link_name, node)