Esempio n. 1
0
def _bands_from_force_constants(data: ForceConstants,
                                q_distance: Quantity,
                                insert_gamma: bool = True,
                                frequencies_only: bool = False,
                                **calc_modes_kwargs
                                ) -> Tuple[Union[QpointPhononModes,
                                                 QpointFrequencies],
                                           XTickLabels, SplitArgs]:
    structure = data.crystal.to_spglib_cell()
    bandpath = seekpath.get_explicit_k_path(
        structure,
        reference_distance=q_distance.to('1 / angstrom').magnitude)

    if insert_gamma:
        _insert_gamma(bandpath)

    x_tick_labels = _get_tick_labels(bandpath)
    split_args = {'indices': _get_break_points(bandpath)}

    print(
        "Computing phonon modes: {n_modes} modes across {n_qpts} q-points"
        .format(n_modes=(data.crystal.n_atoms * 3),
                n_qpts=len(bandpath["explicit_kpoints_rel"])))
    qpts = bandpath["explicit_kpoints_rel"]

    if frequencies_only:
        modes = data.calculate_qpoint_frequencies(qpts,
                                                  reduce_qpts=False,
                                                  **calc_modes_kwargs)
    else:
        modes = data.calculate_qpoint_phonon_modes(qpts,
                                                   reduce_qpts=False,
                                                   **calc_modes_kwargs)
    return modes, x_tick_labels, split_args
Esempio n. 2
0
    def test_create_from_phonopy_without_installed_modules_raises_err(
            self, phonopy_args, mocker):
        # Mock import of yaml, h5py to raise ModuleNotFoundError
        import builtins
        real_import = builtins.__import__

        def mocked_import(name, *args, **kwargs):
            if name == 'h5py' or name == 'yaml':
                raise ModuleNotFoundError
            return real_import(name, *args, **kwargs)

        mocker.patch('builtins.__import__', side_effect=mocked_import)
        with pytest.raises(ImportPhonopyReaderError):
            ForceConstants.from_phonopy(**phonopy_args)
Esempio n. 3
0
def getForceConstants(material):
    docs_dir = os.path.dirname(os.path.abspath(__file__))
    try:
        return ForceConstants.from_castep(str(Path(docs_dir, material + ".castep_bin")))
    except FileNotFoundError:
        print('{} not found in {}. Fetching remote content.'.format(material, docs_dir))
        return fetchForceConstants(material)
Esempio n. 4
0
def fetchForceConstants(material):
    base_url = "https://raw.githubusercontent.com/g5t/brille/master/docs/tutorials"
    file_to_fetch = material + ".castep_bin"
    with tempfile.TemporaryDirectory() as tmp_dir:
        r = requests.get(base_url + "/" + file_to_fetch)
        if not r.ok:
            raise Exception("Fetching {} failed with reason '{}'".format(file_to_fetch, r.reason))
        out_path = Path(tmp_dir, file_to_fetch)
        open(str(out_path), 'wb').write(r.content)
        idata = ForceConstants.from_castep(str(out_path))
    return idata
Esempio n. 5
0
def force_constants_from_file(filename: Union[str, os.PathLike]
                              ) -> ForceConstants:
    """
    Load force constants data from file

    Parameters
    ----------
    filename
        Data file

    Returns
    -------
    ForceConstants
    """
    path = pathlib.Path(filename)
    if path.suffix == '.hdf5':
        if (path.parent / 'phonopy.yaml').is_file():
            return ForceConstants.from_phonopy(path=path.parent,
                                               summary_name='phonopy.yaml',
                                               fc_name=path.name)
        raise ValueError("Phonopy force_constants.hdf5 file "
                         "must be accompanied by phonopy.yaml")
    elif path.suffix == '.yaml':
        # Assume this is a (renamed?) phonopy.yaml file
        if (path.parent / 'force_constants.hdf5').is_file():
            fc_name = 'force_constants.hdf5'
        else:
            fc_name = 'FORCE_CONSTANTS'

        return ForceConstants.from_phonopy(path=path.parent,
                                           fc_name=fc_name,
                                           summary_name=path.name)
    elif path.suffix in ('.castep_bin', '.check'):
        return ForceConstants.from_castep(filename)
    elif path.suffix == '.json':
        return ForceConstants.from_json_file(filename)
    else:
        raise ValueError("File not recognised. Filename should be "
                         "*.yaml or force_constants.hdf5 (phonopy), "
                         "*.castep_bin or *.check "
                         "(castep) or *.json (JSON from Euphonic).")
Esempio n. 6
0
def _get_debye_waller(temperature: Quantity,
                      fc: ForceConstants,
                      grid: Optional[Sequence[int]] = None,
                      grid_spacing: Quantity = 0.1 * ureg('1/angstrom'),
                      **calc_modes_kwargs
                      ) -> DebyeWaller:
    """Generate Debye-Waller data from force constants and grid specification
    """
    mp_grid_spec = _grid_spec_from_args(fc.crystal, grid=grid,
                                        grid_spacing=grid_spacing)
    print("Calculating Debye-Waller factor on {} q-point grid"
          .format(' x '.join(map(str, mp_grid_spec))))
    dw_phonons = fc.calculate_qpoint_phonon_modes(
        euphonic.util.mp_grid(mp_grid_spec),
        **calc_modes_kwargs)
    return dw_phonons.calculate_debye_waller(temperature)
Esempio n. 7
0
    def test_create_from_phonopy_without_cloader_is_ok(self, material,
                                                       phonopy_args, mocker):
        # Mock 'from yaml import CLoader as Loader' to raise ImportError
        import builtins
        real_import = builtins.__import__

        def mocked_import(name, globals, locals, fromlist, level):
            if name == 'yaml':
                if fromlist is not None and fromlist[0] == 'CSafeLoader':
                    raise ImportError
            return real_import(name, globals, locals, fromlist, level)

        mocker.patch('builtins.__import__', side_effect=mocked_import)

        phonopy_args['path'] = get_phonopy_path(material, '')
        fc = ForceConstants.from_phonopy(**phonopy_args)
        expected_fc = get_expected_fc(material)
        check_force_constants(fc, expected_fc)
Esempio n. 8
0
    def setup_euphonic(self):
        from euphonic import ForceConstants
        from euphonic_sqw_models import CoherentCrystal

        fc = ForceConstants.from_castep('demo/datafiles/quartz.castep_bin')
        self.euobj = CoherentCrystal(fc,
                                     debye_waller_grid=[6, 6, 6],
                                     temperature=100,
                                     negative_e=True,
                                     asr=True,
                                     chunk=10000,
                                     use_c=True)

        self.scalefac = 200
        self.effective_fwhm = 1
        self.intrinsic_fwhm = 0.1

        self.wsc = self.m.cut_sqw('demo/datafiles/quartz_cut.sqw',
                                  [-3.02, -2.98], [5, 0.5, 38])
Esempio n. 9
0
def test_calculate_qpoint_phonon_modes(seedname, use_c, n_threads, benchmark):
    # Set up
    fc = ForceConstants.from_castep(
        os.path.join(get_data_path(), f'{seedname}.castep_bin'))
    qpts = get_qpts()
    # Benchmark
    if use_c:
        benchmark(fc.calculate_qpoint_phonon_modes,
                  qpts,
                  use_c=True,
                  fall_back_on_python=False,
                  n_threads=n_threads,
                  asr='reciprocal',
                  eta_scale=0.75)
    elif n_threads == 1:
        benchmark(fc.calculate_qpoint_phonon_modes,
                  qpts,
                  use_c=False,
                  asr='reciprocal',
                  eta_scale=0.75)
Esempio n. 10
0
def test_calculate_structure_factor(seedname, benchmark):
    # Set up
    qpts = get_qpts()
    fc = ForceConstants.from_castep(
        os.path.join(get_data_path(), f'{seedname}.castep_bin'))
    phonons = fc.calculate_qpoint_phonon_modes(qpts,
                                               use_c=True,
                                               fall_back_on_python=False,
                                               n_threads=5)
    fm = ureg('fm')
    scattering_lengths = {
        'La': 8.24 * fm,
        'Zr': 7.16 * fm,
        'O': 5.803 * fm,
        'C': 6.646 * fm,
        'Si': 4.1491 * fm,
        'H': -3.7390 * fm,
        'N': 9.36 * fm,
        'S': 2.847 * fm,
        'Nb': 7.054 * fm
    }
    # Benchmark
    benchmark(phonons.calculate_structure_factor,
              scattering_lengths=scattering_lengths)
 def get_quartz_fc():
     return ForceConstants.from_castep(
         get_castep_path('quartz', 'quartz.castep_bin'))
 def get_si2_fc():
     return ForceConstants.from_castep(
         get_castep_path('Si2-sc-skew', 'Si2-sc-skew.castep_bin'))
 def test_calc_qpt_ph_mds_asr_with_nonsense_fc_raises_warning(self, asr):
     fc = ForceConstants.from_json_file(
         os.path.join(get_fc_dir(), 'quartz_random_force_constants.json'))
     with pytest.warns(UserWarning):
         fc.calculate_qpoint_phonon_modes(get_test_qpts(), asr=asr)
 def get_lzo_fc():
     return ForceConstants.from_castep(
         get_castep_path('LZO', 'La2Zr2O7.castep_bin'))
Esempio n. 15
0
 def test_create_from_castep_with_no_fc_raises_runtime_error(self):
     with pytest.raises(RuntimeError):
         ForceConstants.from_castep(
             get_castep_path('h-BN', 'h-BN_no_force_constants.castep_bin'))
Esempio n. 16
0
 def create_from_json(self, request):
     material = request.param
     expected_fc = get_expected_fc(material)
     fc = ForceConstants.from_json_file(get_json_file(material))
     return fc, expected_fc
 def get_si2_qpt_ph_modes(self, request):
     fc = ForceConstants.from_castep(
         get_castep_path('Si2-sc-skew', 'Si2-sc-skew.castep_bin'))
     kwargs = self.get_multithreaded_kwargs(request.param)
     return fc.calculate_qpoint_phonon_modes(get_test_qpts(), **kwargs)
Esempio n. 18
0
 def create_from_dict(self, request):
     material = request.param
     expected_fc = get_expected_fc(material)
     fc = ForceConstants.from_dict(expected_fc.to_dict())
     return fc, expected_fc
Esempio n. 19
0
 def create_from_phonopy(self, request):
     material, phonopy_args = request.param
     phonopy_args['path'] = get_phonopy_path(material, '')
     fc = ForceConstants.from_phonopy(**phonopy_args)
     expected_fc = get_expected_fc(material)
     return fc, expected_fc
Esempio n. 20
0
 def serialise_to_dict(self, request):
     fc, expected_fc = request.param
     # Convert to dict, then back to object to test
     fc_dict = fc.to_dict()
     fc_from_dict = ForceConstants.from_dict(fc_dict)
     return fc_from_dict, expected_fc
Esempio n. 21
0
 def test_serialise_to_json_file(self, fc, tmpdir):
     output_file = str(tmpdir.join('tmp.test'))
     fc.to_json_file(output_file)
     check_json_metadata(output_file, 'ForceConstants')
     deserialised_fc = ForceConstants.from_json_file(output_file)
     check_force_constants(fc, deserialised_fc)
Esempio n. 22
0
 def test_faulty_object_creation(self, inject_faulty_elements):
     faulty_args, faulty_kwargs, expected_exception = inject_faulty_elements
     with pytest.raises(expected_exception):
         ForceConstants(*faulty_args, **faulty_kwargs)
Esempio n. 23
0
def calculate_optimum_eta(filename: str,
                          eta_min: float = 0.25,
                          eta_max: float = 1.5,
                          eta_step: float = 0.25,
                          n: int = 100,
                          print_to_terminal: bool = False):
    """
    Calculate the optimum eta and other etas from the filename castep_bin file

    Parameters
    ----------
    filename : str
        The path and name of the .castep_bin/.check to read from
    eta_min : float, optional, Default: 0.25
        The minimum value of eta to test
    eta_max : float, optional, Default: 1.5
        The maximum value of eta to test
    eta_step : float, optional, Default: 0.25
        The difference between each eta to test
    n : int, optional, Default: 100
        The number of times to loop over q-points. A higher value will get a more reliable timing, but will take longer
    print_to_terminal : bool, optional, Default: False
        Whether to print the outcome to terminal or not

    Returns
    -------
    Tuple[float, float, float, np.array, np.array, np.array]:
        A tuple of the optimal eta, the time it took to initialise the optimal eta,
        the time per qpoint for the optimal eta, other etas, their initialisation times and their times per qpoint.
    """
    etas = np.arange(eta_min, eta_max + eta_step / 100, eta_step)
    t_init = np.zeros(len(etas), dtype=np.float64)
    t_tot = np.zeros(len(etas), dtype=np.float64)

    idata = ForceConstants.from_castep(filename)
    sfmt = '{:20s}'
    tfmt = '{: 3.2f}'
    etafmt = '{: 2.2f}'
    for i, eta in enumerate(etas):
        if print_to_terminal:
            print(('Results for eta ' + etafmt).format(eta))
        # Time Ewald sum initialisation
        start = time.time()
        idata._dipole_correction_init(eta_scale=eta)
        end = time.time()
        t_init[i] = end - start
        if print_to_terminal:
            print((sfmt + ': ' + tfmt + ' s').format('Ewald init time',
                                                     t_init[i]))

        # Time per qpt
        start = time.time()
        for n in range(n):
            idata._calculate_dipole_correction(np.array([0.5, 0.5, 0.5]))
        end = time.time()
        t_tot[i] = end - start
        if print_to_terminal:
            print(
                (sfmt + ': ' + tfmt + ' ms\n').format('Ewald time/qpt',
                                                      t_tot[i] * 1000 / n))

    opt = np.argmin(t_tot)
    if print_to_terminal:
        print('******************************')
        print(('Suggested optimum eta is ' + etafmt).format(etas[opt]))
        print((sfmt + ': ' + tfmt + ' s').format('init time', t_init[opt]))
        print((sfmt + ': ' + tfmt + ' ms\n').format('time/qpt',
                                                    t_tot[opt] * 1000 / n))

    return etas[opt], t_init[opt], t_tot[opt], etas, t_init, t_tot
Esempio n. 24
0
def sample_sphere_dos(fc: ForceConstants,
                      mod_q: Quantity,
                      sampling: str = 'golden',
                      npts: int = 1000, jitter: bool = False,
                      energy_bins: Quantity = None,
                      **calc_modes_args
                      ) -> Spectrum1D:
    """Sample the phonon DOS, averaging over a sphere of constant |q|

    Parameters
    ----------

    fc
        Force constant data for system

    mod_q
        radius of sphere from which vector q samples are taken (in units
        of inverse length; usually 1/angstrom).

    sampling
        Sphere-sampling scheme. (Case-insensitive) options are:

            - 'golden':
                Fibonnaci-like sampling that steps regularly along one
                spherical coordinate while making irrational steps in
                the other

            - 'sphere-projected-grid':
                Regular 2-D square mesh projected onto sphere. npts will
                be distributed as evenly as possible (i.e. using twice
                as many 'longitude' as 'lattitude' lines), rounding up
                if necessary.

            - 'spherical-polar-grid':
                Mesh over regular subdivisions in spherical polar
                coordinates.  npts will be rounded up as necessary in
                the same scheme as for sphere-projected-grid. 'Latitude'
                lines are evenly-spaced in z

            - 'spherical-polar-improved':
                npts distributed as regularly as possible using
                spherical polar coordinates: 'latitude' lines are
                evenly-spaced in z and points are distributed among
                these rings to obtain most even spacing possible.

            - 'random-sphere':
                Points are distributed randomly in unit square and
                projected onto sphere.

    npts
        Number of samples. Note that some sampling methods have
        constraints on valid values and will round up as appropriate.

    jitter
        For non-random sampling schemes, apply an additional random
        displacement to each point.

    energy_bins
        Preferred energy bin edges. If not provided, will setup
        1000 bins (1001 bin edges) from 0 to 1.05 * [max energy]

    **calc_modes_args
        other keyword arguments (e.g. 'use_c') will be passed to
        ForceConstants.calculate_qpoint_phonon_modes()

    Returns
    -------
    Spectrum1D

    """

    qpts_cart = _get_qpts_sphere(npts, sampling=sampling, jitter=jitter
                                 ) * mod_q
    qpts_frac = _qpts_cart_to_frac(qpts_cart, fc.crystal)

    phonons = fc.calculate_qpoint_frequencies(qpts_frac, **calc_modes_args
                                              )  # type: QpointFrequencies

    if energy_bins is None:
        energy_bins = _get_default_bins(phonons)

    return phonons.calculate_dos(energy_bins)
 def get_quartz_qpt_ph_modes(self, request):
     fc = ForceConstants.from_castep(
         get_castep_path('quartz', 'quartz.castep_bin'))
     kwargs = self.get_multithreaded_kwargs(request.param)
     return fc.calculate_qpoint_phonon_modes(
         get_test_qpts('split'), **kwargs)
Esempio n. 26
0
def sample_sphere_structure_factor(
    fc: ForceConstants,
    mod_q: Quantity,
    dw: DebyeWaller = None,
    dw_spacing: Quantity = 0.025 * ureg('1/angstrom'),
    temperature: Optional[Quantity] = 273. * ureg['K'],
    sampling: str = 'golden',
    npts: int = 1000, jitter: bool = False,
    energy_bins: Quantity = None,
    scattering_lengths: Union[dict, str] = 'Sears1992',
    **calc_modes_args
) -> Spectrum1D:
    """Sample structure factor, averaging over a sphere of constant |q|

    (Specifically, this is the one-phonon inelastic-scattering structure
    factor as implemented in
    QpointPhononModes.calculate_structure_factor().)

    Parameters
    ----------

    fc
        Force constant data for system

    mod_q
        scalar radius of sphere from which vector q samples are taken

    dw
        Debye-Waller exponent used for evaluation of scattering
        function. If not provided, this is generated automatically over
        Monkhorst-Pack q-point mesh determined by ``dw_spacing``.

    dw_spacing
        Maximum distance between q-points in automatic q-point mesh (if used)
        for Debye-Waller calculation.

    temperature
        Temperature for Debye-Waller calculation. If both temperature and dw
        are set to None, Debye-Waller factor will be omitted.

    sampling
        Sphere-sampling scheme. (Case-insensitive) options are:
            - 'golden':
                Fibonnaci-like sampling that steps regularly along one
                spherical coordinate while making irrational steps in
                the other

            - 'sphere-projected-grid':
                Regular 2-D square mesh projected onto sphere. npts will
                be distributed as evenly as possible (i.e. using twice
                as many 'longitude' as 'lattitude' lines), rounding up
                if necessary.

            - 'spherical-polar-grid':
                Mesh over regular subdivisions in spherical polar
                coordinates.  npts will be rounded up as necessary in
                the same scheme as for sphere-projected-grid. 'Latitude'
                lines are evenly-spaced in z

            - 'spherical-polar-improved':
                npts distributed as regularly as possible using
                spherical polar coordinates: 'latitude' lines are
                evenly-spaced in z and points are distributed among
                these rings to obtain most even spacing possible.

            - 'random-sphere':
                Points are distributed randomly in unit square and
                projected onto sphere.

    npts
        Number of samples. Note that some sampling methods have
            constraints on valid values and will round up as
            appropriate.

    jitter
        For non-random sampling schemes, apply an additional random
            displacement to each point.

    energy_bins
        Preferred energy bin edges. If not provided, will setup 1000
        bins (1001 bin edges) from 0 to 1.05 * [max energy]

    scattering_lengths
        Dict of neutron scattering lengths labelled by element. If a
        string is provided, this selects coherent scattering lengths
        from reference data by setting the 'label' argument of the
        euphonic.util.get_reference_data() function.

    **calc_modes_args
        other keyword arguments (e.g. 'use_c') will be passed to
        ForceConstants.calculate_qpoint_phonon_modes()

    Returns
    -------
    Spectrum1D

    """

    if isinstance(scattering_lengths, str):
        scattering_lengths = get_reference_data(
            physical_property='coherent_scattering_length',
            collection=scattering_lengths)  # type: dict

    if temperature is not None:
        if (dw is None):
            dw_qpts = mp_grid(fc.crystal.get_mp_grid_spec(dw_spacing))
            dw_phonons = fc.calculate_qpoint_phonon_modes(dw_qpts,
                                                          **calc_modes_args)
            dw = dw_phonons.calculate_debye_waller(temperature
                                                   )  # type: DebyeWaller
        else:
            if not np.isclose(dw.temperature.to('K').magnitude,
                              temperature.to('K').magnitude):
                raise ValueError('Temperature argument is not consistent with '
                                 'temperature stored in DebyeWaller object.')

    qpts_cart = _get_qpts_sphere(npts, sampling=sampling, jitter=jitter
                                 ) * mod_q

    qpts_frac = _qpts_cart_to_frac(qpts_cart, fc.crystal)

    phonons = fc.calculate_qpoint_phonon_modes(qpts_frac, **calc_modes_args
                                               )  # type: QpointPhononModes

    if energy_bins is None:
        energy_bins = _get_default_bins(phonons)

    s = phonons.calculate_structure_factor(
        scattering_lengths=scattering_lengths, dw=dw)

    return s.calculate_1d_average(energy_bins)
 def get_cahgo2_qpt_ph_modes(self, request):
     fc = ForceConstants.from_phonopy(
         path=get_phonopy_path('CaHgO2', ''),
         summary_name='mp-7041-20180417.yaml')
     kwargs = self.get_multithreaded_kwargs(request.param)
     return fc.calculate_qpoint_phonon_modes(get_test_qpts(), **kwargs)
class TestForceConstantsCalculateQPointPhononModes:
    def get_lzo_fc():
        return ForceConstants.from_castep(
            get_castep_path('LZO', 'La2Zr2O7.castep_bin'))

    lzo_params = [
        (get_lzo_fc(), 'LZO', [get_test_qpts(),
                               {}], 'LZO_no_asr_qpoint_phonon_modes.json'),
        (get_lzo_fc(), 'LZO', [get_test_qpts(), {
            'asr': 'realspace'
        }], 'LZO_realspace_qpoint_phonon_modes.json'),
        (get_lzo_fc(), 'LZO', [get_test_qpts(), {
            'asr': 'reciprocal'
        }], 'LZO_reciprocal_qpoint_phonon_modes.json')
    ]

    def get_si2_fc():
        return ForceConstants.from_castep(
            get_castep_path('Si2-sc-skew', 'Si2-sc-skew.castep_bin'))

    si2_params = [
        (get_si2_fc(), 'Si2-sc-skew', [get_test_qpts(), {}],
         'Si2-sc-skew_no_asr_qpoint_phonon_modes.json'),
        (get_si2_fc(), 'Si2-sc-skew', [get_test_qpts(), {
            'asr': 'realspace'
        }], 'Si2-sc-skew_realspace_qpoint_phonon_modes.json'),
        (get_si2_fc(), 'Si2-sc-skew', [get_test_qpts(), {
            'asr': 'reciprocal'
        }], 'Si2-sc-skew_reciprocal_qpoint_phonon_modes.json')
    ]

    def get_quartz_fc():
        return ForceConstants.from_castep(
            get_castep_path('quartz', 'quartz.castep_bin'))

    quartz_params = [
        (get_quartz_fc(), 'quartz',
         [get_test_qpts(), {
             'asr': 'reciprocal',
             'splitting': False
         }], 'quartz_reciprocal_qpoint_phonon_modes.json'),
        (get_quartz_fc(), 'quartz', [
            get_test_qpts(), {
                'asr': 'reciprocal',
                'splitting': False,
                'eta_scale': 0.75
            }
        ], 'quartz_reciprocal_qpoint_phonon_modes.json'),
        (get_quartz_fc(), 'quartz', [
            get_test_qpts('split'), {
                'asr': 'reciprocal',
                'splitting': True,
                'insert_gamma': False
            }
        ], 'quartz_split_reciprocal_qpoint_phonon_modes.json'),
        (get_quartz_fc(), 'quartz', [
            get_test_qpts('split_insert_gamma'), {
                'asr': 'reciprocal',
                'splitting': True,
                'insert_gamma': True
            }
        ], 'quartz_split_reciprocal_qpoint_phonon_modes.json')
    ]

    nacl_params = [
        (ForceConstants.from_phonopy(path=get_phonopy_path('NaCl', ''),
                                     summary_name='phonopy_nacl.yaml'), 'NaCl',
         [get_test_qpts(), {
             'asr': 'reciprocal'
         }], 'NaCl_reciprocal_qpoint_phonon_modes.json')
    ]

    cahgo2_params = [
        (ForceConstants.from_phonopy(path=get_phonopy_path('CaHgO2', ''),
                                     summary_name='mp-7041-20180417.yaml'),
         'CaHgO2', [get_test_qpts(), {
             'asr': 'reciprocal'
         }], 'CaHgO2_reciprocal_qpoint_phonon_modes.json')
    ]

    @pytest.mark.parametrize(
        'fc, material, all_args, expected_qpoint_phonon_modes_file',
        lzo_params + quartz_params + nacl_params + si2_params + cahgo2_params)
    @pytest.mark.parametrize('reduce_qpts, n_threads', [(False, 0), (True, 0),
                                                        (True, 1), (True, 2)])
    def test_calculate_qpoint_phonon_modes(self, fc, material, all_args,
                                           expected_qpoint_phonon_modes_file,
                                           reduce_qpts, n_threads):
        func_kwargs = all_args[1]
        func_kwargs['reduce_qpts'] = reduce_qpts
        if n_threads == 0:
            func_kwargs['use_c'] = False
        else:
            func_kwargs['use_c'] = True
            func_kwargs['n_threads'] = n_threads
        qpoint_phonon_modes = fc.calculate_qpoint_phonon_modes(
            all_args[0], **func_kwargs)
        expected_qpoint_phonon_modes = ExpectedQpointPhononModes(
            os.path.join(get_qpt_ph_modes_dir(material),
                         expected_qpoint_phonon_modes_file))
        # Only give gamma-acoustic modes special treatment if the acoustic
        # sum rule has been applied
        if not 'asr' in func_kwargs.keys():
            gamma_atol = None
        else:
            gamma_atol = 0.5
        check_qpt_ph_modes(qpoint_phonon_modes,
                           expected_qpoint_phonon_modes,
                           frequencies_atol=1e-4,
                           frequencies_rtol=2e-5,
                           acoustic_gamma_atol=gamma_atol)

    @pytest.mark.parametrize(
        ('fc, material, all_args, expected_qpoint_phonon_modes_file, '
         'expected_modw_file'), [(get_quartz_fc(), 'quartz', [
             mp_grid([5, 5, 4]), {
                 'asr': 'reciprocal',
                 'return_mode_widths': True
             }
         ], 'quartz_554_full_qpoint_phonon_modes.json',
                                  'quartz_554_full_mode_widths.json'),
                                 (get_lzo_fc(), 'LZO', [
                                     mp_grid([2, 2, 2]), {
                                         'asr': 'reciprocal',
                                         'return_mode_widths': True
                                     }
                                 ], 'lzo_222_full_qpoint_phonon_modes.json',
                                  'lzo_222_full_mode_widths.json')])
    @pytest.mark.parametrize('n_threads', [0, 2])
    def test_calculate_qpoint_phonon_modes_with_mode_widths(
            self, fc, material, all_args, expected_qpoint_phonon_modes_file,
            expected_modw_file, n_threads):
        func_kwargs = all_args[1]
        if n_threads == 0:
            func_kwargs['use_c'] = False
        else:
            func_kwargs['use_c'] = True
            func_kwargs['n_threads'] = n_threads
        qpoint_phonon_modes, modw = fc.calculate_qpoint_phonon_modes(
            all_args[0], **func_kwargs)

        with open(os.path.join(get_fc_dir(), expected_modw_file), 'r') as fp:
            modw_dict = json.load(fp)
        expected_modw = modw_dict['mode_widths'] * ureg(
            modw_dict['mode_widths_unit'])
        expected_qpoint_phonon_modes = ExpectedQpointPhononModes(
            os.path.join(get_qpt_ph_modes_dir(material),
                         expected_qpoint_phonon_modes_file))
        # Only give gamma-acoustic modes special treatment if the acoustic
        # sum rule has been applied
        if not 'asr' in func_kwargs.keys():
            gamma_atol = None
        else:
            gamma_atol = 0.5

        check_qpt_ph_modes(qpoint_phonon_modes,
                           expected_qpoint_phonon_modes,
                           frequencies_atol=1e-4,
                           frequencies_rtol=2e-5,
                           acoustic_gamma_atol=gamma_atol)
        assert modw.units == expected_modw.units
        npt.assert_allclose(modw.magnitude,
                            expected_modw.magnitude,
                            atol=2e-4,
                            rtol=5e-5)

    # ForceConstants stores some values (supercell image list, vectors
    # for the Ewald sum) so check repeated calculations give the same
    # result
    def test_repeated_calculate_qpoint_phonon_modes_doesnt_change_result(self):
        fc = get_fc('quartz')
        qpt_ph_modes1 = fc.calculate_qpoint_phonon_modes(get_test_qpts(),
                                                         asr='realspace')
        qpt_ph_modes2 = fc.calculate_qpoint_phonon_modes(get_test_qpts(),
                                                         asr='realspace')
        check_qpt_ph_modes(qpt_ph_modes1, qpt_ph_modes2)

    @pytest.mark.parametrize(
        'fc, material, qpt, kwargs, expected_qpt_ph_modes_file',
        [(get_fc('quartz'), 'quartz', np.array([[1., 1., 1.]]), {
            'splitting': True
        }, 'quartz_single_qpoint_phonon_modes.json')])
    def test_calculate_qpoint_phonon_modes_single_qpt(
            self, fc, material, qpt, kwargs, expected_qpt_ph_modes_file):
        qpoint_phonon_modes = fc.calculate_qpoint_phonon_modes(qpt, **kwargs)
        expected_qpoint_phonon_modes = ExpectedQpointPhononModes(
            os.path.join(get_qpt_ph_modes_dir(material),
                         expected_qpt_ph_modes_file))
        check_qpt_ph_modes(qpoint_phonon_modes,
                           expected_qpoint_phonon_modes,
                           frequencies_atol=1e-4,
                           frequencies_rtol=2e-5)

    weights = np.array([0.1, 0.05, 0.05, 0.2, 0.2, 0.15, 0.15, 0.2, 0.1])
    weights_output_split_gamma = np.array([
        0.1, 0.05, 0.025, 0.025, 0.2, 0.1, 0.1, 0.075, 0.075, 0.075, 0.075,
        0.2, 0.1
    ])

    @pytest.mark.parametrize(
        'fc, qpts, weights, expected_weights, kwargs',
        [(get_fc('quartz'), get_test_qpts(), weights, weights, {}),
         (get_fc('quartz'), get_test_qpts('split_insert_gamma'), weights,
          weights_output_split_gamma, {
              'insert_gamma': True
          })])
    def test_calculate_qpoint_phonon_modes_with_weights_sets_weights(
            self, fc, qpts, weights, expected_weights, kwargs):
        qpt_ph_modes_weighted = fc.calculate_qpoint_phonon_modes(
            qpts, weights=weights, **kwargs)
        npt.assert_allclose(qpt_ph_modes_weighted.weights, expected_weights)

    @pytest.mark.parametrize(
        'fc, qpts, weights, expected_weights, kwargs',
        [(get_fc('quartz'), get_test_qpts(), weights, weights, {}),
         (get_fc('quartz'), get_test_qpts('split_insert_gamma'), weights,
          weights_output_split_gamma, {
              'insert_gamma': True
          })])
    def test_calculate_qpoint_phonon_modes_with_weights_doesnt_change_result(
            self, fc, qpts, weights, expected_weights, kwargs):
        qpt_ph_modes_weighted = fc.calculate_qpoint_phonon_modes(
            qpts, weights=weights, **kwargs)
        qpt_ph_modes_unweighted = fc.calculate_qpoint_phonon_modes(
            qpts, **kwargs)
        qpt_ph_modes_unweighted.weights = expected_weights
        check_qpt_ph_modes(qpt_ph_modes_weighted, qpt_ph_modes_unweighted)

    @pytest.mark.parametrize('asr', ['realspace', 'reciprocal'])
    def test_calc_qpt_ph_mds_asr_with_nonsense_fc_raises_warning(self, asr):
        fc = ForceConstants.from_json_file(
            os.path.join(get_fc_dir(), 'quartz_random_force_constants.json'))
        with pytest.warns(UserWarning):
            fc.calculate_qpoint_phonon_modes(get_test_qpts(), asr=asr)
# For some reason we _have_ to load euphonic before Matlab
from euphonic import ForceConstants
from pace_neutrons import EuphonicWrapper

# Setting (os.RTLD_NOW | os.RTLD_DEEPBIND) flags causes a crash here...
#import sys; sys.setdlopenflags(10)

from pace_neutrons import Matlab
m = Matlab()
import numpy as np
from matlab import double as md

fc = ForceConstants.from_castep('quartz/quartz.castep_bin')
euobj = EuphonicWrapper(fc,
                        debye_waller_grid=[6, 6, 6],
                        temperature=100,
                        negative_e=True,
                        asr=True,
                        chunk=10000,
                        use_c=True)

scalefac = 1e12
effective_fwhm = 1
intrinsic_fwhm = 0.1

wsc = m.cut_sqw('quartz/2ph_m4_0_ECut.sqw', [-3.02, -2.98], [5, 0.5, 38])

# Calculate spectra with simple energy convolution (fixed width Gaussian)
wsim = m.disp2sqw_eval(wsc, euobj.horace_disp, (scalefac), effective_fwhm)

# Calculate spectra with full instrument resolution convolution
Esempio n. 30
0
 def test_create_from_phonopy_with_bad_inputs_raises_err(
         self, phonopy_args, err):
     with pytest.raises(err):
         ForceConstants.from_phonopy(**phonopy_args)