File: atomic_weighting.py

package info (click to toggle)
python-dynasor 2.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 22,008 kB
  • sloc: python: 5,263; sh: 20; makefile: 3
file content (138 lines) | stat: -rw-r--r-- 5,427 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import numpy as np
from typing import Dict
from warnings import warn
from dynasor.post_processing.weights import Weights
from dynasor.sample import Sample, StaticSample, DynamicSample
from copy import deepcopy


def get_weighted_sample(sample: Sample, weights: Weights) -> Sample:
    r"""
    Weights correlation functions with atomic weighting factors

    The weighting of a partial dynamic structure factor
    :math:`S_\mathrm{AB}(\boldsymbol{q}, \omega)`
    for atom types :math:`A` and :math:`B` is carried out as

    .. math::

        S_\mathrm{AB}(\boldsymbol{q}, \omega)
        = f_\mathrm{A}(\boldsymbol{q}) f_\mathrm{B}(\boldsymbol{q})
        S_\mathrm{AB}(\boldsymbol{q}, \omega)

    :math:`f_\mathrm{A}(\boldsymbol{q})` and :math:`f_\mathrm{B}(\boldsymbol{q})`
    are atom-type and :math:`\boldsymbol{q}`-point dependent weights.

    If sample has incoherent correlation functions, but :attr:`weights` does not contain
    information on how to weight the incoherent part, then it will be dropped from the returned
    :attr:`Sample` object (and analogously for current correlation functions).

    Parameters
    ----------
    sample
        input sample to be weighted
    weights
        object containing the weights :math:`f_\mathrm{X}(\boldsymbol{q})`

    Returns
    -------
        A :class:`Sample` instance with the weighted partial and total structure factors.
    """

    # check input arguments
    if sample.has_incoherent and not weights.supports_incoherent:
        warn('The Weights does not support incoherent scattering, dropping the latter '
             'from the weighted sample.')

    if sample.has_currents and not weights.supports_currents:
        warn('The Weights does not support current correlations, dropping the latter '
             'from the weighted sample.')

    # setup new input dicts for new Sample
    data_dict = dict()
    for key in sample.dimensions:
        data_dict[key] = sample[key]
    meta_data = deepcopy(sample.meta_data)

    # generate atomic weights for each q-point and compile to arrays
    if 'q_norms' in sample.dimensions:
        q_norms = sample.q_norms
    else:
        q_norms = np.linalg.norm(sample.q_points, axis=1)

    weights_coh = dict()
    for at in sample.atom_types:
        weight_array = np.reshape([weights.get_weight_coh(at, q) for q in q_norms], (-1, 1))
        weights_coh[at] = weight_array
    if sample.has_incoherent and weights.supports_incoherent:
        weights_incoh = dict()
        for at in sample.atom_types:
            weight_array = np.reshape([weights.get_weight_incoh(at, q) for q in q_norms], (-1, 1))
            weights_incoh[at] = weight_array

    # weighting of correlation functions
    if isinstance(sample, StaticSample):
        data_dict_Sq = _compute_weighting_coherent(sample, 'Sq', weights_coh)
        data_dict.update(data_dict_Sq)
    elif isinstance(sample, DynamicSample):
        # coherent
        Fqt_coh_dict = _compute_weighting_coherent(sample, 'Fqt_coh', weights_coh)
        data_dict.update(Fqt_coh_dict)
        Sqw_coh_dict = _compute_weighting_coherent(sample, 'Sqw_coh', weights_coh)
        data_dict.update(Sqw_coh_dict)

        # incoherent
        if sample.has_incoherent and weights.supports_incoherent:
            Fqt_incoh_dict = _compute_weighting_incoherent(sample, 'Fqt_incoh', weights_incoh)
            data_dict.update(Fqt_incoh_dict)
            Sqw_incoh_dict = _compute_weighting_incoherent(sample, 'Sqw_incoh', weights_incoh)
            data_dict.update(Sqw_incoh_dict)
            data_dict['Fqt'] = data_dict['Fqt_coh'] + data_dict['Fqt_incoh']
            data_dict['Sqw'] = data_dict['Sqw_coh'] + data_dict['Sqw_incoh']
        else:
            data_dict['Fqt'] = data_dict['Fqt_coh'].copy()
            data_dict['Sqw'] = data_dict['Sqw_coh'].copy()

        # currents
        if sample.has_currents and weights.supports_currents:
            Clqt_dict = _compute_weighting_coherent(sample, 'Clqt', weights_coh)
            data_dict.update(Clqt_dict)
            Clqw_dict = _compute_weighting_coherent(sample, 'Clqw', weights_coh)
            data_dict.update(Clqw_dict)

            Ctqt_dict = _compute_weighting_coherent(sample, 'Ctqt', weights_coh)
            data_dict.update(Ctqt_dict)
            Ctqw_dict = _compute_weighting_coherent(sample, 'Ctqw', weights_coh)
            data_dict.update(Ctqw_dict)

    return sample.__class__(data_dict, **meta_data)


def _compute_weighting_coherent(sample: Sample, name: str, weight_dict: Dict):
    """
    Helper function for weighting and summing partial coherent correlation functions.
    """
    data_dict = dict()
    total = np.zeros(sample[name].shape)
    for s1, s2 in sample.pairs:
        key_pair = f'{name}_{s1}_{s2}'
        partial = weight_dict[s1] * weight_dict[s2] * sample[key_pair]
        data_dict[key_pair] = partial
        total += partial
    data_dict[name] = total
    return data_dict


def _compute_weighting_incoherent(sample: Sample, name: str, weight_dict: Dict):
    """
    Helper function for weighting and summing partial incoherent correlation functions.
    """
    data_dict = dict()
    total = np.zeros(sample[name].shape)
    for s1 in sample.atom_types:
        key = f'{name}_{s1}'
        partial = weight_dict[s1] * sample[key]
        data_dict[key] = partial
        total += partial
    data_dict[name] = total
    return data_dict