AOT-biomaps 2.9.356__py3-none-any.whl → 2.9.373__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.
Potentially problematic release.
This version of AOT-biomaps might be problematic. Click here for more details.
- AOT_biomaps/AOT_Acoustic/AcousticTools.py +17 -0
- AOT_biomaps/AOT_Acoustic/StructuredWave.py +15 -1
- AOT_biomaps/AOT_Acoustic/_mainAcoustic.py +42 -15
- AOT_biomaps/AOT_Experiment/Tomography.py +22 -2
- AOT_biomaps/AOT_Recon/AnalyticRecon.py +108 -152
- AOT_biomaps/AOT_Recon/_mainRecon.py +111 -8
- AOT_biomaps/__init__.py +18 -1
- {aot_biomaps-2.9.356.dist-info → aot_biomaps-2.9.373.dist-info}/METADATA +1 -1
- {aot_biomaps-2.9.356.dist-info → aot_biomaps-2.9.373.dist-info}/RECORD +11 -11
- {aot_biomaps-2.9.356.dist-info → aot_biomaps-2.9.373.dist-info}/WHEEL +0 -0
- {aot_biomaps-2.9.356.dist-info → aot_biomaps-2.9.373.dist-info}/top_level.txt +0 -0
|
@@ -217,3 +217,20 @@ def next_power_of_2(n):
|
|
|
217
217
|
"""Calculate the next power of 2 greater than or equal to n."""
|
|
218
218
|
return int(2 ** np.ceil(np.log2(n)))
|
|
219
219
|
|
|
220
|
+
def hex_to_binary_profile(hex_string, n_piezos=192):
|
|
221
|
+
hex_string = hex_string.strip().replace(" ", "").replace("\n", "")
|
|
222
|
+
if set(hex_string.lower()) == {'f'}:
|
|
223
|
+
return np.ones(n_piezos, dtype=int)
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
n_char = len(hex_string)
|
|
227
|
+
n_bits = n_char * 4
|
|
228
|
+
binary_str = bin(int(hex_string, 16))[2:].zfill(n_bits)
|
|
229
|
+
if len(binary_str) < n_piezos:
|
|
230
|
+
# Tronquer/padder en fonction de la taille réelle de la sonde
|
|
231
|
+
binary_str = binary_str.ljust(n_piezos, '0')
|
|
232
|
+
elif len(binary_str) > n_piezos:
|
|
233
|
+
binary_str = binary_str[:n_piezos]
|
|
234
|
+
return np.array([int(b) for b in binary_str])
|
|
235
|
+
except ValueError:
|
|
236
|
+
return np.zeros(n_piezos, dtype=int)
|
|
@@ -2,6 +2,7 @@ from AOT_biomaps.Config import config
|
|
|
2
2
|
from ._mainAcoustic import AcousticField
|
|
3
3
|
from .AcousticEnums import WaveType
|
|
4
4
|
from .AcousticTools import detect_space_0_and_space_1, getAngle
|
|
5
|
+
from .AcousticTools import hex_to_binary_profile
|
|
5
6
|
|
|
6
7
|
import os
|
|
7
8
|
import numpy as np
|
|
@@ -156,7 +157,20 @@ class StructuredWave(AcousticField):
|
|
|
156
157
|
int: Decimation frequency.
|
|
157
158
|
"""
|
|
158
159
|
try:
|
|
159
|
-
|
|
160
|
+
profile = hex_to_binary_profile(self.getName_field()[6:-4], self.params['num_elements'])
|
|
161
|
+
|
|
162
|
+
if set(self.getName_field()[6:-4].lower().replace(" ", "")) == {'f'}:
|
|
163
|
+
fs_key = 0.0 # fs_key est en mm^-1 (0.0 mm^-1)
|
|
164
|
+
else:
|
|
165
|
+
ft_prof = np.fft.fft(profile)
|
|
166
|
+
idx_max = np.argmax(np.abs(ft_prof[1:len(profile)//2])) + 1
|
|
167
|
+
freqs = np.fft.fftfreq(len(profile), d=self.params['dx'])
|
|
168
|
+
|
|
169
|
+
# freqs est en m^-1 car delta_x est en mètres.
|
|
170
|
+
fs_m_inv = abs(freqs[idx_max])
|
|
171
|
+
|
|
172
|
+
fs_key = fs_m_inv # Fréquence spatiale en mm^-1
|
|
173
|
+
return int(fs_key / (1/(len(profile)*self.params['dx'])))
|
|
160
174
|
except Exception as e:
|
|
161
175
|
print(f"Error calculating decimation frequency: {e}")
|
|
162
176
|
return None
|
|
@@ -93,6 +93,8 @@ class AcousticField(ABC):
|
|
|
93
93
|
'num_elements': params.acoustic['num_elements'],
|
|
94
94
|
'element_width': params.acoustic['element_width'],
|
|
95
95
|
'element_height': params.acoustic['element_height'],
|
|
96
|
+
'height_phantom': params.acoustic['phantom']['height'] if 'phantom' in params.acoustic and 'height' in params.acoustic['phantom'] else None,
|
|
97
|
+
'width_phantom': params.acoustic['phantom']['width'] if 'phantom' in params.acoustic and 'width' in params.acoustic['phantom'] else None,
|
|
96
98
|
'Xrange': params.general['Xrange'],
|
|
97
99
|
'Yrange': params.general['Yrange'],
|
|
98
100
|
'Zrange': params.general['Zrange'],
|
|
@@ -104,6 +106,7 @@ class AcousticField(ABC):
|
|
|
104
106
|
'Nx': int(np.round((params.general['Xrange'][1] - params.general['Xrange'][0])/params.general['dx'])),
|
|
105
107
|
'Ny': int(np.round((params.general['Yrange'][1] - params.general['Yrange'][0])/params.general['dy'])) if params.general['Yrange'] is not None else 1,
|
|
106
108
|
'Nz': int(np.round((params.general['Zrange'][1] - params.general['Zrange'][0])/params.general['dz'])),
|
|
109
|
+
'Nt': params.general['Nt'] if 'Nt' in params.general else None,
|
|
107
110
|
'probeWidth': params.acoustic['num_elements'] * params.acoustic['element_width'],
|
|
108
111
|
'IsAbsorbingMedium': params.acoustic['isAbsorbingMedium'],
|
|
109
112
|
}
|
|
@@ -114,8 +117,11 @@ class AcousticField(ABC):
|
|
|
114
117
|
|
|
115
118
|
self.params['f_AQ'] = int(1/self.kgrid.dt)
|
|
116
119
|
else:
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
if self.params['Nt'] is None:
|
|
121
|
+
Nt = ceil((self.params['Zrange'][1] - self.params['Zrange'][0])*float(params.acoustic['f_AQ']) / self.params['c0'])
|
|
122
|
+
self.params['Nt'] = Nt
|
|
123
|
+
else:
|
|
124
|
+
Nt = self.params['Nt']
|
|
119
125
|
self.kgrid.setTime(Nt,1/float(params.acoustic['f_AQ']))
|
|
120
126
|
self.params['f_AQ'] = int(float(params.acoustic['f_AQ']))
|
|
121
127
|
|
|
@@ -505,13 +511,25 @@ class AcousticField(ABC):
|
|
|
505
511
|
try:
|
|
506
512
|
# --- 1. Grid setup ---
|
|
507
513
|
dx = self.params['dx']
|
|
508
|
-
if dx >= self.params['element_width']
|
|
514
|
+
if dx >= self.params['element_width']:
|
|
509
515
|
dx = self.params['element_width'] / 2
|
|
510
|
-
|
|
511
|
-
|
|
516
|
+
if self.params['width_phantom'] is not None:
|
|
517
|
+
Nx = int(np.round((self.params['width_phantom'])/dx))
|
|
518
|
+
else:
|
|
519
|
+
Nx = int(round((self.params['Xrange'][1] - self.params['Xrange'][0]) / dx))
|
|
520
|
+
if self.params['height_phantom'] is not None:
|
|
521
|
+
Nz = int(np.round((self.params['height_phantom'])/dx))
|
|
522
|
+
else:
|
|
523
|
+
Nz = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / dx))
|
|
512
524
|
else:
|
|
513
|
-
|
|
514
|
-
|
|
525
|
+
if self.params['width_phantom'] is not None:
|
|
526
|
+
Nx = int(np.round((self.params['width_phantom'])/self.params['dx']))
|
|
527
|
+
else:
|
|
528
|
+
Nx = int(round((self.params['Xrange'][1] - self.params['Xrange'][0]) / self.params['dx']))
|
|
529
|
+
if self.params['height_phantom'] is not None:
|
|
530
|
+
Nz = int(np.round((self.params['height_phantom'])/self.params['dz']))
|
|
531
|
+
else:
|
|
532
|
+
Nz = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / self.params['dz']))
|
|
515
533
|
|
|
516
534
|
# --- 2. Time and space factors ---
|
|
517
535
|
self.factorT = int(np.ceil(self.params['f_AQ'] / self.params['f_saving']))
|
|
@@ -530,17 +548,14 @@ class AcousticField(ABC):
|
|
|
530
548
|
sensor.mask = np.ones((Nx, Nz))
|
|
531
549
|
|
|
532
550
|
# --- 5. PML setup ---
|
|
533
|
-
total_size_x = next_power_of_2(Nx)
|
|
534
551
|
total_size_z = next_power_of_2(Nz)
|
|
535
|
-
pml_x_size = (total_size_x - Nx) // 2
|
|
536
552
|
pml_z_size = (total_size_z - Nz) // 2
|
|
537
|
-
pml_x_size = max(pml_x_size, 50) # Ensure a minimum PML size of 50 grid points to avoid parasitic reflections
|
|
538
553
|
pml_z_size = max(pml_z_size, 50) # Ensure a minimum PML size of 50 grid points to avoid parasitic reflections
|
|
539
554
|
|
|
540
555
|
# --- 6. Simulation options ---
|
|
541
556
|
simulation_options = SimulationOptions(
|
|
542
557
|
pml_inside=False,
|
|
543
|
-
pml_size=[
|
|
558
|
+
pml_size=[0, pml_z_size],
|
|
544
559
|
use_sg=False,
|
|
545
560
|
save_to_disk=True,
|
|
546
561
|
input_filename=os.path.join(gettempdir(), "KwaveIN.h5"),
|
|
@@ -583,11 +598,23 @@ class AcousticField(ABC):
|
|
|
583
598
|
dx = self.params['dx']
|
|
584
599
|
if dx >= self.params['element_width']:
|
|
585
600
|
dx = self.params['element_width'] / 2
|
|
586
|
-
|
|
587
|
-
|
|
601
|
+
if self.params['width_phantom'] is not None:
|
|
602
|
+
Nx = int(np.round((self.params['width_phantom'])/dx))
|
|
603
|
+
else:
|
|
604
|
+
Nx = int(round((self.params['Xrange'][1] - self.params['Xrange'][0]) / dx))
|
|
605
|
+
if self.params['height_phantom'] is not None:
|
|
606
|
+
Nz = int(np.round((self.params['height_phantom'])/dx))
|
|
607
|
+
else:
|
|
608
|
+
Nz = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / dx))
|
|
588
609
|
else:
|
|
589
|
-
|
|
590
|
-
|
|
610
|
+
if self.params['width_phantom'] is not None:
|
|
611
|
+
Nx = int(np.round((self.params['width_phantom'])/self.params['dx']))
|
|
612
|
+
else:
|
|
613
|
+
Nx = int(round((self.params['Xrange'][1] - self.params['Xrange'][0]) / self.params['dx']))
|
|
614
|
+
if self.params['height_phantom'] is not None:
|
|
615
|
+
Nz = int(np.round((self.params['height_phantom'])/self.params['dz']))
|
|
616
|
+
else:
|
|
617
|
+
Nz = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / self.params['dz']))
|
|
591
618
|
|
|
592
619
|
# --- 2. Time and space factors (common) ---
|
|
593
620
|
factorT = int(np.ceil(self.params['f_AQ'] / self.params['f_saving']))
|
|
@@ -340,6 +340,27 @@ class Tomography(Experiment):
|
|
|
340
340
|
if self.AOsignal_withoutTumor is not None:
|
|
341
341
|
self.AOsignal_withoutTumor = self.AOsignal_withoutTumor[:, index]
|
|
342
342
|
self.AcousticFields = newAcousticFields
|
|
343
|
+
self.theta = [field.angle for field in newAcousticFields]
|
|
344
|
+
self.decimations = [field.f_s for field in newAcousticFields]
|
|
345
|
+
|
|
346
|
+
def selectDecimations(self, decimations):
|
|
347
|
+
if self.AOsignal_withTumor is None and self.AOsignal_withoutTumor is None:
|
|
348
|
+
raise ValueError("AO signals are not initialized. Please load or generate the AO signals first.")
|
|
349
|
+
if self.AcousticFields is None or len(self.AcousticFields) == 0:
|
|
350
|
+
raise ValueError("AcousticFields is not initialized. Please generate the system matrix first.")
|
|
351
|
+
newAcousticFields = []
|
|
352
|
+
index = []
|
|
353
|
+
for i, field in enumerate(self.AcousticFields):
|
|
354
|
+
if field.f_s in decimations:
|
|
355
|
+
newAcousticFields.append(field)
|
|
356
|
+
index.append(i)
|
|
357
|
+
if self.AOsignal_withTumor is not None:
|
|
358
|
+
self.AOsignal_withTumor = self.AOsignal_withTumor[:, index]
|
|
359
|
+
if self.AOsignal_withoutTumor is not None:
|
|
360
|
+
self.AOsignal_withoutTumor = self.AOsignal_withoutTumor[:, index]
|
|
361
|
+
self.AcousticFields = newAcousticFields
|
|
362
|
+
self.decimations = [field.f_s for field in newAcousticFields]
|
|
363
|
+
self.theta = [field.angle for field in newAcousticFields]
|
|
343
364
|
|
|
344
365
|
def selectPatterns(self, pattern_names):
|
|
345
366
|
if self.AOsignal_withTumor is None and self.AOsignal_withoutTumor is None:
|
|
@@ -440,8 +461,7 @@ class Tomography(Experiment):
|
|
|
440
461
|
patterns.append({"fileName": pair})
|
|
441
462
|
|
|
442
463
|
return patterns
|
|
443
|
-
|
|
444
|
-
|
|
464
|
+
|
|
445
465
|
def _generate_patterns(self, N,angles = None):
|
|
446
466
|
def format_angle(a):
|
|
447
467
|
return f"{'1' if a < 0 else '0'}{abs(a):02d}"
|
|
@@ -18,91 +18,6 @@ class AnalyticRecon(Recon):
|
|
|
18
18
|
self.Lc = Lc # in meters
|
|
19
19
|
self.AOsignal_demoldulated = None
|
|
20
20
|
|
|
21
|
-
def parse_and_demodulate(self, withTumor=True):
|
|
22
|
-
|
|
23
|
-
if withTumor:
|
|
24
|
-
AOsignal = self.experiment.AOsignal_withTumor
|
|
25
|
-
else:
|
|
26
|
-
AOsignal = self.experiment.AOsignal_withoutTumor
|
|
27
|
-
delta_x = self.experiment.params.general['dx'] # en m
|
|
28
|
-
n_piezos = self.experiment.params.acoustic['num_elements']
|
|
29
|
-
demodulated_data = {}
|
|
30
|
-
structured_buffer = {}
|
|
31
|
-
|
|
32
|
-
for i in trange(len(self.experiment.AcousticFields), desc="Demodulating AO signals"):
|
|
33
|
-
label = self.experiment.AcousticFields[i].getName_field()
|
|
34
|
-
|
|
35
|
-
parts = label.split("_")
|
|
36
|
-
hex_pattern = parts[0]
|
|
37
|
-
angle_code = parts[-1]
|
|
38
|
-
|
|
39
|
-
# Angle
|
|
40
|
-
if angle_code.startswith("1"):
|
|
41
|
-
angle_deg = -int(angle_code[1:])
|
|
42
|
-
else:
|
|
43
|
-
angle_deg = int(angle_code)
|
|
44
|
-
angle_rad = np.deg2rad(angle_deg)
|
|
45
|
-
|
|
46
|
-
# Onde Plane (f_s = 0)
|
|
47
|
-
if set(hex_pattern.lower().replace(" ", "")) == {'f'}:
|
|
48
|
-
fs_key = 0.0 # fs_key est en mm^-1 (0.0 mm^-1)
|
|
49
|
-
demodulated_data[(fs_key, angle_rad)] = np.array(AOsignal[:,i])
|
|
50
|
-
continue
|
|
51
|
-
|
|
52
|
-
# Onde Structurée
|
|
53
|
-
profile = hex_to_binary_profile(hex_pattern, n_piezos)
|
|
54
|
-
|
|
55
|
-
# Calcul FS (Fréquence de Structuration)
|
|
56
|
-
ft_prof = np.fft.fft(profile)
|
|
57
|
-
# On regarde uniquement la partie positive non DC
|
|
58
|
-
idx_max = np.argmax(np.abs(ft_prof[1:len(profile)//2])) + 1
|
|
59
|
-
freqs = np.fft.fftfreq(len(profile), d=delta_x)
|
|
60
|
-
|
|
61
|
-
# freqs est en m^-1 car delta_x est en mètres.
|
|
62
|
-
fs_m_inv = abs(freqs[idx_max])
|
|
63
|
-
|
|
64
|
-
# *** CORRECTION 1: Conversion de f_s en mm^-1 (mm^-1 est utilisé dans iRadon) ***
|
|
65
|
-
fs_key = fs_m_inv / 1000.0 # Fréquence spatiale en mm^-1
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if fs_key == 0: continue
|
|
69
|
-
|
|
70
|
-
# Calcul de la Phase (Shift)
|
|
71
|
-
phase = get_phase_deterministic(profile)
|
|
72
|
-
|
|
73
|
-
# Stockage par (fs, theta) et phase
|
|
74
|
-
key = (fs_key, angle_rad)
|
|
75
|
-
if key not in structured_buffer:
|
|
76
|
-
structured_buffer[key] = {}
|
|
77
|
-
|
|
78
|
-
# La moyenne est nécessaire si plusieurs acquisitions ont la même phase (pour le SNR)
|
|
79
|
-
if phase in structured_buffer[key]:
|
|
80
|
-
structured_buffer[key][phase] = (structured_buffer[key][phase] + np.array(AOsignal[:,i])) / 2
|
|
81
|
-
else:
|
|
82
|
-
structured_buffer[key][phase] = np.array(AOsignal[:,i])
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
for (fs, theta), phases in structured_buffer.items():
|
|
87
|
-
s0 = phases.get(0.0, 0)
|
|
88
|
-
s_pi_2 = phases.get(np.pi/2, 0)
|
|
89
|
-
s_pi = phases.get(np.pi, 0)
|
|
90
|
-
s_3pi_2 = phases.get(3*np.pi/2, 0)
|
|
91
|
-
|
|
92
|
-
# Assurer que les zéros sont des vecteurs de la bonne taille
|
|
93
|
-
example = next(val for val in phases.values() if not isinstance(val, int))
|
|
94
|
-
if isinstance(s0, int): s0 = np.zeros_like(example)
|
|
95
|
-
if isinstance(s_pi, int): s_pi = np.zeros_like(example)
|
|
96
|
-
if isinstance(s_pi_2, int): s_pi_2 = np.zeros_like(example)
|
|
97
|
-
if isinstance(s_3pi_2, int): s_3pi_2 = np.zeros_like(example)
|
|
98
|
-
|
|
99
|
-
real = s0 - s_pi
|
|
100
|
-
imag = s_pi_2 - s_3pi_2
|
|
101
|
-
|
|
102
|
-
demodulated_data[(fs, theta)] = (real - 1j * imag) / (2/np.pi)
|
|
103
|
-
|
|
104
|
-
return demodulated_data
|
|
105
|
-
|
|
106
21
|
def run(self, processType = ProcessType.PYTHON, withTumor= True):
|
|
107
22
|
"""
|
|
108
23
|
This method is a placeholder for the analytic reconstruction process.
|
|
@@ -126,8 +41,13 @@ class AnalyticRecon(Recon):
|
|
|
126
41
|
Parameters:
|
|
127
42
|
analyticType: The type of analytic reconstruction to perform (default is iFOURIER).
|
|
128
43
|
"""
|
|
44
|
+
if withTumor:
|
|
45
|
+
AOsignal = self.experiment.AOsignal_withTumor
|
|
46
|
+
else:
|
|
47
|
+
AOsignal = self.experiment.AOsignal_withoutTumor
|
|
48
|
+
|
|
129
49
|
d_t = 1 / float(self.experiment.params.acoustic['f_saving'])
|
|
130
|
-
t_array = np.arange(0,
|
|
50
|
+
t_array = np.arange(0, AOsignal.shape[0])*d_t
|
|
131
51
|
Z = t_array * self.experiment.params.acoustic['c0']
|
|
132
52
|
X_m = np.arange(0, self.experiment.params.acoustic['num_elements'])* self.experiment.params.general['dx']
|
|
133
53
|
dfX = 1 / (X_m[1] - X_m[0]) / len(X_m)
|
|
@@ -135,7 +55,7 @@ class AnalyticRecon(Recon):
|
|
|
135
55
|
self.AOsignal_demoldulated = self.parse_and_demodulate(withTumor=True)
|
|
136
56
|
if self.analyticType == AnalyticType.iFOURIER:
|
|
137
57
|
self.reconPhantom = self._iFourierRecon(
|
|
138
|
-
R =
|
|
58
|
+
R = AOsignal,
|
|
139
59
|
z = Z,
|
|
140
60
|
X_m=X_m,
|
|
141
61
|
theta=self.experiment.theta,
|
|
@@ -148,7 +68,7 @@ class AnalyticRecon(Recon):
|
|
|
148
68
|
|
|
149
69
|
elif self.analyticType == AnalyticType.iRADON:
|
|
150
70
|
self.reconPhantom = self._iRadonRecon(
|
|
151
|
-
R=
|
|
71
|
+
R=AOsignal,
|
|
152
72
|
z=Z,
|
|
153
73
|
X_m=X_m,
|
|
154
74
|
theta=self.experiment.theta,
|
|
@@ -165,7 +85,7 @@ class AnalyticRecon(Recon):
|
|
|
165
85
|
self.AOsignal_demoldulated = self.parse_and_demodulate(withTumor=False)
|
|
166
86
|
if self.analyticType == AnalyticType.iFOURIER:
|
|
167
87
|
self.reconLaser = self._iFourierRecon(
|
|
168
|
-
R =
|
|
88
|
+
R = AOsignal ,
|
|
169
89
|
z = Z,
|
|
170
90
|
X_m=X_m,
|
|
171
91
|
theta=self.experiment.theta,
|
|
@@ -177,7 +97,7 @@ class AnalyticRecon(Recon):
|
|
|
177
97
|
)
|
|
178
98
|
elif self.analyticType == AnalyticType.iRADON:
|
|
179
99
|
self.reconLaser = self._iRadonRecon(
|
|
180
|
-
R=
|
|
100
|
+
R=AOsignal ,
|
|
181
101
|
z=Z,
|
|
182
102
|
X_m=X_m,
|
|
183
103
|
theta=self.experiment.theta,
|
|
@@ -203,7 +123,14 @@ class AnalyticRecon(Recon):
|
|
|
203
123
|
ActiveLIST,
|
|
204
124
|
withTumor,
|
|
205
125
|
):
|
|
206
|
-
|
|
126
|
+
"""
|
|
127
|
+
Reconstruction d'image utilisant la méthode iFourier (GPU).
|
|
128
|
+
Normalisation physique complète incluse.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
# ======================================================
|
|
132
|
+
# 1. Préparation GPU
|
|
133
|
+
# ======================================================
|
|
207
134
|
R = cp.asarray(R)
|
|
208
135
|
z = cp.asarray(z)
|
|
209
136
|
X_m = cp.asarray(X_m)
|
|
@@ -211,28 +138,26 @@ class AnalyticRecon(Recon):
|
|
|
211
138
|
decimation = cp.asarray(decimation)
|
|
212
139
|
DelayLAWS = cp.asarray(DelayLAWS)
|
|
213
140
|
ActiveLIST = cp.asarray(ActiveLIST)
|
|
214
|
-
# Normalisation DelayLAWS (ms → s si besoin)
|
|
215
|
-
DelayLAWS_s = cp.where(cp.max(DelayLAWS) > 1e-3, DelayLAWS / 1000.0, DelayLAWS)
|
|
216
|
-
# Regroupement tirs (décimation, angle)
|
|
217
|
-
ScanParam_cpu = cp.asnumpy(
|
|
218
|
-
cp.stack([decimation, cp.round(theta, 4)], axis=1)
|
|
219
|
-
)
|
|
220
141
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
)
|
|
142
|
+
# Normalisation DelayLAWS (ms -> s si nécessaire)
|
|
143
|
+
DelayLAWS_s = cp.where(cp.max(DelayLAWS) > 1e-3, DelayLAWS / 1000.0, DelayLAWS)
|
|
224
144
|
|
|
145
|
+
# Regroupement tirs (CPU pour np.unique plus rapide)
|
|
146
|
+
ScanParam_cpu = cp.asnumpy(cp.stack([decimation, cp.round(theta, 4)], axis=1))
|
|
147
|
+
_, ia_cpu, ib_cpu = np.unique(ScanParam_cpu, axis=0, return_index=True, return_inverse=True)
|
|
225
148
|
ia = cp.asarray(ia_cpu)
|
|
226
149
|
ib = cp.asarray(ib_cpu)
|
|
227
150
|
|
|
228
|
-
|
|
229
|
-
#
|
|
230
|
-
#
|
|
151
|
+
# ======================================================
|
|
152
|
+
# 2. Structuration complexe
|
|
153
|
+
# ======================================================
|
|
231
154
|
F_complex_cpu, theta_u_cpu, decim_u_cpu = add_sincos_cpu(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
155
|
+
cp.asnumpy(R),
|
|
156
|
+
cp.asnumpy(decimation),
|
|
157
|
+
np.radians(cp.asnumpy(theta))
|
|
235
158
|
)
|
|
159
|
+
|
|
160
|
+
# Calcul des centres de rotation
|
|
236
161
|
M0 = EvalDelayLawOS_center(
|
|
237
162
|
X_m,
|
|
238
163
|
theta_u_cpu,
|
|
@@ -241,29 +166,38 @@ class AnalyticRecon(Recon):
|
|
|
241
166
|
c
|
|
242
167
|
)
|
|
243
168
|
|
|
244
|
-
# Transfert GPU
|
|
169
|
+
# Transfert GPU
|
|
245
170
|
F_complex = cp.asarray(F_complex_cpu)
|
|
246
171
|
theta_u = cp.asarray(theta_u_cpu)
|
|
247
172
|
decim_u = cp.asarray(decim_u_cpu)
|
|
173
|
+
M0_gpu = cp.asarray(M0)
|
|
248
174
|
|
|
175
|
+
# ======================================================
|
|
176
|
+
# 3. Paramètres de la grille
|
|
177
|
+
# ======================================================
|
|
249
178
|
Nz = z.size
|
|
250
179
|
Nx = X_m.size
|
|
251
180
|
dx = X_m[1] - X_m[0]
|
|
252
|
-
|
|
253
181
|
X_grid, Z_grid = cp.meshgrid(X_m, z)
|
|
254
182
|
idx0_x = Nx // 2
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
)
|
|
183
|
+
|
|
184
|
+
# Angles uniques
|
|
185
|
+
angles_group, ia_u, ib_u = cp.unique(theta_u, return_index=True, return_inverse=True)
|
|
259
186
|
Ntheta = angles_group.size
|
|
260
187
|
|
|
188
|
+
# Initialisation reconstruction
|
|
261
189
|
I_final = cp.zeros((Nz, Nx), dtype=cp.complex64)
|
|
262
190
|
|
|
263
|
-
#
|
|
264
|
-
|
|
191
|
+
# ======================================================
|
|
192
|
+
# 4. Boucle Inverse Fourier X
|
|
193
|
+
# ======================================================
|
|
194
|
+
for i_ang in trange(
|
|
195
|
+
Ntheta,
|
|
196
|
+
desc=f"AOT-BioMaps -- iFourier ({'with tumor' if withTumor else 'without tumor'}) -- GPU",
|
|
197
|
+
unit="angle"
|
|
198
|
+
):
|
|
265
199
|
|
|
266
|
-
# Grille (z, fx)
|
|
200
|
+
# Grille Fourier locale (z, fx)
|
|
267
201
|
F_fx_z = cp.zeros((Nz, Nx), dtype=cp.complex64)
|
|
268
202
|
|
|
269
203
|
# Indices correspondant à cet angle
|
|
@@ -278,7 +212,7 @@ class AnalyticRecon(Recon):
|
|
|
278
212
|
if 0 <= ip < Nx:
|
|
279
213
|
F_fx_z[:, ip] = trace_z
|
|
280
214
|
|
|
281
|
-
# Mapping négatif (symétrie hermitienne
|
|
215
|
+
# Mapping négatif (symétrie hermitienne MATLAB)
|
|
282
216
|
if n != 0:
|
|
283
217
|
im = idx0_x - n
|
|
284
218
|
if 0 <= im < Nx:
|
|
@@ -289,21 +223,30 @@ class AnalyticRecon(Recon):
|
|
|
289
223
|
# Correction DC
|
|
290
224
|
F_fx_z[:, idx0_x] *= 0.5
|
|
291
225
|
|
|
292
|
-
#
|
|
226
|
+
# Inverse Fourier X (GPU) + facteur Nx pour correspondance MATLAB
|
|
293
227
|
I_spatial = ifourierx_gpu(F_fx_z, dx) * Nx
|
|
294
228
|
|
|
295
|
-
#
|
|
229
|
+
# Rotation spatiale autour du centre M0
|
|
296
230
|
I_rot = rotate_theta_gpu(
|
|
297
231
|
X_grid,
|
|
298
232
|
Z_grid,
|
|
299
233
|
I_spatial,
|
|
300
234
|
-angles_group[i_ang],
|
|
301
|
-
|
|
235
|
+
M0_gpu[i_ang, :]
|
|
302
236
|
)
|
|
303
237
|
|
|
304
|
-
# Somme incohérente
|
|
238
|
+
# Somme incohérente
|
|
305
239
|
I_final += I_rot
|
|
306
|
-
|
|
240
|
+
|
|
241
|
+
# ======================================================
|
|
242
|
+
# 5. Normalisation physique finale
|
|
243
|
+
# ======================================================
|
|
244
|
+
Ntheta_total = len(theta_u)
|
|
245
|
+
Ntirs_complex = (R.shape[1] - Ntheta_total) / 4.0 # 4 phases par tir
|
|
246
|
+
|
|
247
|
+
I_final /= (Ntheta_total * Ntirs_complex)
|
|
248
|
+
I_final *= dx # normalisation physique sur l’axe x
|
|
249
|
+
|
|
307
250
|
return cp.real(I_final).get()
|
|
308
251
|
|
|
309
252
|
def _iRadonRecon(
|
|
@@ -319,23 +262,24 @@ class AnalyticRecon(Recon):
|
|
|
319
262
|
DelayLAWS,
|
|
320
263
|
ActiveLIST,
|
|
321
264
|
withTumor,
|
|
322
|
-
):
|
|
265
|
+
):
|
|
323
266
|
"""
|
|
324
267
|
Reconstruction d'image utilisant la méthode iRadon.
|
|
325
|
-
|
|
326
|
-
:return: Image reconstruite.
|
|
268
|
+
Normalisation physique correcte (phases, angles, dz).
|
|
327
269
|
"""
|
|
328
|
-
|
|
270
|
+
|
|
329
271
|
# ======================================================
|
|
330
|
-
# 1. AddSinCos (structuration)
|
|
272
|
+
# 1. AddSinCos (structuration) — CPU volontairement
|
|
331
273
|
# ======================================================
|
|
332
274
|
theta = np.radians(theta)
|
|
333
275
|
F_ct_kx, theta_u, decim_u = add_sincos_cpu(R, decimation, theta)
|
|
276
|
+
|
|
334
277
|
ScanParam = np.stack([decimation, theta], axis=1)
|
|
335
278
|
_, ia, _ = np.unique(ScanParam, axis=0, return_index=True, return_inverse=True)
|
|
279
|
+
|
|
336
280
|
ActiveLIST = np.asarray(ActiveLIST).T
|
|
337
281
|
DelayLAWS = np.asarray(DelayLAWS).T
|
|
338
|
-
ActiveLIST_unique = ActiveLIST[:,ia]
|
|
282
|
+
ActiveLIST_unique = ActiveLIST[:, ia]
|
|
339
283
|
|
|
340
284
|
# ======================================================
|
|
341
285
|
# 2. FFT z
|
|
@@ -343,8 +287,7 @@ class AnalyticRecon(Recon):
|
|
|
343
287
|
z_gpu = cp.asarray(z)
|
|
344
288
|
Fin = fourierz_gpu(z, F_ct_kx)
|
|
345
289
|
|
|
346
|
-
|
|
347
|
-
dz = float(z[1] - z[0])
|
|
290
|
+
dz = float(z[1] - z[0]) # <<< Δz PHYSIQUE
|
|
348
291
|
fz = cp.fft.fftshift(cp.fft.fftfreq(len(z), d=dz))
|
|
349
292
|
|
|
350
293
|
Nz, Nk = Fin.shape
|
|
@@ -354,7 +297,7 @@ class AnalyticRecon(Recon):
|
|
|
354
297
|
# ======================================================
|
|
355
298
|
decim_gpu = cp.asarray(decim_u)
|
|
356
299
|
I0 = decim_gpu == 0
|
|
357
|
-
F0 = Fin * I0[None, :]
|
|
300
|
+
F0 = Fin * I0[None, :]
|
|
358
301
|
|
|
359
302
|
DEC, FZ = cp.meshgrid(decim_gpu, fz)
|
|
360
303
|
|
|
@@ -381,40 +324,53 @@ class AnalyticRecon(Recon):
|
|
|
381
324
|
Xc = float(np.mean(X_m))
|
|
382
325
|
|
|
383
326
|
# ======================================================
|
|
384
|
-
# 6.
|
|
327
|
+
# 6. Centre de rotation M0
|
|
385
328
|
# ======================================================
|
|
386
|
-
M0 = EvalDelayLawOS_center(X_m,theta, DelayLAWS[:, ia], ActiveLIST_unique, c)
|
|
329
|
+
M0 = EvalDelayLawOS_center(X_m, theta, DelayLAWS[:, ia], ActiveLIST_unique, c)
|
|
387
330
|
M0_gpu = cp.asarray(M0)
|
|
388
331
|
|
|
389
332
|
# ======================================================
|
|
390
333
|
# 7. Rétroprojection
|
|
391
334
|
# ======================================================
|
|
392
|
-
Irec_list = []
|
|
393
335
|
Irec = cp.zeros_like(X, dtype=cp.complex64)
|
|
394
|
-
|
|
336
|
+
|
|
337
|
+
for i in trange(
|
|
338
|
+
len(theta_u),
|
|
339
|
+
desc=f"AOT-BioMaps -- iRadon ({'with tumor' if withTumor else 'without tumor'}) -- GPU",
|
|
340
|
+
unit="angle"
|
|
341
|
+
):
|
|
395
342
|
th = float(theta_u[i])
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
Tind = (T - z_gpu[0]) / (z_gpu[1] - z_gpu[0])
|
|
343
|
+
|
|
344
|
+
T = (X - M0_gpu[i, 0]) * cp.sin(th) + (Z - M0_gpu[i, 1]) * cp.cos(th) + M0_gpu[i, 1]
|
|
345
|
+
S = (X - Xc) * cp.cos(th) - (Z - M0_gpu[i, 1]) * cp.sin(th)
|
|
346
|
+
h0 = cp.exp(1j * 2 * cp.pi * decim_u[i] * df0x * S)
|
|
347
|
+
|
|
348
|
+
# interpolation linéaire en z
|
|
349
|
+
Tind = (T - z_gpu[0]) / dz
|
|
404
350
|
i0 = cp.floor(Tind).astype(cp.int32)
|
|
405
351
|
i1 = i0 + 1
|
|
406
|
-
i0 = cp.clip(i0, 0, Nz-1)
|
|
407
|
-
i1 = cp.clip(i1, 0, Nz-1)
|
|
352
|
+
i0 = cp.clip(i0, 0, Nz - 1)
|
|
353
|
+
i1 = cp.clip(i1, 0, Nz - 1)
|
|
408
354
|
w = Tind - i0
|
|
409
355
|
|
|
410
|
-
proj_sup = (1-w)*Fsup[i0, i] + w*Fsup[i1, i]
|
|
411
|
-
proj_inf = (1-w)*Finf[i0, i] + w*Finf[i1, i]
|
|
356
|
+
proj_sup = (1 - w) * Fsup[i0, i] + w * Fsup[i1, i]
|
|
357
|
+
proj_inf = (1 - w) * Finf[i0, i] + w * Finf[i1, i]
|
|
358
|
+
|
|
359
|
+
# >>> SOMME BRUTE (correcte)
|
|
360
|
+
Irec += 2 * h0 * proj_sup + proj_inf
|
|
361
|
+
|
|
362
|
+
# ======================================================
|
|
363
|
+
# 8. NORMALISATION PHYSIQUE GLOBALE
|
|
364
|
+
# ======================================================
|
|
365
|
+
|
|
366
|
+
Ntheta = len(theta_u)
|
|
412
367
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
# Ajouter à la liste
|
|
416
|
-
Irec_list.append(cp.real(Irec).get())
|
|
417
|
-
|
|
368
|
+
# nombre de tirs complexes indépendants (4 phases)
|
|
369
|
+
Ntirs_complex = (R.shape[1] - Ntheta) / 4.0
|
|
418
370
|
|
|
419
|
-
|
|
371
|
+
# normalisation finale
|
|
372
|
+
Irec /= (Ntheta * Ntirs_complex)
|
|
373
|
+
print(f"dz normalization: {dz}")
|
|
374
|
+
Irec *= dz
|
|
420
375
|
|
|
376
|
+
return cp.real(Irec).get()
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from AOT_biomaps.Config import config
|
|
2
|
-
from AOT_biomaps.AOT_Experiment.Tomography import Tomography
|
|
2
|
+
from AOT_biomaps.AOT_Experiment.Tomography import Tomography, hex_to_binary_profile
|
|
3
3
|
from .ReconEnums import ReconType
|
|
4
|
-
from .ReconTools import mse, ssim
|
|
4
|
+
from .ReconTools import mse, ssim, get_phase_deterministic
|
|
5
5
|
|
|
6
6
|
import os
|
|
7
7
|
import numpy as np
|
|
8
8
|
import matplotlib.pyplot as plt
|
|
9
9
|
from abc import ABC, abstractmethod
|
|
10
|
+
from tqdm import trange
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class Recon(ABC):
|
|
@@ -166,8 +167,14 @@ class Recon(ABC):
|
|
|
166
167
|
ssim_value = ssim(self.experiment.OpticImage.phantom, theta, data_range=data_range)
|
|
167
168
|
self.SSIM.append(ssim_value)
|
|
168
169
|
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
def show(self, withTumor=True, savePath=None, scale='same'):
|
|
171
|
+
"""
|
|
172
|
+
Display the reconstructed images.
|
|
173
|
+
Args:
|
|
174
|
+
withTumor (bool): If True, displays reconPhantom. If False, displays reconLaser. Default is True.
|
|
175
|
+
savePath (str): Path to save the figure. If None, the figure is not saved. Default is None.
|
|
176
|
+
scale (str): Scale for the aspect ratio of the plots. Default is 'same'. Options are 'same' or 'auto'.
|
|
177
|
+
"""
|
|
171
178
|
if withTumor:
|
|
172
179
|
if self.reconPhantom is None:
|
|
173
180
|
raise ValueError("Reconstructed phantom with tumor is empty. Run reconstruction first.")
|
|
@@ -181,12 +188,19 @@ class Recon(ABC):
|
|
|
181
188
|
fig, axs = plt.subplots(1, 1, figsize=(10, 10))
|
|
182
189
|
else:
|
|
183
190
|
fig, axs = plt.subplots(1, 2, figsize=(20, 10))
|
|
191
|
+
if scale == 'same':
|
|
192
|
+
vmin = 0
|
|
193
|
+
vmax = 1
|
|
194
|
+
elif scale == 'auto':
|
|
195
|
+
vmin = np.min(self.experiment.OpticImage.phantom)
|
|
196
|
+
vmax = np.max(self.experiment.OpticImage.phantom)
|
|
197
|
+
|
|
184
198
|
# Phantom original
|
|
185
199
|
im1 = axs[1].imshow(
|
|
186
200
|
self.experiment.OpticImage.phantom,
|
|
187
201
|
cmap='hot',
|
|
188
|
-
vmin=
|
|
189
|
-
vmax=
|
|
202
|
+
vmin=vmin,
|
|
203
|
+
vmax=vmax,
|
|
190
204
|
extent=(
|
|
191
205
|
self.experiment.params.general['Xrange'][0],
|
|
192
206
|
self.experiment.params.general['Xrange'][1],
|
|
@@ -199,12 +213,18 @@ class Recon(ABC):
|
|
|
199
213
|
axs[1].set_xlabel("x (mm)", fontsize=12)
|
|
200
214
|
axs[1].set_ylabel("z (mm)", fontsize=12)
|
|
201
215
|
axs[1].tick_params(axis='both', which='major', labelsize=8)
|
|
216
|
+
if scale == 'same':
|
|
217
|
+
vmin = 0
|
|
218
|
+
vmax = 1
|
|
219
|
+
elif scale == 'auto':
|
|
220
|
+
vmin = np.min(image)
|
|
221
|
+
vmax = np.max(image)
|
|
202
222
|
# Phantom reconstruit
|
|
203
223
|
im0 = axs[0].imshow(
|
|
204
224
|
image,
|
|
205
225
|
cmap='hot',
|
|
206
|
-
vmin=
|
|
207
|
-
vmax=
|
|
226
|
+
vmin=vmin,
|
|
227
|
+
vmax=vmax,
|
|
208
228
|
extent=(
|
|
209
229
|
self.experiment.params.general['Xrange'][0],
|
|
210
230
|
self.experiment.params.general['Xrange'][1],
|
|
@@ -288,4 +308,87 @@ class Recon(ABC):
|
|
|
288
308
|
|
|
289
309
|
plt.show()
|
|
290
310
|
|
|
311
|
+
def parse_and_demodulate(self, withTumor=True):
|
|
312
|
+
|
|
313
|
+
if withTumor:
|
|
314
|
+
AOsignal = self.experiment.AOsignal_withTumor
|
|
315
|
+
else:
|
|
316
|
+
AOsignal = self.experiment.AOsignal_withoutTumor
|
|
317
|
+
delta_x = self.experiment.params.general['dx'] # en m
|
|
318
|
+
n_piezos = self.experiment.params.acoustic['num_elements']
|
|
319
|
+
demodulated_data = {}
|
|
320
|
+
structured_buffer = {}
|
|
321
|
+
|
|
322
|
+
for i in trange(len(self.experiment.AcousticFields), desc="Demodulating AO signals"):
|
|
323
|
+
label = self.experiment.AcousticFields[i].getName_field()
|
|
324
|
+
|
|
325
|
+
parts = label.split("_")
|
|
326
|
+
hex_pattern = parts[0]
|
|
327
|
+
angle_code = parts[-1]
|
|
328
|
+
|
|
329
|
+
# Angle
|
|
330
|
+
if angle_code.startswith("1"):
|
|
331
|
+
angle_deg = -int(angle_code[1:])
|
|
332
|
+
else:
|
|
333
|
+
angle_deg = int(angle_code)
|
|
334
|
+
angle_rad = np.deg2rad(angle_deg)
|
|
335
|
+
|
|
336
|
+
# Onde Plane (f_s = 0)
|
|
337
|
+
if set(hex_pattern.lower().replace(" ", "")) == {'f'}:
|
|
338
|
+
fs_key = 0.0 # fs_key est en mm^-1 (0.0 mm^-1)
|
|
339
|
+
demodulated_data[(fs_key, angle_rad)] = np.array(AOsignal[:,i])
|
|
340
|
+
continue
|
|
341
|
+
|
|
342
|
+
# Onde Structurée
|
|
343
|
+
profile = hex_to_binary_profile(hex_pattern, n_piezos)
|
|
344
|
+
|
|
345
|
+
# Calcul FS (Fréquence de Structuration)
|
|
346
|
+
ft_prof = np.fft.fft(profile)
|
|
347
|
+
# On regarde uniquement la partie positive non DC
|
|
348
|
+
idx_max = np.argmax(np.abs(ft_prof[1:len(profile)//2])) + 1
|
|
349
|
+
freqs = np.fft.fftfreq(len(profile), d=delta_x)
|
|
350
|
+
|
|
351
|
+
# freqs est en m^-1 car delta_x est en mètres.
|
|
352
|
+
fs_m_inv = abs(freqs[idx_max])
|
|
353
|
+
|
|
354
|
+
# *** CORRECTION 1: Conversion de f_s en mm^-1 (mm^-1 est utilisé dans iRadon) ***
|
|
355
|
+
fs_key = fs_m_inv / 1000.0 # Fréquence spatiale en mm^-1
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
if fs_key == 0: continue
|
|
359
|
+
|
|
360
|
+
# Calcul de la Phase (Shift)
|
|
361
|
+
phase = get_phase_deterministic(profile)
|
|
362
|
+
|
|
363
|
+
# Stockage par (fs, theta) et phase
|
|
364
|
+
key = (fs_key, angle_rad)
|
|
365
|
+
if key not in structured_buffer:
|
|
366
|
+
structured_buffer[key] = {}
|
|
367
|
+
|
|
368
|
+
# La moyenne est nécessaire si plusieurs acquisitions ont la même phase (pour le SNR)
|
|
369
|
+
if phase in structured_buffer[key]:
|
|
370
|
+
structured_buffer[key][phase] = (structured_buffer[key][phase] + np.array(AOsignal[:,i])) / 2
|
|
371
|
+
else:
|
|
372
|
+
structured_buffer[key][phase] = np.array(AOsignal[:,i])
|
|
373
|
+
|
|
291
374
|
|
|
375
|
+
|
|
376
|
+
for (fs, theta), phases in structured_buffer.items():
|
|
377
|
+
s0 = phases.get(0.0, 0)
|
|
378
|
+
s_pi_2 = phases.get(np.pi/2, 0)
|
|
379
|
+
s_pi = phases.get(np.pi, 0)
|
|
380
|
+
s_3pi_2 = phases.get(3*np.pi/2, 0)
|
|
381
|
+
|
|
382
|
+
# Assurer que les zéros sont des vecteurs de la bonne taille
|
|
383
|
+
example = next(val for val in phases.values() if not isinstance(val, int))
|
|
384
|
+
if isinstance(s0, int): s0 = np.zeros_like(example)
|
|
385
|
+
if isinstance(s_pi, int): s_pi = np.zeros_like(example)
|
|
386
|
+
if isinstance(s_pi_2, int): s_pi_2 = np.zeros_like(example)
|
|
387
|
+
if isinstance(s_3pi_2, int): s_3pi_2 = np.zeros_like(example)
|
|
388
|
+
|
|
389
|
+
real = s0 - s_pi
|
|
390
|
+
imag = s_pi_2 - s_3pi_2
|
|
391
|
+
|
|
392
|
+
demodulated_data[(fs, theta)] = (real - 1j * imag) / (2/np.pi)
|
|
393
|
+
|
|
394
|
+
return demodulated_data
|
AOT_biomaps/__init__.py
CHANGED
|
@@ -85,7 +85,7 @@ from .AOT_Recon.AOT_PotentialFunctions.RelativeDifferences import *
|
|
|
85
85
|
from .Config import config
|
|
86
86
|
from .Settings import *
|
|
87
87
|
|
|
88
|
-
__version__ = '2.9.
|
|
88
|
+
__version__ = '2.9.373'
|
|
89
89
|
__process__ = config.get_process()
|
|
90
90
|
|
|
91
91
|
def initialize(process=None):
|
|
@@ -202,6 +202,23 @@ def initialize(process=None):
|
|
|
202
202
|
|
|
203
203
|
|
|
204
204
|
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
205
222
|
|
|
206
223
|
|
|
207
224
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
AOT_biomaps/Config.py,sha256=ghEOP1n8aO1pR-su13wMeAZAxZRfry5hH67NbtZ8SqI,3614
|
|
2
2
|
AOT_biomaps/Settings.py,sha256=v8fPhnvvcfBJP29m1RLOTEr3jndGLGwbUiORXmsj2Bo,2853
|
|
3
|
-
AOT_biomaps/__init__.py,sha256=
|
|
3
|
+
AOT_biomaps/__init__.py,sha256=fgpEUPXUQbaCtMxY_uHJtjrQTvQBwltYoAQtHk1zCuM,4408
|
|
4
4
|
AOT_biomaps/AOT_Acoustic/AcousticEnums.py,sha256=s5kXa6jKzbS4btwbubrVcynLOr0yg5tth5vL_FGfbMk,1802
|
|
5
|
-
AOT_biomaps/AOT_Acoustic/AcousticTools.py,sha256=
|
|
5
|
+
AOT_biomaps/AOT_Acoustic/AcousticTools.py,sha256=7kuWIIGyzZPQrzRI0zVvdwNUp7qKUE67yCYOMzSb0Ug,8283
|
|
6
6
|
AOT_biomaps/AOT_Acoustic/FocusedWave.py,sha256=3kGKKDx_3Msy5COYqIwzROPORGWvNjw8UsDanBfkMXE,11037
|
|
7
7
|
AOT_biomaps/AOT_Acoustic/IrregularWave.py,sha256=yZhtxkR6zlciRcEpdTR0BAhvgQl40XHKFaF8f4VXarE,3035
|
|
8
8
|
AOT_biomaps/AOT_Acoustic/PlaneWave.py,sha256=xza-rj5AUWDecLkGDxRcULrwZVWeBvGnEP2d51TyR04,1447
|
|
9
|
-
AOT_biomaps/AOT_Acoustic/StructuredWave.py,sha256=
|
|
9
|
+
AOT_biomaps/AOT_Acoustic/StructuredWave.py,sha256=DRTjD-zrmX12FHrvwOeEo-Rk1fHYm9gfCcebz4WhtXc,18930
|
|
10
10
|
AOT_biomaps/AOT_Acoustic/__init__.py,sha256=t9M2rRqa_L9pk7W2FeELTkHEMuP4DBr4gBRldMqsQbg,491
|
|
11
|
-
AOT_biomaps/AOT_Acoustic/_mainAcoustic.py,sha256=
|
|
11
|
+
AOT_biomaps/AOT_Acoustic/_mainAcoustic.py,sha256=M0CKApSCuKiCupj9pf9uOEhuuzJVNSlLvhgTpBQN5Q8,46128
|
|
12
12
|
AOT_biomaps/AOT_Experiment/ExperimentTools.py,sha256=aFvJw6J_jfFVTDFnG7J3a61SHEgORdZKZS0UI82VMaY,2637
|
|
13
13
|
AOT_biomaps/AOT_Experiment/Focus.py,sha256=B2nBawmv-NG2AWJx9zgQ8GlN6aFB9FwTSqX-M-phKXg,3193
|
|
14
|
-
AOT_biomaps/AOT_Experiment/Tomography.py,sha256=
|
|
14
|
+
AOT_biomaps/AOT_Experiment/Tomography.py,sha256=9mJDwV9WVphoX8drL7MgN3WhS6fjYwS6HWQD3x1CrVs,37625
|
|
15
15
|
AOT_biomaps/AOT_Experiment/__init__.py,sha256=H9zMLeBLA6uhbaHohAa-2u5mDDxqJi8oE5c6tShdQp8,308
|
|
16
16
|
AOT_biomaps/AOT_Experiment/_mainExperiment.py,sha256=zSfuNrsz7nhiKrGIdK6CAXjlI2T6qYC5-JXHFgPNzhc,24674
|
|
17
17
|
AOT_biomaps/AOT_Optic/Absorber.py,sha256=jEodzRy7gkEH-wbazVasRQiri0dU16BfapmR-qnTSvM,867
|
|
@@ -21,14 +21,14 @@ AOT_biomaps/AOT_Optic/__init__.py,sha256=HSUVhfz0NzwHHZZ9KP9Xyfu33IgP_rYJX86J-gE
|
|
|
21
21
|
AOT_biomaps/AOT_Optic/_mainOptic.py,sha256=Wk63CcgWbU-ygMfjNK80islaUbGGJpTXgZY3_C2KQNY,8179
|
|
22
22
|
AOT_biomaps/AOT_Recon/AOT_biomaps_kernels.cubin,sha256=JWy-bdtBTZdnNlDbJGZKwXyF-2u1wICtmlOC_YxEL6o,82528
|
|
23
23
|
AOT_biomaps/AOT_Recon/AlgebraicRecon.py,sha256=CGBXZyYEZ3TOTFOKSt-h7NGuFbuI9PNr3YTWTbSLxDo,46832
|
|
24
|
-
AOT_biomaps/AOT_Recon/AnalyticRecon.py,sha256=
|
|
24
|
+
AOT_biomaps/AOT_Recon/AnalyticRecon.py,sha256=z4VJtqL-atoZLflG7vQKHNeTXXjhYG_us8l0xfo5XsU,14514
|
|
25
25
|
AOT_biomaps/AOT_Recon/BayesianRecon.py,sha256=RnnPa-tTcvirwiNPnCRZnSM4NWeEEltYET-piBbp34g,12671
|
|
26
26
|
AOT_biomaps/AOT_Recon/DeepLearningRecon.py,sha256=RfVcEsi4GeGqJn0_SPxwQPQx6IQjin79WKh2UarMRLI,1383
|
|
27
27
|
AOT_biomaps/AOT_Recon/PrimalDualRecon.py,sha256=JbFhxiyUoSTnlJgHbOWIfUUwhwfZoi39RJMnfkagegY,16504
|
|
28
28
|
AOT_biomaps/AOT_Recon/ReconEnums.py,sha256=KAf55RqHAr2ilt6pxFrUBGQOn-7HA8NP6TyL-1FNiXo,19714
|
|
29
29
|
AOT_biomaps/AOT_Recon/ReconTools.py,sha256=CV2BwdEwvNd3B02G5LYoKsRGlONwIupuv617S2AOWZE,25322
|
|
30
30
|
AOT_biomaps/AOT_Recon/__init__.py,sha256=xs_argJqXKFl76xP7-jiUc1ynOEEtY7XZ0gDxD5uVZc,246
|
|
31
|
-
AOT_biomaps/AOT_Recon/_mainRecon.py,sha256=
|
|
31
|
+
AOT_biomaps/AOT_Recon/_mainRecon.py,sha256=hubU5SWEeAv94k_DNbdze4wfUeBw-4smboqRyzlmy_k,18058
|
|
32
32
|
AOT_biomaps/AOT_Recon/AOT_Optimizers/DEPIERRO.py,sha256=qA1n722GLQJH3V8HcLr5q_GxEwBS_NRlIT3E6JZk-Ag,9479
|
|
33
33
|
AOT_biomaps/AOT_Recon/AOT_Optimizers/LS.py,sha256=bCu1rKzFXPbYQ7jV3L3E_jVQpb6LIEC5MIlN1-mCNdY,22814
|
|
34
34
|
AOT_biomaps/AOT_Recon/AOT_Optimizers/MAPEM.py,sha256=vQLCB0L4FSXJKn2_6kdIdWrI6WZ82KuqUh7CSqBGVuo,25766
|
|
@@ -42,7 +42,7 @@ AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/__init__.py,sha256=RwrJdLOFbAFBFnRx
|
|
|
42
42
|
AOT_biomaps/AOT_Recon/AOT_SparseSMatrix/SparseSMatrix_CSR.py,sha256=RACc2P5oxmp0uPLAGnNj9mEtAxa_OlepNgCawKij3jI,12062
|
|
43
43
|
AOT_biomaps/AOT_Recon/AOT_SparseSMatrix/SparseSMatrix_SELL.py,sha256=ti3dZQsb_Uu62C7Bn65Z-yf-R5NKCFsmnBT5GlLd_HY,15138
|
|
44
44
|
AOT_biomaps/AOT_Recon/AOT_SparseSMatrix/__init__.py,sha256=8nou-hqjQjuCTLhoL5qv4EM_lMPFviAZAZKSPhi84jE,67
|
|
45
|
-
aot_biomaps-2.9.
|
|
46
|
-
aot_biomaps-2.9.
|
|
47
|
-
aot_biomaps-2.9.
|
|
48
|
-
aot_biomaps-2.9.
|
|
45
|
+
aot_biomaps-2.9.373.dist-info/METADATA,sha256=pJCjnmUoIHGqV_s_popa7BNlrTn4LPP3h7mxRqlUiTQ,700
|
|
46
|
+
aot_biomaps-2.9.373.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
aot_biomaps-2.9.373.dist-info/top_level.txt,sha256=6STF-lT4kaAnBHJYCripmN5mZABoHjMuY689JdiDphk,12
|
|
48
|
+
aot_biomaps-2.9.373.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|