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
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)
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)