AOT-biomaps 2.9.339__py3-none-any.whl → 2.9.356__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.
- AOT_biomaps/AOT_Experiment/ExperimentTools.py +15 -25
- AOT_biomaps/AOT_Experiment/Tomography.py +40 -47
- AOT_biomaps/AOT_Recon/AnalyticRecon.py +283 -97
- AOT_biomaps/AOT_Recon/ReconTools.py +162 -1
- AOT_biomaps/AOT_Recon/_mainRecon.py +6 -2
- AOT_biomaps/__init__.py +18 -1
- {aot_biomaps-2.9.339.dist-info → aot_biomaps-2.9.356.dist-info}/METADATA +1 -1
- {aot_biomaps-2.9.339.dist-info → aot_biomaps-2.9.356.dist-info}/RECORD +10 -10
- {aot_biomaps-2.9.339.dist-info → aot_biomaps-2.9.356.dist-info}/WHEEL +0 -0
- {aot_biomaps-2.9.339.dist-info → aot_biomaps-2.9.356.dist-info}/top_level.txt +0 -0
|
@@ -1,32 +1,22 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
|
-
def calc_mat_os(xm, fx,
|
|
3
|
+
def calc_mat_os(xm, fx, bool_active_list, signal_type):
|
|
4
|
+
"""
|
|
5
|
+
xm : vecteur des positions réelles des éléments (en m)
|
|
6
|
+
fx : fréquence spatiale (en m^-1)
|
|
7
|
+
signal_type : 'cos' ou 'sin'
|
|
8
|
+
"""
|
|
4
9
|
num_els = len(xm)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
else:
|
|
12
|
-
# sin(0) = 0 -> Tout est inactif
|
|
13
|
-
mask = np.zeros(num_els, dtype=bool)
|
|
10
|
+
num_cols = bool_active_list.shape[1]
|
|
11
|
+
|
|
12
|
+
if signal_type == 'cos':
|
|
13
|
+
mask = (np.cos(2 * np.pi * fx * xm) > 0).astype(float)
|
|
14
|
+
elif signal_type == 'sin':
|
|
15
|
+
mask = (np.sin(2 * np.pi * fx * xm) > 0).astype(float)
|
|
14
16
|
else:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
# Sécurité : si fx est tellement grand que half_period < 1
|
|
19
|
-
half_period_elements = max(1, half_period_elements)
|
|
20
|
-
|
|
21
|
-
indices = np.arange(num_els)
|
|
22
|
-
if signal_type == 'cos':
|
|
23
|
-
mask = ((indices // half_period_elements) % 2 == 0)
|
|
24
|
-
else:
|
|
25
|
-
# Déphasage de 90° pour le sinus : on décale d'une demi-demi-période
|
|
26
|
-
shift = half_period_elements // 2
|
|
27
|
-
mask = (((indices + shift) // half_period_elements) % 2 == 0)
|
|
28
|
-
|
|
29
|
-
return np.tile(mask[:, np.newaxis], (1, bool_active_list.shape[1]))
|
|
17
|
+
mask = np.ones(num_els) # Sécurité
|
|
18
|
+
|
|
19
|
+
return np.tile(mask[:, np.newaxis], (1, num_cols))
|
|
30
20
|
|
|
31
21
|
def convert_to_hex_list(matrix):
|
|
32
22
|
"""
|
|
@@ -18,6 +18,8 @@ class Tomography(Experiment):
|
|
|
18
18
|
self.patterns = None
|
|
19
19
|
self.theta = []
|
|
20
20
|
self.decimations = []
|
|
21
|
+
self.ActiveList = []
|
|
22
|
+
self.DelayLaw = []
|
|
21
23
|
|
|
22
24
|
# PUBLIC METHODS
|
|
23
25
|
def check(self):
|
|
@@ -66,8 +68,11 @@ class Tomography(Experiment):
|
|
|
66
68
|
self.AcousticFields = self._generateAcousticFields_STRUCT_CPU(fieldDataPath, show_log, nameBlock)
|
|
67
69
|
for i in range(len(self.AcousticFields)):
|
|
68
70
|
profile = hex_to_binary_profile(self.AcousticFields[i].getName_field()[6:-4], self.params.acoustic['num_elements'])
|
|
71
|
+
self.ActiveList.append(profile)
|
|
69
72
|
angle = self.AcousticFields[i].angle
|
|
70
73
|
self.theta.append(angle)
|
|
74
|
+
Delay = 1000 * (1/self.params.acoustic['c0']) * np.sin(np.deg2rad(angle)) * np.arange(1, self.params.acoustic['num_elements'] + 1) * self.params.acoustic['element_width']
|
|
75
|
+
self.DelayLaw.append(Delay - np.min(Delay))
|
|
71
76
|
|
|
72
77
|
if set(self.AcousticFields[i].getName_field()[6:-4].lower().replace(" ", "")) == {'f'}:
|
|
73
78
|
fs_key = 0.0 # fs_key est en mm^-1 (0.0 mm^-1)
|
|
@@ -83,6 +88,7 @@ class Tomography(Experiment):
|
|
|
83
88
|
|
|
84
89
|
# fs = n * dfx => n = fs / dfx with dfx = 1/(N*delta_x)
|
|
85
90
|
self.decimations.append(int(fs_key / (1/(len(profile)*self.params.general['dx']))))
|
|
91
|
+
|
|
86
92
|
else:
|
|
87
93
|
raise ValueError("Unsupported wave type.")
|
|
88
94
|
|
|
@@ -314,20 +320,8 @@ class Tomography(Experiment):
|
|
|
314
320
|
raise ValueError("Either N (>=2) or both decimations and angles must be provided for pattern generation.")
|
|
315
321
|
|
|
316
322
|
def saveAOsignals_matlab(self, filePath):
|
|
317
|
-
ActiveList = []
|
|
318
|
-
DelayLaw = []
|
|
319
|
-
c = self.params.acoustic['c0']
|
|
320
|
-
NbElemts = self.params.acoustic['num_elements']
|
|
321
|
-
pitch = self.params.acoustic['element_width']
|
|
322
|
-
|
|
323
|
-
for i in range(len(self.AcousticFields)):
|
|
324
|
-
profile = hex_to_binary_profile(self.AcousticFields[i].getName_field()[6:-4], NbElemts)
|
|
325
|
-
ActiveList.append(profile)
|
|
326
|
-
angle = self.AcousticFields[i].angle
|
|
327
|
-
Delay = 1000 * (1/c) * np.sin(np.deg2rad(angle)) * np.arange(1, NbElemts + 1) * pitch
|
|
328
|
-
DelayLaw.append(Delay - np.min(Delay))
|
|
329
323
|
|
|
330
|
-
savemat(filePath, {'data': self.AOsignal_withTumor, 'thetas': self.theta, 'decimations': self.decimations, 'ActiveList' : ActiveList, 'DelayLaw': DelayLaw})
|
|
324
|
+
savemat(filePath, {'data': self.AOsignal_withTumor, 'thetas': self.theta, 'decimations': self.decimations, 'ActiveList' : self.ActiveList, 'DelayLaw': self.DelayLaw})
|
|
331
325
|
|
|
332
326
|
def selectAngles(self, angles):
|
|
333
327
|
|
|
@@ -380,74 +374,73 @@ class Tomography(Experiment):
|
|
|
380
374
|
self.AcousticFields = newAcousticFields
|
|
381
375
|
|
|
382
376
|
def _genereate_patterns_from_decimations(self, decimations, angles):
|
|
383
|
-
if isinstance(decimations, list):
|
|
384
|
-
|
|
377
|
+
if isinstance(decimations, list):
|
|
378
|
+
decimations = np.array(decimations)
|
|
379
|
+
if isinstance(angles, list):
|
|
380
|
+
angles = np.array(angles)
|
|
385
381
|
|
|
386
382
|
angles = np.sort(angles)
|
|
387
383
|
decimations = np.sort(decimations)
|
|
388
384
|
|
|
389
385
|
num_elements = self.params.acoustic['num_elements']
|
|
390
|
-
|
|
386
|
+
Width = self.params.acoustic['element_width'] # en m
|
|
387
|
+
kerf = self.params.acoustic.get('kerf', 0.00000) # en m
|
|
388
|
+
Nactuators = self.params.acoustic['num_elements']
|
|
391
389
|
|
|
392
390
|
# --- Calcul du nombre de Scans ---
|
|
393
391
|
if 0 in decimations:
|
|
394
|
-
Nscans = 4 * angles
|
|
395
|
-
offSet = angles.shape[0]
|
|
392
|
+
Nscans = 4 * len(angles) * (len(decimations) - 1) + len(angles)
|
|
396
393
|
else:
|
|
397
|
-
Nscans = 4 * angles
|
|
398
|
-
offSet = 0
|
|
394
|
+
Nscans = 4 * len(angles) * len(decimations)
|
|
399
395
|
|
|
400
396
|
ActiveLIST = np.ones((num_elements, Nscans))
|
|
401
|
-
Xm = np.arange(1, num_elements + 1) * dx_mm
|
|
402
|
-
dFx = 1 / (num_elements * dx_mm)
|
|
403
397
|
|
|
404
|
-
#
|
|
398
|
+
# --- Calcul des positions centrées des éléments (en m) ---
|
|
399
|
+
Xc = (Width + (Nactuators - 1) * (kerf + Width)) / 2
|
|
400
|
+
Xm = np.array([Width * (i - 1) + Width / 2 - Xc for i in range(1, Nactuators + 1)])
|
|
401
|
+
|
|
402
|
+
# --- Gestion de l'onde plane (tous les piezo ON) au début ---
|
|
403
|
+
if 0 in decimations:
|
|
404
|
+
I_plane = np.arange(len(angles))
|
|
405
|
+
ActiveLIST[:, I_plane] = 1 # Tous les piezo ON pour les len(angles) premières colonnes
|
|
406
|
+
|
|
407
|
+
# --- Traitement des décimations non nulles ---
|
|
405
408
|
active_decimations = decimations[decimations != 0]
|
|
409
|
+
dFx = 1 / (Nactuators * Width) # fx de base (en m^-1)
|
|
406
410
|
|
|
407
411
|
for i_dec in range(len(active_decimations)):
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
Icos = idx_base
|
|
411
|
-
Incos = idx_base + len(angles)
|
|
412
|
-
Isin = idx_base + 2 * len(angles)
|
|
413
|
-
Insin = idx_base + 3 * len(angles)
|
|
412
|
+
# Décalage des indices pour placer les motifs modulés après l'onde plane
|
|
413
|
+
I = np.arange(len(angles)) + len(angles) + (i_dec * 4 * len(angles))
|
|
414
414
|
|
|
415
|
-
|
|
415
|
+
Icos = I
|
|
416
|
+
Incos = I + 1* len(angles)
|
|
417
|
+
Isin = I + 3 * len(angles)
|
|
418
|
+
Insin = I + 2 * len(angles)
|
|
416
419
|
|
|
417
|
-
|
|
418
|
-
valid_icos = Icos[Icos < Nscans]
|
|
419
|
-
if valid_icos.size > 0:
|
|
420
|
-
ActiveLIST[:, valid_icos] = calc_mat_os(Xm, fx, dx_mm, ActiveLIST[:, valid_icos], 'cos')
|
|
421
|
-
if (Incos < Nscans).any():
|
|
422
|
-
ActiveLIST[:, Incos[Incos < Nscans]] = 1 - ActiveLIST[:, valid_icos]
|
|
420
|
+
fx = dFx * active_decimations[i_dec]
|
|
423
421
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
422
|
+
# Appliquer les motifs modulés
|
|
423
|
+
ActiveLIST[:, Icos] = calc_mat_os(Xm, fx, ActiveLIST[:, Icos[:1]], 'cos')
|
|
424
|
+
ActiveLIST[:, Incos] = 1 - ActiveLIST[:, Icos]
|
|
425
|
+
ActiveLIST[:, Isin] = calc_mat_os(Xm, fx, ActiveLIST[:, Isin[:1]], 'sin')
|
|
426
|
+
ActiveLIST[:, Insin] = 1 - ActiveLIST[:, Isin]
|
|
429
427
|
|
|
430
428
|
# --- Conversion au format attendu ---
|
|
431
|
-
# 1. On convertit toute la matrice en liste de strings Hexa
|
|
432
429
|
hexa_list = convert_to_hex_list(ActiveLIST)
|
|
433
430
|
|
|
434
|
-
# 2. Fonction interne de formatage d'angle (pour coller à votre ancien code)
|
|
435
431
|
def format_angle(a):
|
|
436
432
|
return f"{'1' if a < 0 else '0'}{abs(a):02d}"
|
|
437
433
|
|
|
438
|
-
# 3. Construction de la liste de dictionnaires
|
|
439
434
|
patterns = []
|
|
440
435
|
print(f"Generating {Nscans} patterns from decimations and angles...")
|
|
441
436
|
for i in range(Nscans):
|
|
442
|
-
# On retrouve l'angle correspondant à l'index i
|
|
443
|
-
# La logique est cyclique sur la taille de 'angles'
|
|
444
437
|
angle_val = angles[i % len(angles)]
|
|
445
|
-
|
|
446
438
|
hex_pattern = hexa_list[i]
|
|
447
439
|
pair = f"{hex_pattern}_{format_angle(angle_val)}"
|
|
448
440
|
patterns.append({"fileName": pair})
|
|
449
441
|
|
|
450
442
|
return patterns
|
|
443
|
+
|
|
451
444
|
|
|
452
445
|
def _generate_patterns(self, N,angles = None):
|
|
453
446
|
def format_angle(a):
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
from ._mainRecon import Recon
|
|
2
2
|
from .ReconEnums import ReconType, AnalyticType, ProcessType
|
|
3
3
|
from AOT_biomaps.AOT_Experiment.Tomography import hex_to_binary_profile
|
|
4
|
-
from .ReconTools import get_phase_deterministic
|
|
4
|
+
from .ReconTools import fourierz_gpu, get_phase_deterministic, add_sincos_cpu, EvalDelayLawOS_center, ifourierx_gpu, rotate_theta_gpu, filter_radon_gpu, ifourierz_gpu
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
from tqdm import trange
|
|
8
|
-
import
|
|
9
|
-
import tqdm
|
|
8
|
+
import cupy as cp
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
class AnalyticRecon(Recon):
|
|
13
|
-
def __init__(self, analyticType,
|
|
12
|
+
def __init__(self, analyticType, Lc = None,**kwargs):
|
|
14
13
|
super().__init__(**kwargs)
|
|
15
14
|
self.reconType = ReconType.Analytic
|
|
16
15
|
self.analyticType = analyticType
|
|
16
|
+
if self.analyticType == AnalyticType.iRADON and Lc is None:
|
|
17
|
+
raise ValueError("Lc parameter must be provided for iRADON analytic reconstruction.")
|
|
18
|
+
self.Lc = Lc # in meters
|
|
17
19
|
self.AOsignal_demoldulated = None
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
21
|
def parse_and_demodulate(self, withTumor=True):
|
|
22
22
|
|
|
23
23
|
if withTumor:
|
|
@@ -46,7 +46,7 @@ class AnalyticRecon(Recon):
|
|
|
46
46
|
# Onde Plane (f_s = 0)
|
|
47
47
|
if set(hex_pattern.lower().replace(" ", "")) == {'f'}:
|
|
48
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])
|
|
49
|
+
demodulated_data[(fs_key, angle_rad)] = np.array(AOsignal[:,i])
|
|
50
50
|
continue
|
|
51
51
|
|
|
52
52
|
# Onde Structurée
|
|
@@ -77,9 +77,9 @@ class AnalyticRecon(Recon):
|
|
|
77
77
|
|
|
78
78
|
# La moyenne est nécessaire si plusieurs acquisitions ont la même phase (pour le SNR)
|
|
79
79
|
if phase in structured_buffer[key]:
|
|
80
|
-
structured_buffer[key][phase] = (structured_buffer[key][phase] + np.array(AOsignal[i])) / 2
|
|
80
|
+
structured_buffer[key][phase] = (structured_buffer[key][phase] + np.array(AOsignal[:,i])) / 2
|
|
81
81
|
else:
|
|
82
|
-
structured_buffer[key][phase] = np.array(AOsignal[i])
|
|
82
|
+
structured_buffer[key][phase] = np.array(AOsignal[:,i])
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
|
|
@@ -126,109 +126,295 @@ class AnalyticRecon(Recon):
|
|
|
126
126
|
Parameters:
|
|
127
127
|
analyticType: The type of analytic reconstruction to perform (default is iFOURIER).
|
|
128
128
|
"""
|
|
129
|
+
d_t = 1 / float(self.experiment.params.acoustic['f_saving'])
|
|
130
|
+
t_array = np.arange(0, self.experiment.AOsignal_withTumor.shape[0])*d_t
|
|
131
|
+
Z = t_array * self.experiment.params.acoustic['c0']
|
|
132
|
+
X_m = np.arange(0, self.experiment.params.acoustic['num_elements'])* self.experiment.params.general['dx']
|
|
133
|
+
dfX = 1 / (X_m[1] - X_m[0]) / len(X_m)
|
|
129
134
|
if withTumor:
|
|
130
135
|
self.AOsignal_demoldulated = self.parse_and_demodulate(withTumor=True)
|
|
131
136
|
if self.analyticType == AnalyticType.iFOURIER:
|
|
132
|
-
self.reconPhantom = self._iFourierRecon(
|
|
137
|
+
self.reconPhantom = self._iFourierRecon(
|
|
138
|
+
R = self.experiment.AOsignal_withTumor,
|
|
139
|
+
z = Z,
|
|
140
|
+
X_m=X_m,
|
|
141
|
+
theta=self.experiment.theta,
|
|
142
|
+
decimation=self.experiment.decimations,
|
|
143
|
+
c=self.experiment.params.acoustic['c0'],
|
|
144
|
+
DelayLAWS=self.experiment.DelayLaw,
|
|
145
|
+
ActiveLIST=self.experiment.ActiveList,
|
|
146
|
+
withTumor=True,
|
|
147
|
+
)
|
|
148
|
+
|
|
133
149
|
elif self.analyticType == AnalyticType.iRADON:
|
|
134
|
-
self.reconPhantom = self._iRadonRecon(
|
|
150
|
+
self.reconPhantom = self._iRadonRecon(
|
|
151
|
+
R=self.experiment.AOsignal_withTumor,
|
|
152
|
+
z=Z,
|
|
153
|
+
X_m=X_m,
|
|
154
|
+
theta=self.experiment.theta,
|
|
155
|
+
decimation=self.experiment.decimations,
|
|
156
|
+
df0x=dfX,
|
|
157
|
+
Lc =self.Lc,
|
|
158
|
+
c=self.experiment.params.acoustic['c0'],
|
|
159
|
+
DelayLAWS=self.experiment.DelayLaw,
|
|
160
|
+
ActiveLIST=self.experiment.ActiveList,
|
|
161
|
+
withTumor=True)
|
|
135
162
|
else:
|
|
136
163
|
raise ValueError(f"Unknown analytic type: {self.analyticType}")
|
|
137
164
|
else:
|
|
138
165
|
self.AOsignal_demoldulated = self.parse_and_demodulate(withTumor=False)
|
|
139
166
|
if self.analyticType == AnalyticType.iFOURIER:
|
|
140
|
-
self.reconLaser = self._iFourierRecon(
|
|
167
|
+
self.reconLaser = self._iFourierRecon(
|
|
168
|
+
R = self.experiment.AOsignal_withoutTumor,
|
|
169
|
+
z = Z,
|
|
170
|
+
X_m=X_m,
|
|
171
|
+
theta=self.experiment.theta,
|
|
172
|
+
decimation=self.experiment.decimations,
|
|
173
|
+
c=self.experiment.params.acoustic['c0'],
|
|
174
|
+
DelayLAWS=self.experiment.DelayLaw,
|
|
175
|
+
ActiveLIST=self.experiment.ActiveList,
|
|
176
|
+
withTumor=False,
|
|
177
|
+
)
|
|
141
178
|
elif self.analyticType == AnalyticType.iRADON:
|
|
142
|
-
self.reconLaser = self._iRadonRecon(
|
|
179
|
+
self.reconLaser = self._iRadonRecon(
|
|
180
|
+
R=self.experiment.AOsignal_withoutTumor,
|
|
181
|
+
z=Z,
|
|
182
|
+
X_m=X_m,
|
|
183
|
+
theta=self.experiment.theta,
|
|
184
|
+
decimation=self.experiment.decimations,
|
|
185
|
+
df0x=dfX,
|
|
186
|
+
Lc = self.Lc,
|
|
187
|
+
c=self.experiment.params.acoustic['c0'],
|
|
188
|
+
DelayLAWS=self.experiment.DelayLaw,
|
|
189
|
+
ActiveLIST=self.experiment.ActiveList,
|
|
190
|
+
withTumor=False)
|
|
143
191
|
else:
|
|
144
192
|
raise ValueError(f"Unknown analytic type: {self.analyticType}")
|
|
145
193
|
|
|
146
|
-
def _iFourierRecon(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
194
|
+
def _iFourierRecon(
|
|
195
|
+
self,
|
|
196
|
+
R,
|
|
197
|
+
z,
|
|
198
|
+
X_m,
|
|
199
|
+
theta,
|
|
200
|
+
decimation,
|
|
201
|
+
c,
|
|
202
|
+
DelayLAWS,
|
|
203
|
+
ActiveLIST,
|
|
204
|
+
withTumor,
|
|
205
|
+
):
|
|
206
|
+
# --- 1. Préparation des données ---
|
|
207
|
+
R = cp.asarray(R)
|
|
208
|
+
z = cp.asarray(z)
|
|
209
|
+
X_m = cp.asarray(X_m)
|
|
210
|
+
theta = cp.asarray(theta)
|
|
211
|
+
decimation = cp.asarray(decimation)
|
|
212
|
+
DelayLAWS = cp.asarray(DelayLAWS)
|
|
213
|
+
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
|
+
|
|
221
|
+
_, ia_cpu, ib_cpu = np.unique(
|
|
222
|
+
ScanParam_cpu, axis=0, return_index=True, return_inverse=True
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
ia = cp.asarray(ia_cpu)
|
|
226
|
+
ib = cp.asarray(ib_cpu)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# --- 2. Structuration complexe ---
|
|
230
|
+
# add_sincos_gpu doit être l'équivalent GPU de add_sincos_cpu
|
|
231
|
+
F_complex_cpu, theta_u_cpu, decim_u_cpu = add_sincos_cpu(
|
|
232
|
+
cp.asnumpy(R),
|
|
233
|
+
cp.asnumpy(decimation),
|
|
234
|
+
np.radians(cp.asnumpy(theta))
|
|
235
|
+
)
|
|
236
|
+
M0 = EvalDelayLawOS_center(
|
|
237
|
+
X_m,
|
|
238
|
+
theta_u_cpu,
|
|
239
|
+
DelayLAWS_s.T[:, ia],
|
|
240
|
+
ActiveLIST.T[:, ia],
|
|
241
|
+
c
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Transfert GPU (UNE FOIS)
|
|
245
|
+
F_complex = cp.asarray(F_complex_cpu)
|
|
246
|
+
theta_u = cp.asarray(theta_u_cpu)
|
|
247
|
+
decim_u = cp.asarray(decim_u_cpu)
|
|
248
|
+
|
|
249
|
+
Nz = z.size
|
|
250
|
+
Nx = X_m.size
|
|
251
|
+
dx = X_m[1] - X_m[0]
|
|
252
|
+
|
|
253
|
+
X_grid, Z_grid = cp.meshgrid(X_m, z)
|
|
254
|
+
idx0_x = Nx // 2
|
|
255
|
+
# Angles uniques après compression
|
|
256
|
+
angles_group, ia_u, ib_u = cp.unique(
|
|
257
|
+
theta_u, return_index=True, return_inverse=True
|
|
258
|
+
)
|
|
259
|
+
Ntheta = angles_group.size
|
|
260
|
+
|
|
261
|
+
I_final = cp.zeros((Nz, Nx), dtype=cp.complex64)
|
|
262
|
+
|
|
263
|
+
# --- 3. Boucle InverseFourierX ---
|
|
264
|
+
for i_ang in trange(Ntheta, desc=f"AOT-BioMaps -- Analytic Reconstruction Tomography: iFourier ({'with tumor' if withTumor else 'without tumor'}) ---- processing on single GPU ----", unit="angle"):
|
|
265
|
+
|
|
266
|
+
# Grille (z, fx)
|
|
267
|
+
F_fx_z = cp.zeros((Nz, Nx), dtype=cp.complex64)
|
|
268
|
+
|
|
269
|
+
# Indices correspondant à cet angle
|
|
270
|
+
indices = cp.where(ib_u == i_ang)[0]
|
|
271
|
+
|
|
272
|
+
for idx in indices:
|
|
273
|
+
n = int(decim_u[idx])
|
|
274
|
+
trace_z = F_complex[:, idx]
|
|
275
|
+
|
|
276
|
+
# Mapping positif
|
|
277
|
+
ip = idx0_x + n
|
|
278
|
+
if 0 <= ip < Nx:
|
|
279
|
+
F_fx_z[:, ip] = trace_z
|
|
280
|
+
|
|
281
|
+
# Mapping négatif (symétrie hermitienne Matlab)
|
|
282
|
+
if n != 0:
|
|
283
|
+
im = idx0_x - n
|
|
284
|
+
if 0 <= im < Nx:
|
|
285
|
+
col_conj = cp.zeros(Nz, dtype=cp.complex64)
|
|
286
|
+
col_conj[1:] = cp.conj(trace_z[:-1])
|
|
287
|
+
F_fx_z[:, im] = col_conj
|
|
288
|
+
|
|
289
|
+
# Correction DC
|
|
290
|
+
F_fx_z[:, idx0_x] *= 0.5
|
|
291
|
+
|
|
292
|
+
# --- Inverse Fourier X (GPU) ---
|
|
293
|
+
I_spatial = ifourierx_gpu(F_fx_z, dx) * Nx
|
|
294
|
+
|
|
295
|
+
# --- Rotation spatiale GPU ---
|
|
296
|
+
I_rot = rotate_theta_gpu(
|
|
297
|
+
X_grid,
|
|
298
|
+
Z_grid,
|
|
299
|
+
I_spatial,
|
|
300
|
+
-angles_group[i_ang],
|
|
301
|
+
M0[i_ang, :]
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Somme incohérente (OriginIm = sum)
|
|
305
|
+
I_final += I_rot
|
|
306
|
+
I_final /= Ntheta
|
|
307
|
+
return cp.real(I_final).get()
|
|
308
|
+
|
|
309
|
+
def _iRadonRecon(
|
|
310
|
+
self,
|
|
311
|
+
R,
|
|
312
|
+
z,
|
|
313
|
+
X_m,
|
|
314
|
+
theta,
|
|
315
|
+
decimation,
|
|
316
|
+
df0x,
|
|
317
|
+
Lc,
|
|
318
|
+
c,
|
|
319
|
+
DelayLAWS,
|
|
320
|
+
ActiveLIST,
|
|
321
|
+
withTumor,
|
|
322
|
+
):
|
|
185
323
|
"""
|
|
186
324
|
Reconstruction d'image utilisant la méthode iRadon.
|
|
187
325
|
|
|
188
326
|
:return: Image reconstruite.
|
|
189
327
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
328
|
+
|
|
329
|
+
# ======================================================
|
|
330
|
+
# 1. AddSinCos (structuration)
|
|
331
|
+
# ======================================================
|
|
332
|
+
theta = np.radians(theta)
|
|
333
|
+
F_ct_kx, theta_u, decim_u = add_sincos_cpu(R, decimation, theta)
|
|
334
|
+
ScanParam = np.stack([decimation, theta], axis=1)
|
|
335
|
+
_, ia, _ = np.unique(ScanParam, axis=0, return_index=True, return_inverse=True)
|
|
336
|
+
ActiveLIST = np.asarray(ActiveLIST).T
|
|
337
|
+
DelayLAWS = np.asarray(DelayLAWS).T
|
|
338
|
+
ActiveLIST_unique = ActiveLIST[:,ia]
|
|
339
|
+
|
|
340
|
+
# ======================================================
|
|
341
|
+
# 2. FFT z
|
|
342
|
+
# ======================================================
|
|
343
|
+
z_gpu = cp.asarray(z)
|
|
344
|
+
Fin = fourierz_gpu(z, F_ct_kx)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
dz = float(z[1] - z[0])
|
|
348
|
+
fz = cp.fft.fftshift(cp.fft.fftfreq(len(z), d=dz))
|
|
349
|
+
|
|
350
|
+
Nz, Nk = Fin.shape
|
|
351
|
+
|
|
352
|
+
# ======================================================
|
|
353
|
+
# 3. Filtrage OS exact
|
|
354
|
+
# ======================================================
|
|
355
|
+
decim_gpu = cp.asarray(decim_u)
|
|
356
|
+
I0 = decim_gpu == 0
|
|
357
|
+
F0 = Fin * I0[None, :] # I0 broadcastée sur les lignes
|
|
358
|
+
|
|
359
|
+
DEC, FZ = cp.meshgrid(decim_gpu, fz)
|
|
360
|
+
|
|
361
|
+
Hinf = cp.abs(FZ) < cp.abs(DEC) * df0x
|
|
362
|
+
Hsup = FZ >= 0
|
|
363
|
+
|
|
364
|
+
Fc = 1 / Lc
|
|
365
|
+
FILTER = filter_radon_gpu(fz, Fc)[:, None]
|
|
366
|
+
|
|
367
|
+
Finf = F0 * FILTER[:, :F0.shape[1]] * Hinf[:, :F0.shape[1]]
|
|
368
|
+
Fsup = Fin * FILTER * Hsup
|
|
369
|
+
|
|
370
|
+
# ======================================================
|
|
371
|
+
# 4. Retour espace z
|
|
372
|
+
# ======================================================
|
|
373
|
+
Finf = ifourierz_gpu(z, Finf)
|
|
374
|
+
Fsup = ifourierz_gpu(z, Fsup)
|
|
375
|
+
|
|
376
|
+
# ======================================================
|
|
377
|
+
# 5. Grille image
|
|
378
|
+
# ======================================================
|
|
379
|
+
X_gpu = cp.asarray(X_m)
|
|
380
|
+
X, Z = cp.meshgrid(X_gpu, z_gpu)
|
|
381
|
+
Xc = float(np.mean(X_m))
|
|
382
|
+
|
|
383
|
+
# ======================================================
|
|
384
|
+
# 6. Calcul du centre M0 pour chaque angle
|
|
385
|
+
# ======================================================
|
|
386
|
+
M0 = EvalDelayLawOS_center(X_m,theta, DelayLAWS[:, ia], ActiveLIST_unique, c)
|
|
387
|
+
M0_gpu = cp.asarray(M0)
|
|
388
|
+
|
|
389
|
+
# ======================================================
|
|
390
|
+
# 7. Rétroprojection
|
|
391
|
+
# ======================================================
|
|
392
|
+
Irec_list = []
|
|
393
|
+
Irec = cp.zeros_like(X, dtype=cp.complex64)
|
|
394
|
+
for i in trange(len(theta_u), desc=f"AOT-BioMaps -- Analytic Reconstruction Tomography: iRadon ({'with tumor' if withTumor else 'without tumor'}) ---- processing on single GPU ----", unit="angle"):
|
|
395
|
+
th = float(theta_u[i])
|
|
396
|
+
|
|
397
|
+
# calcul de T, S, h0...
|
|
398
|
+
T = (X - M0_gpu[i,0]) * cp.sin(th) + (Z - M0_gpu[i,1]) * cp.cos(th) + M0_gpu[i,1]
|
|
399
|
+
S = (X - Xc) * cp.cos(th) - (Z - M0_gpu[i,1]) * cp.sin(th)
|
|
400
|
+
h0 = cp.exp(1j * 2*cp.pi * decim_u[i] * df0x * S)
|
|
401
|
+
|
|
402
|
+
# interpolation GPU
|
|
403
|
+
Tind = (T - z_gpu[0]) / (z_gpu[1] - z_gpu[0])
|
|
404
|
+
i0 = cp.floor(Tind).astype(cp.int32)
|
|
405
|
+
i1 = i0 + 1
|
|
406
|
+
i0 = cp.clip(i0, 0, Nz-1)
|
|
407
|
+
i1 = cp.clip(i1, 0, Nz-1)
|
|
408
|
+
w = Tind - i0
|
|
409
|
+
|
|
410
|
+
proj_sup = (1-w)*Fsup[i0, i] + w*Fsup[i1, i]
|
|
411
|
+
proj_inf = (1-w)*Finf[i0, i] + w*Finf[i1, i]
|
|
412
|
+
|
|
413
|
+
Irec += 2*h0*proj_sup + proj_inf
|
|
414
|
+
Irec /= i+1
|
|
415
|
+
# Ajouter à la liste
|
|
416
|
+
Irec_list.append(cp.real(Irec).get())
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
return Irec_list
|
|
420
|
+
|
|
@@ -7,6 +7,8 @@ from numba import njit, prange
|
|
|
7
7
|
from torch_sparse import coalesce
|
|
8
8
|
from scipy.signal.windows import hann
|
|
9
9
|
from itertools import groupby
|
|
10
|
+
import cupy as cp
|
|
11
|
+
from cupyx.scipy.ndimage import map_coordinates
|
|
10
12
|
|
|
11
13
|
def load_recon(hdr_path):
|
|
12
14
|
"""
|
|
@@ -528,4 +530,163 @@ def get_phase_deterministic(profile):
|
|
|
528
530
|
elif idx == 4 :
|
|
529
531
|
phase = 3*np.pi/2
|
|
530
532
|
|
|
531
|
-
return phase
|
|
533
|
+
return phase
|
|
534
|
+
|
|
535
|
+
def add_sincos_cpu(R, decimation, theta):
|
|
536
|
+
decimation = np.asarray(decimation)
|
|
537
|
+
theta = np.asarray(theta)
|
|
538
|
+
|
|
539
|
+
ScanParam = np.stack([decimation, theta], axis=1)
|
|
540
|
+
uniq, ia, ib = np.unique(ScanParam, axis=0, return_index=True, return_inverse=True)
|
|
541
|
+
|
|
542
|
+
theta_u = uniq[:,1]
|
|
543
|
+
decim_u = uniq[:,0]
|
|
544
|
+
|
|
545
|
+
theta0 = np.unique(theta_u)
|
|
546
|
+
N0 = len(theta0)
|
|
547
|
+
|
|
548
|
+
Rg = np.asarray(R)
|
|
549
|
+
Nz = Rg.shape[0]
|
|
550
|
+
Nk = N0 + (Rg.shape[1] - N0)//4
|
|
551
|
+
|
|
552
|
+
Iout = np.zeros((Nz, Nk), dtype=np.complex64)
|
|
553
|
+
# fx = 0 (onde plane)
|
|
554
|
+
Iout[:, :N0] = Rg[:, :N0]
|
|
555
|
+
|
|
556
|
+
k = N0
|
|
557
|
+
for i in range(N0, len(ia)):
|
|
558
|
+
idx = np.where(ib == i)[0]
|
|
559
|
+
h1, h2, h3, h4 = Rg[:, idx].T
|
|
560
|
+
Iout[:, k] = ((h1 - h2) - 1j*(h3 - h4)) / 2
|
|
561
|
+
k += 1
|
|
562
|
+
|
|
563
|
+
return Iout, theta_u, decim_u
|
|
564
|
+
|
|
565
|
+
def fourierz_gpu(z, X):
|
|
566
|
+
dz = float(z[1] - z[0])
|
|
567
|
+
Nz = X.shape[0]
|
|
568
|
+
|
|
569
|
+
return cp.fft.fftshift(
|
|
570
|
+
cp.fft.fft(
|
|
571
|
+
cp.fft.ifftshift(X, axes=0),
|
|
572
|
+
axis=0
|
|
573
|
+
),
|
|
574
|
+
axes=0
|
|
575
|
+
) * (Nz * dz)
|
|
576
|
+
|
|
577
|
+
def ifourierz_gpu(z, X):
|
|
578
|
+
dz = float(z[1] - z[0])
|
|
579
|
+
Nz = X.shape[0]
|
|
580
|
+
|
|
581
|
+
return cp.fft.ifftshift(
|
|
582
|
+
cp.fft.ifft(
|
|
583
|
+
cp.fft.fftshift(X, axes=0),
|
|
584
|
+
axis=0
|
|
585
|
+
),
|
|
586
|
+
axes=0
|
|
587
|
+
) * (1 / dz)
|
|
588
|
+
|
|
589
|
+
def ifourierx_gpu(F_fx_z, dx):
|
|
590
|
+
"""
|
|
591
|
+
Inverse Fourier along X (axis=1), Matlab-compatible
|
|
592
|
+
F_fx_z : (Nz, Nx) complex cupy array
|
|
593
|
+
dx : scalar (spacing in x)
|
|
594
|
+
"""
|
|
595
|
+
|
|
596
|
+
return (
|
|
597
|
+
cp.fft.ifftshift(
|
|
598
|
+
cp.fft.ifft(
|
|
599
|
+
cp.fft.fftshift(F_fx_z, axes=1),
|
|
600
|
+
axis=1
|
|
601
|
+
),
|
|
602
|
+
axes=1
|
|
603
|
+
) * (1.0 / dx)
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
def EvalDelayLawOS_center(X_m, theta, DelayLAWS, ActiveLIST, c):
|
|
607
|
+
"""
|
|
608
|
+
Retourne le centre de rotation C pour chaque angle
|
|
609
|
+
X_m : positions des éléments de la sonde
|
|
610
|
+
DelayLAWS : delays en secondes (chaque colonne = angle, chaque ligne = élément)
|
|
611
|
+
ActiveLIST : masque des éléments actifs (1 = actif)
|
|
612
|
+
c : vitesse du son
|
|
613
|
+
"""
|
|
614
|
+
Nangle = DelayLAWS.shape[1]
|
|
615
|
+
C = np.zeros((Nangle, 2))
|
|
616
|
+
|
|
617
|
+
ct = DelayLAWS * c # convert seconds to distance
|
|
618
|
+
|
|
619
|
+
for i in range(Nangle):
|
|
620
|
+
active_idx = np.where(ActiveLIST[:, i] == 1)[0]
|
|
621
|
+
if len(active_idx) == 0:
|
|
622
|
+
continue
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
angle_i = np.round(theta[i], 5)
|
|
626
|
+
# unit vector orthogonal to wavefront
|
|
627
|
+
u = np.array([np.sin(angle_i), np.cos(angle_i)])
|
|
628
|
+
|
|
629
|
+
# initial positions X0, Z0
|
|
630
|
+
X0 = X_m - u[0] * ct[:, i]
|
|
631
|
+
Z0 = 0 - u[1] * ct[:, i]
|
|
632
|
+
|
|
633
|
+
if Z0[-1] - Z0[0] != 0:
|
|
634
|
+
C[i, 0] = (Z0[-1]*X0[0] - Z0[0]*X0[-1]) / (Z0[-1] - Z0[0])
|
|
635
|
+
C[i, 1] = 0
|
|
636
|
+
|
|
637
|
+
return C
|
|
638
|
+
|
|
639
|
+
def rotate_theta_gpu(X, Z, Iin, theta, C):
|
|
640
|
+
"""
|
|
641
|
+
GPU equivalent of RotateTheta.m
|
|
642
|
+
X, Z, Iin : cupy arrays (Nz, Nx)
|
|
643
|
+
theta : scalar (float)
|
|
644
|
+
C : (2,) array-like
|
|
645
|
+
"""
|
|
646
|
+
|
|
647
|
+
# --- Translation ---
|
|
648
|
+
X_rel = X - C[0]
|
|
649
|
+
Z_rel = Z - C[1]
|
|
650
|
+
|
|
651
|
+
c = cp.cos(theta)
|
|
652
|
+
s = cp.sin(theta)
|
|
653
|
+
|
|
654
|
+
# --- Rotation (Matlab convention) ---
|
|
655
|
+
Xout = c * X_rel + s * Z_rel
|
|
656
|
+
Zout = -s * X_rel + c * Z_rel
|
|
657
|
+
|
|
658
|
+
# Back to original frame
|
|
659
|
+
Xout += C[0]
|
|
660
|
+
Zout += C[1]
|
|
661
|
+
|
|
662
|
+
# --- Conversion coordonnées -> indices ---
|
|
663
|
+
# Grille régulière supposée
|
|
664
|
+
dx = X[0, 1] - X[0, 0]
|
|
665
|
+
dz = Z[1, 0] - Z[0, 0]
|
|
666
|
+
|
|
667
|
+
x0 = X[0, 0]
|
|
668
|
+
z0 = Z[0, 0]
|
|
669
|
+
|
|
670
|
+
ix = (Xout - x0) / dx
|
|
671
|
+
iz = (Zout - z0) / dz
|
|
672
|
+
|
|
673
|
+
# --- Interpolation bilinéaire GPU ---
|
|
674
|
+
# map_coordinates attend (ndim, Npoints)
|
|
675
|
+
coords = cp.stack([iz.ravel(), ix.ravel()])
|
|
676
|
+
|
|
677
|
+
Iout = map_coordinates(
|
|
678
|
+
Iin,
|
|
679
|
+
coords,
|
|
680
|
+
order=1, # bilinear
|
|
681
|
+
mode='constant',
|
|
682
|
+
cval=0.0
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
return Iout.reshape(Iin.shape)
|
|
686
|
+
|
|
687
|
+
def filter_radon_gpu(fz, Fc):
|
|
688
|
+
FILTER = cp.abs(fz)
|
|
689
|
+
FILTER = cp.where(cp.abs(fz) > Fc, 0, FILTER)
|
|
690
|
+
FILTER *= cp.exp(-2 * cp.abs(fz / Fc)**10)
|
|
691
|
+
return FILTER
|
|
692
|
+
|
|
@@ -169,7 +169,9 @@ class Recon(ABC):
|
|
|
169
169
|
|
|
170
170
|
def show(self, withTumor=True, savePath=None):
|
|
171
171
|
if withTumor:
|
|
172
|
-
if self.reconPhantom is None
|
|
172
|
+
if self.reconPhantom is None:
|
|
173
|
+
raise ValueError("Reconstructed phantom with tumor is empty. Run reconstruction first.")
|
|
174
|
+
if isinstance(self.reconPhantom, (list, tuple)) and len(self.reconPhantom) == 0:
|
|
173
175
|
raise ValueError("Reconstructed phantom with tumor is empty. Run reconstruction first.")
|
|
174
176
|
if isinstance(self.reconPhantom, list):
|
|
175
177
|
image = self.reconPhantom[-1]
|
|
@@ -217,7 +219,9 @@ class Recon(ABC):
|
|
|
217
219
|
axs[0].tick_params(axis='both', which='major', labelsize=8)
|
|
218
220
|
axs[0].tick_params(axis='y', which='both', left=False, right=False, labelleft=False)
|
|
219
221
|
else:
|
|
220
|
-
if self.reconLaser is None
|
|
222
|
+
if self.reconLaser is None:
|
|
223
|
+
raise ValueError("Reconstructed laser without tumor is empty. Run reconstruction first.")
|
|
224
|
+
if isinstance(self.reconLaser, (list, tuple)) and len(self.reconLaser) == 0:
|
|
221
225
|
raise ValueError("Reconstructed laser without tumor is empty. Run reconstruction first.")
|
|
222
226
|
if isinstance(self.reconLaser, list):
|
|
223
227
|
image = self.reconLaser[-1]
|
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.356'
|
|
89
89
|
__process__ = config.get_process()
|
|
90
90
|
|
|
91
91
|
def initialize(process=None):
|
|
@@ -185,6 +185,23 @@ def initialize(process=None):
|
|
|
185
185
|
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
188
205
|
|
|
189
206
|
|
|
190
207
|
|
|
@@ -1,6 +1,6 @@
|
|
|
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=prD0ZZNE6dc-NWf_N0QIPLTrsRD3fAtK78ptZscj3Yo,4374
|
|
4
4
|
AOT_biomaps/AOT_Acoustic/AcousticEnums.py,sha256=s5kXa6jKzbS4btwbubrVcynLOr0yg5tth5vL_FGfbMk,1802
|
|
5
5
|
AOT_biomaps/AOT_Acoustic/AcousticTools.py,sha256=h2sCtGVcDtyLtEF1q7sLZmuWivWmesVGUBPnW-ndQqc,7535
|
|
6
6
|
AOT_biomaps/AOT_Acoustic/FocusedWave.py,sha256=3kGKKDx_3Msy5COYqIwzROPORGWvNjw8UsDanBfkMXE,11037
|
|
@@ -9,9 +9,9 @@ AOT_biomaps/AOT_Acoustic/PlaneWave.py,sha256=xza-rj5AUWDecLkGDxRcULrwZVWeBvGnEP2
|
|
|
9
9
|
AOT_biomaps/AOT_Acoustic/StructuredWave.py,sha256=jTLVlOhYLWJb5MxZPxhq3OFVlz2McoyMPBmfLvnekDU,18209
|
|
10
10
|
AOT_biomaps/AOT_Acoustic/__init__.py,sha256=t9M2rRqa_L9pk7W2FeELTkHEMuP4DBr4gBRldMqsQbg,491
|
|
11
11
|
AOT_biomaps/AOT_Acoustic/_mainAcoustic.py,sha256=RdmhRF1i0KAlpsP7_wnZ7F4J27br3eUc4XR91Qq7C64,44158
|
|
12
|
-
AOT_biomaps/AOT_Experiment/ExperimentTools.py,sha256=
|
|
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=GGbXVUnRhvSRLL1QEg5ZgAhtWIg9RfH7aADJ5u-78HQ,36383
|
|
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=uZp4Va9z04dG7neZFGAmmAUygs8JyfrDuOr1_lKIERc,16651
|
|
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
|
-
AOT_biomaps/AOT_Recon/ReconTools.py,sha256
|
|
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=MvDnfsiJ7v-UmtCFmA1vmKGzV9zd2xdnt27CAWBubko,13470
|
|
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.356.dist-info/METADATA,sha256=eiJaF8-8bnGyUaK14BMcAiv645TibZb5uk8thsji2bE,700
|
|
46
|
+
aot_biomaps-2.9.356.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
aot_biomaps-2.9.356.dist-info/top_level.txt,sha256=6STF-lT4kaAnBHJYCripmN5mZABoHjMuY689JdiDphk,12
|
|
48
|
+
aot_biomaps-2.9.356.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|