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.

@@ -157,8 +157,6 @@ def calculate_envelope_squared(field):
157
157
  print(f"Erreur dans calculate_envelope_squared: {e}")
158
158
  raise
159
159
 
160
-
161
-
162
160
  def getPattern(pathFile):
163
161
  """
164
162
  Get the pattern from a file path.
@@ -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 N < 1:
285
- raise ValueError("N must be a positive integer.")
286
- self.patterns = self._generate_patterns(N)
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 _generate_patterns(self, N):
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
- angle_choices = list(range(-20, 21))
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"Application de l'apodisation (Alpha={alpha}, Div={divergence_deg}°) sur {len(self.AcousticFields)} champs...")
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 terminée.")
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.318'
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AOT_biomaps
3
- Version: 2.9.318
3
+ Version: 2.9.323
4
4
  Summary: Acousto-Optic Tomography
5
5
  Home-page: https://github.com/LucasDuclos/AcoustoOpticTomography
6
6
  Author: Lucas Duclos
@@ -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=JzWlV3kQ0eqvYRCkDaPawjpBhG0lagMhcLDnBLaY5Fs,4298
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=al7xXKMY5e-qQQ7nrQVPVAmqYiB320OluNlY6ti8iKc,7539
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=JO-yLOSnCd8Da2HC9uJ1uI0GD-_Ca1PX9URzAk_EAiQ,31149
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=A4IQV7IETu9MgYr7hjLNPTImzjf8CEU4cZ2e0EgJNWA,19878
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.318.dist-info/METADATA,sha256=ynPqtHAnkFQBks7GrB91EadzCQxdCC7PFc0kHG3H-Zo,700
45
- aot_biomaps-2.9.318.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
46
- aot_biomaps-2.9.318.dist-info/top_level.txt,sha256=6STF-lT4kaAnBHJYCripmN5mZABoHjMuY689JdiDphk,12
47
- aot_biomaps-2.9.318.dist-info/RECORD,,
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,,