AOT-biomaps 2.9.212__py3-none-any.whl → 2.9.233__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.

@@ -7,6 +7,8 @@ import psutil
7
7
  import numpy as np
8
8
  import matplotlib.pyplot as plt
9
9
  from tqdm import trange
10
+ import h5py
11
+ from scipy.io import loadmat
10
12
 
11
13
  class Tomography(Experiment):
12
14
  def __init__(self, **kwargs):
@@ -433,3 +435,71 @@ class Tomography(Experiment):
433
435
  listAcousticFields.append(AcousticField)
434
436
  progress_bar.set_postfix_str("")
435
437
  return listAcousticFields
438
+
439
+ def load_experimentalAO(self, pathAO, withTumor = True, h5name='AOsignal'):
440
+ """
441
+ Load experimental AO signals from specified file paths.
442
+ Args:
443
+ path_withTumor: Path to the AO signal with tumor.
444
+ path_withoutTumor: Path to the AO signal without tumor.
445
+ """
446
+ if not os.path.exists(pathAO):
447
+ raise FileNotFoundError(f"File {pathAO} not found.")
448
+
449
+ if pathAO.endswith('.npy'):
450
+ ao_signal = np.load(pathAO)
451
+ elif pathAO.endswith('.h5'):
452
+ with h5py.File(pathAO, 'r') as f:
453
+ if h5name not in f:
454
+ raise KeyError(f"Dataset '{h5name}' not found in the HDF5 file.")
455
+ ao_signal = f[h5name][:]
456
+ elif pathAO.endswith('.mat'):
457
+ mat_data = loadmat(pathAO)
458
+ if h5name not in mat_data:
459
+ raise KeyError(f"Dataset '{h5name}' not found in the .mat file.")
460
+ ao_signal = mat_data[h5name]
461
+ elif pathAO.endswith('.hdr'):
462
+ ao_signal = self._loadAOSignal(pathAO)
463
+ else:
464
+ raise ValueError("Unsupported file format. Supported formats are: .npy, .h5, .mat, .hdr")
465
+
466
+ if withTumor:
467
+ self.AOsignal_withTumor = ao_signal
468
+ else:
469
+ self.AOsignal_withoutTumor = ao_signal
470
+
471
+ def check_experimentalAO(self, activeListPath, withTumor=True):
472
+ """
473
+ Check if the experimental AO signals are correctly initialized.
474
+ """
475
+ if withTumor:
476
+ if self.AOsignal_withTumor is None:
477
+ raise ValueError("Experimental AOsignal with tumor is not initialized. Please load the experimental AO signal with tumor first.")
478
+ else:
479
+ if self.AOsignal_withoutTumor is None:
480
+ raise ValueError("Experimental AOsignal without tumor is not initialized. Please load the experimental AO signal without tumor first.")
481
+ if self.AcousticFields is not None:
482
+ # get min time shape between all AO signals
483
+ print()
484
+
485
+ if self.AcousticFields[0].field.shape[0] > self.AOsignal_withTumor.shape[0]:
486
+ self.cutAcousticFields(max_t=self.AOsignal_withTumor.shape[0]/float(self.params.acoustic['f_saving']))
487
+ else:
488
+ for i in range(len(self.AcousticFields)):
489
+ min_time_shape = min(self.AcousticFields[i].field.shape[0])
490
+ if withTumor:
491
+ self.AOsignal_withTumor = self.AOsignal_withTumor[:min_time_shape, :]
492
+ else:
493
+ self.AOsignal_withoutTumor = self.AOsignal_withoutTumor[:min_time_shape, :]
494
+
495
+ for field in self.AcousticFields:
496
+ if activeListPath is not None:
497
+ with open(activeListPath, 'r') as file:
498
+ lines = file.readlines()
499
+ expected_name = lines[self.AcousticFields.index(field)].strip()
500
+ nameField = field.getName_field()
501
+ if nameField.startswith("field_"):
502
+ nameField = nameField[len("field_"):]
503
+ if nameField != expected_name:
504
+ raise ValueError(f"Field name {nameField} does not match the expected name {expected_name} from the active list.")
505
+ print("Experimental AO signals are correctly initialized.")
@@ -77,7 +77,6 @@ class Experiment(ABC):
77
77
  raise ValueError(f"Field {field.getName_field()} has an invalid shape: {field.field.shape}. Expected shape to be at least ({max_sample},).")
78
78
  self.AcousticFields[i].field = field.field[min_sample:max_sample, :, :]
79
79
 
80
-
81
80
  def addNoise(self, noiseType='gaussian', noiseLvl=0.1, withTumor=True):
82
81
  """
83
82
  Ajoute du bruit (gaussien ou poisson) au signal AO sélectionné.
@@ -290,28 +289,48 @@ class Experiment(ABC):
290
289
 
291
290
  @staticmethod
292
291
  def _loadAOSignal(AOsignalPath):
293
- # if extension is .cdh load .cdf file
294
292
  if AOsignalPath.endswith(".cdh"):
295
293
  with open(AOsignalPath, "r") as file:
296
294
  cdh_content = file.readlines()
297
-
298
- n_events = int([line.split(":")[1].strip() for line in cdh_content if "Number of events" in line][0])
299
- n_acquisitions = int([line.split(":")[1].strip() for line in cdh_content if "Number of acquisitions per event" in line][0])
300
-
301
- AOsignal_matrix = np.zeros((n_events, n_acquisitions), dtype=np.float32)
302
-
303
- with open(AOsignalPath.replace(".cdh", ".cdf"), "rb") as file:
304
- for event in range(n_events):
305
- num_elements = int([line.split(":")[1].strip() for line in cdh_content if "Number of US transducers" in line][0])
306
- hex_length = (num_elements + 3) // 4
307
- file.read(hex_length // 2)
308
-
309
- signal = np.frombuffer(file.read(n_acquisitions * 4), dtype=np.float32)
310
- AOsignal_matrix[event, :] = signal
311
-
312
- return AOsignal_matrix
313
- if AOsignalPath.endswith(".npy"):
314
- return np.load(AOsignalPath)
295
+
296
+ cdf_path = AOsignalPath.replace(".cdh", ".cdf")
297
+
298
+ # Extraire les paramètres depuis le fichier .cdh
299
+ n_scans = int([line.split(":")[1].strip() for line in cdh_content if "Number of events" in line][0])
300
+ n_acquisitions_per_event = int([line.split(":")[1].strip() for line in cdh_content if "Number of acquisitions per event" in line][0])
301
+ num_elements = int([line.split(":")[1].strip() for line in cdh_content if "Number of US transducers" in line][0])
302
+
303
+ # Initialisation des structures
304
+ AO_signal = np.zeros((n_acquisitions_per_event, n_scans), dtype=np.float32)
305
+ active_lists = []
306
+ angles = []
307
+
308
+ # Lecture du fichier binaire
309
+ with open(cdf_path, "rb") as file:
310
+ for j in trange(n_scans, desc="Lecture des événements"):
311
+ # Lire l'activeList : 48 caractères hex = 24 bytes
312
+ active_list_bytes = file.read(24)
313
+ active_list_hex = active_list_bytes.hex()
314
+ active_lists.append(active_list_hex)
315
+
316
+ # Lire l'angle (1 byte signé)
317
+ angle_byte = file.read(1)
318
+ angle = np.frombuffer(angle_byte, dtype=np.int8)[0]
319
+ angles.append(angle)
320
+
321
+ # Lire le signal AO (float32)
322
+ data = np.frombuffer(file.read(n_acquisitions_per_event * 4), dtype=np.float32)
323
+ if len(data) != n_acquisitions_per_event:
324
+ raise ValueError(f"Erreur à l'événement {j} : attendu {n_acquisitions_per_event}, obtenu {len(data)}")
325
+ AO_signal[:, j] = data
326
+
327
+ return AO_signal
328
+
329
+
330
+ elif AOsignalPath.endswith(".npy"):
331
+ return np.load(AOsignalPath) # Supposé déjà au bon format
332
+ else:
333
+ raise ValueError("Format de fichier non supporté. Utilisez .cdh/.cdf ou .npy.")
315
334
 
316
335
  def saveAOsignals_Castor(self, save_directory, withTumor=True):
317
336
  if withTumor:
@@ -339,10 +358,10 @@ class Experiment(ABC):
339
358
  header_content = (
340
359
  f"Data filename: {'AOSignals_withTumor.cdf' if withTumor else 'AOSignals_withoutTumor.cdf'}\n"
341
360
  f"Number of events: {nScan}\n"
342
- f"Number of acquisitions per event: {AO_signal.shape[1]}\n"
361
+ f"Number of acquisitions per event: {AO_signal.shape[0]}\n"
343
362
  f"Start time (s): 0\n"
344
363
  f"Duration (s): 1\n"
345
- f"Acquisition frequency (Hz): {1/self.AcousticFields[0].kgrid.dt}\n"
364
+ f"Acquisition frequency (Hz): {self.params.acoustic['f_saving']}\n"
346
365
  f"Data mode: histogram\n"
347
366
  f"Data type: AOT\n"
348
367
  f"Number of US transducers: {self.params.acoustic['num_elements']}"
@@ -1,6 +1,8 @@
1
1
  from AOT_biomaps.AOT_Recon.ReconEnums import PotentialType
2
- from AOT_biomaps.AOT_Recon.ReconTools import _build_adjacency_sparse
2
+ from AOT_biomaps.AOT_Recon.ReconTools import _build_adjacency_sparse, calculate_memory_requirement, check_gpu_memory
3
3
  from AOT_biomaps.Config import config
4
+
5
+ import warnings
4
6
  import numpy as np
5
7
  import torch
6
8
  from tqdm import trange
@@ -11,9 +13,42 @@ if config.get_process() == 'gpu':
11
13
  except ImportError:
12
14
  raise ImportError("torch_scatter and torch_sparse are required for GPU processing. Please install them using 'pip install torch-scatter torch-sparse' with correct link (follow instructions https://github.com/LucasDuclos/AcoustoOpticTomography/edit/main/README.md).")
13
15
 
14
- def _DEPIERRO_GPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration, withTumor, max_saves=5000):
15
- # Initialisation du device
16
- device = torch.device(f"cuda:{config.select_best_gpu()}")
16
+ def DEPIERRO(
17
+ SMatrix,
18
+ y,
19
+ numIterations,
20
+ beta,
21
+ sigma,
22
+ isSavingEachIteration,
23
+ withTumor,
24
+ max_saves,
25
+ show_logs):
26
+ """
27
+ This method implements the DEPIERRO algorithm using either CPU or single-GPU PyTorch acceleration.
28
+ Multi-GPU and Multi-CPU modes are not implemented for this algorithm.
29
+ """
30
+ try:
31
+ tumor_str = "WITH" if withTumor else "WITHOUT"
32
+ # Auto-select device and method
33
+ if device is None:
34
+ if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
35
+ device = torch.device(f"cuda:{config.select_best_gpu()}")
36
+ use_gpu = True
37
+ else:
38
+ device = torch.device("cpu")
39
+ use_gpu = False
40
+ else:
41
+ use_gpu = device.type == "cuda"
42
+ # Dispatch to the appropriate implementation
43
+ if use_gpu:
44
+ return _DEPIERRO_GPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration, tumor_str, device, max_saves, show_logs)
45
+ else:
46
+ return _DEPIERRO_CPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration, tumor_str, device, max_saves, show_logs)
47
+ except Exception as e:
48
+ print(f"Error in MLEM: {type(e).__name__}: {e}")
49
+ return None, None
50
+
51
+ def _DEPIERRO_GPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
17
52
  # Conversion des données en tenseurs PyTorch (float64)
18
53
  A_matrix_torch = torch.tensor(SMatrix, dtype=torch.float64, device=device)
19
54
  y_torch = torch.tensor(y, dtype=torch.float64, device=device)
@@ -33,7 +68,7 @@ def _DEPIERRO_GPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration,
33
68
  # Construction de la matrice d'adjacence
34
69
  adj_index, adj_values = _build_adjacency_sparse(Z, X, device=device, dtype=torch.float64)
35
70
  # Description pour la barre de progression
36
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: DE PIERRO (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()}"
71
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: DE PIERRO (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()}"
37
72
  # Configuration pour la sauvegarde des itérations
38
73
  saved_indices = [0]
39
74
 
@@ -47,7 +82,8 @@ def _DEPIERRO_GPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration,
47
82
  save_indices.append(numIterations - 1)
48
83
 
49
84
  # Boucle principale MAP-EM
50
- for it in trange(numIterations, desc=description):
85
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
86
+ for it in iterator:
51
87
  theta_p = matrix_theta_torch[-1]
52
88
  theta_p_flat = theta_p.reshape(-1)
53
89
  # Étape 1 : Projection avant
@@ -92,7 +128,7 @@ def _DEPIERRO_GPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration,
92
128
  else:
93
129
  return matrix_theta_torch[-1].cpu().numpy(), None
94
130
 
95
- def _DEPIERRO_CPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration, withTumor, max_saves=5000):
131
+ def _DEPIERRO_CPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
96
132
  try:
97
133
  if beta is None or sigma is None:
98
134
  raise ValueError("Depierro95 optimizer requires beta and sigma parameters.")
@@ -120,9 +156,10 @@ def _DEPIERRO_CPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration,
120
156
  if save_indices[-1] != numIterations - 1:
121
157
  save_indices.append(numIterations - 1)
122
158
 
123
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: DE PIERRO (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single CPU ----"
159
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: DE PIERRO (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
124
160
 
125
- for p in trange(numIterations, desc=description):
161
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
162
+ for it in iterator:
126
163
  theta_p = matrix_theta[-1]
127
164
  theta_p_flat = theta_p.reshape(-1)
128
165
  q_flat = np.dot(A_flat, theta_p_flat)
@@ -141,9 +178,9 @@ def _DEPIERRO_CPU(SMatrix, y, numIterations, beta, sigma, isSavingEachIteration,
141
178
  theta_p_plus_1_flat = np.clip(theta_p_plus_1_flat, a_min=0, a_max=None)
142
179
  theta_next = theta_p_plus_1_flat.reshape(Z, X)
143
180
  matrix_theta[-1] = theta_next
144
- if isSavingEachIteration and p in save_indices:
181
+ if isSavingEachIteration and it in save_indices:
145
182
  I_reconMatrix.append(theta_next.copy())
146
- saved_indices.append(p)
183
+ saved_indices.append(it)
147
184
 
148
185
  if isSavingEachIteration:
149
186
  return I_reconMatrix, saved_indices
@@ -2,6 +2,7 @@ from AOT_biomaps.Config import config
2
2
  import torch
3
3
  import numpy as np
4
4
  from tqdm import trange
5
+ from AOT_biomaps.AOT_Recon.ReconTools import calculate_memory_requirement, check_gpu_memory
5
6
 
6
7
  def LS(
7
8
  SMatrix,
@@ -12,6 +13,7 @@ def LS(
12
13
  withTumor=True,
13
14
  device=None,
14
15
  max_saves=5000,
16
+ show_logs=True
15
17
  ):
16
18
  """
17
19
  Least Squares reconstruction using Projected Gradient Descent (PGD) with non-negativity constraint.
@@ -20,15 +22,15 @@ def LS(
20
22
  tumor_str = "WITH" if withTumor else "WITHOUT"
21
23
  # Force GPU usage for now
22
24
  if device is None:
23
- if not torch.cuda.is_available():
25
+ if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
24
26
  raise RuntimeError("CUDA is required for this implementation.")
25
27
  device = torch.device(f"cuda:{config.select_best_gpu()}")
26
28
  else:
27
29
  if device.type != "cuda":
28
30
  raise RuntimeError("Only GPU implementation is available for now.")
29
- return _LS_GPU_stable(SMatrix, y, numIterations, alpha, isSavingEachIteration, tumor_str, max_saves)
31
+ return _LS_GPU_stable(SMatrix, y, numIterations, alpha, isSavingEachIteration, tumor_str, max_saves, show_logs=show_logs)
30
32
 
31
- def _LS_GPU_stable(SMatrix, y, numIterations, alpha, isSavingEachIteration, tumor_str, max_saves=5000):
33
+ def _LS_GPU_stable(SMatrix, y, numIterations, alpha, isSavingEachIteration, tumor_str, max_saves=5000, show_logs=True):
32
34
  """
33
35
  Stable GPU implementation of LS using projected gradient descent with diagonal preconditioner.
34
36
  """
@@ -65,13 +67,14 @@ def _LS_GPU_stable(SMatrix, y, numIterations, alpha, isSavingEachIteration, tumo
65
67
  AT_r = torch.empty(ZX, device=device)
66
68
  description = f"AOT-BioMaps -- Stable LS Reconstruction ---- {tumor_str} TUMOR ---- GPU {torch.cuda.current_device()}"
67
69
 
68
- for k in trange(numIterations, desc=description):
70
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
71
+ for it in iterator:
69
72
  # Calcul du résidu (inplace)
70
73
  torch.matmul(A_flat, lambda_k, out=r_k)
71
74
  r_k = y_flat - r_k
72
- if isSavingEachIteration and k in save_indices:
75
+ if isSavingEachIteration and it in save_indices:
73
76
  lambda_history.append(lambda_k.clone().reshape(Z, X) * (norm_y / norm_A))
74
- saved_indices.append(k)
77
+ saved_indices.append(it)
75
78
 
76
79
  # Gradient préconditionné (inplace)
77
80
  torch.matmul(A_flat.T, r_k, out=AT_r)
@@ -2,13 +2,94 @@ from AOT_biomaps.AOT_Recon.ReconEnums import PotentialType
2
2
  from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.Quadratic import _Omega_QUADRATIC_CPU, _Omega_QUADRATIC_GPU
3
3
  from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.RelativeDifferences import _Omega_RELATIVE_DIFFERENCE_CPU, _Omega_RELATIVE_DIFFERENCE_GPU
4
4
  from AOT_biomaps.AOT_Recon.AOT_PotentialFunctions.Huber import _Omega_HUBER_PIECEWISE_CPU, _Omega_HUBER_PIECEWISE_GPU
5
- from AOT_biomaps.AOT_Recon.ReconTools import _build_adjacency_sparse
5
+ from AOT_biomaps.AOT_Recon.ReconTools import _build_adjacency_sparse, check_gpu_memory, calculate_memory_requirement
6
6
  from AOT_biomaps.Config import config
7
+
8
+ import warnings
7
9
  import numpy as np
8
10
  import torch
9
11
  from tqdm import trange
10
12
 
11
- def _MAPEM_CPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSavingEachIteration, withTumor, max_saves=5000):
13
+ def MAPEM(
14
+ SMatrix,
15
+ y,
16
+ Omega,
17
+ beta,
18
+ delta=None,
19
+ gamma=None,
20
+ sigma=None,
21
+ numIterations=100,
22
+ isSavingEachIteration=True,
23
+ withTumor=True,
24
+ device=None,
25
+ max_saves=5000,
26
+ show_logs=True):
27
+ """
28
+ This method implements the MAPEM algorithm using either CPU or single-GPU PyTorch acceleration.
29
+ Multi-GPU and Multi-CPU modes are not implemented for this algorithm.
30
+ """
31
+ try:
32
+ tumor_str = "WITH" if withTumor else "WITHOUT"
33
+ # Auto-select device and method
34
+ if device is None:
35
+ if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
36
+ device = torch.device(f"cuda:{config.select_best_gpu()}")
37
+ use_gpu = True
38
+ else:
39
+ device = torch.device("cpu")
40
+ use_gpu = False
41
+ else:
42
+ use_gpu = device.type == "cuda"
43
+ # Dispatch to the appropriate implementation
44
+ if use_gpu:
45
+ return _MAPEM_GPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True)
46
+ else:
47
+ return _MAPEM_CPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True)
48
+ except Exception as e:
49
+ print(f"Error in MLEM: {type(e).__name__}: {e}")
50
+ return None, None
51
+
52
+ def MAPEM_STOP(
53
+ SMatrix,
54
+ y,
55
+ Omega,
56
+ beta,
57
+ delta=None,
58
+ gamma=None,
59
+ sigma=None,
60
+ numIterations=100,
61
+ isSavingEachIteration=True,
62
+ withTumor=True,
63
+ device=None,
64
+ max_saves=5000,
65
+ show_logs=True):
66
+ """
67
+ This method implements the MAPEM_STOP algorithm using either CPU or single-GPU PyTorch acceleration.
68
+ Multi-GPU and Multi-CPU modes are not implemented for this algorithm.
69
+ """
70
+ try:
71
+ tumor_str = "WITH" if withTumor else "WITHOUT"
72
+ # Auto-select device and method
73
+ if device is None:
74
+ if torch.cuda.is_available() and check_gpu_memory(config.select_best_gpu(), calculate_memory_requirement(SMatrix, y), show_logs=show_logs):
75
+ device = torch.device(f"cuda:{config.select_best_gpu()}")
76
+ use_gpu = True
77
+ else:
78
+ device = torch.device("cpu")
79
+ use_gpu = False
80
+ else:
81
+ use_gpu = device.type == "cuda"
82
+ # Dispatch to the appropriate implementation
83
+ if use_gpu:
84
+ return _MAPEM_GPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True)
85
+ else:
86
+ return _MAPEM_CPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True)
87
+ except Exception as e:
88
+ print(f"Error in MLEM: {type(e).__name__}: {e}")
89
+ return None, None
90
+
91
+
92
+ def _MAPEM_CPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True):
12
93
  """
13
94
  MAPEM version CPU simple - sans GPU - torch uniquement
14
95
  """
@@ -42,7 +123,6 @@ def _MAPEM_CPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
42
123
  theta_list = [I_0]
43
124
  results = [I_0.numpy()]
44
125
  saved_indices = [0]
45
- previous = -np.inf
46
126
  normalization_factor = SMatrix.sum(dim=(0, 3)).reshape(-1)
47
127
  adj_index, adj_values = _build_adjacency_sparse(Z, X)
48
128
 
@@ -56,13 +136,14 @@ def _MAPEM_CPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
56
136
  save_indices.append(numIterations - 1)
57
137
 
58
138
  if Omega == PotentialType.HUBER_PIECEWISE:
59
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single CPU ----"
139
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
60
140
  elif Omega == PotentialType.RELATIVE_DIFFERENCE:
61
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single CPU ----"
141
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
62
142
  elif Omega == PotentialType.QUADRATIC:
63
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single CPU ----"
143
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
64
144
 
65
- for p in trange(numIterations, desc=description):
145
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
146
+ for it in iterator:
66
147
  theta_p = theta_list[-1]
67
148
  theta_p_flat = theta_p.reshape(-1)
68
149
  q_flat = A_flat @ theta_p_flat
@@ -80,14 +161,13 @@ def _MAPEM_CPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
80
161
  theta_next_flat = torch.clamp(theta_next_flat, min=0)
81
162
  theta_next = theta_next_flat.reshape(Z, X)
82
163
  theta_list[-1] = theta_next
83
- if isSavingEachIteration and p in save_indices:
164
+ if isSavingEachIteration and it in save_indices:
84
165
  results.append(theta_next.numpy())
85
- saved_indices.append(p+1)
166
+ saved_indices.append(it+1)
86
167
  log_likelihood = (y_flat * torch.log(q_flat + 1e-8) - (q_flat + 1e-8)).sum()
87
168
  penalized_log_likelihood = log_likelihood - beta * U_value
88
- current = penalized_log_likelihood.item()
89
- if (p + 1) % 100 == 0:
90
- print(f"Iter {p+1}: logL={log_likelihood:.3e}, U={U_value:.3e}, penalized logL={penalized_log_likelihood:.3e}")
169
+ if (it + 1) % 100 == 0:
170
+ print(f"Iter {it+1}: logL={log_likelihood:.3e}, U={U_value:.3e}, penalized logL={penalized_log_likelihood:.3e}")
91
171
 
92
172
  if isSavingEachIteration:
93
173
  return results, saved_indices
@@ -97,7 +177,7 @@ def _MAPEM_CPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
97
177
  print(f"An error occurred in _MAPEM_CPU_STOP: {e}")
98
178
  return None, None
99
179
 
100
- def _MAPEM_GPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSavingEachIteration, withTumor, max_saves=5000):
180
+ def _MAPEM_GPU_STOP(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
101
181
  """
102
182
  Maximum A Posteriori (MAP) estimation for Bayesian reconstruction.
103
183
  This method computes the MAP estimate of the parameters given the data.
@@ -123,7 +203,6 @@ def _MAPEM_GPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
123
203
  else:
124
204
  raise ValueError(f"Unknown potential type: {Omega}")
125
205
 
126
- device = torch.device(f"cuda:{config.select_best_gpu()}")
127
206
  A_matrix_torch = torch.tensor(SMatrix, dtype=torch.float32).to(device)
128
207
  y_torch = torch.tensor(y, dtype=torch.float32).to(device)
129
208
  T, Z, X, N = SMatrix.shape
@@ -150,13 +229,14 @@ def _MAPEM_GPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
150
229
  save_indices.append(numIterations - 1)
151
230
 
152
231
  if Omega == PotentialType.HUBER_PIECEWISE:
153
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
232
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
154
233
  elif Omega == PotentialType.RELATIVE_DIFFERENCE:
155
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
234
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
156
235
  elif Omega == PotentialType.QUADRATIC:
157
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
236
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) + STOP condition (penalized log-likelihood) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
158
237
 
159
- for p in trange(numIterations, desc=description):
238
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
239
+ for it in iterator:
160
240
  theta_p = matrix_theta_torch[-1]
161
241
  theta_p_flat = theta_p.reshape(-1)
162
242
  q_flat = A_flat @ theta_p_flat
@@ -176,18 +256,18 @@ def _MAPEM_GPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
176
256
  theta_p_plus_1_flat = torch.clamp(theta_p_plus_1_flat, min=0)
177
257
  theta_next = theta_p_plus_1_flat.reshape(Z, X)
178
258
  matrix_theta_torch[-1] = theta_next
179
- if isSavingEachIteration and p in save_indices:
259
+ if isSavingEachIteration and it in save_indices:
180
260
  matrix_theta_from_gpu_MAPEM.append(theta_next.cpu().numpy())
181
- saved_indices.append(p+1)
261
+ saved_indices.append(it+1)
182
262
  log_likelihood = (y_flat * (torch.log(q_flat + torch.finfo(torch.float32).tiny)) - (q_flat + torch.finfo(torch.float32).tiny)).sum()
183
263
  penalized_log_likelihood = log_likelihood - beta * U_value
184
- if p == 0 or (p + 1) % 100 == 0:
264
+ if it == 0 or (it + 1) % 100 == 0:
185
265
  current = penalized_log_likelihood.item()
186
266
  if current <= previous:
187
267
  nb_false_successive += 1
188
268
  else:
189
269
  nb_false_successive = 0
190
- print(f"Iter {p + 1}: lnL without term ln(m_i !) inside={log_likelihood.item():.8e}, Gibbs energy function U={U_value.item():.4e}, penalized lnL without term ln(m_i !) inside={penalized_log_likelihood.item():.8e}, p lnL (current {current:.8e} - previous {previous:.8e} > 0)={(current - previous > 0)}, nb_false_successive={nb_false_successive}")
270
+ print(f"Iter {it + 1}: lnL without term ln(m_i !) inside={log_likelihood.item():.8e}, Gibbs energy function U={U_value.item():.4e}, penalized lnL without term ln(m_i !) inside={penalized_log_likelihood.item():.8e}, p lnL (current {current:.8e} - previous {previous:.8e} > 0)={(current - previous > 0)}, nb_false_successive={nb_false_successive}")
191
271
  previous = current
192
272
 
193
273
  del A_matrix_torch, y_torch, A_flat, y_flat, I_0, normalization_factor, normalization_factor_flat
@@ -202,7 +282,7 @@ def _MAPEM_GPU_STOP(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma,
202
282
  torch.cuda.empty_cache()
203
283
  return None, None
204
284
 
205
- def _MAPEM_CPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSavingEachIteration, withTumor, max_saves=5000):
285
+ def _MAPEM_CPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, max_saves, show_logs=True):
206
286
  try:
207
287
  if not isinstance(Omega, PotentialType):
208
288
  raise TypeError(f"Omega must be of type PotentialType, got {type(Omega)}")
@@ -225,7 +305,6 @@ def _MAPEM_CPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSa
225
305
  raise ValueError(f"Unknown potential type: {Omega}")
226
306
 
227
307
  T, Z, X, N = SMatrix.shape
228
- J = Z * X
229
308
  A_flat = np.transpose(SMatrix, (0, 3, 1, 2)).reshape(T * N, Z * X)
230
309
  y_flat = y.reshape(-1)
231
310
  theta_0 = np.ones((Z, X), dtype=np.float32)
@@ -246,13 +325,14 @@ def _MAPEM_CPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSa
246
325
  save_indices.append(numIterations - 1)
247
326
 
248
327
  if Omega == PotentialType.HUBER_PIECEWISE:
249
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single CPU ----"
328
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
250
329
  elif Omega == PotentialType.RELATIVE_DIFFERENCE:
251
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single CPU ----"
330
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
252
331
  elif Omega == PotentialType.QUADRATIC:
253
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single CPU ----"
332
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC β:{beta:.4f}, σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single CPU ----"
254
333
 
255
- for p in trange(numIterations, desc=description):
334
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
335
+ for it in iterator:
256
336
  theta_p = matrix_theta_np[-1]
257
337
  theta_p_flat = theta_p.reshape(-1)
258
338
  q_flat = A_flat @ theta_p_flat
@@ -270,9 +350,9 @@ def _MAPEM_CPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSa
270
350
  theta_p_plus_1_flat = np.clip(theta_p_plus_1_flat, 0, None)
271
351
  theta_next = theta_p_plus_1_flat.reshape(Z, X)
272
352
  matrix_theta_np.append(theta_next)
273
- if isSavingEachIteration and p in save_indices:
353
+ if isSavingEachIteration and it in save_indices:
274
354
  I_reconMatrix.append(theta_next.copy())
275
- saved_indices.append(p+1)
355
+ saved_indices.append(it+1)
276
356
 
277
357
  if isSavingEachIteration:
278
358
  return I_reconMatrix, saved_indices
@@ -282,7 +362,7 @@ def _MAPEM_CPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSa
282
362
  print(f"An error occurred in _MAPEM_CPU: {e}")
283
363
  return None, None
284
364
 
285
- def _MAPEM_GPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSavingEachIteration, withTumor, max_saves=5000):
365
+ def _MAPEM_GPU(SMatrix, y, Omega, beta, delta, gamma, sigma, numIterations, isSavingEachIteration, tumor_str, device, max_saves, show_logs=True):
286
366
  """
287
367
  Maximum A Posteriori (MAP) estimation for Bayesian reconstruction using GPU.
288
368
  This method computes the MAP estimate of the parameters given the data.
@@ -308,7 +388,6 @@ def _MAPEM_GPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSa
308
388
  else:
309
389
  raise ValueError(f"Unknown potential type: {Omega}")
310
390
 
311
- device = torch.device(f"cuda:{config.select_best_gpu()}")
312
391
  A_matrix_torch = torch.tensor(SMatrix, dtype=torch.float32).to(device)
313
392
  y_torch = torch.tensor(y, dtype=torch.float32).to(device)
314
393
  T, Z, X, N = SMatrix.shape
@@ -333,13 +412,14 @@ def _MAPEM_GPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSa
333
412
  save_indices.append(numIterations - 1)
334
413
 
335
414
  if Omega == PotentialType.HUBER_PIECEWISE:
336
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
415
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse HUBER β:{beta:.4f}, δ:{delta:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
337
416
  elif Omega == PotentialType.RELATIVE_DIFFERENCE:
338
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
417
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse RD β:{beta:.4f}, γ:{gamma:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
339
418
  elif Omega == PotentialType.QUADRATIC:
340
- description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC σ:{sigma:.4f}) ---- {'WITH' if withTumor else 'WITHOUT'} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
419
+ description = f"AOT-BioMaps -- Bayesian Reconstruction Tomography: MAP-EM (Sparse QUADRATIC σ:{sigma:.4f}) ---- {tumor_str} TUMOR ---- processing on single GPU no.{torch.cuda.current_device()} ----"
341
420
 
342
- for p in trange(numIterations, desc=description):
421
+ iterator = trange(numIterations, desc=description) if show_logs else range(numIterations)
422
+ for it in iterator:
343
423
  theta_p = matrix_theta_torch[-1]
344
424
  theta_p_flat = theta_p.reshape(-1)
345
425
  q_flat = A_flat @ theta_p_flat
@@ -359,9 +439,9 @@ def _MAPEM_GPU(SMatrix, y, Omega, numIterations, beta, delta, gamma, sigma, isSa
359
439
  theta_p_plus_1_flat = torch.clamp(theta_p_plus_1_flat, min=0)
360
440
  theta_next = theta_p_plus_1_flat.reshape(Z, X)
361
441
  matrix_theta_torch.append(theta_next)
362
- if isSavingEachIteration and p in save_indices:
442
+ if isSavingEachIteration and it in save_indices:
363
443
  I_reconMatrix.append(theta_next.cpu().numpy())
364
- saved_indices.append(p+1)
444
+ saved_indices.append(it+1)
365
445
 
366
446
  del A_matrix_torch, y_torch, A_flat, y_flat, theta_0, normalization_factor, normalization_factor_flat
367
447
  torch.cuda.empty_cache()