advisor-scattering 0.5.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.
- advisor/__init__.py +3 -0
- advisor/__main__.py +7 -0
- advisor/app.py +40 -0
- advisor/controllers/__init__.py +6 -0
- advisor/controllers/app_controller.py +69 -0
- advisor/controllers/feature_controller.py +25 -0
- advisor/domain/__init__.py +23 -0
- advisor/domain/core/__init__.py +8 -0
- advisor/domain/core/lab.py +121 -0
- advisor/domain/core/lattice.py +79 -0
- advisor/domain/core/sample.py +101 -0
- advisor/domain/geometry.py +212 -0
- advisor/domain/unit_converter.py +82 -0
- advisor/features/__init__.py +6 -0
- advisor/features/scattering_geometry/controllers/__init__.py +5 -0
- advisor/features/scattering_geometry/controllers/scattering_geometry_controller.py +26 -0
- advisor/features/scattering_geometry/domain/__init__.py +5 -0
- advisor/features/scattering_geometry/domain/brillouin_calculator.py +410 -0
- advisor/features/scattering_geometry/domain/core.py +516 -0
- advisor/features/scattering_geometry/ui/__init__.py +5 -0
- advisor/features/scattering_geometry/ui/components/__init__.py +17 -0
- advisor/features/scattering_geometry/ui/components/angles_to_hkl_components.py +150 -0
- advisor/features/scattering_geometry/ui/components/hk_angles_components.py +430 -0
- advisor/features/scattering_geometry/ui/components/hkl_scan_components.py +526 -0
- advisor/features/scattering_geometry/ui/components/hkl_to_angles_components.py +315 -0
- advisor/features/scattering_geometry/ui/scattering_geometry_tab.py +725 -0
- advisor/features/structure_factor/controllers/__init__.py +6 -0
- advisor/features/structure_factor/controllers/structure_factor_controller.py +25 -0
- advisor/features/structure_factor/domain/__init__.py +6 -0
- advisor/features/structure_factor/domain/structure_factor_calculator.py +107 -0
- advisor/features/structure_factor/ui/__init__.py +6 -0
- advisor/features/structure_factor/ui/components/__init__.py +12 -0
- advisor/features/structure_factor/ui/components/customized_plane_components.py +358 -0
- advisor/features/structure_factor/ui/components/hkl_plane_components.py +391 -0
- advisor/features/structure_factor/ui/structure_factor_tab.py +273 -0
- advisor/resources/__init__.py +0 -0
- advisor/resources/config/app_config.json +14 -0
- advisor/resources/config/tips.json +4 -0
- advisor/resources/data/nacl.cif +111 -0
- advisor/resources/icons/bz_caculator.jpg +0 -0
- advisor/resources/icons/bz_calculator.png +0 -0
- advisor/resources/icons/minus.svg +3 -0
- advisor/resources/icons/placeholder.png +0 -0
- advisor/resources/icons/plus.svg +3 -0
- advisor/resources/icons/reset.png +0 -0
- advisor/resources/icons/sf_calculator.jpg +0 -0
- advisor/resources/icons/sf_calculator.png +0 -0
- advisor/resources/icons.qrc +6 -0
- advisor/resources/qss/styles.qss +348 -0
- advisor/resources/resources_rc.py +83 -0
- advisor/ui/__init__.py +7 -0
- advisor/ui/init_window.py +566 -0
- advisor/ui/main_window.py +174 -0
- advisor/ui/tab_interface.py +44 -0
- advisor/ui/tips.py +30 -0
- advisor/ui/utils/__init__.py +6 -0
- advisor/ui/utils/readcif.py +129 -0
- advisor/ui/visualizers/HKLScan2DVisualizer.py +224 -0
- advisor/ui/visualizers/__init__.py +8 -0
- advisor/ui/visualizers/coordinate_visualizer.py +203 -0
- advisor/ui/visualizers/scattering_visualizer.py +301 -0
- advisor/ui/visualizers/structure_factor_visualizer.py +426 -0
- advisor/ui/visualizers/structure_factor_visualizer_2d.py +235 -0
- advisor/ui/visualizers/unitcell_visualizer.py +518 -0
- advisor_scattering-0.5.0.dist-info/METADATA +122 -0
- advisor_scattering-0.5.0.dist-info/RECORD +69 -0
- advisor_scattering-0.5.0.dist-info/WHEEL +5 -0
- advisor_scattering-0.5.0.dist-info/entry_points.txt +3 -0
- advisor_scattering-0.5.0.dist-info/top_level.txt +1 -0
advisor/__init__.py
ADDED
advisor/__main__.py
ADDED
advisor/app.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Application bootstrap for Advisor-Scattering (Advanced Visual Scattering Toolkit for Reciprocal-space)."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from PyQt5.QtWidgets import QApplication
|
|
6
|
+
from PyQt5.QtCore import Qt, QLocale, QFile, QIODevice
|
|
7
|
+
|
|
8
|
+
from advisor.controllers import AppController
|
|
9
|
+
from advisor.resources import resources_rc
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_stylesheet() -> str:
|
|
13
|
+
"""Load QSS stylesheet if present."""
|
|
14
|
+
base_dir = os.path.dirname(os.path.abspath(__file__))
|
|
15
|
+
qss_path = os.path.join(base_dir, "resources", "qss", "styles.qss")
|
|
16
|
+
if os.path.exists(qss_path):
|
|
17
|
+
with open(qss_path, "r", encoding="utf-8") as handle:
|
|
18
|
+
return handle.read()
|
|
19
|
+
return ""
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main():
|
|
23
|
+
"""Main application entry point."""
|
|
24
|
+
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
|
|
25
|
+
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
|
|
26
|
+
|
|
27
|
+
app = QApplication(sys.argv)
|
|
28
|
+
app.setApplicationName("Advisor-Scattering")
|
|
29
|
+
QLocale.setDefault(QLocale(QLocale.English, QLocale.UnitedStates))
|
|
30
|
+
app.setStyleSheet(load_stylesheet())
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
controller = AppController(app)
|
|
34
|
+
controller.show()
|
|
35
|
+
|
|
36
|
+
sys.exit(app.exec_())
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
main()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Top-level application controller."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from PyQt5.QtWidgets import QApplication
|
|
8
|
+
|
|
9
|
+
from advisor.features import ScatteringGeometryController, StructureFactorController
|
|
10
|
+
from advisor.ui.init_window import InitWindow
|
|
11
|
+
from advisor.ui.main_window import MainWindow
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AppController:
|
|
15
|
+
"""Coordinates application startup and feature wiring."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, qt_app: QApplication):
|
|
18
|
+
self.app = qt_app
|
|
19
|
+
self.config = self._load_config()
|
|
20
|
+
self.parameters: Optional[dict] = None
|
|
21
|
+
|
|
22
|
+
self.main_window = MainWindow(controller=self)
|
|
23
|
+
self.init_window = InitWindow(controller=self)
|
|
24
|
+
self.main_window.attach_init_view(self.init_window)
|
|
25
|
+
|
|
26
|
+
self.features = [
|
|
27
|
+
ScatteringGeometryController(self),
|
|
28
|
+
StructureFactorController(self),
|
|
29
|
+
]
|
|
30
|
+
for feature in self.features:
|
|
31
|
+
self.main_window.add_feature_tab(
|
|
32
|
+
feature.view, feature.title, feature.icon, feature.description
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
self.init_window.initialized.connect(self.apply_parameters)
|
|
36
|
+
|
|
37
|
+
def show(self):
|
|
38
|
+
"""Show the main window."""
|
|
39
|
+
self.main_window.show()
|
|
40
|
+
|
|
41
|
+
def apply_parameters(self, params: dict):
|
|
42
|
+
"""Store and propagate global parameters, then show tabs."""
|
|
43
|
+
self.parameters = params
|
|
44
|
+
for feature in self.features:
|
|
45
|
+
feature.set_parameters(params)
|
|
46
|
+
self.main_window.show_tabs()
|
|
47
|
+
|
|
48
|
+
def reset_parameters(self):
|
|
49
|
+
"""Reset parameters and return to init view."""
|
|
50
|
+
self.parameters = None
|
|
51
|
+
if hasattr(self.init_window, "reset_inputs"):
|
|
52
|
+
self.init_window.reset_inputs()
|
|
53
|
+
self.main_window.show_init()
|
|
54
|
+
|
|
55
|
+
def get_parameters(self) -> dict:
|
|
56
|
+
"""Return the current global parameters."""
|
|
57
|
+
return self.parameters or {}
|
|
58
|
+
|
|
59
|
+
def _load_config(self) -> dict:
|
|
60
|
+
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
61
|
+
config_path = os.path.join(base_dir, "resources", "config", "app_config.json")
|
|
62
|
+
try:
|
|
63
|
+
with open(config_path, "r", encoding="utf-8") as handle:
|
|
64
|
+
return json.load(handle)
|
|
65
|
+
except Exception:
|
|
66
|
+
return {
|
|
67
|
+
"app_name": "Advisor-Scattering",
|
|
68
|
+
"window_size": {"width": 1200, "height": 800},
|
|
69
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Base feature controller."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from PyQt5.QtWidgets import QWidget
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FeatureController:
|
|
8
|
+
"""Base class for feature controllers."""
|
|
9
|
+
|
|
10
|
+
title: str = "Feature"
|
|
11
|
+
description: str = ""
|
|
12
|
+
icon: Optional[str] = None
|
|
13
|
+
|
|
14
|
+
def __init__(self, app_controller):
|
|
15
|
+
self.app_controller = app_controller
|
|
16
|
+
self.view: Optional[QWidget] = None
|
|
17
|
+
|
|
18
|
+
def set_parameters(self, params: dict):
|
|
19
|
+
"""Propagate global parameters to the feature."""
|
|
20
|
+
raise NotImplementedError
|
|
21
|
+
|
|
22
|
+
def build_view(self) -> QWidget:
|
|
23
|
+
"""Create and return the tab widget."""
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Domain layer with calculation and model logic."""
|
|
2
|
+
|
|
3
|
+
from .geometry import (
|
|
4
|
+
get_real_space_vectors,
|
|
5
|
+
get_reciprocal_space_vectors,
|
|
6
|
+
euler_to_matrix,
|
|
7
|
+
angle_to_matrix,
|
|
8
|
+
get_rotation,
|
|
9
|
+
sample_to_lab_conversion,
|
|
10
|
+
lab_to_sample_conversion,
|
|
11
|
+
)
|
|
12
|
+
from .unit_converter import UnitConverter
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"get_real_space_vectors",
|
|
16
|
+
"get_reciprocal_space_vectors",
|
|
17
|
+
"euler_to_matrix",
|
|
18
|
+
"angle_to_matrix",
|
|
19
|
+
"get_rotation",
|
|
20
|
+
"sample_to_lab_conversion",
|
|
21
|
+
"lab_to_sample_conversion",
|
|
22
|
+
"UnitConverter",
|
|
23
|
+
]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""This is a class for the lab."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from advisor.domain import angle_to_matrix
|
|
6
|
+
from .sample import Sample
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Lab:
|
|
11
|
+
"""This is a class for the lab."""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
"""Initialize the lab."""
|
|
15
|
+
self.sample = Sample()
|
|
16
|
+
|
|
17
|
+
self.theta = 0
|
|
18
|
+
self.phi = 0
|
|
19
|
+
self.chi = 0
|
|
20
|
+
self.a_vec_lab = None
|
|
21
|
+
self.b_vec_lab = None
|
|
22
|
+
self.c_vec_lab = None
|
|
23
|
+
self.a_star_vec_lab = None
|
|
24
|
+
self.b_star_vec_lab = None
|
|
25
|
+
self.c_star_vec_lab = None
|
|
26
|
+
|
|
27
|
+
def initialize(
|
|
28
|
+
self, a, b, c, alpha, beta, gamma, roll, pitch, yaw, theta, phi, chi
|
|
29
|
+
):
|
|
30
|
+
"""Initialize the lab."""
|
|
31
|
+
self.sample.initialize(a, b, c, alpha, beta, gamma, roll, pitch, yaw)
|
|
32
|
+
self.theta = theta
|
|
33
|
+
self.phi = phi
|
|
34
|
+
self.chi = chi
|
|
35
|
+
self.calculate_real_space_vectors()
|
|
36
|
+
self.calculate_reciprocal_space_vectors()
|
|
37
|
+
|
|
38
|
+
def get_sample_angles(self):
|
|
39
|
+
"""Get the sample angles."""
|
|
40
|
+
return self.theta, self.phi, self.chi
|
|
41
|
+
|
|
42
|
+
def get_lattice_angles(self):
|
|
43
|
+
"""get the lattice euler angles: roll pitch and yaw"""
|
|
44
|
+
return self.sample.get_lattice_angles()
|
|
45
|
+
|
|
46
|
+
def get_lattice_parameters(self):
|
|
47
|
+
"""Get the parameters of the sample."""
|
|
48
|
+
return self.sample.get_lattice_parameters()
|
|
49
|
+
|
|
50
|
+
def get_real_space_vectors(self, is_normalized=False):
|
|
51
|
+
"""Get the real space vectors in the lab frame."""
|
|
52
|
+
if is_normalized:
|
|
53
|
+
return self.a_vec_lab / np.linalg.norm(self.a_vec_lab), self.b_vec_lab / np.linalg.norm(self.b_vec_lab), self.c_vec_lab / np.linalg.norm(self.c_vec_lab)
|
|
54
|
+
return self.a_vec_lab, self.b_vec_lab, self.c_vec_lab
|
|
55
|
+
|
|
56
|
+
def get_reciprocal_space_vectors(self, is_normalized=False):
|
|
57
|
+
"""Get the reciprocal space vectors in the lab frame."""
|
|
58
|
+
if is_normalized:
|
|
59
|
+
return self.a_star_vec_lab / np.linalg.norm(self.a_star_vec_lab), self.b_star_vec_lab / np.linalg.norm(self.b_star_vec_lab), self.c_star_vec_lab / np.linalg.norm(self.c_star_vec_lab)
|
|
60
|
+
return self.a_star_vec_lab, self.b_star_vec_lab, self.c_star_vec_lab
|
|
61
|
+
|
|
62
|
+
def calculate_real_space_vectors(self):
|
|
63
|
+
"""Get the real space vectors in the lab frame."""
|
|
64
|
+
a_vec_sample, b_vec_sample, c_vec_sample = self.sample.get_real_space_vectors()
|
|
65
|
+
rotation_matrix = angle_to_matrix(self.theta, self.phi, self.chi)
|
|
66
|
+
self.a_vec_lab = rotation_matrix @ a_vec_sample
|
|
67
|
+
self.b_vec_lab = rotation_matrix @ b_vec_sample
|
|
68
|
+
self.c_vec_lab = rotation_matrix @ c_vec_sample
|
|
69
|
+
|
|
70
|
+
def calculate_reciprocal_space_vectors(self):
|
|
71
|
+
"""Get the reciprocal space vectors in the lab frame."""
|
|
72
|
+
a_star_vec_sample, b_star_vec_sample, c_star_vec_sample = (
|
|
73
|
+
self.sample.get_reciprocal_space_vectors()
|
|
74
|
+
)
|
|
75
|
+
rotation_matrix = angle_to_matrix(self.theta, self.phi, self.chi)
|
|
76
|
+
self.a_star_vec_lab = rotation_matrix @ a_star_vec_sample
|
|
77
|
+
self.b_star_vec_lab = rotation_matrix @ b_star_vec_sample
|
|
78
|
+
self.c_star_vec_lab = rotation_matrix @ c_star_vec_sample
|
|
79
|
+
|
|
80
|
+
def get_lab_basis(self):
|
|
81
|
+
"""Get the lab orthogonal basis vectors, in the lab frame."""
|
|
82
|
+
ex_lab = np.array([1, 0, 0])
|
|
83
|
+
ey_lab = np.array([0, 1, 0])
|
|
84
|
+
ez_lab = np.array([0, 0, 1])
|
|
85
|
+
return ex_lab, ey_lab, ez_lab
|
|
86
|
+
|
|
87
|
+
def get_sample_basis(self):
|
|
88
|
+
"""Get the sample orthogonal basis vectors, in the lab frame."""
|
|
89
|
+
ex_sample_in_sample, ey_sample_in_sample, ez_sample_in_sample = (
|
|
90
|
+
self.sample.get_sample_basis()
|
|
91
|
+
) # sample basis in the sample frame
|
|
92
|
+
|
|
93
|
+
rotation_matrix = angle_to_matrix(self.theta, self.phi, self.chi)
|
|
94
|
+
|
|
95
|
+
# sample basis in the lab frame
|
|
96
|
+
ex_sample_in_lab = rotation_matrix @ ex_sample_in_sample
|
|
97
|
+
ey_sample_in_lab = rotation_matrix @ ey_sample_in_sample
|
|
98
|
+
ez_sample_in_lab = rotation_matrix @ ez_sample_in_sample
|
|
99
|
+
return ex_sample_in_lab, ey_sample_in_lab, ez_sample_in_lab
|
|
100
|
+
|
|
101
|
+
def get_lattice_basis(self):
|
|
102
|
+
"""Get the lattice orthogonal basis vectors, in the lab frame."""
|
|
103
|
+
ex_lattice_in_sample, ey_lattice_in_sample, ez_lattice_in_sample = (
|
|
104
|
+
self.sample.get_lattice_basis()
|
|
105
|
+
) # lattice basis in the sample frame
|
|
106
|
+
|
|
107
|
+
rotation_matrix = angle_to_matrix(self.theta, self.phi, self.chi)
|
|
108
|
+
|
|
109
|
+
# lattice basis in the lab frame
|
|
110
|
+
ex_lattice_in_lab = rotation_matrix @ ex_lattice_in_sample
|
|
111
|
+
ey_lattice_in_lab = rotation_matrix @ ey_lattice_in_sample
|
|
112
|
+
ez_lattice_in_lab = rotation_matrix @ ez_lattice_in_sample
|
|
113
|
+
return ex_lattice_in_lab, ey_lattice_in_lab, ez_lattice_in_lab
|
|
114
|
+
|
|
115
|
+
def rotate(self, theta, phi, chi):
|
|
116
|
+
"""Rotate the lab."""
|
|
117
|
+
self.theta = theta
|
|
118
|
+
self.phi = phi
|
|
119
|
+
self.chi = chi
|
|
120
|
+
self.calculate_real_space_vectors()
|
|
121
|
+
self.calculate_reciprocal_space_vectors()
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""This is a module for the lattice class."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from advisor.domain import (
|
|
6
|
+
get_real_space_vectors,
|
|
7
|
+
get_reciprocal_space_vectors,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Lattice:
|
|
12
|
+
"""This is a class for the lattice."""
|
|
13
|
+
|
|
14
|
+
def __init__(self):
|
|
15
|
+
"""Initialize the sample."""
|
|
16
|
+
self.a = None
|
|
17
|
+
self.b = None
|
|
18
|
+
self.c = None
|
|
19
|
+
self.alpha = None
|
|
20
|
+
self.beta = None
|
|
21
|
+
self.gamma = None
|
|
22
|
+
|
|
23
|
+
# vectors in the lattice frame
|
|
24
|
+
self.a_vec_lattice = None
|
|
25
|
+
self.b_vec_lattice = None
|
|
26
|
+
self.c_vec_lattice = None
|
|
27
|
+
|
|
28
|
+
# reciprocal vectors in the lattice frame
|
|
29
|
+
self.a_star_vec_lattice = None
|
|
30
|
+
self.b_star_vec_lattice = None
|
|
31
|
+
self.c_star_vec_lattice = None
|
|
32
|
+
|
|
33
|
+
def initialize(self, a, b, c, alpha, beta, gamma):
|
|
34
|
+
"""Initialize the sample.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
a, b, c (float): Lattice constants in Angstroms
|
|
38
|
+
alpha, beta, gamma (float): Lattice angles in degrees
|
|
39
|
+
roll, pitch, yaw (float): Euler angles in degrees
|
|
40
|
+
"""
|
|
41
|
+
# First set the lattice parameters
|
|
42
|
+
self.a = a
|
|
43
|
+
self.b = b
|
|
44
|
+
self.c = c
|
|
45
|
+
self.alpha = alpha
|
|
46
|
+
self.beta = beta
|
|
47
|
+
self.gamma = gamma
|
|
48
|
+
|
|
49
|
+
# Then calculate vectors in sample coordinate system
|
|
50
|
+
self.a_vec_lattice, self.b_vec_lattice, self.c_vec_lattice = (
|
|
51
|
+
get_real_space_vectors(a, b, c, alpha, beta, gamma)
|
|
52
|
+
)
|
|
53
|
+
self.a_star_vec_lattice, self.b_star_vec_lattice, self.c_star_vec_lattice = (
|
|
54
|
+
get_reciprocal_space_vectors(a, b, c, alpha, beta, gamma)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def get_lattice_parameters(self):
|
|
58
|
+
"""Get the parameters of the sample. if None, raise "initialize the sample first"."""
|
|
59
|
+
try:
|
|
60
|
+
a, b, c = self.a, self.b, self.c
|
|
61
|
+
alpha, beta, gamma = self.alpha, self.beta, self.gamma
|
|
62
|
+
return a, b, c, alpha, beta, gamma
|
|
63
|
+
except KeyError as exc:
|
|
64
|
+
raise ValueError("initialize the sample first") from exc
|
|
65
|
+
|
|
66
|
+
def get_real_space_vectors(self):
|
|
67
|
+
"""Get the real space vectors in the lattice frame."""
|
|
68
|
+
return self.a_vec_lattice, self.b_vec_lattice, self.c_vec_lattice
|
|
69
|
+
|
|
70
|
+
def get_reciprocal_space_vectors(self):
|
|
71
|
+
"""Get the reciprocal space vectors in the lattice frame."""
|
|
72
|
+
return self.a_star_vec_lattice, self.b_star_vec_lattice, self.c_star_vec_lattice
|
|
73
|
+
|
|
74
|
+
def get_lattice_basis(self):
|
|
75
|
+
"""Get the lattice orthogonal basis vectors, in the lattice frame."""
|
|
76
|
+
ex_lattice_in_lattice = np.array([1, 0, 0])
|
|
77
|
+
ey_lattice_in_lattice = np.array([0, 1, 0])
|
|
78
|
+
ez_lattice_in_lattice = np.array([0, 0, 1])
|
|
79
|
+
return ex_lattice_in_lattice, ey_lattice_in_lattice, ez_lattice_in_lattice
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""This is a module for the sample class."""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from advisor.domain import euler_to_matrix
|
|
6
|
+
from .lattice import Lattice
|
|
7
|
+
|
|
8
|
+
class Sample:
|
|
9
|
+
"""This is a class for the sample."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize the sample."""
|
|
13
|
+
self.lattice = Lattice()
|
|
14
|
+
self.roll = 0
|
|
15
|
+
self.pitch = 0
|
|
16
|
+
self.yaw = 0
|
|
17
|
+
self.a_vec_sample = None
|
|
18
|
+
self.b_vec_sample = None
|
|
19
|
+
self.c_vec_sample = None
|
|
20
|
+
self.a_star_vec_sample = None
|
|
21
|
+
self.b_star_vec_sample = None
|
|
22
|
+
self.c_star_vec_sample = None
|
|
23
|
+
|
|
24
|
+
def initialize(self, a, b, c, alpha, beta, gamma, roll, pitch, yaw):
|
|
25
|
+
"""Initialize the sample.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
a, b, c (float): Lattice constants in Angstroms
|
|
29
|
+
alpha, beta, gamma (float): Lattice angles in degrees
|
|
30
|
+
roll, pitch, yaw (float): Euler angles in degrees
|
|
31
|
+
"""
|
|
32
|
+
self.lattice.initialize(a, b, c, alpha, beta, gamma)
|
|
33
|
+
self.roll = roll
|
|
34
|
+
self.pitch = pitch
|
|
35
|
+
self.yaw = yaw
|
|
36
|
+
self.calculate_real_space_vectors()
|
|
37
|
+
self.calculate_reciprocal_space_vectors()
|
|
38
|
+
|
|
39
|
+
def get_lattice_parameters(self):
|
|
40
|
+
"""Get the parameters of the sample. if None, raise "initialize the sample first"."""
|
|
41
|
+
try:
|
|
42
|
+
return self.lattice.get_lattice_parameters()
|
|
43
|
+
except KeyError as exc:
|
|
44
|
+
raise ValueError("initialize the sample first") from exc
|
|
45
|
+
|
|
46
|
+
def get_lattice_angles(self):
|
|
47
|
+
"""get the lattice euler angles: roll pitch and yaw"""
|
|
48
|
+
return self.roll, self.pitch, self.yaw
|
|
49
|
+
|
|
50
|
+
def get_real_space_vectors(self):
|
|
51
|
+
"""Get the real space vectors in the sample frame."""
|
|
52
|
+
return self.a_vec_sample, self.b_vec_sample, self.c_vec_sample
|
|
53
|
+
|
|
54
|
+
def get_reciprocal_space_vectors(self):
|
|
55
|
+
"""Get the reciprocal space vectors in the sample frame."""
|
|
56
|
+
return self.a_star_vec_sample, self.b_star_vec_sample, self.c_star_vec_sample
|
|
57
|
+
|
|
58
|
+
def get_reciprocal_sample_basis(self):
|
|
59
|
+
"""Get the reciprocal sample basis vectors."""
|
|
60
|
+
return self.a_star_vec_sample, self.b_star_vec_sample, self.c_star_vec_sample
|
|
61
|
+
|
|
62
|
+
def get_sample_basis(self):
|
|
63
|
+
"""Get the sample orthogonal basis vectors, in the sample frame."""
|
|
64
|
+
ex_sample_in_sample = np.array([1, 0, 0])
|
|
65
|
+
ey_sample_in_sample = np.array([0, 1, 0])
|
|
66
|
+
ez_sample_in_sample = np.array([0, 0, 1])
|
|
67
|
+
return ex_sample_in_sample, ey_sample_in_sample, ez_sample_in_sample
|
|
68
|
+
|
|
69
|
+
def get_lattice_basis(self):
|
|
70
|
+
"""Get the lattice orthogonal basis vectors, in sample frame."""
|
|
71
|
+
ex_lattice_in_lattice, ey_lattice_in_lattice, ez_lattice_in_lattice = (
|
|
72
|
+
self.lattice.get_lattice_basis()
|
|
73
|
+
)
|
|
74
|
+
rotation_matrix = euler_to_matrix(self.roll, self.pitch, self.yaw)
|
|
75
|
+
ex_lattice = rotation_matrix @ ex_lattice_in_lattice
|
|
76
|
+
ey_lattice = rotation_matrix @ ey_lattice_in_lattice
|
|
77
|
+
ez_lattice = rotation_matrix @ ez_lattice_in_lattice
|
|
78
|
+
return ex_lattice, ey_lattice, ez_lattice
|
|
79
|
+
|
|
80
|
+
def calculate_real_space_vectors(self):
|
|
81
|
+
"""Get the real space vectors in the sample frame."""
|
|
82
|
+
a_vec_lattice, b_vec_lattice, c_vec_lattice = (
|
|
83
|
+
self.lattice.get_real_space_vectors()
|
|
84
|
+
)
|
|
85
|
+
rotation_matrix = euler_to_matrix(self.roll, self.pitch, self.yaw)
|
|
86
|
+
self.a_vec_sample = rotation_matrix @ a_vec_lattice
|
|
87
|
+
self.b_vec_sample = rotation_matrix @ b_vec_lattice
|
|
88
|
+
self.c_vec_sample = rotation_matrix @ c_vec_lattice
|
|
89
|
+
|
|
90
|
+
def calculate_reciprocal_space_vectors(self):
|
|
91
|
+
"""Get the reciprocal space vectors in the sample frame."""
|
|
92
|
+
a_star_vec_lattice, b_star_vec_lattice, c_star_vec_lattice = (
|
|
93
|
+
self.lattice.get_reciprocal_space_vectors()
|
|
94
|
+
)
|
|
95
|
+
rotation_matrix = euler_to_matrix(self.roll, self.pitch, self.yaw)
|
|
96
|
+
self.a_star_vec_sample = rotation_matrix @ a_star_vec_lattice
|
|
97
|
+
self.b_star_vec_sample = rotation_matrix @ b_star_vec_lattice
|
|
98
|
+
self.c_star_vec_sample = rotation_matrix @ c_star_vec_lattice
|
|
99
|
+
|
|
100
|
+
def rotate(self, theta, phi, chi):
|
|
101
|
+
"""Rotate the sample."""
|