AOT-biomaps 2.9.377__py3-none-any.whl → 2.9.379__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.
@@ -190,7 +190,7 @@ class StructuredWave(AcousticField):
190
190
  """
191
191
  return f"{'1' if self.angle < 0 else '0'}{abs(self.angle):02d}"
192
192
 
193
- def _apply_delay(self,dx=None):
193
+ def _apply_delay(self,dt=None,dx=None,c0=None):
194
194
  """
195
195
  Apply a temporal delay to the signal for each transducer element.
196
196
 
@@ -198,9 +198,13 @@ class StructuredWave(AcousticField):
198
198
  ndarray: Array of delayed signals.
199
199
  """
200
200
  try:
201
+ print(f"dx in _apply_delay: {dx}")
201
202
  is_positive = self.angle >= 0
202
203
  if dx is None:
203
204
  dx = self.params['dx']
205
+ if c0 is None:
206
+ c0 = self.params['c0']
207
+ actual_dt = dt if dt is not None else self.kgrid.dt
204
208
  # Calculate the total number of grid points for all elements
205
209
  total_grid_points = self.params['num_elements'] * int(round(self.params['element_width'] / dx))
206
210
 
@@ -212,10 +216,10 @@ class StructuredWave(AcousticField):
212
216
 
213
217
  # Calculate delays based on physical positions
214
218
  for i in range(total_grid_points):
215
- delays[i] = (element_positions[i] * np.tan(np.deg2rad(abs(self.angle)))) / self.params['c0'] # Delay in seconds
219
+ delays[i] = (element_positions[i] * np.tan(np.deg2rad(abs(self.angle)))) / c0 # Delay in seconds
216
220
 
217
221
 
218
- delay_samples = np.round(delays / self.kgrid.dt).astype(int)
222
+ delay_samples = np.round(delays / actual_dt).astype(int)
219
223
  max_delay = np.max(np.abs(delay_samples))
220
224
 
221
225
  delayed_signals = np.zeros((total_grid_points, len(self.burst) + max_delay))
@@ -332,76 +336,119 @@ class StructuredWave(AcousticField):
332
336
  f_hdr2.write(headerFieldGlob)
333
337
  except Exception as e:
334
338
  print(f"Error saving HDR/IMG files: {e}")
335
-
336
- def _SetUpSource(self, source, Nx, dx, factorT):
337
- """
338
- Set up source for both 2D and 3D structured waves.
339
- """
340
- active_list = np.array([int(char) for char in ''.join(f"{int(self.pattern.activeList[i:i+2], 16):08b}" for i in range(0, len(self.pattern.activeList), 2))])
341
- element_width_grid_points = int(round(self.params['element_width'] / dx))
342
-
343
- if source.p_mask.ndim == 2:
344
- element_width_grid_points = int(round(self.params['element_width'] / dx))
345
- total_elements_width = self.params['num_elements'] * element_width_grid_points
346
-
347
- # Vérifier que les éléments rentrent dans le grid
348
- if total_elements_width > Nx:
349
- raise ValueError(f"La largeur totale des éléments ({total_elements_width}) dépasse Nx ({Nx}).")
350
-
351
- remaining_space = Nx - total_elements_width
352
- if remaining_space < 0:
353
- raise ValueError(f"Pas assez d'espace pour placer les éléments: total_elements_width ({total_elements_width}) > Nx ({Nx}).")
354
-
355
- spacing = remaining_space // (self.params['num_elements'] + 1)
356
- center_index = np.argmin(np.abs(np.linspace(self.params['Xrange'][0], self.params['Xrange'][1], Nx)))
357
-
358
- activeListGrid = np.zeros(total_elements_width, dtype=int)
359
- current_position = center_index - (total_elements_width + (self.params['num_elements'] - 1) * spacing) // 2
360
-
361
- # Placement des éléments actifs
362
- for i in range(self.params['num_elements']):
363
- if active_list[i] == 1:
364
- x_pos = max(0, current_position) # Éviter les indices négatifs
365
- x_end = x_pos + element_width_grid_points
366
- if x_end > Nx:
367
- x_end = Nx # Limiter à Nx
368
- source.p_mask[x_pos:x_end,0] = 1
369
-
370
- start_idx = i * element_width_grid_points
371
- end_idx = start_idx + element_width_grid_points
372
- if end_idx > total_elements_width:
373
- end_idx = total_elements_width
374
- activeListGrid[start_idx:end_idx] = 1
375
-
376
- current_position += element_width_grid_points + spacing
377
-
378
- # Chargement des signaux retardés
379
- if factorT != 1:
380
- delayedSignal = self._apply_delay(dx=dx)
381
- else:
382
- delayedSignal = self.delayedSignal
383
-
384
- # Vérification de la taille de delayedSignal
385
- num_active_elements = np.sum(activeListGrid == 1)
386
- if delayedSignal.shape[0] < num_active_elements:
387
- raise ValueError(f"delayedSignal a une taille insuffisante: {delayedSignal.shape[0]} < {num_active_elements}.")
388
-
389
- # Assigner source.p
390
- source.p = float(self.params['voltage']) * float(self.params['sensitivity']) * delayedSignal[activeListGrid == 1, :]
391
-
392
339
 
393
- elif source.p_mask.ndim == 3:
394
- # --- 3D ---
395
- center_index_x = Nx // 2
396
- center_index_y = self.params['Ny'] // 2
397
- spacing = (Nx - self.params['num_elements'] * element_width_grid_points) // (self.params['num_elements'] + 1)
398
- current_position = center_index_x - (self.params['num_elements'] * element_width_grid_points + (self.params['num_elements'] - 1) * spacing) // 2
399
-
400
- for i in range(self.params['num_elements']):
401
- if active_list[i] == 1:
402
- x_pos = current_position
403
- source.p_mask[x_pos:x_pos + element_width_grid_points, center_index_y, 0] = 1
404
- current_position += element_width_grid_points + spacing
405
-
406
- delayed_signals = self._apply_delay()
407
- source.p = float(self.params['voltage']) * float(self.params['sensitivity']) * delayed_signals.T
340
+ def _SetUpSource(self, source, Nx, dt, dx, c0, factorT):
341
+ active_list = np.array([int(char) for char in ''.join(f"{int(self.pattern.activeList[i:i+2], 16):08b}" for i in range(0, len(self.pattern.activeList), 2))])
342
+
343
+ # Largeur d'un élément en pixels
344
+ el_width_px = int(round(self.params['element_width'] / dx))
345
+ # Largeur totale de la sonde en pixels
346
+ total_sonde_px = self.params['num_elements'] * el_width_px
347
+
348
+ # On récupère pva_nx depuis l'appel ou on le recalcule
349
+ pva_nx = int(np.round(self.params['width_phantom'] / dx))
350
+ air_margin = (Nx - pva_nx) // 2
351
+
352
+ # Position de départ pour que la sonde soit centrée sur le PHANTOM
353
+ # On commence à la fin de la marge d'air, et on centre la sonde dans le pva_nx
354
+ current_position = air_margin + (pva_nx - total_sonde_px) // 2
355
+
356
+ activeListGrid = np.zeros(total_sonde_px, dtype=int)
357
+
358
+ for i in range(self.params['num_elements']):
359
+ if active_list[i] == 1:
360
+ x_start = current_position
361
+ x_end = x_start + el_width_px
362
+
363
+ # On remplit le masque k-Wave (z=0)
364
+ source.p_mask[x_start:x_end, 0] = 1
365
+
366
+ # On marque les indices actifs pour injecter le signal delayed
367
+ idx_start = i * el_width_px
368
+ idx_end = idx_start + el_width_px
369
+ activeListGrid[idx_start:idx_end] = 1
370
+
371
+ current_position += el_width_px # Pas de "spacing" variable, les éléments sont collés
372
+
373
+ # Injection du signal
374
+ if factorT != 1:
375
+ delayedSignal = self._apply_delay(self, dt=dt, dx=dx, c0=c0)
376
+ else:
377
+ delayedSignal = self.delayedSignal
378
+
379
+ # On injecte uniquement là où p_mask == 1
380
+ source.p = float(self.params['voltage']) * float(self.params['sensitivity']) * delayedSignal[activeListGrid == 1, :]
381
+ return source
382
+
383
+ # def _SetUpSource(self, source, Nx, dx, factorT):
384
+ # """
385
+ # Set up source for both 2D and 3D structured waves.
386
+ # """
387
+ # active_list = np.array([int(char) for char in ''.join(f"{int(self.pattern.activeList[i:i+2], 16):08b}" for i in range(0, len(self.pattern.activeList), 2))])
388
+ # element_width_grid_points = int(round(self.params['element_width'] / dx))
389
+
390
+ # if source.p_mask.ndim == 2:
391
+ # element_width_grid_points = int(round(self.params['element_width'] / dx))
392
+ # total_elements_width = self.params['num_elements'] * element_width_grid_points
393
+
394
+ # # Vérifier que les éléments rentrent dans le grid
395
+ # if total_elements_width > Nx:
396
+ # raise ValueError(f"La largeur totale des éléments ({total_elements_width}) dépasse Nx ({Nx}).")
397
+
398
+ # remaining_space = Nx - total_elements_width
399
+ # if remaining_space < 0:
400
+ # raise ValueError(f"Pas assez d'espace pour placer les éléments: total_elements_width ({total_elements_width}) > Nx ({Nx}).")
401
+
402
+ # spacing = remaining_space // (self.params['num_elements'] + 1)
403
+ # center_index = np.argmin(np.abs(np.linspace(self.params['Xrange'][0], self.params['Xrange'][1], Nx)))
404
+
405
+ # activeListGrid = np.zeros(total_elements_width, dtype=int)
406
+ # current_position = center_index - (total_elements_width + (self.params['num_elements'] - 1) * spacing) // 2
407
+
408
+ # # Placement des éléments actifs
409
+ # for i in range(self.params['num_elements']):
410
+ # if active_list[i] == 1:
411
+ # x_pos = max(0, current_position) # Éviter les indices négatifs
412
+ # x_end = x_pos + element_width_grid_points
413
+ # if x_end > Nx:
414
+ # x_end = Nx # Limiter à Nx
415
+ # source.p_mask[x_pos:x_end,0] = 1
416
+
417
+ # start_idx = i * element_width_grid_points
418
+ # end_idx = start_idx + element_width_grid_points
419
+ # if end_idx > total_elements_width:
420
+ # end_idx = total_elements_width
421
+ # activeListGrid[start_idx:end_idx] = 1
422
+
423
+ # current_position += element_width_grid_points + spacing
424
+
425
+ # # Chargement des signaux retardés
426
+ # if factorT != 1:
427
+ # delayedSignal = self._apply_delay(dx=dx)
428
+ # else:
429
+ # delayedSignal = self.delayedSignal
430
+
431
+ # # Vérification de la taille de delayedSignal
432
+ # num_active_elements = np.sum(activeListGrid == 1)
433
+ # if delayedSignal.shape[0] < num_active_elements:
434
+ # raise ValueError(f"delayedSignal a une taille insuffisante: {delayedSignal.shape[0]} < {num_active_elements}.")
435
+
436
+ # # Assigner source.p
437
+ # source.p = float(self.params['voltage']) * float(self.params['sensitivity']) * delayedSignal[activeListGrid == 1, :]
438
+
439
+
440
+ # elif source.p_mask.ndim == 3:
441
+ # # --- 3D ---
442
+ # center_index_x = Nx // 2
443
+ # center_index_y = self.params['Ny'] // 2
444
+ # spacing = (Nx - self.params['num_elements'] * element_width_grid_points) // (self.params['num_elements'] + 1)
445
+ # current_position = center_index_x - (self.params['num_elements'] * element_width_grid_points + (self.params['num_elements'] - 1) * spacing) // 2
446
+
447
+ # for i in range(self.params['num_elements']):
448
+ # if active_list[i] == 1:
449
+ # x_pos = current_position
450
+ # source.p_mask[x_pos:x_pos + element_width_grid_points, center_index_y, 0] = 1
451
+ # current_position += element_width_grid_points + spacing
452
+
453
+ # delayed_signals = self._apply_delay()
454
+ # source.p = float(self.params['voltage']) * float(self.params['sensitivity']) * delayed_signals.T
@@ -513,7 +513,7 @@ class AcousticField(ABC):
513
513
  dx = self.params['dx']
514
514
  air_margin = 20
515
515
  if dx >= self.params['element_width']:
516
- dx = self.params['element_width'] / 2
516
+ dx = self.params['element_width']/2
517
517
  if self.params['width_phantom'] is not None:
518
518
  pva_nx = int(np.round((self.params['width_phantom'])/dx))
519
519
  Nx = pva_nx + 2 * air_margin
@@ -530,29 +530,46 @@ class AcousticField(ABC):
530
530
  else:
531
531
  Nx = int(round((self.params['Xrange'][1] - self.params['Xrange'][0]) / self.params['dx']))
532
532
  if self.params['height_phantom'] is not None:
533
- Nz = int(np.round((self.params['height_phantom'])/self.params['dz']))
533
+ Nz = int(np.round((self.params['height_phantom'])/self.params['dx']))
534
534
  else:
535
- Nz = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / self.params['dz']))
536
-
535
+ Nz = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / self.params['dx']))
536
+
537
+ Nx_final = int(round((self.params['Xrange'][1] - self.params['Xrange'][0]) / self.params['dx']))
538
+ Nz_final = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / self.params['dx']))
537
539
  # --- 2. Time and space factors ---
538
540
  factorT = int(np.ceil(self.params['f_AQ'] / self.params['f_saving']))
539
- factorX = int(np.ceil(Nx / self.params['Nx']))
540
- factorZ = int(np.ceil(Nz / self.params['Nz']))
541
+ factorX = int(np.ceil(self.params['dx'] / dx))
542
+ factorZ = factorX
541
543
 
542
544
  # --- 3. Grid and source initialization ---
543
545
  kgrid = kWaveGrid([Nx, Nz], [dx, dx])
544
- kgrid.setTime(self.kgrid.Nt, 1 / self.params['f_AQ'])
545
-
546
- medium = kWaveMedium()
547
- medium.sound_speed = np.full((Nx, Nz), 343.0)
548
- medium.density = np.full((Nx, Nz), 1.2)
549
- x_start, x_end = air_margin, air_margin + pva_nx
550
- medium.sound_speed[x_start:x_end, :] = self.params['c0'] # 1540 m/s
551
- medium.density[x_start:x_end, :] = self.params.get('density', 1000.0)
546
+
547
+ # --- CORRECTIF : Définition du Medium avec hétérogénéité ---
548
+ # Initialisation en float32 (essentiel pour GPU)
549
+ c_map = np.full((Nx, Nz), 343.0, dtype=np.float32) # Air par défaut
550
+ rho_map = np.full((Nx, Nz), 1.2, dtype=np.float32)
551
+
552
+ # Insertion du bloc de PVA
553
+ x_start = air_margin
554
+ x_end = air_margin + pva_nx
555
+ c_map[x_start:x_end, :] = self.params['c0']
556
+ rho_map[x_start:x_end, :] = self.params.get('density', 1000.0)
557
+
558
+ medium = kWaveMedium(sound_speed=c_map, density=rho_map)
559
+
560
+ # --- CORRECTIF : Recalcul du pas de temps (CFL) ---
561
+ # k-Wave a besoin d'un dt basé sur la vitesse MAXIMALE (1540 m/s)
562
+ c_mean = np.mean(c_map[:, 0]) # mean speed at z=0
563
+ c_max = np.max(c_map)
564
+ cfl = 0.3 # Valeur de sécurité
565
+ dt = cfl * dx / c_max
566
+ kgrid.setTime(self.kgrid.Nt, dt)
552
567
 
553
568
 
554
569
  source = kSource()
555
570
  source.p_mask = np.zeros((Nx, Nz))
571
+ # Appel à la méthode spécialisée
572
+ source = self._SetUpSource(source, Nx, dt, dx, c_mean,factorT) # factorT=1 pour simplifier
556
573
 
557
574
  # --- 4. Sensor setup ---
558
575
  sensor = kSensor()
@@ -564,11 +581,14 @@ class AcousticField(ABC):
564
581
  # --- 7. Simulation options ---
565
582
  simulation_options = SimulationOptions(
566
583
  pml_inside=False, # PML ajoutée autour de la grille Air+PVA
567
- pml_size=[pml_size, pml_size],
584
+ pml_size=[1, pml_size],
568
585
  use_sg=False,
569
586
  save_to_disk=True,
570
587
  input_filename=os.path.join(gettempdir(), "KwaveIN.h5"),
571
- output_filename=os.path.join(gettempdir(), "KwaveOUT.h5")
588
+ output_filename=os.path.join(gettempdir(), "KwaveOUT.h5"),
589
+ smooth_c0 = True,
590
+ smooth_rho0 = True,
591
+ smooth_p0 = True
572
592
  )
573
593
 
574
594
  execution_options = SimulationExecutionOptions(
@@ -577,9 +597,6 @@ class AcousticField(ABC):
577
597
  show_sim_log=show_log
578
598
  )
579
599
 
580
- # --- 7. Call specialized function to set up source.p_mask and source.p ---
581
- self._SetUpSource(source, Nx, dx, factorT)
582
-
583
600
  # --- 8. Run simulation ---
584
601
  sensor_data = kspaceFirstOrder2D(
585
602
  kgrid=kgrid,
@@ -592,11 +609,12 @@ class AcousticField(ABC):
592
609
 
593
610
  # --- 9. Post-process results ---
594
611
  data = sensor_data['p'].reshape(kgrid.Nt, Nz, Nx)
595
-
596
612
  if factorT != 1 or factorX != 1 or factorZ != 1:
597
- return reshape_field(data, [factorT, factorX, factorZ])
613
+ data = reshape_field(data, [factorT, factorX, factorZ])
614
+ xStart = (Nx//2)//factorX - (Nx_final//2)
615
+ return data[:, :Nz_final, xStart:xStart+Nx_final]
598
616
  else:
599
- return data
617
+ return data[:, :Nz_final, xStart:xStart+Nx_final]
600
618
 
601
619
  except Exception as e:
602
620
  print(f"Error generating 2D acoustic field: {e}")
@@ -681,7 +699,7 @@ class AcousticField(ABC):
681
699
  return None
682
700
 
683
701
  @abstractmethod
684
- def _SetUpSource(self, source, Nx, dx, factorT):
702
+ def _SetUpSource(self, source, Nx, dt, dx, c0, factorT):
685
703
  """
686
704
  Abstract method: each subclass must implement its own source setup.
687
705
  """
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.377'
88
+ __version__ = '2.9.379'
89
89
  __process__ = config.get_process()
90
90
 
91
91
  def initialize(process=None):
@@ -238,6 +238,8 @@ def initialize(process=None):
238
238
 
239
239
 
240
240
 
241
+
242
+
241
243
 
242
244
 
243
245
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AOT_biomaps
3
- Version: 2.9.377
3
+ Version: 2.9.379
4
4
  Summary: Acousto-Optic Tomography
5
5
  Home-page: https://github.com/LucasDuclos/AcoustoOpticTomography
6
6
  Author: Lucas Duclos
@@ -1,14 +1,14 @@
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=iHVPbCjGgvJte8drsv-Q9SbpaKvs9I7Sp7lIiMs1RQw,4416
3
+ AOT_biomaps/__init__.py,sha256=6qGbHw4T2-BgS21iC2JvKHMzIQZqodCkFuHn-CV56dM,4420
4
4
  AOT_biomaps/AOT_Acoustic/AcousticEnums.py,sha256=s5kXa6jKzbS4btwbubrVcynLOr0yg5tth5vL_FGfbMk,1802
5
5
  AOT_biomaps/AOT_Acoustic/AcousticTools.py,sha256=7kuWIIGyzZPQrzRI0zVvdwNUp7qKUE67yCYOMzSb0Ug,8283
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
- AOT_biomaps/AOT_Acoustic/StructuredWave.py,sha256=CpmvyHmwVvYuGhC1bL6VDQERC70gDQNgIdKNZI22Zpw,18978
9
+ AOT_biomaps/AOT_Acoustic/StructuredWave.py,sha256=f7jI0hJ3VPjUlt3R9FYoI6At4JlQmyN3_J2OX3z13Is,21297
10
10
  AOT_biomaps/AOT_Acoustic/__init__.py,sha256=t9M2rRqa_L9pk7W2FeELTkHEMuP4DBr4gBRldMqsQbg,491
11
- AOT_biomaps/AOT_Acoustic/_mainAcoustic.py,sha256=D5ACa6aaJlpCzzYtrMwyakRCwVubx_sGsrzdfX9dEC0,46714
11
+ AOT_biomaps/AOT_Acoustic/_mainAcoustic.py,sha256=ZyGgf2nCENgOXNetxaTgFLNWGmn_MysVWCAVlsCINQs,47702
12
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
14
  AOT_biomaps/AOT_Experiment/Tomography.py,sha256=9mJDwV9WVphoX8drL7MgN3WhS6fjYwS6HWQD3x1CrVs,37625
@@ -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.377.dist-info/METADATA,sha256=NdzR0ymQDys8preXk1PFjTiYkiVFpToYJLIOx_4-OhM,700
46
- aot_biomaps-2.9.377.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
47
- aot_biomaps-2.9.377.dist-info/top_level.txt,sha256=6STF-lT4kaAnBHJYCripmN5mZABoHjMuY689JdiDphk,12
48
- aot_biomaps-2.9.377.dist-info/RECORD,,
45
+ aot_biomaps-2.9.379.dist-info/METADATA,sha256=_NqtecKRJ65mMrnnLL8Tub7dl5WcoUYL9nQEXqrYwDA,700
46
+ aot_biomaps-2.9.379.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
47
+ aot_biomaps-2.9.379.dist-info/top_level.txt,sha256=6STF-lT4kaAnBHJYCripmN5mZABoHjMuY689JdiDphk,12
48
+ aot_biomaps-2.9.379.dist-info/RECORD,,