AOT-biomaps 2.9.67__tar.gz → 2.9.232__tar.gz
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-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/AcousticTools.py +35 -115
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/StructuredWave.py +2 -2
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/_mainAcoustic.py +22 -20
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Experiment/Tomography.py +505 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Experiment/_mainExperiment.py +203 -70
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Optic/_mainOptic.py +204 -0
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/AOT_Optimizers/DEPIERRO.py +191 -0
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/AOT_Optimizers/LS.py +106 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/AOT_Optimizers/MAPEM.py +173 -68
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/AOT_Optimizers/MLEM.py +213 -0
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/AOT_Optimizers/PDHG.py +221 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/AOT_Optimizers/__init__.py +2 -1
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/RelativeDifferences.py +10 -14
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/AlgebraicRecon.py +929 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/AnalyticRecon.py +3 -0
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/BayesianRecon.py +230 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/DeepLearningRecon.py +4 -1
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/PrimalDualRecon.py +210 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/ReconEnums.py +24 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/ReconTools.py +52 -120
- aot_biomaps-2.9.232/AOT_biomaps/AOT_Recon/_mainRecon.py +288 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/__init__.py +158 -36
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps.egg-info/PKG-INFO +1 -1
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps.egg-info/SOURCES.txt +1 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/PKG-INFO +1 -1
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/setup.py +166 -1
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Experiment/Tomography.py +0 -311
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Optic/_mainOptic.py +0 -138
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Recon/AOT_Optimizers/DEPIERRO.py +0 -132
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Recon/AOT_Optimizers/MLEM.py +0 -275
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Recon/AOT_Optimizers/PDHG.py +0 -182
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Recon/AlgebraicRecon.py +0 -629
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Recon/BayesianRecon.py +0 -156
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Recon/PrimalDualRecon.py +0 -66
- aot_biomaps-2.9.67/AOT_biomaps/AOT_Recon/_mainRecon.py +0 -149
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/AcousticEnums.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/FocusedWave.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/IrregularWave.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/PlaneWave.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Acoustic/__init__.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Experiment/Focus.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Experiment/__init__.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Optic/Absorber.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Optic/Laser.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Optic/OpticEnums.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Optic/__init__.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/Huber.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/Quadratic.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/AOT_PotentialFunctions/__init__.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/AOT_Recon/__init__.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/Config.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps/Settings.py +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps.egg-info/dependency_links.txt +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps.egg-info/requires.txt +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/AOT_biomaps.egg-info/top_level.txt +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/README.md +0 -0
- {aot_biomaps-2.9.67 → aot_biomaps-2.9.232}/setup.cfg +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from AOT_biomaps.Config import config
|
|
2
2
|
|
|
3
|
+
from scipy.signal import hilbert
|
|
3
4
|
import os
|
|
4
5
|
import h5py
|
|
5
6
|
import numpy as np
|
|
@@ -109,136 +110,55 @@ def reshape_field(field, factor, device=None):
|
|
|
109
110
|
if isinstance(field, np.ndarray):
|
|
110
111
|
return downsampled.cpu().numpy()
|
|
111
112
|
else:
|
|
112
|
-
return downsampled
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def CPU_hilbert(signal, axis=0):
|
|
116
|
-
"""
|
|
117
|
-
Compute the Hilbert transform of a real signal using NumPy.
|
|
118
|
-
|
|
119
|
-
Parameters:
|
|
120
|
-
- signal: Input real signal (numpy.ndarray).
|
|
121
|
-
- axis: Axis along which to compute the Hilbert transform.
|
|
122
|
-
|
|
123
|
-
Returns:
|
|
124
|
-
- analytic_signal: The analytic signal of the input.
|
|
125
|
-
"""
|
|
126
|
-
fft_signal = np.fft.fftn(signal, axes=[axis])
|
|
127
|
-
h = np.zeros_like(signal)
|
|
128
|
-
|
|
129
|
-
if axis == 0:
|
|
130
|
-
h[0 : signal.shape[0] // 2 + 1, ...] = 1
|
|
131
|
-
h[signal.shape[0] // 2 + 1 :, ...] = 2
|
|
132
|
-
else:
|
|
133
|
-
raise ValueError("Axis not supported for this implementation.")
|
|
134
|
-
|
|
135
|
-
analytic_signal = np.fft.ifftn(fft_signal * h, axes=[axis])
|
|
136
|
-
return analytic_signal
|
|
137
|
-
|
|
138
|
-
def GPU_hilbert(signal, axis=0):
|
|
139
|
-
"""
|
|
140
|
-
Compute the Hilbert transform of a real signal using PyTorch.
|
|
141
|
-
|
|
142
|
-
Parameters:
|
|
143
|
-
- signal: Input real signal (torch.Tensor).
|
|
144
|
-
- axis: Axis along which to compute the Hilbert transform.
|
|
113
|
+
return downsampled.cpu().numpy()
|
|
145
114
|
|
|
146
|
-
|
|
147
|
-
- analytic_signal: The analytic signal of the input.
|
|
115
|
+
def calculate_envelope_squared(field):
|
|
148
116
|
"""
|
|
149
|
-
|
|
150
|
-
h = torch.zeros_like(signal)
|
|
151
|
-
if axis == 0:
|
|
152
|
-
h[0 : signal.shape[0] // 2 + 1, ...] = 1
|
|
153
|
-
h[signal.shape[0] // 2 + 1 :, ...] = 2
|
|
154
|
-
else:
|
|
155
|
-
raise ValueError("Axis not supported for this implementation.")
|
|
117
|
+
Calcule l'enveloppe au carré du champ acoustique en utilisant scipy.signal.hilbert (CPU uniquement).
|
|
156
118
|
|
|
157
|
-
|
|
158
|
-
|
|
119
|
+
Args:
|
|
120
|
+
field: Champ acoustique (numpy.ndarray) de forme (T, X, Z) ou (T, X, Y, Z).
|
|
159
121
|
|
|
160
|
-
def calculate_envelope_squared(field, isGPU):
|
|
161
|
-
"""
|
|
162
|
-
Calculate the analytic envelope of the acoustic field using either CPU or GPU with PyTorch.
|
|
163
|
-
Parameters:
|
|
164
|
-
- field: Input acoustic field (numpy.ndarray or torch.Tensor).
|
|
165
|
-
- isGPU (bool): If True, use GPU for computation. Otherwise, use CPU.
|
|
166
122
|
Returns:
|
|
167
|
-
|
|
123
|
+
envelope (numpy.ndarray): Enveloppe au carré du champ acoustique.
|
|
168
124
|
"""
|
|
169
125
|
try:
|
|
170
126
|
if field is None:
|
|
171
|
-
raise ValueError("
|
|
127
|
+
raise ValueError("Le champ acoustique n'est pas généré. Veuillez d'abord générer le champ.")
|
|
172
128
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
else:
|
|
177
|
-
acoustic_field = field.detach().clone().to(dtype=torch.float32)
|
|
178
|
-
|
|
179
|
-
# Handle GPU/CPU transfer
|
|
180
|
-
if isGPU:
|
|
181
|
-
if not torch.cuda.is_available():
|
|
182
|
-
print("CUDA is not available, falling back to CPU.")
|
|
183
|
-
isGPU = False
|
|
129
|
+
if not isinstance(field, np.ndarray):
|
|
130
|
+
if hasattr(field, 'cpu'):
|
|
131
|
+
field = field.cpu().numpy() # Si c'est un tenseur PyTorch sur GPU/CPU
|
|
184
132
|
else:
|
|
185
|
-
#
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
elif len(acoustic_field.shape) == 4:
|
|
208
|
-
if isGPU:
|
|
209
|
-
return torch.stack([
|
|
210
|
-
torch.abs(GPU_hilbert(slice_data[:, y, z], axis=0))**2
|
|
211
|
-
for y in range(slice_data.shape[1])
|
|
212
|
-
for z in range(slice_data.shape[2])
|
|
213
|
-
]).reshape(slice_data.shape[1], slice_data.shape[2], -1).permute(2, 0, 1)
|
|
214
|
-
else:
|
|
215
|
-
envelope = torch.zeros_like(slice_data)
|
|
216
|
-
for y in range(slice_data.shape[1]):
|
|
217
|
-
for z in range(slice_data.shape[2]):
|
|
218
|
-
envelope[:, y, z] = torch.from_numpy(
|
|
219
|
-
np.abs(CPU_hilbert(slice_data[:, y, z].cpu().numpy(), axis=0))**2
|
|
220
|
-
)
|
|
221
|
-
return envelope
|
|
222
|
-
|
|
223
|
-
# Process slices
|
|
224
|
-
num_slices = acoustic_field.shape[0]
|
|
225
|
-
slice_indices = range(num_slices)
|
|
226
|
-
|
|
227
|
-
if isGPU:
|
|
228
|
-
envelopes = [process_slice(i) for i in slice_indices]
|
|
229
|
-
else:
|
|
230
|
-
with ThreadPoolExecutor() as executor:
|
|
231
|
-
envelopes = list(executor.map(process_slice, slice_indices))
|
|
232
|
-
|
|
233
|
-
# Combine results
|
|
234
|
-
envelope = torch.stack(envelopes, axis=0)
|
|
235
|
-
return envelope.cpu().numpy() if isGPU else envelope.numpy()
|
|
133
|
+
field = np.array(field) # Conversion générique
|
|
134
|
+
|
|
135
|
+
if len(field.shape) not in [3, 4]:
|
|
136
|
+
raise ValueError("Le champ acoustique doit être un tableau 3D (T, X, Z) ou 4D (T, X, Y, Z).")
|
|
137
|
+
|
|
138
|
+
# Calcul de l'enveloppe avec scipy.signal.hilbert
|
|
139
|
+
if len(field.shape) == 3:
|
|
140
|
+
T, X, Z = field.shape
|
|
141
|
+
envelope = np.zeros_like(field)
|
|
142
|
+
for x in range(X):
|
|
143
|
+
for z in range(Z):
|
|
144
|
+
envelope[:, x, z] = np.abs(hilbert(field[:, x, z], axis=0)) ** 2
|
|
145
|
+
elif len(field.shape) == 4:
|
|
146
|
+
T, X, Y, Z = field.shape
|
|
147
|
+
envelope = np.zeros_like(field)
|
|
148
|
+
for x in range(X):
|
|
149
|
+
for y in range(Y):
|
|
150
|
+
for z in range(Z):
|
|
151
|
+
envelope[:, x, y, z] = np.abs(hilbert(field[:, x, y, z], axis=0)) ** 2
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
return envelope
|
|
236
155
|
|
|
237
156
|
except Exception as e:
|
|
238
|
-
print(f"
|
|
157
|
+
print(f"Erreur dans calculate_envelope_squared: {e}")
|
|
239
158
|
raise
|
|
240
159
|
|
|
241
160
|
|
|
161
|
+
|
|
242
162
|
def getPattern(pathFile):
|
|
243
163
|
"""
|
|
244
164
|
Get the pattern from a file path.
|
|
@@ -292,8 +292,8 @@ class StructuredWave(AcousticField):
|
|
|
292
292
|
f"!number format := short float\n"
|
|
293
293
|
f"!number of bytes per pixel := 4\n"
|
|
294
294
|
f"scaling factor (mm/pixel) [1] := {self.params['dx'] * 1000}\n"
|
|
295
|
-
f"scaling factor (mm/pixel) [2] := {self.params['
|
|
296
|
-
f"scaling factor (s/pixel) [3] := {1 / self.params['
|
|
295
|
+
f"scaling factor (mm/pixel) [2] := {self.params['dz'] * 1000}\n"
|
|
296
|
+
f"scaling factor (s/pixel) [3] := {1 / self.params['f_saving']}\n"
|
|
297
297
|
f"first pixel offset (mm) [1] := {self.params['Xrange'][0] * 1e3}\n"
|
|
298
298
|
f"first pixel offset (mm) [2] := {self.params['Zrange'][0] * 1e3}\n"
|
|
299
299
|
f"first pixel offset (s) [3] := 0\n"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import AOT_biomaps.Settings
|
|
2
2
|
from AOT_biomaps.Config import config
|
|
3
|
-
from AOT_biomaps.AOT_Acoustic.AcousticTools import calculate_envelope_squared,
|
|
3
|
+
from AOT_biomaps.AOT_Acoustic.AcousticTools import calculate_envelope_squared, loadmat
|
|
4
4
|
from .AcousticTools import next_power_of_2, reshape_field
|
|
5
5
|
from .AcousticEnums import TypeSim, Dim, FormatSave, WaveType
|
|
6
6
|
|
|
@@ -19,10 +19,12 @@ from kwave.kspaceFirstOrder3D import kspaceFirstOrder3D
|
|
|
19
19
|
from kwave.kspaceFirstOrder2D import kspaceFirstOrder2D
|
|
20
20
|
from kwave.options.simulation_options import SimulationOptions
|
|
21
21
|
from kwave.options.simulation_execution_options import SimulationExecutionOptions
|
|
22
|
+
from AOT_biomaps.Settings import Params
|
|
22
23
|
|
|
23
24
|
from tempfile import gettempdir
|
|
24
25
|
from math import ceil
|
|
25
26
|
from abc import ABC, abstractmethod
|
|
27
|
+
import logging
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
|
|
@@ -75,7 +77,7 @@ class AcousticField(ABC):
|
|
|
75
77
|
print(f"Initialization error: {e}")
|
|
76
78
|
raise
|
|
77
79
|
if params != None:
|
|
78
|
-
if type(params) !=
|
|
80
|
+
if type(params) != Params:
|
|
79
81
|
raise TypeError("params must be an instance of the Params class")
|
|
80
82
|
|
|
81
83
|
self.params = {
|
|
@@ -225,6 +227,7 @@ class AcousticField(ABC):
|
|
|
225
227
|
Generate the acoustic field based on the specified simulation type and parameters.
|
|
226
228
|
"""
|
|
227
229
|
try:
|
|
230
|
+
logging.getLogger('root').setLevel(logging.ERROR)
|
|
228
231
|
if self.params['typeSim'] == TypeSim.FIELD2.value:
|
|
229
232
|
raise NotImplementedError("FIELD2 simulation is not implemented yet.")
|
|
230
233
|
elif self.params['typeSim'] == TypeSim.KWAVE.value:
|
|
@@ -233,10 +236,10 @@ class AcousticField(ABC):
|
|
|
233
236
|
field = self._generate_acoustic_field_KWAVE_2D(isGpu, show_log)
|
|
234
237
|
except Exception as e:
|
|
235
238
|
raise RuntimeError(f"Failed to generate 2D acoustic field: {e}")
|
|
236
|
-
self.field = calculate_envelope_squared(field,
|
|
239
|
+
self.field = reshape_field(calculate_envelope_squared(field),[self.factorT, self.factorX, self.factorZ])
|
|
237
240
|
elif self.params["dim"] == Dim.D3.value:
|
|
238
241
|
field = self._generate_acoustic_field_KWAVE_3D(isGpu, show_log)
|
|
239
|
-
self.field = calculate_envelope_squared(field,
|
|
242
|
+
self.field = reshape_field(calculate_envelope_squared(field),[self.factorT, self.factorX, self.factorZ])
|
|
240
243
|
elif self.params['typeSim'] == TypeSim.HYDRO.value:
|
|
241
244
|
raise ValueError("Cannot generate field for Hydrophone simulation, load exciting acquisitions.")
|
|
242
245
|
else:
|
|
@@ -265,7 +268,7 @@ class AcousticField(ABC):
|
|
|
265
268
|
print(f"Error in save_field method: {e}")
|
|
266
269
|
raise
|
|
267
270
|
|
|
268
|
-
def load_field(self, folderPath, formatSave=FormatSave.HDR_IMG):
|
|
271
|
+
def load_field(self, folderPath, formatSave=FormatSave.HDR_IMG, nameBlock=None):
|
|
269
272
|
"""
|
|
270
273
|
Load the acoustic field from a file in the specified format.
|
|
271
274
|
|
|
@@ -286,7 +289,7 @@ class AcousticField(ABC):
|
|
|
286
289
|
raise NotImplementedError("3D KWAVE field loading is not implemented yet.")
|
|
287
290
|
elif formatSave.value == FormatSave.H5.value:
|
|
288
291
|
if self.params["dim"] == Dim.D2.value:
|
|
289
|
-
self._load_field_h5(folderPath)
|
|
292
|
+
self._load_field_h5(folderPath,nameBlock)
|
|
290
293
|
elif self.params["dim"] == Dim.D3.value:
|
|
291
294
|
raise NotImplementedError("H5 KWAVE field loading is not implemented yet.")
|
|
292
295
|
elif formatSave.value == FormatSave.NPY.value:
|
|
@@ -502,7 +505,7 @@ class AcousticField(ABC):
|
|
|
502
505
|
try:
|
|
503
506
|
# --- 1. Grid setup ---
|
|
504
507
|
dx = self.params['dx']
|
|
505
|
-
if dx >= self.params['element_width']:
|
|
508
|
+
if dx >= self.params['element_width']*2:
|
|
506
509
|
dx = self.params['element_width'] / 2
|
|
507
510
|
Nx = int(round((self.params['Xrange'][1] - self.params['Xrange'][0]) / dx))
|
|
508
511
|
Nz = int(round((self.params['Zrange'][1] - self.params['Zrange'][0]) / dx))
|
|
@@ -511,16 +514,14 @@ class AcousticField(ABC):
|
|
|
511
514
|
Nz = self.params['Nz']
|
|
512
515
|
|
|
513
516
|
# --- 2. Time and space factors ---
|
|
514
|
-
factorT = int(np.ceil(self.params['f_AQ'] / self.params['f_saving']))
|
|
515
|
-
factorX = int(np.ceil(Nx / self.params['Nx']))
|
|
516
|
-
factorZ = int(np.ceil(Nz / self.params['Nz']))
|
|
517
|
+
self.factorT = int(np.ceil(self.params['f_AQ'] / self.params['f_saving']))
|
|
518
|
+
self.factorX = int(np.ceil(Nx / self.params['Nx']))
|
|
519
|
+
self.factorZ = int(np.ceil(Nz / self.params['Nz']))
|
|
517
520
|
|
|
518
521
|
# --- 3. Grid and source initialization ---
|
|
519
522
|
kgrid = kWaveGrid([Nx, Nz], [dx, dx])
|
|
520
523
|
kgrid.setTime(self.kgrid.Nt, 1 / self.params['f_AQ'])
|
|
521
524
|
|
|
522
|
-
print(f"Grid size: Nx={Nx}, Nz={Nz}, dx={dx*1000:.3f} mm, dt={kgrid.dt*1e9:.3f} ns, Nt={kgrid.Nt}, f_AQ={self.params['f_AQ']/1e6:.2f} MHz")
|
|
523
|
-
|
|
524
525
|
source = kSource()
|
|
525
526
|
source.p_mask = np.zeros((Nx, Nz))
|
|
526
527
|
|
|
@@ -533,6 +534,8 @@ class AcousticField(ABC):
|
|
|
533
534
|
total_size_z = next_power_of_2(Nz)
|
|
534
535
|
pml_x_size = (total_size_x - Nx) // 2
|
|
535
536
|
pml_z_size = (total_size_z - Nz) // 2
|
|
537
|
+
pml_x_size = max(pml_x_size, 50) # Ensure a minimum PML size of 50 grid points to avoid parasitic reflections
|
|
538
|
+
pml_z_size = max(pml_z_size, 50) # Ensure a minimum PML size of 50 grid points to avoid parasitic reflections
|
|
536
539
|
|
|
537
540
|
# --- 6. Simulation options ---
|
|
538
541
|
simulation_options = SimulationOptions(
|
|
@@ -551,7 +554,7 @@ class AcousticField(ABC):
|
|
|
551
554
|
)
|
|
552
555
|
|
|
553
556
|
# --- 7. Call specialized function to set up source.p_mask and source.p ---
|
|
554
|
-
self._SetUpSource(source, Nx, dx, factorT)
|
|
557
|
+
self._SetUpSource(source, Nx, dx, self.factorT)
|
|
555
558
|
|
|
556
559
|
# --- 8. Run simulation ---
|
|
557
560
|
sensor_data = kspaceFirstOrder2D(
|
|
@@ -565,10 +568,7 @@ class AcousticField(ABC):
|
|
|
565
568
|
|
|
566
569
|
# --- 9. Post-process results ---
|
|
567
570
|
data = sensor_data['p'].reshape(kgrid.Nt, Nz, Nx)
|
|
568
|
-
|
|
569
|
-
return reshape_field(data, [factorT, factorX, factorZ])
|
|
570
|
-
else:
|
|
571
|
-
return data
|
|
571
|
+
return data
|
|
572
572
|
|
|
573
573
|
except Exception as e:
|
|
574
574
|
print(f"Error generating 2D acoustic field: {e}")
|
|
@@ -655,7 +655,7 @@ class AcousticField(ABC):
|
|
|
655
655
|
"""
|
|
656
656
|
pass
|
|
657
657
|
|
|
658
|
-
def _load_field_h5(self, filePath):
|
|
658
|
+
def _load_field_h5(self, filePath,nameBlock):
|
|
659
659
|
"""
|
|
660
660
|
Load the 2D acoustic field from an H5 file.
|
|
661
661
|
|
|
@@ -666,8 +666,10 @@ class AcousticField(ABC):
|
|
|
666
666
|
- field (numpy.ndarray): The loaded acoustic field.
|
|
667
667
|
"""
|
|
668
668
|
try:
|
|
669
|
-
|
|
670
|
-
|
|
669
|
+
if nameBlock is None:
|
|
670
|
+
nameBlock = 'data'
|
|
671
|
+
with h5py.File(os.path.join(filePath, self.getName_field()+".h5"), 'r') as f:
|
|
672
|
+
self.field = f[nameBlock][:]
|
|
671
673
|
except Exception as e:
|
|
672
674
|
print(f"Error in _load_field_h5 method: {e}")
|
|
673
675
|
raise
|