AOT-biomaps 2.9.318__py3-none-any.whl → 2.9.321__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 +0 -2
- AOT_biomaps/AOT_Experiment/ExperimentTools.py +60 -0
- AOT_biomaps/AOT_Experiment/Tomography.py +85 -5
- AOT_biomaps/AOT_Recon/ReconTools.py +0 -3
- AOT_biomaps/__init__.py +4 -1
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.321.dist-info}/METADATA +1 -1
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.321.dist-info}/RECORD +9 -8
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.321.dist-info}/WHEEL +0 -0
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.321.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
def calc_mat_os(xm, fx, dx, bool_active_list, signal_type):
|
|
4
|
+
num_els = len(xm)
|
|
5
|
+
|
|
6
|
+
# Cas limite : Fréquence nulle (Décimation 0)
|
|
7
|
+
if fx == 0:
|
|
8
|
+
if signal_type == 'cos':
|
|
9
|
+
# cos(0) = 1 -> Tout est actif
|
|
10
|
+
mask = np.ones(num_els, dtype=bool)
|
|
11
|
+
else:
|
|
12
|
+
# sin(0) = 0 -> Tout est inactif
|
|
13
|
+
mask = np.zeros(num_els, dtype=bool)
|
|
14
|
+
else:
|
|
15
|
+
# Calcul normal pour fx > 0
|
|
16
|
+
half_period_elements = round(1 / (2 * fx * dx))
|
|
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]))
|
|
30
|
+
|
|
31
|
+
def convert_to_hex_list(matrix):
|
|
32
|
+
"""
|
|
33
|
+
Convertit une matrice binaire en liste de strings hexa (paquets de 4 bits).
|
|
34
|
+
Chaque colonne devient une chaîne de caractères.
|
|
35
|
+
"""
|
|
36
|
+
n_els, n_scans = matrix.shape
|
|
37
|
+
|
|
38
|
+
# 1. Padding pour s'assurer que n_els est multiple de 4
|
|
39
|
+
remainder = n_els % 4
|
|
40
|
+
if remainder != 0:
|
|
41
|
+
padding = np.zeros((4 - remainder, n_scans))
|
|
42
|
+
matrix = np.vstack([matrix, padding])
|
|
43
|
+
|
|
44
|
+
# 2. Reshape pour isoler des blocs de 4 bits (nibbles)
|
|
45
|
+
# Shape résultante : (Nombre de blocs, 4 bits, Nombre de scans)
|
|
46
|
+
blocks = matrix.reshape(-1, 4, n_scans)
|
|
47
|
+
|
|
48
|
+
# 3. Calcul de la valeur décimale de chaque bloc (0 à 15)
|
|
49
|
+
# On considère le premier élément comme le bit de poids faible (LSB)
|
|
50
|
+
weights = np.array([1, 2, 4, 8]).reshape(1, 4, 1)
|
|
51
|
+
dec_values = np.sum(blocks * weights, axis=1).astype(int)
|
|
52
|
+
|
|
53
|
+
# 4. Conversion en caractères Hexadécimaux
|
|
54
|
+
# On définit la table de conversion pour la rapidité
|
|
55
|
+
hex_table = np.array(list("0123456789abcdef"))
|
|
56
|
+
hex_matrix = hex_table[dec_values]
|
|
57
|
+
|
|
58
|
+
# 5. Assemblage des chaînes (de l'élément N vers 0 pour l'ordre Shift Register standard)
|
|
59
|
+
return ["".join(hex_matrix[::-1, col]) for col in range(n_scans)]
|
|
60
|
+
|
|
@@ -2,6 +2,7 @@ from ._mainExperiment import Experiment
|
|
|
2
2
|
from AOT_biomaps.AOT_Acoustic.AcousticEnums import WaveType
|
|
3
3
|
from AOT_biomaps.AOT_Acoustic.StructuredWave import StructuredWave
|
|
4
4
|
from AOT_biomaps.Config import config
|
|
5
|
+
from AOT_biomaps.AOT_Experiment.ExperimentTools import calc_mat_os, convert_to_hex_list
|
|
5
6
|
import os
|
|
6
7
|
import psutil
|
|
7
8
|
import numpy as np
|
|
@@ -273,7 +274,7 @@ class Tomography(Experiment):
|
|
|
273
274
|
line = f"({coords}, {angles})\n"
|
|
274
275
|
file.write(line)
|
|
275
276
|
|
|
276
|
-
def generateActiveList(self, N):
|
|
277
|
+
def generateActiveList(self, N, decimations = None, angles = None):
|
|
277
278
|
"""
|
|
278
279
|
Génère une liste de patterns d'activation équilibrés et réguliers.
|
|
279
280
|
Args:
|
|
@@ -281,11 +282,15 @@ class Tomography(Experiment):
|
|
|
281
282
|
Returns:
|
|
282
283
|
list: Liste de strings au format "hex_angle".
|
|
283
284
|
"""
|
|
285
|
+
if decimations is not None and angles is not None:
|
|
286
|
+
self._genereate_patterns_from_decimations(decimations, angles)
|
|
284
287
|
if N < 1:
|
|
285
288
|
raise ValueError("N must be a positive integer.")
|
|
286
289
|
self.patterns = self._generate_patterns(N)
|
|
287
290
|
if not self._check_patterns(self.patterns):
|
|
288
291
|
raise ValueError("Generated patterns failed validation.")
|
|
292
|
+
|
|
293
|
+
|
|
289
294
|
|
|
290
295
|
def selectAngles(self, angles):
|
|
291
296
|
|
|
@@ -337,7 +342,76 @@ class Tomography(Experiment):
|
|
|
337
342
|
self.AOsignal_withoutTumor = self.AOsignal_withoutTumor[:, indices]
|
|
338
343
|
self.AcousticFields = newAcousticFields
|
|
339
344
|
|
|
340
|
-
def
|
|
345
|
+
def _genereate_patterns_from_decimations(self, decimations, angles):
|
|
346
|
+
if isinstance(decimations, list): decimations = np.array(decimations)
|
|
347
|
+
if isinstance(angles, list): angles = np.array(angles)
|
|
348
|
+
|
|
349
|
+
angles = np.sort(angles)
|
|
350
|
+
decimations = np.sort(decimations)
|
|
351
|
+
|
|
352
|
+
num_elements = self.params.acoustic['num_elements']
|
|
353
|
+
dx_mm = self.params.general['dx'] * 1e3
|
|
354
|
+
|
|
355
|
+
# --- Calcul du nombre de Scans ---
|
|
356
|
+
if 0 in decimations:
|
|
357
|
+
Nscans = 4 * angles.shape[0] * (decimations.shape[0] - 1) + angles.shape[0]
|
|
358
|
+
offSet = angles.shape[0]
|
|
359
|
+
else:
|
|
360
|
+
Nscans = 4 * angles.shape[0] * decimations.shape[0]
|
|
361
|
+
offSet = 0
|
|
362
|
+
|
|
363
|
+
ActiveLIST = np.ones((num_elements, Nscans))
|
|
364
|
+
Xm = np.arange(1, num_elements + 1) * dx_mm
|
|
365
|
+
dFx = 1 / (num_elements * dx_mm)
|
|
366
|
+
|
|
367
|
+
# On traite séparément les décimations non nulles pour la boucle
|
|
368
|
+
active_decimations = decimations[decimations != 0]
|
|
369
|
+
|
|
370
|
+
for i_dec in range(len(active_decimations)):
|
|
371
|
+
idx_base = (np.arange(len(angles))) + (i_dec * 4 * len(angles)) + offSet
|
|
372
|
+
|
|
373
|
+
Icos = idx_base
|
|
374
|
+
Incos = idx_base + len(angles)
|
|
375
|
+
Isin = idx_base + 2 * len(angles)
|
|
376
|
+
Insin = idx_base + 3 * len(angles)
|
|
377
|
+
|
|
378
|
+
fx = dFx * active_decimations[i_dec]
|
|
379
|
+
|
|
380
|
+
# Remplissage des 4 phases
|
|
381
|
+
valid_icos = Icos[Icos < Nscans]
|
|
382
|
+
if valid_icos.size > 0:
|
|
383
|
+
ActiveLIST[:, valid_icos] = calc_mat_os(Xm, fx, dx_mm, ActiveLIST[:, valid_icos], 'cos')
|
|
384
|
+
if (Incos < Nscans).any():
|
|
385
|
+
ActiveLIST[:, Incos[Incos < Nscans]] = 1 - ActiveLIST[:, valid_icos]
|
|
386
|
+
|
|
387
|
+
valid_isin = Isin[Isin < Nscans]
|
|
388
|
+
if valid_isin.size > 0:
|
|
389
|
+
ActiveLIST[:, valid_isin] = calc_mat_os(Xm, fx, dx_mm, ActiveLIST[:, valid_isin], 'sin')
|
|
390
|
+
if (Insin < Nscans).any():
|
|
391
|
+
ActiveLIST[:, Insin[Insin < Nscans]] = 1 - ActiveLIST[:, valid_isin]
|
|
392
|
+
|
|
393
|
+
# --- Conversion au format attendu ---
|
|
394
|
+
# 1. On convertit toute la matrice en liste de strings Hexa
|
|
395
|
+
hexa_list = convert_to_hex_list(ActiveLIST)
|
|
396
|
+
|
|
397
|
+
# 2. Fonction interne de formatage d'angle (pour coller à votre ancien code)
|
|
398
|
+
def format_angle(a):
|
|
399
|
+
return f"{'1' if a < 0 else '0'}{abs(a):02d}"
|
|
400
|
+
|
|
401
|
+
# 3. Construction de la liste de dictionnaires
|
|
402
|
+
patterns = []
|
|
403
|
+
for i in range(Nscans):
|
|
404
|
+
# On retrouve l'angle correspondant à l'index i
|
|
405
|
+
# La logique est cyclique sur la taille de 'angles'
|
|
406
|
+
angle_val = angles[i % len(angles)]
|
|
407
|
+
|
|
408
|
+
hex_pattern = hexa_list[i]
|
|
409
|
+
pair = f"{hex_pattern}_{format_angle(angle_val)}"
|
|
410
|
+
patterns.append({"fileName": pair})
|
|
411
|
+
|
|
412
|
+
return patterns
|
|
413
|
+
|
|
414
|
+
def _generate_patterns(self, N,angles = None):
|
|
341
415
|
def format_angle(a):
|
|
342
416
|
return f"{'1' if a < 0 else '0'}{abs(a):02d}"
|
|
343
417
|
|
|
@@ -348,7 +422,13 @@ class Tomography(Experiment):
|
|
|
348
422
|
return hex_string
|
|
349
423
|
|
|
350
424
|
num_elements = self.params.acoustic['num_elements']
|
|
351
|
-
|
|
425
|
+
if angles is None:
|
|
426
|
+
angle_choices = list(range(-20, 21))
|
|
427
|
+
else:
|
|
428
|
+
# convert np.array to list if necessary
|
|
429
|
+
if isinstance(angles, np.ndarray):
|
|
430
|
+
angles = angles.tolist()
|
|
431
|
+
angle_choices = angles
|
|
352
432
|
|
|
353
433
|
# 1. Trouver TOUS les diviseurs PAIRS de num_elements (y compris num_elements)
|
|
354
434
|
divs = [d for d in range(2, num_elements + 1) if num_elements % d == 0 and d % 2 == 0]
|
|
@@ -451,7 +531,7 @@ class Tomography(Experiment):
|
|
|
451
531
|
divergence_deg (float): Angle d'ouverture du masque pour suivre l'élargissement du faisceau.
|
|
452
532
|
0.0 = Droit, 0.5 = Légère ouverture (conseillé).
|
|
453
533
|
"""
|
|
454
|
-
print(f"
|
|
534
|
+
print(f"Applying apodization (Alpha={alpha}, Div={divergence_deg}°) on {len(self.AcousticFields)} fields...")
|
|
455
535
|
|
|
456
536
|
probe_width = self.params.acoustic['num_elements'] * self.params.acoustic['element_width']
|
|
457
537
|
|
|
@@ -512,7 +592,7 @@ class Tomography(Experiment):
|
|
|
512
592
|
# 8. Mise à jour de l'objet
|
|
513
593
|
self.AcousticFields[i].field = field_apodized
|
|
514
594
|
|
|
515
|
-
print("Apodisation
|
|
595
|
+
print("Apodisation done.")
|
|
516
596
|
|
|
517
597
|
# PRIVATE METHODS
|
|
518
598
|
def _generateAcousticFields_STRUCT_CPU(self, fieldDataPath=None, show_log=False, nameBlock=None):
|
|
@@ -221,7 +221,6 @@ def calculate_memory_requirement(SMatrix, y):
|
|
|
221
221
|
# --- 3. Final Result ---
|
|
222
222
|
return total_bytes / (1024 ** 3)
|
|
223
223
|
|
|
224
|
-
|
|
225
224
|
def check_gpu_memory(device_index, required_memory, show_logs=True):
|
|
226
225
|
"""Check if enough memory is available on the specified GPU."""
|
|
227
226
|
free_memory, _ = torch.cuda.mem_get_info(f"cuda:{device_index}")
|
|
@@ -252,7 +251,6 @@ def _backward_projection(SMatrix, e_p, c_p):
|
|
|
252
251
|
total += SMatrix[_t, _z, _x, _n] * e_p[_t, _n]
|
|
253
252
|
c_p[_z, _x] = total
|
|
254
253
|
|
|
255
|
-
|
|
256
254
|
def _build_adjacency_sparse(Z, X, device, corner=(0.5 - np.sqrt(2) / 4) / np.sqrt(2), face=0.5 - np.sqrt(2) / 4,dtype=torch.float32):
|
|
257
255
|
rows, cols, weights = [], [], []
|
|
258
256
|
for z in range(Z):
|
|
@@ -273,7 +271,6 @@ def _build_adjacency_sparse(Z, X, device, corner=(0.5 - np.sqrt(2) / 4) / np.sqr
|
|
|
273
271
|
index, values = coalesce(index, values, m=Z*X, n=Z*X)
|
|
274
272
|
return index, values
|
|
275
273
|
|
|
276
|
-
|
|
277
274
|
def power_method(P, PT, data, Z, X, n_it=10):
|
|
278
275
|
x = torch.randn(Z * X, device=data.device)
|
|
279
276
|
x = x / torch.norm(x)
|
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.321'
|
|
89
89
|
__process__ = config.get_process()
|
|
90
90
|
|
|
91
91
|
def initialize(process=None):
|
|
@@ -178,6 +178,9 @@ def initialize(process=None):
|
|
|
178
178
|
|
|
179
179
|
|
|
180
180
|
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
181
184
|
|
|
182
185
|
|
|
183
186
|
|
|
@@ -1,16 +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=6TSP5wI6TYb3icQQXws5eVgqxv0-F2F9HDYXj9uot6A,4304
|
|
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=h2sCtGVcDtyLtEF1q7sLZmuWivWmesVGUBPnW-ndQqc,7535
|
|
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
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=BkHSX_foyyj5UrHZWQH5F9DGeV8o2fkp3euEbcvE4vA,2399
|
|
12
13
|
AOT_biomaps/AOT_Experiment/Focus.py,sha256=B2nBawmv-NG2AWJx9zgQ8GlN6aFB9FwTSqX-M-phKXg,3193
|
|
13
|
-
AOT_biomaps/AOT_Experiment/Tomography.py,sha256=
|
|
14
|
+
AOT_biomaps/AOT_Experiment/Tomography.py,sha256=qH7QlAPp5Er1AhMbWDpbOT6VRJHgrYUdUxazuEMAc_A,34569
|
|
14
15
|
AOT_biomaps/AOT_Experiment/__init__.py,sha256=H9zMLeBLA6uhbaHohAa-2u5mDDxqJi8oE5c6tShdQp8,308
|
|
15
16
|
AOT_biomaps/AOT_Experiment/_mainExperiment.py,sha256=zSfuNrsz7nhiKrGIdK6CAXjlI2T6qYC5-JXHFgPNzhc,24674
|
|
16
17
|
AOT_biomaps/AOT_Optic/Absorber.py,sha256=jEodzRy7gkEH-wbazVasRQiri0dU16BfapmR-qnTSvM,867
|
|
@@ -25,7 +26,7 @@ AOT_biomaps/AOT_Recon/BayesianRecon.py,sha256=RnnPa-tTcvirwiNPnCRZnSM4NWeEEltYET
|
|
|
25
26
|
AOT_biomaps/AOT_Recon/DeepLearningRecon.py,sha256=RfVcEsi4GeGqJn0_SPxwQPQx6IQjin79WKh2UarMRLI,1383
|
|
26
27
|
AOT_biomaps/AOT_Recon/PrimalDualRecon.py,sha256=JbFhxiyUoSTnlJgHbOWIfUUwhwfZoi39RJMnfkagegY,16504
|
|
27
28
|
AOT_biomaps/AOT_Recon/ReconEnums.py,sha256=KAf55RqHAr2ilt6pxFrUBGQOn-7HA8NP6TyL-1FNiXo,19714
|
|
28
|
-
AOT_biomaps/AOT_Recon/ReconTools.py,sha256=
|
|
29
|
+
AOT_biomaps/AOT_Recon/ReconTools.py,sha256=py1zKVEa0j7EfmcNZS2lpVQwzlkY6rRWsDQ8izWlme4,19872
|
|
29
30
|
AOT_biomaps/AOT_Recon/__init__.py,sha256=xs_argJqXKFl76xP7-jiUc1ynOEEtY7XZ0gDxD5uVZc,246
|
|
30
31
|
AOT_biomaps/AOT_Recon/_mainRecon.py,sha256=exoa2UBMfMHjemxAU9dW0mhEfsP6Oe1qjSfrTrgbIcY,13125
|
|
31
32
|
AOT_biomaps/AOT_Recon/AOT_Optimizers/DEPIERRO.py,sha256=qA1n722GLQJH3V8HcLr5q_GxEwBS_NRlIT3E6JZk-Ag,9479
|
|
@@ -41,7 +42,7 @@ AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/__init__.py,sha256=RwrJdLOFbAFBFnRx
|
|
|
41
42
|
AOT_biomaps/AOT_Recon/AOT_SparseSMatrix/SparseSMatrix_CSR.py,sha256=RACc2P5oxmp0uPLAGnNj9mEtAxa_OlepNgCawKij3jI,12062
|
|
42
43
|
AOT_biomaps/AOT_Recon/AOT_SparseSMatrix/SparseSMatrix_SELL.py,sha256=ti3dZQsb_Uu62C7Bn65Z-yf-R5NKCFsmnBT5GlLd_HY,15138
|
|
43
44
|
AOT_biomaps/AOT_Recon/AOT_SparseSMatrix/__init__.py,sha256=8nou-hqjQjuCTLhoL5qv4EM_lMPFviAZAZKSPhi84jE,67
|
|
44
|
-
aot_biomaps-2.9.
|
|
45
|
-
aot_biomaps-2.9.
|
|
46
|
-
aot_biomaps-2.9.
|
|
47
|
-
aot_biomaps-2.9.
|
|
45
|
+
aot_biomaps-2.9.321.dist-info/METADATA,sha256=DMnk4rlTFW95pX0welgBZD3GdTkjeFbn3vwXNyUxSHs,700
|
|
46
|
+
aot_biomaps-2.9.321.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
aot_biomaps-2.9.321.dist-info/top_level.txt,sha256=6STF-lT4kaAnBHJYCripmN5mZABoHjMuY689JdiDphk,12
|
|
48
|
+
aot_biomaps-2.9.321.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|