orochi.pdfsim 4.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- orochi/__init__.py +22 -0
- orochi/pdfsim/__init__.py +4 -0
- orochi/pdfsim/_old/no_q_depend.py +84 -0
- orochi/pdfsim/_old/q_depend.py +123 -0
- orochi/pdfsim/gr_histogram/_old/cpu.py +313 -0
- orochi/pdfsim/gr_histogram/_old/epf.py +60 -0
- orochi/pdfsim/gr_histogram/_old/gpu.py +58 -0
- orochi/pdfsim/gr_histogram/histogram/cpu.py +86 -0
- orochi/pdfsim/gr_histogram/histogram/pdf_no_q_depend_gpu.py +194 -0
- orochi/pdfsim/gr_histogram/histogram/pdf_q_depend_cpu.py +187 -0
- orochi/pdfsim/gr_histogram/profile/cpu.py +274 -0
- orochi/pdfsim/io/save.py +11 -0
- orochi/pdfsim/io/xyz.py +13 -0
- orochi/pdfsim/macro/structural_analysis_with_predictor.py +17 -0
- orochi/pdfsim/params/default.py +147 -0
- orochi/pdfsim/params/spring8_bl22xu_fpd.py +17 -0
- orochi/pdfsim/restraint/correlation.py +33 -0
- orochi/pdfsim/restraint/penalty.py +49 -0
- orochi/pdfsim/shape/spheroid.py +12 -0
- orochi/pdfsim/simulator.py +1456 -0
- orochi/pdfsim/submodules/explain/params.py +64 -0
- orochi/pdfsim/submodules/explain/reasoning.py +113 -0
- orochi/pdfsim/submodules/explain/scoring.py +93 -0
- orochi/pdfsim/submodules/explain/visualize.py +77 -0
- orochi/pdfsim/submodules/lang_model.py +41 -0
- orochi/pdfsim/submodules/phase_update.py +28 -0
- orochi/pdfsim/submodules/refinement.py +488 -0
- orochi/pdfsim/submodules/subgroup.py +216 -0
- orochi/pdfsim/version.py +23 -0
- orochi_pdfsim-4.0.0.dist-info/METADATA +256 -0
- orochi_pdfsim-4.0.0.dist-info/RECORD +34 -0
- orochi_pdfsim-4.0.0.dist-info/WHEEL +5 -0
- orochi_pdfsim-4.0.0.dist-info/licenses/LICENSE.rst +682 -0
- orochi_pdfsim-4.0.0.dist-info/top_level.txt +1 -0
orochi/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
##############################################################################
|
|
3
|
+
#
|
|
4
|
+
# (c) 2025 National Institute for Materials Science (NIMS).
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
#
|
|
7
|
+
# File coded by: Tominaka Laboratory members and community contributors.
|
|
8
|
+
#
|
|
9
|
+
# See GitHub contributions for a more detailed list of contributors.
|
|
10
|
+
# https://github.com/Tominaka-Laboratory/orochi.pdf-simulator/graphs/contributors
|
|
11
|
+
#
|
|
12
|
+
# See LICENSE.rst for license information.
|
|
13
|
+
#
|
|
14
|
+
##############################################################################
|
|
15
|
+
"""Blank namespace package for module orochi."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
from pkgutil import extend_path
|
|
19
|
+
|
|
20
|
+
__path__ = extend_path(__path__, __name__)
|
|
21
|
+
|
|
22
|
+
# End of file
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#old one before refactoring
|
|
2
|
+
|
|
3
|
+
# import numpy as np
|
|
4
|
+
# from numpy.typing import NDArray
|
|
5
|
+
|
|
6
|
+
# def calc_gij(self, aij: NDArray[np.int64]) -> NDArray[np.float64]:
|
|
7
|
+
# """
|
|
8
|
+
# Calculates the scattering factor product g_ij (Q-independent).
|
|
9
|
+
|
|
10
|
+
# This function calculates the scattering factor product g_ij, assuming that
|
|
11
|
+
# the atomic scattering factors are independent of the scattering vector Q.
|
|
12
|
+
# This simplification is often used for simpler models or when Q-dependence
|
|
13
|
+
# is not significant. The calculation uses the atomic numbers (zi) to
|
|
14
|
+
# approximate the scattering factors.
|
|
15
|
+
|
|
16
|
+
# Parameters
|
|
17
|
+
# ----------
|
|
18
|
+
# self : Simulator
|
|
19
|
+
# The Simulator object, which must contain the atomic numbers (zi)
|
|
20
|
+
# and atomic symbols.
|
|
21
|
+
# aij : NDArray[np.int64]
|
|
22
|
+
# A 2D array representing the atomic pairs. Each row contains the indices
|
|
23
|
+
# of the two atoms in a pair.
|
|
24
|
+
|
|
25
|
+
# Returns
|
|
26
|
+
# -------
|
|
27
|
+
# numpy.ndarray
|
|
28
|
+
# A 1D NumPy array representing g_ij, the scattering factor product
|
|
29
|
+
# for each atomic pair.
|
|
30
|
+
|
|
31
|
+
# Notes
|
|
32
|
+
# -----
|
|
33
|
+
# The function performs the following steps:
|
|
34
|
+
# 1. Retrieves the atomic numbers zi for each unique atom.
|
|
35
|
+
# 2. Assigns the corresponding zi to each atom in the pairs defined by aij.
|
|
36
|
+
# 3. Calculates the product of the atomic numbers for each pair.
|
|
37
|
+
# 4. Normalizes the product by the square of the average atomic number,
|
|
38
|
+
# weighted by the atomic occupancies.
|
|
39
|
+
# """
|
|
40
|
+
# symbols_all = self.phase.model["symbol"]
|
|
41
|
+
# occ = self.phase.model["occ"]
|
|
42
|
+
|
|
43
|
+
# sfs = np.ones_like(symbols_all).astype(float)
|
|
44
|
+
# fij = np.ones_like(aij).astype(float)
|
|
45
|
+
|
|
46
|
+
# symbols = np.unique(symbols_all)
|
|
47
|
+
# for atom in symbols:
|
|
48
|
+
# zi = self.zi[atom]
|
|
49
|
+
# sfs[np.where(symbols_all == atom)] = zi
|
|
50
|
+
# fij[np.where(aij == atom)] = zi
|
|
51
|
+
|
|
52
|
+
# gij = np.abs(fij[:, 0] * fij[:, 1])
|
|
53
|
+
# gij /= np.square(np.average(sfs * occ)) # fij/<cf>2
|
|
54
|
+
# return gij
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# def calc_scattering_factors(self) -> NDArray[np.float64]:
|
|
59
|
+
# """
|
|
60
|
+
# Calculates the atomic scattering factors (Q-independent approximation).
|
|
61
|
+
|
|
62
|
+
# This function calculates the atomic scattering factors f(Q) using the
|
|
63
|
+
# approximation that they are equal to the atomic numbers (zi). This
|
|
64
|
+
# is a simplification that neglects the Q-dependence of the scattering factors.
|
|
65
|
+
|
|
66
|
+
# Parameters
|
|
67
|
+
# ----------
|
|
68
|
+
# self : Simulator
|
|
69
|
+
# The Simulator object, which must contain the atomic symbols and
|
|
70
|
+
# atomic numbers (zi).
|
|
71
|
+
|
|
72
|
+
# Returns
|
|
73
|
+
# -------
|
|
74
|
+
# numpy.ndarray
|
|
75
|
+
# A 1D NumPy array of the atomic scattering factors f(Q) for each atom
|
|
76
|
+
# in the structure.
|
|
77
|
+
# """
|
|
78
|
+
# symbols_all = self.phase.model["symbol"]
|
|
79
|
+
# sfs = np.ones_like(symbols_all).astype(float)
|
|
80
|
+
# symbols = np.unique(symbols_all)
|
|
81
|
+
# for atom in symbols:
|
|
82
|
+
# zi = self.zi[atom]
|
|
83
|
+
# sfs[np.where(symbols_all == atom)] = zi
|
|
84
|
+
# return sfs
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# import numpy as np
|
|
2
|
+
# from scipy.fft import dct
|
|
3
|
+
# import scipy.interpolate as intp
|
|
4
|
+
# from numpy.typing import NDArray
|
|
5
|
+
|
|
6
|
+
# def calc_gij(self, aij: NDArray[np.int64]) -> NDArray[np.complex128]:
|
|
7
|
+
# """
|
|
8
|
+
# Calculates the scattering factor product g_ij(Q) with Q-dependence.
|
|
9
|
+
|
|
10
|
+
# This function calculates the scattering factor product g_ij(Q), which accounts for
|
|
11
|
+
# the Q-dependence of the atomic scattering factors. This is important for accurate
|
|
12
|
+
# PDF calculations, especially when dealing with materials containing elements with
|
|
13
|
+
# significant differences in their scattering factors. The calculation involves
|
|
14
|
+
# obtaining the atomic scattering factors f0, f1, and f2, and then performing
|
|
15
|
+
# a discrete cosine transform (DCT) to obtain the real-space representation.
|
|
16
|
+
|
|
17
|
+
# Parameters
|
|
18
|
+
# ----------
|
|
19
|
+
# self : Simulator
|
|
20
|
+
# The Simulator object, which must contain the atomic scattering factors
|
|
21
|
+
# (f0s, f1f2s), atomic symbols, and relevant parameters (qmax, number_scf_function, pad).
|
|
22
|
+
# aij : NDArray[np.int64]
|
|
23
|
+
# A 2D array representing the atomic pairs. Each row contains the indices
|
|
24
|
+
# of the two atoms in a pair.
|
|
25
|
+
|
|
26
|
+
# Returns
|
|
27
|
+
# -------
|
|
28
|
+
# NDArray[np.complex128]
|
|
29
|
+
# A 2D NumPy array representing g_ij(r), the scattering factor product
|
|
30
|
+
# in real space. The shape is (n_pairs, n_r_points).
|
|
31
|
+
|
|
32
|
+
# Notes
|
|
33
|
+
# -----
|
|
34
|
+
# The function performs the following steps:
|
|
35
|
+
# 1. Creates a Q-space vector.
|
|
36
|
+
# 2. Retrieves atomic scattering factors f0, f1, f2 for each unique atom.
|
|
37
|
+
# 3. Calculates the scattering factor product for each atomic pair.
|
|
38
|
+
# 4. Calculates the average scattering factor.
|
|
39
|
+
# 5. Normalizes the scattering factor product.
|
|
40
|
+
# 6. Applies a Discrete Cosine Transform (DCT) to obtain the real-space
|
|
41
|
+
# representation.
|
|
42
|
+
# 7. Interpolates the result to match the desired r-space grid.
|
|
43
|
+
# """
|
|
44
|
+
# q = np.linspace(0, self["qmax"], self["number_scf_function"])
|
|
45
|
+
# symbols_all = self.phase.model["symbol"]
|
|
46
|
+
# sfs = np.zeros((symbols_all.size, q.size)) + 0.0j
|
|
47
|
+
# fij = np.ones(np.append(aij.shape, q.size)).astype(float) + 0.0j
|
|
48
|
+
|
|
49
|
+
# symbols = np.unique(symbols_all)
|
|
50
|
+
# for atom in symbols:
|
|
51
|
+
# f0 = self.f0s[atom](q)
|
|
52
|
+
# f1, f2 = self.f1f2s[atom](self["energy"])
|
|
53
|
+
# sf = f0 + f1 + 1.0j * f2
|
|
54
|
+
# sfs[np.where(symbols_all == atom)] = sf
|
|
55
|
+
# fij[np.where(aij == atom)] = sf
|
|
56
|
+
|
|
57
|
+
# gij = fij[:, 0] * fij[:, 1]
|
|
58
|
+
# occ = self.phase.model["occ"]
|
|
59
|
+
# ave = np.average(sfs * occ[:, np.newaxis], axis=0)
|
|
60
|
+
# gij /= np.square(ave) # fij/<cf>2
|
|
61
|
+
# gij = np.abs(gij)
|
|
62
|
+
|
|
63
|
+
# number_scf_function = self["number_scf_function"] * self["pad"]
|
|
64
|
+
# gij = dct(gij, n=number_scf_function, type=2, norm=None, axis=1) / (
|
|
65
|
+
# 2.0 * number_scf_function
|
|
66
|
+
# )
|
|
67
|
+
|
|
68
|
+
# if (self.r[1] - self.r[1]) != (self["qmax"] * np.float64(self["pad"])):
|
|
69
|
+
# r = (
|
|
70
|
+
# np.arange(0, np.float64(number_scf_function), 1.0)
|
|
71
|
+
# * np.pi
|
|
72
|
+
# / (self["qmax"] * np.float64(self["pad"]))
|
|
73
|
+
# )
|
|
74
|
+
# r_new = np.arange(r[0], r[-1], self.r[1] - self.r[0])
|
|
75
|
+
# gij_new = np.empty((0, r_new.size))
|
|
76
|
+
|
|
77
|
+
# for g in gij:
|
|
78
|
+
# gn = intp.interp1d(r, g, fill_value=0.0)(r_new)
|
|
79
|
+
# gij_new = np.append(gij_new, gn.reshape(1, -1), axis=0)
|
|
80
|
+
|
|
81
|
+
# norm = np.sum(gij, axis=-1)
|
|
82
|
+
# gij = gij_new
|
|
83
|
+
# norm2 = np.sum(gij, axis=-1)
|
|
84
|
+
# gij = gij / norm2[:, np.newaxis] * norm[:, np.newaxis]
|
|
85
|
+
|
|
86
|
+
# gij = np.append(gij[:, :0:-1], gij, axis=-1)
|
|
87
|
+
# return gij
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# def calc_scattering_factors(self) -> NDArray[np.complex128]:
|
|
92
|
+
# """
|
|
93
|
+
# Calculates the atomic scattering factors with Q-dependence.
|
|
94
|
+
|
|
95
|
+
# This function calculates the atomic scattering factors f(Q) for all unique atomic
|
|
96
|
+
# symbols in the Phase object. It combines the contributions from the
|
|
97
|
+
# normal scattering factor (f0) and the anomalous scattering factors (f1, f2),
|
|
98
|
+
# which are energy-dependent.
|
|
99
|
+
|
|
100
|
+
# Parameters
|
|
101
|
+
# ----------
|
|
102
|
+
# self : Simulator
|
|
103
|
+
# The Simulator object, which must contain the atomic symbols,
|
|
104
|
+
# the Q-values, and the functions to calculate f0, f1, and f2
|
|
105
|
+
# (self.f0s, self.f1f2s).
|
|
106
|
+
|
|
107
|
+
# Returns
|
|
108
|
+
# -------
|
|
109
|
+
# numpy.ndarray
|
|
110
|
+
# A 2D NumPy array of the atomic scattering factors f(Q) for each atom.
|
|
111
|
+
# The shape is (n_atoms, n_q_points). The values are complex.
|
|
112
|
+
# """
|
|
113
|
+
# symbols = np.unique(self.symbols)
|
|
114
|
+
# q = np.linspace(0, self["qmax"], self["number_scf_function"])
|
|
115
|
+
# sfs = np.zeros((self.symbols.size, q.size)) + 0.0j
|
|
116
|
+
|
|
117
|
+
# for atom in symbols:
|
|
118
|
+
# f0 = self.f0s[atom](q)
|
|
119
|
+
# f1, f2 = self.f1f2s[atom](self["energy"])
|
|
120
|
+
# sf = f0 + f1 + 1.0j * f2
|
|
121
|
+
# sfs[np.where(self.symbols == atom)] = sf
|
|
122
|
+
|
|
123
|
+
# return sfs
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#old one before refactoring
|
|
2
|
+
|
|
3
|
+
# import numpy as np
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# def calc_gr_histogram(self, q_dependence=False):
|
|
7
|
+
# """
|
|
8
|
+
# Prepares for the pair distribution function g(r) histogram calculation using CPU.
|
|
9
|
+
|
|
10
|
+
# This function prepares the histogram for calculating the pair distribution
|
|
11
|
+
# function (PDF) g(r). It groups pair data to enhance computational
|
|
12
|
+
# efficiency by performing similar calculations in batches. Based on the
|
|
13
|
+
# `q_dependence` parameter, it selects the appropriate structure factor
|
|
14
|
+
# and PDF calculation functions.
|
|
15
|
+
|
|
16
|
+
# Parameters
|
|
17
|
+
# ----------
|
|
18
|
+
# self : Calculator
|
|
19
|
+
# An instance of the Calculator class for PDF calculation.
|
|
20
|
+
# q_dependence : bool, optional
|
|
21
|
+
# A flag indicating whether to consider Q-dependent structure factors.
|
|
22
|
+
# Defaults to False.
|
|
23
|
+
|
|
24
|
+
# Returns
|
|
25
|
+
# -------
|
|
26
|
+
# r : numpy.ndarray
|
|
27
|
+
# Array of radial distances r.
|
|
28
|
+
# gr : numpy.ndarray
|
|
29
|
+
# The calculated histogram of the pair distribution function g(r).
|
|
30
|
+
|
|
31
|
+
# Notes
|
|
32
|
+
# -----
|
|
33
|
+
# This function calculates the histogram through the following steps:
|
|
34
|
+
|
|
35
|
+
# 1. Determines the range of pair data to be used for calculation using
|
|
36
|
+
# the `set_r_range` function.
|
|
37
|
+
# 2. Groups the pair data using the `grouping` function.
|
|
38
|
+
# 3. Selects the appropriate structure factor and PDF calculation functions
|
|
39
|
+
# based on the `q_dependence` parameter.
|
|
40
|
+
# 4. Calculates the histogram of g(r) using the selected functions.
|
|
41
|
+
# 5. Normalizes the histogram if necessary.
|
|
42
|
+
|
|
43
|
+
# """
|
|
44
|
+
# # data_in_r_range = set_r_range(self)
|
|
45
|
+
# ai = self.pairs["symbol"][:, 0]
|
|
46
|
+
# aj = self.pairs["symbol"][:, 1]
|
|
47
|
+
# rij = self.pairs["distance"]
|
|
48
|
+
# sij = self.pairs["adp"]
|
|
49
|
+
# cij = self.pairs["occ"]
|
|
50
|
+
# r = self.r
|
|
51
|
+
# r_pair = self.r_pair
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# grouped_pairs = grouping(self, rij, cij, sij, ai, aj, r)
|
|
55
|
+
# rij = grouped_pairs["rij"]
|
|
56
|
+
# cij = grouped_pairs["cij"]
|
|
57
|
+
# sij = grouped_pairs["sij"]
|
|
58
|
+
# bin_min = grouped_pairs["bin_min"]
|
|
59
|
+
# bin_max = grouped_pairs["bin_max"]
|
|
60
|
+
# same_aij_groups = grouped_pairs["same_aij_groups"]
|
|
61
|
+
# same_uij_groups = grouped_pairs["same_uij_groups"]
|
|
62
|
+
# unique_aij = grouped_pairs["unique_aij"]
|
|
63
|
+
|
|
64
|
+
# if q_dependence:
|
|
65
|
+
# from ..structure_factor.q_depend import calc_gij
|
|
66
|
+
# from .histogram.pdf_q_depend_cpu import calc_pdf
|
|
67
|
+
# else:
|
|
68
|
+
# from ..structure_factor.no_q_depend import calc_gij
|
|
69
|
+
# from .histogram.pdf_no_q_depend_cpu import calc_pdf
|
|
70
|
+
|
|
71
|
+
# gij = calc_gij(self, unique_aij)
|
|
72
|
+
# gr = calc_pdf(
|
|
73
|
+
# r,
|
|
74
|
+
# rij,
|
|
75
|
+
# cij,
|
|
76
|
+
# sij,
|
|
77
|
+
# gij,
|
|
78
|
+
# same_aij_groups,
|
|
79
|
+
# same_uij_groups,
|
|
80
|
+
# bin_min,
|
|
81
|
+
# bin_max,
|
|
82
|
+
# r_pair,
|
|
83
|
+
# )
|
|
84
|
+
|
|
85
|
+
# if not q_dependence:
|
|
86
|
+
# gr /= r
|
|
87
|
+
|
|
88
|
+
# gr *= (self["qmax"] * self["pad"]) / np.pi
|
|
89
|
+
# gr /= self.phase.model["occ"].size
|
|
90
|
+
# return r, gr
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# def calc_simulation_range(self, r_pair):
|
|
94
|
+
# """
|
|
95
|
+
# Calculates the simulation range.
|
|
96
|
+
|
|
97
|
+
# This function determines the range of data to be used for PDF calculation
|
|
98
|
+
# based on the provided `r_pair`. The calculation range is determined by the
|
|
99
|
+
# minimum and maximum values of `self.r` extended by the range of `r_pair`.
|
|
100
|
+
|
|
101
|
+
# Parameters
|
|
102
|
+
# ----------
|
|
103
|
+
# self : Calculator
|
|
104
|
+
# An instance of the Calculator class for PDF calculation.
|
|
105
|
+
# r_pair : numpy.ndarray
|
|
106
|
+
# Array of pair distances r_ij.
|
|
107
|
+
|
|
108
|
+
# Returns
|
|
109
|
+
# -------
|
|
110
|
+
# numpy.ndarray
|
|
111
|
+
# An array of indices representing the simulation range.
|
|
112
|
+
# """
|
|
113
|
+
# eval_min = self.r[0] - r_pair[-1]
|
|
114
|
+
# eval_max = self.r[-1] + r_pair[-1]
|
|
115
|
+
|
|
116
|
+
# if eval_min <= 0:
|
|
117
|
+
# eval_min = 0
|
|
118
|
+
# simulation_range = np.where((self.rij > eval_min) & (self.rij < eval_max))
|
|
119
|
+
# return simulation_range[0]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# def make_bins(self, r, rij):
|
|
123
|
+
# """
|
|
124
|
+
# Generates histogram bins.
|
|
125
|
+
|
|
126
|
+
# This function generates histogram bins based on the provided arrays of
|
|
127
|
+
# radial distances `r` and pair distances `rij`. It calculates which bins
|
|
128
|
+
# each `rij` value contributes to and returns the minimum and maximum
|
|
129
|
+
# bin indices for each pair.
|
|
130
|
+
|
|
131
|
+
# Parameters
|
|
132
|
+
# ----------
|
|
133
|
+
# self : Calculator
|
|
134
|
+
# An instance of the Calculator class for PDF calculation.
|
|
135
|
+
# r : numpy.ndarray
|
|
136
|
+
# Array of radial distances r.
|
|
137
|
+
# rij : numpy.ndarray
|
|
138
|
+
# Array of pair distances r_ij.
|
|
139
|
+
|
|
140
|
+
# Returns
|
|
141
|
+
# -------
|
|
142
|
+
# bin_min : numpy.ndarray
|
|
143
|
+
# Array of minimum bin indices for each rij value.
|
|
144
|
+
# bin_max : numpy.ndarray
|
|
145
|
+
# Array of maximum bin indices for each rij value.
|
|
146
|
+
# """
|
|
147
|
+
# rstep = r[1] - r[0]
|
|
148
|
+
# shift = (rij - r[0]) // rstep + 1
|
|
149
|
+
# rmax_id = r.size - 1
|
|
150
|
+
|
|
151
|
+
# n = self.num_p_peak - 1
|
|
152
|
+
# bin_min = shift - n
|
|
153
|
+
# bin_max = shift + n
|
|
154
|
+
|
|
155
|
+
# bin_min[bin_min > rmax_id] = -1
|
|
156
|
+
# bin_min[bin_min < 0] = 0
|
|
157
|
+
# bin_max[bin_max < 0] = 1
|
|
158
|
+
# return bin_min.flatten(), bin_max.flatten()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# # def grouping(self, rij, cij, sij, ai, aj, r):
|
|
162
|
+
# # """
|
|
163
|
+
# # Groups pair data.
|
|
164
|
+
|
|
165
|
+
# # This function groups pair data based on the atomic pair type (ai, aj) and
|
|
166
|
+
# # the mean-square relative displacement (sij) to enhance the efficiency of
|
|
167
|
+
# # PDF calculation. It organizes the data so that similar calculations can
|
|
168
|
+
# # be performed together.
|
|
169
|
+
|
|
170
|
+
# # Parameters
|
|
171
|
+
# # ----------
|
|
172
|
+
# # self : Calculator
|
|
173
|
+
# # An instance of the Calculator class for PDF calculation.
|
|
174
|
+
# # rij : numpy.ndarray
|
|
175
|
+
# # Array of pair distances r_ij.
|
|
176
|
+
# # cij : numpy.ndarray
|
|
177
|
+
# # Array of coherence lengths c_ij.
|
|
178
|
+
# # sij : numpy.ndarray
|
|
179
|
+
# # Array of mean-square relative displacements u_ij.
|
|
180
|
+
# # ai : numpy.ndarray
|
|
181
|
+
# # Array of indices for atom i.
|
|
182
|
+
# # aj : numpy.ndarray
|
|
183
|
+
# # Array of indices for atom j.
|
|
184
|
+
# # r : numpy.ndarray
|
|
185
|
+
# # Array of radial distances r.
|
|
186
|
+
|
|
187
|
+
# # Returns
|
|
188
|
+
# # -------
|
|
189
|
+
# # grouped_pairs : dict
|
|
190
|
+
# # A dictionary containing the grouped pair data.
|
|
191
|
+
# # Keys include 'rij', 'cij', 'sij', 'bin_min', 'bin_max',
|
|
192
|
+
# # 'same_aij_groups', 'same_uij_groups', and 'unique_aij'.
|
|
193
|
+
# # """
|
|
194
|
+
# # grouped_pairs = {}
|
|
195
|
+
|
|
196
|
+
# # # order the aij array
|
|
197
|
+
# # aij = self.pair["symbol"]
|
|
198
|
+
# # aij = np.sort(aij, axis=-1)
|
|
199
|
+
# # self.pair_name = aij[:, 0].astype(object) + aij[:, 1].astype(object)
|
|
200
|
+
# # self.pair_order = np.argsort(self.pair_name)
|
|
201
|
+
# # aij = aij[self.pair_order]
|
|
202
|
+
|
|
203
|
+
# # unique_aij, index_aij, counts_aij = np.unique(
|
|
204
|
+
# # aij, return_index=True, return_counts=True, axis=0
|
|
205
|
+
# # )
|
|
206
|
+
|
|
207
|
+
# # index_sort = np.argsort(index_aij)
|
|
208
|
+
# # index_aij = index_aij[index_sort]
|
|
209
|
+
# # counts_aij = counts_aij[index_sort]
|
|
210
|
+
# # self.pair_group_bounds = index_aij + counts_aij
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# # rij = self.pairs["distance"][sort]
|
|
215
|
+
# # cij = self.pairs["occ"][sort]
|
|
216
|
+
# # sij = self.pairs["adp"][sort]
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
# # # find unique aij for scattering_factors
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# # rij = np.split(rij, same_aij_groups[:-1])
|
|
223
|
+
# # cij = np.split(cij, same_aij_groups[:-1])
|
|
224
|
+
# # sij = np.split(sij, same_aij_groups[:-1])
|
|
225
|
+
|
|
226
|
+
# # bin_min = np.split(bin_min, same_aij_groups[:-1])
|
|
227
|
+
# # bin_max = np.split(bin_max, same_aij_groups[:-1])
|
|
228
|
+
|
|
229
|
+
# # rearrange the par by sorting them on the basis of simga values (adps)
|
|
230
|
+
# # number_of_unique_aij = len(rij)
|
|
231
|
+
# # same_uij_groups = np.array([])
|
|
232
|
+
|
|
233
|
+
# # for x in range(number_of_unique_aij):
|
|
234
|
+
# # order_in_local_sigma = np.argsort(sij[x])
|
|
235
|
+
# # sorted_local_sigma = sij[x][order_in_local_sigma]
|
|
236
|
+
# # unique_local_sigma, counts = np.unique(
|
|
237
|
+
# # sorted_local_sigma, return_counts=True, axis=0
|
|
238
|
+
# # )
|
|
239
|
+
|
|
240
|
+
# # rij[x] = rij[x][order_in_local_sigma]
|
|
241
|
+
# # cij[x] = cij[x][order_in_local_sigma]
|
|
242
|
+
# # sij[x] = sorted_local_sigma
|
|
243
|
+
# # # bin_min[x] = bin_min[x][order_in_local_sigma]
|
|
244
|
+
# # # bin_max[x] = bin_max[x][order_in_local_sigma]
|
|
245
|
+
|
|
246
|
+
# # same_uij_groups = np.concatenate([same_uij_groups, counts], axis=0)
|
|
247
|
+
|
|
248
|
+
# # rij = np.concatenate(rij, axis=0)
|
|
249
|
+
# # cij = np.concatenate(cij, axis=0)
|
|
250
|
+
# # sij = np.concatenate(sij, axis=0)
|
|
251
|
+
# # bin_min = np.concatenate(bin_min, axis=0)
|
|
252
|
+
# # bin_max = np.concatenate(bin_max, axis=0)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# # grouped_pairs["rij"] = rij
|
|
257
|
+
# # grouped_pairs["cij"] = cij
|
|
258
|
+
# # grouped_pairs["sij"] = sij
|
|
259
|
+
# # grouped_pairs["bin_min"] = bin_min
|
|
260
|
+
# # grouped_pairs["bin_max"] = bin_max
|
|
261
|
+
# # grouped_pairs["same_aij_groups"] = same_aij_groups
|
|
262
|
+
# # # grouped_pairs["same_uij_groups"] = same_uij_groups
|
|
263
|
+
# # # grouped_pairs["unique_aij"] = unique_aij
|
|
264
|
+
|
|
265
|
+
# # return grouped_pairs
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
# # def set_r_range(self):
|
|
269
|
+
# # """
|
|
270
|
+
# # Sets the range of radial distances r to be used for calculation.
|
|
271
|
+
|
|
272
|
+
# # This function determines the range of radial distances r to be used for
|
|
273
|
+
# # PDF calculation. The range is calculated based on the specified r range
|
|
274
|
+
# # and the width of the Gaussian function. It also calls the
|
|
275
|
+
# # `calc_simulation_range` function to limit the calculation range.
|
|
276
|
+
|
|
277
|
+
# # Parameters
|
|
278
|
+
# # ----------
|
|
279
|
+
# # self : Calculator
|
|
280
|
+
# # An instance of the Calculator class for PDF calculation.
|
|
281
|
+
|
|
282
|
+
# # Returns
|
|
283
|
+
# # -------
|
|
284
|
+
# # data_in_r_range : dict
|
|
285
|
+
# # A dictionary containing the range of radial distances r to be used
|
|
286
|
+
# # for calculation, along with related pair data.
|
|
287
|
+
# # Keys include 'ai', 'aj', 'rij', 'sij', 'cij', 'r', and 'r_pair'.
|
|
288
|
+
# # """
|
|
289
|
+
# # # calculate evaluation range (from r[0] to r[-1] + gaussian width)
|
|
290
|
+
|
|
291
|
+
# # # data_in_r_range = {}
|
|
292
|
+
|
|
293
|
+
# # # rstep = self.r[1] - self.r[0]
|
|
294
|
+
# # # r_extension = self.num_p_peak / self["qmax"] * 2.0
|
|
295
|
+
# # # r_pair = np.arange(0.0, self.num_p_peak / self["qmax"], rstep)
|
|
296
|
+
# # # r_pair = np.append(-r_pair[:0:-1], r_pair)
|
|
297
|
+
|
|
298
|
+
# # r = np.arange(self.r[0], self.r[-1] + rstep + r_extension, rstep)
|
|
299
|
+
|
|
300
|
+
# # # limit simulation_range
|
|
301
|
+
# # sr = calc_simulation_range(self, r_pair)
|
|
302
|
+
|
|
303
|
+
# # data_in_r_range["ai"] = self.ai[sr]
|
|
304
|
+
# # data_in_r_range["aj"] = self.aj[sr]
|
|
305
|
+
# # data_in_r_range["rij"] = self.rij[sr]
|
|
306
|
+
|
|
307
|
+
# # sij = self.sij * self.peak_width
|
|
308
|
+
# # data_in_r_range["sij"] = sij[sr]
|
|
309
|
+
# # data_in_r_range["cij"] = self.cij[sr]
|
|
310
|
+
# # data_in_r_range["r"] = r
|
|
311
|
+
# # data_in_r_range["r_pair"] = r_pair
|
|
312
|
+
|
|
313
|
+
# # return data_in_r_range
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# This is for future work
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def read_phase_for_epf(self):
|
|
5
|
+
self.read_phase_lattice()
|
|
6
|
+
self.read_phase_shape()
|
|
7
|
+
self.calc_translational_vector()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def calc_gr_epf(self):
|
|
11
|
+
r, gr = self.calc_gr_histogram_for_epf()
|
|
12
|
+
gr *= (self["qmax"] * self["pad"]) / np.pi
|
|
13
|
+
|
|
14
|
+
density = self.calc_density(gr, r)
|
|
15
|
+
gr = self.convolution_with_q(gr, r, self["qmax"])
|
|
16
|
+
self.gr = intp.interp1d(r, gr, fill_value="extrapolate")(self.r)
|
|
17
|
+
self.density = intp.interp1d(r, density, fill_value="extrapolate")(self.r)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def calc_gr_histogram_for_epf(self):
|
|
21
|
+
xyz = self["phase"]["map", "xyz"].reshape(-1, 3)
|
|
22
|
+
xyz = np.dot(self.g, xyz.T).T
|
|
23
|
+
|
|
24
|
+
map = self["phase"]["map", "value"]
|
|
25
|
+
map = map.flatten()
|
|
26
|
+
self.Np = np.sum(map)
|
|
27
|
+
|
|
28
|
+
rstep = self.r[1] - self.r[0]
|
|
29
|
+
r_extension = self.num_p_peak / self["qmax"]
|
|
30
|
+
r = np.arange(0, self.r[-1] + rstep + r_extension, rstep)
|
|
31
|
+
|
|
32
|
+
tvs = self.translational_vectors.reshape(-1, 3)
|
|
33
|
+
|
|
34
|
+
if self["sampling_probability"] != 1.0:
|
|
35
|
+
probability = self["sampling_probability"]
|
|
36
|
+
rand = np.random.rand(map.size)
|
|
37
|
+
use = np.where((rand < probability) | (map > np.amax(map) / 100.0))
|
|
38
|
+
xyz = xyz[use]
|
|
39
|
+
ratio = np.sum(map[use]) / np.sum(map)
|
|
40
|
+
map = map[use]
|
|
41
|
+
# self.par.logger.info("sampling probability: " + str(probability))
|
|
42
|
+
|
|
43
|
+
if self["simulation_type"] == "epf":
|
|
44
|
+
if self["processor_type"] == "cpu":
|
|
45
|
+
from orochi.pdfsim.calculator.epf_cpu import calc_epf_cpu
|
|
46
|
+
|
|
47
|
+
gr = calc_epf_cpu(map, xyz, tvs, r)
|
|
48
|
+
return r, gr / ratio**2.0
|
|
49
|
+
|
|
50
|
+
else:
|
|
51
|
+
from orochi.pdfsim.calculator.epf_gpu import calc_epf_gpu
|
|
52
|
+
|
|
53
|
+
gr = calc_epf_gpu(map, xyz, tvs, r)
|
|
54
|
+
return r, gr / ratio**2.0
|
|
55
|
+
|
|
56
|
+
elif self["simulation_type"] == "partial_epf":
|
|
57
|
+
from orochi.pdfsim.calculator.epf_partial import calc_partial_epf
|
|
58
|
+
|
|
59
|
+
origin = np.dot(self.g, np.array(self["partial_epf_origin"]))
|
|
60
|
+
return r, calc_partial_epf(map, xyz, tvs, r, origin)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def calc_gr_histogram(self):
|
|
5
|
+
"""
|
|
6
|
+
Calculates the pair distribution function g(r) histogram using GPU.
|
|
7
|
+
|
|
8
|
+
This function calculates the pair distribution function g(r) histogram
|
|
9
|
+
using GPU acceleration. It performs a direct calculation using CUDA without
|
|
10
|
+
the grouping strategy employed in the CPU version.
|
|
11
|
+
|
|
12
|
+
Parameters
|
|
13
|
+
----------
|
|
14
|
+
self : Calculator
|
|
15
|
+
An instance of the Calculator class for PDF calculation.
|
|
16
|
+
|
|
17
|
+
Returns
|
|
18
|
+
-------
|
|
19
|
+
r : numpy.ndarray
|
|
20
|
+
Array of radial distances r.
|
|
21
|
+
gr : numpy.ndarray
|
|
22
|
+
The calculated histogram of the pair distribution function g(r).
|
|
23
|
+
|
|
24
|
+
Notes
|
|
25
|
+
-----
|
|
26
|
+
This function performs the following steps:
|
|
27
|
+
|
|
28
|
+
1. Calculates the radial distances `r` and `r_rij`.
|
|
29
|
+
2. Calculates the scattering factors using `calc_scattering_factors`.
|
|
30
|
+
3. Obtains atomic coordinates, translational vectors, occupancies, and
|
|
31
|
+
atomic displacement parameters.
|
|
32
|
+
4. Calls the CUDA-accelerated `calc_pdf` function to compute the histogram.
|
|
33
|
+
5. Normalizes the resulting histogram.
|
|
34
|
+
"""
|
|
35
|
+
rstep = self.r[1] - self.r[0]
|
|
36
|
+
r_extension = self.num_p_peak / 2.0 / self["qmax"]
|
|
37
|
+
r = np.arange(self.r[0], self.r[-1] + rstep + r_extension, rstep)
|
|
38
|
+
|
|
39
|
+
r_rij = np.arange(0.0, r_extension, rstep)
|
|
40
|
+
r_rij = np.append(-r_rij[:0:-1], r_rij)
|
|
41
|
+
|
|
42
|
+
from ..structure_factor.no_q_depend import calc_scattering_factors
|
|
43
|
+
from .histogram.pdf_no_q_depend_gpu import calc_pdf
|
|
44
|
+
|
|
45
|
+
sf = calc_scattering_factors(self)
|
|
46
|
+
|
|
47
|
+
xyz = self.phase.model["xyz"]
|
|
48
|
+
occ = self.phase.model["occ"]
|
|
49
|
+
adp = self.phase.model["adp"]
|
|
50
|
+
g = self.phase.model["lattice_vector"].T
|
|
51
|
+
xyz = np.dot(g, xyz.T).T
|
|
52
|
+
tvs = self.translational_vectors
|
|
53
|
+
|
|
54
|
+
gr = calc_pdf(xyz, tvs, occ, sf, adp, r, r_rij)
|
|
55
|
+
gr /= r
|
|
56
|
+
gr *= (self["qmax"] * self["pad"]) / np.pi
|
|
57
|
+
gr /= occ.size
|
|
58
|
+
return r, gr
|