AOT-biomaps 2.9.318__py3-none-any.whl → 2.9.323__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 +89 -8
- AOT_biomaps/AOT_Recon/ReconTools.py +0 -3
- AOT_biomaps/__init__.py +6 -1
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.323.dist-info}/METADATA +1 -1
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.323.dist-info}/RECORD +9 -8
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.323.dist-info}/WHEEL +0 -0
- {aot_biomaps-2.9.318.dist-info → aot_biomaps-2.9.323.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 = None, 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,16 @@ class Tomography(Experiment):
|
|
|
281
282
|
Returns:
|
|
282
283
|
list: Liste de strings au format "hex_angle".
|
|
283
284
|
"""
|
|
284
|
-
if
|
|
285
|
-
|
|
286
|
-
|
|
285
|
+
if decimations is not None and angles is not None:
|
|
286
|
+
self._genereate_patterns_from_decimations(decimations, angles)
|
|
287
|
+
elif N is not None and N > 1:
|
|
288
|
+
self.patterns = self._generate_patterns(N)
|
|
289
|
+
else:
|
|
290
|
+
raise ValueError("Either N (>=2) or both decimations and angles must be provided for pattern generation.")
|
|
287
291
|
if not self._check_patterns(self.patterns):
|
|
288
292
|
raise ValueError("Generated patterns failed validation.")
|
|
293
|
+
|
|
294
|
+
|
|
289
295
|
|
|
290
296
|
def selectAngles(self, angles):
|
|
291
297
|
|
|
@@ -337,7 +343,76 @@ class Tomography(Experiment):
|
|
|
337
343
|
self.AOsignal_withoutTumor = self.AOsignal_withoutTumor[:, indices]
|
|
338
344
|
self.AcousticFields = newAcousticFields
|
|
339
345
|
|
|
340
|
-
def
|
|
346
|
+
def _genereate_patterns_from_decimations(self, decimations, angles):
|
|
347
|
+
if isinstance(decimations, list): decimations = np.array(decimations)
|
|
348
|
+
if isinstance(angles, list): angles = np.array(angles)
|
|
349
|
+
|
|
350
|
+
angles = np.sort(angles)
|
|
351
|
+
decimations = np.sort(decimations)
|
|
352
|
+
|
|
353
|
+
num_elements = self.params.acoustic['num_elements']
|
|
354
|
+
dx_mm = self.params.general['dx'] * 1e3
|
|
355
|
+
|
|
356
|
+
# --- Calcul du nombre de Scans ---
|
|
357
|
+
if 0 in decimations:
|
|
358
|
+
Nscans = 4 * angles.shape[0] * (decimations.shape[0] - 1) + angles.shape[0]
|
|
359
|
+
offSet = angles.shape[0]
|
|
360
|
+
else:
|
|
361
|
+
Nscans = 4 * angles.shape[0] * decimations.shape[0]
|
|
362
|
+
offSet = 0
|
|
363
|
+
|
|
364
|
+
ActiveLIST = np.ones((num_elements, Nscans))
|
|
365
|
+
Xm = np.arange(1, num_elements + 1) * dx_mm
|
|
366
|
+
dFx = 1 / (num_elements * dx_mm)
|
|
367
|
+
|
|
368
|
+
# On traite séparément les décimations non nulles pour la boucle
|
|
369
|
+
active_decimations = decimations[decimations != 0]
|
|
370
|
+
|
|
371
|
+
for i_dec in range(len(active_decimations)):
|
|
372
|
+
idx_base = (np.arange(len(angles))) + (i_dec * 4 * len(angles)) + offSet
|
|
373
|
+
|
|
374
|
+
Icos = idx_base
|
|
375
|
+
Incos = idx_base + len(angles)
|
|
376
|
+
Isin = idx_base + 2 * len(angles)
|
|
377
|
+
Insin = idx_base + 3 * len(angles)
|
|
378
|
+
|
|
379
|
+
fx = dFx * active_decimations[i_dec]
|
|
380
|
+
|
|
381
|
+
# Remplissage des 4 phases
|
|
382
|
+
valid_icos = Icos[Icos < Nscans]
|
|
383
|
+
if valid_icos.size > 0:
|
|
384
|
+
ActiveLIST[:, valid_icos] = calc_mat_os(Xm, fx, dx_mm, ActiveLIST[:, valid_icos], 'cos')
|
|
385
|
+
if (Incos < Nscans).any():
|
|
386
|
+
ActiveLIST[:, Incos[Incos < Nscans]] = 1 - ActiveLIST[:, valid_icos]
|
|
387
|
+
|
|
388
|
+
valid_isin = Isin[Isin < Nscans]
|
|
389
|
+
if valid_isin.size > 0:
|
|
390
|
+
ActiveLIST[:, valid_isin] = calc_mat_os(Xm, fx, dx_mm, ActiveLIST[:, valid_isin], 'sin')
|
|
391
|
+
if (Insin < Nscans).any():
|
|
392
|
+
ActiveLIST[:, Insin[Insin < Nscans]] = 1 - ActiveLIST[:, valid_isin]
|
|
393
|
+
|
|
394
|
+
# --- Conversion au format attendu ---
|
|
395
|
+
# 1. On convertit toute la matrice en liste de strings Hexa
|
|
396
|
+
hexa_list = convert_to_hex_list(ActiveLIST)
|
|
397
|
+
|
|
398
|
+
# 2. Fonction interne de formatage d'angle (pour coller à votre ancien code)
|
|
399
|
+
def format_angle(a):
|
|
400
|
+
return f"{'1' if a < 0 else '0'}{abs(a):02d}"
|
|
401
|
+
|
|
402
|
+
# 3. Construction de la liste de dictionnaires
|
|
403
|
+
patterns = []
|
|
404
|
+
for i in range(Nscans):
|
|
405
|
+
# On retrouve l'angle correspondant à l'index i
|
|
406
|
+
# La logique est cyclique sur la taille de 'angles'
|
|
407
|
+
angle_val = angles[i % len(angles)]
|
|
408
|
+
|
|
409
|
+
hex_pattern = hexa_list[i]
|
|
410
|
+
pair = f"{hex_pattern}_{format_angle(angle_val)}"
|
|
411
|
+
patterns.append({"fileName": pair})
|
|
412
|
+
|
|
413
|
+
return patterns
|
|
414
|
+
|
|
415
|
+
def _generate_patterns(self, N,angles = None):
|
|
341
416
|
def format_angle(a):
|
|
342
417
|
return f"{'1' if a < 0 else '0'}{abs(a):02d}"
|
|
343
418
|
|
|
@@ -348,7 +423,13 @@ class Tomography(Experiment):
|
|
|
348
423
|
return hex_string
|
|
349
424
|
|
|
350
425
|
num_elements = self.params.acoustic['num_elements']
|
|
351
|
-
|
|
426
|
+
if angles is None:
|
|
427
|
+
angle_choices = list(range(-20, 21))
|
|
428
|
+
else:
|
|
429
|
+
# convert np.array to list if necessary
|
|
430
|
+
if isinstance(angles, np.ndarray):
|
|
431
|
+
angles = angles.tolist()
|
|
432
|
+
angle_choices = angles
|
|
352
433
|
|
|
353
434
|
# 1. Trouver TOUS les diviseurs PAIRS de num_elements (y compris num_elements)
|
|
354
435
|
divs = [d for d in range(2, num_elements + 1) if num_elements % d == 0 and d % 2 == 0]
|
|
@@ -451,7 +532,7 @@ class Tomography(Experiment):
|
|
|
451
532
|
divergence_deg (float): Angle d'ouverture du masque pour suivre l'élargissement du faisceau.
|
|
452
533
|
0.0 = Droit, 0.5 = Légère ouverture (conseillé).
|
|
453
534
|
"""
|
|
454
|
-
print(f"
|
|
535
|
+
print(f"Applying apodization (Alpha={alpha}, Div={divergence_deg}°) on {len(self.AcousticFields)} fields...")
|
|
455
536
|
|
|
456
537
|
probe_width = self.params.acoustic['num_elements'] * self.params.acoustic['element_width']
|
|
457
538
|
|
|
@@ -512,7 +593,7 @@ class Tomography(Experiment):
|
|
|
512
593
|
# 8. Mise à jour de l'objet
|
|
513
594
|
self.AcousticFields[i].field = field_apodized
|
|
514
595
|
|
|
515
|
-
print("Apodisation
|
|
596
|
+
print("Apodisation done.")
|
|
516
597
|
|
|
517
598
|
# PRIVATE METHODS
|
|
518
599
|
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.323'
|
|
89
89
|
__process__ = config.get_process()
|
|
90
90
|
|
|
91
91
|
def initialize(process=None):
|
|
@@ -176,6 +176,11 @@ def initialize(process=None):
|
|
|
176
176
|
|
|
177
177
|
|
|
178
178
|
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
179
184
|
|
|
180
185
|
|
|
181
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=CzNrJamLw5SZZ9fGeXRnGrBUqSj90vh2wZx1792YWto,4308
|
|
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=-7HfRDPchTRwxm0SObU_pGN3FH4HN6b1WJvLuacGzFU,34672
|
|
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.323.dist-info/METADATA,sha256=9n72wEg-tUeIC9EWY6rFRJCpFwBOnly-3IQZSVdvLts,700
|
|
46
|
+
aot_biomaps-2.9.323.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
47
|
+
aot_biomaps-2.9.323.dist-info/top_level.txt,sha256=6STF-lT4kaAnBHJYCripmN5mZABoHjMuY689JdiDphk,12
|
|
48
|
+
aot_biomaps-2.9.323.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|