Exemple #1
0
 def _validate_euphonic_input_file(cls, filename_full_path: str) -> dict:
     logger.information("Validate force constants file for interpolation.")
     from dos.load_euphonic import euphonic_available
     if euphonic_available():
         try:
             from euphonic.cli.utils import force_constants_from_file
             force_constants_from_file(filename_full_path)
             return dict(Invalid=False, Comment="")
         except Exception as error:
             if hasattr(error, 'message'):
                 message = error.message
             else:
                 message = str(error)
             return dict(
                 Invalid=True,
                 Comment=
                 f"Problem opening force constants file with Euphonic.: {message}"
             )
     else:
         return dict(
             Invalid=True,
             Comment=
             ("Could not import Euphonic module. "
              "Try running user/AdamJackson/install_euphonic.py from the Script Repository."
              ))
    def _read_file(self):
        """
        Decides if a castep or phonon file should be read then reads the file data
        Raises RuntimeError if no valid file is found.

        @return file_data dictionary holding all required data from the castep or phonon file
        """
        castep_filename = self.getPropertyValue('CASTEPFile')
        phonon_filename = self.getPropertyValue('PHONONFile')
        euphonic_filename = self.getPropertyValue('ForceConstantsFile')

        if phonon_filename and self._spec_type != 'BondTable':
            return self._read_data_from_file(phonon_filename)
        elif castep_filename:
            return self._read_data_from_file(castep_filename)
        elif euphonic_filename:
            if euphonic_available():
                file_data, self._element_isotope = get_data_with_euphonic(
                    euphonic_filename,
                    cutoff=float(self.getPropertyValue('ForceConstantsSampling')),
                    acoustic_sum_rule=None)
            else:
                raise ValueError("Could not load file using Euphonic: you may need to install this library.")

            self._num_ions = file_data['num_ions']
            return file_data

        else:
            raise RuntimeError('No valid data file')
    def validateInputs(self):
        """
        Performs input validation.

        Used to ensure the user is requesting a valid mode.
        """
        issues = dict()

        castep_filename = self.getPropertyValue('CASTEPFile')
        phonon_filename = self.getPropertyValue('PHONONFile')
        euphonic_filename = self.getPropertyValue('ForceConstantsFile')

        pdos_available = bool(phonon_filename or euphonic_filename)

        if not any((castep_filename, phonon_filename, euphonic_filename)):
            msg = 'Must have at least one input file'
            issues['CASTEPFile'] = msg
            issues['PHONONFile'] = msg
            issues['ForceConstantsFile'] = msg

        spec_type = self.getPropertyValue('SpectrumType')
        sum_contributions = self.getProperty('SumContributions').value
        scale_by_cross_section = self.getPropertyValue('ScaleByCrossSection') != 'None'

        ions = self.getProperty('Ions').value
        calc_partial = len(ions) > 0

        if euphonic_filename and not euphonic_available():
            issues['ForceConstantsFile'] = ('Cannot import the Euphonic library for force constants import. '
                                            'This will be included in a future version of Mantid. '
                                            'Until then, it can be installed using users/AdamJackson/install_euphonic.py '
                                            'from the Script Repository.')

        if spec_type == 'IonTable' and not pdos_available:
            issues['SpectrumType'] = 'Cannot produce ion table when only .castep file is provided'

        if spec_type == 'BondAnalysis' and phonon_filename == '' and castep_filename == '':
            issues['SpectrumType'] = 'Require both a .phonon and .castep file for bond analysis'

        if spec_type == 'BondTable' and castep_filename == '':
            issues['SpectrumType'] = 'Require a .castep file for bond table output'

        if spec_type != 'DOS' and calc_partial:
            issues['Ions'] = 'Cannot calculate partial density of states when using %s' % spec_type

        if spec_type != 'DOS' and scale_by_cross_section:
            issues['ScaleByCrossSection'] = 'Cannot scale contributions by cross sections when using %s' % spec_type

        if scale_by_cross_section and not pdos_available:
            issues['ScaleByCrossSection'] = 'Cannot scale by cross sections when only .castep file is provided'

        if not calc_partial and sum_contributions:
            issues['SumContributions'] = 'Cannot sum contributions when not calculating partial density of states'

        return issues
Exemple #4
0
    def runTest(self):
        with tempfile.TemporaryDirectory() as tmp_prefix:

            if not euphonic_available():
                self._install_euphonic_to_tmp_prefix(tmp_prefix)

            import pint  # noqa: F401
            import euphonic  # noqa: F401

            SimulatedDensityOfStates(ForceConstantsFile=find_file('phonopy-Al.yaml'),
                                     Function='Gaussian',
                                     SpectrumType='DOS',
                                     OutputWorkspace='phonopy-Al_DOS')
    def read_vibrational_or_phonon_data(self):
        """Get AbinsData (structure and modes) from force constants data.

        Frequencies/displacements are interpolated using the Euphonic library
        over a regular q-point mesh. The mesh is determined by a Moreno-Soler
        realspace cutoff, related to the size of an equivalent
        supercell. Meshes are rounded up so a very small cutoff will yield
        gamma-point-only sampling.

        """
        if not euphonic_available():
            raise ImportError("Could not import Euphonic library; this is "
                              "required to import force constants from Phonopy or .castep_bin.")

        cutoff = sampling_parameters['force_constants']['qpt_cutoff']
        modes = euphonic_calculate_modes(filename=self._clerk.get_input_filename(), cutoff=cutoff)

        unit_cell = modes.crystal.cell_vectors.to('angstrom').magnitude
        atoms = {f'atom_{atom_index}': {'symbol': str(atom_type),
                                        'sort': atom_index,
                                        'coord': unit_cell.T.dot(atom_r),
                                        'mass': mass}
                 for atom_index, atom_type, atom_r, mass in zip(range(modes.crystal.n_atoms),
                                                                modes.crystal.atom_type,
                                                                modes.crystal.atom_r,
                                                                modes.crystal.atom_mass.to('amu').magnitude)}

        file_data = {'frequencies': modes.frequencies.to('1/cm').magnitude,
                     'weights': modes.weights,
                     'k_vectors': modes.qpts,
                     'atomic_displacements': np.swapaxes(modes.eigenvectors, 1, 2),
                     'unit_cell': unit_cell,
                     'atoms': atoms}

        # save stuff to hdf file
        save_keys = ["frequencies", "weights", "k_vectors", "atomic_displacements", "unit_cell", "atoms"]
        data_to_save = {key: file_data[key] for key in save_keys}
        self.save_ab_initio_data(data=data_to_save)

        return self._rearrange_data(data=file_data)
Exemple #6
0
class AbinsLoadPhonopyTest(unittest.TestCase, abins.input.Tester):
    def setUp(self):
        # A small cutoff is used to limit number of data files
        self.default_cutoff = abins.parameters.sampling['force_constants'][
            'qpt_cutoff']
        abins.parameters.sampling['force_constants']['qpt_cutoff'] = 4.

    def tearDown(self):
        abins.test_helpers.remove_output_files(list_of_names=["_LoadPhonopy"])
        abins.parameters.sampling['force_constants'][
            'qpt_cutoff'] = self.default_cutoff

    @unittest.skipUnless(euphonic_available(),
                         'Optional dependency (euphonic) not available')
    def test_non_existing_file(self):
        with self.assertRaises(IOError):
            bad_phonopy_reader = EuphonicLoader(
                input_ab_initio_filename="NonExistingFile.yaml")
            bad_phonopy_reader.read_vibrational_or_phonon_data()

        with self.assertRaises(TypeError):
            _ = EuphonicLoader(input_ab_initio_filename=1)