-
Notifications
You must be signed in to change notification settings - Fork 0
/
mock_tem_client.py
119 lines (87 loc) · 4.5 KB
/
mock_tem_client.py
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
import numpy as np
class MockTemMicroscopeClient:
"""Mock TEM microscope client for development"""
def __init__(self):
self.service = self.Service()
self.vacuum = self.Vacuum()
self.optics = self.Optics()
self.detectors = self.Detectors()
self.acquisition = self.Acquisition()
self.auto_functions = self.AutoFunctions()
def connect(self, ip_address):
print(f"Mock: Connected to microscope at {ip_address}")
class Service:
class System:
name = "Mock TEM"
serial_number = "MOCK-001"
version = "1.0.0"
system = System()
class Vacuum:
state = "READY"
class Optics:
is_beam_blanked = False
class Detectors:
camera_detectors = ["BM_CETA"]
def get_camera_detector(self, cam):
return type("Detector", (), {"is_operational": True})()
class Acquisition:
def acquire_camera_image(
self, detector_type, frame_size, exposure_time, trial_mode
):
# Create a mock image as a numpy array
mock_image = (
#np.random.rand(frame_size, frame_size) * 255
_generate_periodic_atomic_structure(frame_size, exposure_time, trial_mode)
) # Random grayscale image
return mock_image.astype(np.uint8) # Convert to 8-bit unsigned integer
def acquire_stem_data(self, frame_size, exposure_time, trial_mode):
mock_image = (
#np.random.rand(frame_size, frame_size) * 255
_generate_periodic_atomic_structure(frame_size, exposure_time, trial_mode)
) # Random grayscale image
return mock_image.astype(np.uint8) # Convert to 8-bit unsigned integer
def acquire_stem_image(self, frame_size, exposure_time, trial_mode):
mock_image = (
_generate_periodic_atomic_structure(frame_size, exposure_time, trial_mode)
#np.random.rand(frame_size, frame_size) * 255
) # Random grayscale image
return mock_image.astype(np.uint8) # Convert to 8-bit unsigned integer
class AutoFunctions:
def run_beam_tilt_auto_focus(self, settings):
return type("FocusResult", (), {"focus_value": 1.0})()
def run_objective_auto_stigmator(self, settings):
return type("StigResult", (), {"stigmator_values": {"x": 0.0, "y": 0.0}})()
# Mock settings class
class RunBeamTiltAutoFocusSettings:
def __init__(self, camera_type):
self.camera_type = camera_type
class CameraType:
BM_CETA = "BM_CETA"
def _generate_periodic_atomic_structure(frame_size, exposure_time, trial_mode):
"""Generate a mock image simulating periodic atomic structures with consistent Gaussian widths."""
# Parameters for atomic structure
lattice_constant = frame_size // 10 # Distance between atoms
atom_width = np.random.uniform(0.5, 5.0) # Randomly generate width between 0.5 and 3
# Create meshgrid for the entire image
y, x = np.meshgrid(np.arange(frame_size), np.arange(frame_size))
# Calculate number of atoms needed in each dimension
n_atoms = int(frame_size // lattice_constant + 2) # Add extra atoms for edges and ensure integer
# Create grid of atom positions
atom_positions_x = np.linspace(-lattice_constant, frame_size + lattice_constant, n_atoms)
atom_positions_y = np.linspace(-lattice_constant, frame_size + lattice_constant, n_atoms)
# Add random offsets and displacements to positions
random_offset_x = np.random.uniform(-lattice_constant/4, lattice_constant/4)
random_offset_y = np.random.uniform(-lattice_constant/4, lattice_constant/4)
atom_positions_x = atom_positions_x + random_offset_x + np.random.normal(0, lattice_constant/100, n_atoms)
atom_positions_y = atom_positions_y + random_offset_y + np.random.normal(0, lattice_constant/100, n_atoms)
# Reshape coordinates for broadcasting
x_coords = x[:, :, np.newaxis, np.newaxis]
y_coords = y[:, :, np.newaxis, np.newaxis]
atom_x = atom_positions_x[np.newaxis, np.newaxis, :, np.newaxis]
atom_y = atom_positions_y[np.newaxis, np.newaxis, np.newaxis, :]
# Calculate all Gaussians at once
gaussians = np.exp(-((x_coords - atom_x)**2 + (y_coords - atom_y)**2) / (2 * atom_width**2))
image = np.sum(gaussians, axis=(2, 3))
# Normalize and convert to uint8
image = ((image - image.min()) / (image.max() - image.min()) * 255)
return image.astype(np.uint8)