fullwave25 1.2.6.dev10__tar.gz → 1.3.0.dev0__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.
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/.bumpversion.toml +1 -1
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/.gitignore +7 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/PKG-INFO +37 -2
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/README.md +35 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/__init__.py +5 -2
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium.py +262 -52
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/domain.py +3 -6
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/medium_builder.py +12 -6
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/domain_abdominal_wall.py +4 -10
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/domain_background.py +3 -6
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/domain_scatterer.py +3 -6
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/domain_simple.py +3 -7
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/binary_manager.py +3 -3
- fullwave25-1.3.0.dev0/fullwave/solver/bins/database/relaxation_params_database_num_relax=3_20260828_1513.mat +0 -0
- fullwave25-1.3.0.dev0/fullwave/solver/bins/database/relaxation_params_database_num_relax=3_20260828_1513_invalid_cells.json +4248 -0
- fullwave25-1.3.0.dev0/fullwave/solver/bins/database/relaxation_params_database_num_relax=4_20260828_1456.mat +0 -0
- fullwave25-1.3.0.dev0/fullwave/solver/bins/database/relaxation_params_database_num_relax=4_20260828_1456_invalid_cells.json +2514 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/input_file_writer.py +156 -53
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/pml_builder.py +452 -483
- fullwave25-1.3.0.dev0/fullwave/solver/shipped_database.py +109 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/solver.py +188 -50
- fullwave25-1.3.0.dev0/fullwave/solver/source_type.py +318 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/utils.py +3 -1
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/source.py +75 -21
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/transducer.py +809 -74
- fullwave25-1.3.0.dev0/fullwave/transmit.py +293 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/plot_utils.py +62 -2
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/pulse.py +3 -14
- fullwave25-1.3.0.dev0/fullwave/utils/relaxation_parameters.py +1188 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/pyproject.toml +9 -2
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/uv.lock +63 -1
- fullwave25-1.2.6.dev10/20260120_0844.log +0 -1158
- fullwave25-1.2.6.dev10/fullwave/solver/bins/database/relaxation_params_database_num_relax=2_20260113_0957.mat +0 -0
- fullwave25-1.2.6.dev10/fullwave/utils/relaxation_parameters.py +0 -540
- fullwave25-1.2.6.dev10/ruff.log +0 -1177
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/.pre-commit-config.yaml +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/.python-version +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/CITATION.cff +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/CLAUDE.md +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/CONTRIBUTING.md +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/LICENSE +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/Makefile +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/beamformer.m +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/debug_solver_bin/fullwave2_2d_2_relax_multi_gpu_cuda124 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/debug_solver_bin/fullwave2_2d_exponential_attenuation_multi_gpu +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/debug_solver_bin/fullwave2_2d_exponential_attenuation_multi_gpu_cuda124 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/debug_solver_bin/fullwave2_2d_exponential_attenuation_multi_gpu_cuda124_ +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/debug_solver_bin/fullwave2_3d_exponential_attenuation_multi_gpu_cuda124 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/debug_solver_bin/fullwave2_3d_exponential_attenuation_multi_gpu_cuda124_ +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/experiments/__init__.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/experiments/exp_scatterer_diameter.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/beamformer/__init__.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/beamformer/beamformer.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/constants/__init__.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/constants/material_properties.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/grid.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/__init__.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/__init__.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/data/.keep +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/medium_builder/presets/domain_water_gel.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/sensor.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/__init__.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda124 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda129 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda130 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda118 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda124 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda129 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda130 +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/cuda_utils.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/solver/launcher.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/__init__.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/check_functions.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/coordinates.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/memory_tempfile.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/numerical.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/scatterer.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/signal_filter.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/fullwave/utils/signal_process.py +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/ruff.toml +0 -0
- {fullwave25-1.2.6.dev10 → fullwave25-1.3.0.dev0}/signal_filter_example.png +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: fullwave25
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0.dev0
|
|
4
4
|
Summary: Fullwave 2.5: Ultrasound wave propagation simulation with heterogeneous power law attenuation modelling capabilities
|
|
5
5
|
Author: Masashi Sode, Gianmarco Pinton
|
|
6
6
|
Maintainer: Masashi Sode
|
|
@@ -232,6 +232,41 @@ Here are the main steps to run the Fullwave simulation
|
|
|
232
232
|
4. Define the sensor.
|
|
233
233
|
5. Execute the simulation.
|
|
234
234
|
|
|
235
|
+
## Tutorial: transducers and transmits
|
|
236
|
+
|
|
237
|
+
A named array places itself on the grid, and one call states the transmit.
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
grid = fullwave.Grid(domain_size=(4.5e-2, 4.5e-2), f0=5.208e6, duration=6.7e-5, c0=1540)
|
|
241
|
+
|
|
242
|
+
transducer = fullwave.Transducer.l7_4(grid)
|
|
243
|
+
transducer.plane_wave(angle_deg=2.5)
|
|
244
|
+
|
|
245
|
+
solver = fullwave.Solver(work_dir="./outputs/my_run", grid=grid, medium=medium, transducer=transducer)
|
|
246
|
+
recorded = solver.run()
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The arrays are `l7_4` (linear, 128 elements, 5.208 MHz), `c5_2v` (curved, 49.57 mm radius, 3.7 MHz) and `p4_1c` (phased, 64 elements). `fullwave.TransducerGeometry` builds any other.
|
|
250
|
+
|
|
251
|
+
The transmits are `plane_wave(angle_deg=...)`, `focus(focus_m=...)`, `diverging(virtual_source_m=...)` and `synthetic_aperture(element)`. Each takes `apodization` and `pulse`. Set `transducer.active_source_elements` first to use part of the aperture.
|
|
252
|
+
|
|
253
|
+
Every transducer is additive by default, which is what the calibrated setups use. Pass `source_type="clamped"` for a hard source.
|
|
254
|
+
|
|
255
|
+
`transducer.apply_transducer_stack(...)` paints a probe's backing, matching layer, lens and standoff onto the medium maps before the `Medium` is built. `fullwave.TransducerStack` holds the values.
|
|
256
|
+
|
|
257
|
+
### Which example to read
|
|
258
|
+
|
|
259
|
+
| I want to | example |
|
|
260
|
+
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
261
|
+
| send one plane wave | [simple_plane_wave.py](examples/simple_plane_wave/simple_plane_wave.py) |
|
|
262
|
+
| do the same in 3D | [simple_plane_wave_3d.py](examples/wave_3d/simple_plane_wave_3d.py) |
|
|
263
|
+
| compound plane waves into a B-mode | [plane_wave_compounding.py](examples/linear_transducer/plane_wave_compounding.py) |
|
|
264
|
+
| focus and watch the beam | [linear_transducer_focused_animation.py](examples/linear_transducer/linear_transducer_focused_animation.py) |
|
|
265
|
+
| run a full synthetic aperture | [full_synthetic_aperture.py](examples/linear_transducer/full_synthetic_aperture.py) |
|
|
266
|
+
| do the same on a curved array | [convex_transducer_fsa.py](examples/convex_transducer/convex_transducer_fsa.py) |
|
|
267
|
+
| image through an abdominal wall | [linear_transducer_abdominal_wall.py](examples/linear_transducer/linear_transducer_abdominal_wall.py) |
|
|
268
|
+
| build a layered phantom | [medium_builder_example.py](examples/medium_builder/medium_builder_example.py) |
|
|
269
|
+
|
|
235
270
|
## New simulation development instruction
|
|
236
271
|
|
|
237
272
|
- after the [installation](#installation)
|
|
@@ -193,6 +193,41 @@ Here are the main steps to run the Fullwave simulation
|
|
|
193
193
|
4. Define the sensor.
|
|
194
194
|
5. Execute the simulation.
|
|
195
195
|
|
|
196
|
+
## Tutorial: transducers and transmits
|
|
197
|
+
|
|
198
|
+
A named array places itself on the grid, and one call states the transmit.
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
grid = fullwave.Grid(domain_size=(4.5e-2, 4.5e-2), f0=5.208e6, duration=6.7e-5, c0=1540)
|
|
202
|
+
|
|
203
|
+
transducer = fullwave.Transducer.l7_4(grid)
|
|
204
|
+
transducer.plane_wave(angle_deg=2.5)
|
|
205
|
+
|
|
206
|
+
solver = fullwave.Solver(work_dir="./outputs/my_run", grid=grid, medium=medium, transducer=transducer)
|
|
207
|
+
recorded = solver.run()
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The arrays are `l7_4` (linear, 128 elements, 5.208 MHz), `c5_2v` (curved, 49.57 mm radius, 3.7 MHz) and `p4_1c` (phased, 64 elements). `fullwave.TransducerGeometry` builds any other.
|
|
211
|
+
|
|
212
|
+
The transmits are `plane_wave(angle_deg=...)`, `focus(focus_m=...)`, `diverging(virtual_source_m=...)` and `synthetic_aperture(element)`. Each takes `apodization` and `pulse`. Set `transducer.active_source_elements` first to use part of the aperture.
|
|
213
|
+
|
|
214
|
+
Every transducer is additive by default, which is what the calibrated setups use. Pass `source_type="clamped"` for a hard source.
|
|
215
|
+
|
|
216
|
+
`transducer.apply_transducer_stack(...)` paints a probe's backing, matching layer, lens and standoff onto the medium maps before the `Medium` is built. `fullwave.TransducerStack` holds the values.
|
|
217
|
+
|
|
218
|
+
### Which example to read
|
|
219
|
+
|
|
220
|
+
| I want to | example |
|
|
221
|
+
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
222
|
+
| send one plane wave | [simple_plane_wave.py](examples/simple_plane_wave/simple_plane_wave.py) |
|
|
223
|
+
| do the same in 3D | [simple_plane_wave_3d.py](examples/wave_3d/simple_plane_wave_3d.py) |
|
|
224
|
+
| compound plane waves into a B-mode | [plane_wave_compounding.py](examples/linear_transducer/plane_wave_compounding.py) |
|
|
225
|
+
| focus and watch the beam | [linear_transducer_focused_animation.py](examples/linear_transducer/linear_transducer_focused_animation.py) |
|
|
226
|
+
| run a full synthetic aperture | [full_synthetic_aperture.py](examples/linear_transducer/full_synthetic_aperture.py) |
|
|
227
|
+
| do the same on a curved array | [convex_transducer_fsa.py](examples/convex_transducer/convex_transducer_fsa.py) |
|
|
228
|
+
| image through an abdominal wall | [linear_transducer_abdominal_wall.py](examples/linear_transducer/linear_transducer_abdominal_wall.py) |
|
|
229
|
+
| build a layered phantom | [medium_builder_example.py](examples/medium_builder/medium_builder_example.py) |
|
|
230
|
+
|
|
196
231
|
## New simulation development instruction
|
|
197
232
|
|
|
198
233
|
- after the [installation](#installation)
|
|
@@ -9,7 +9,8 @@ from .grid import Grid
|
|
|
9
9
|
from .medium import Medium, MediumExponentialAttenuation, MediumRelaxationMaps
|
|
10
10
|
from .sensor import Sensor
|
|
11
11
|
from .source import Source
|
|
12
|
-
from .transducer import Transducer, TransducerGeometry
|
|
12
|
+
from .transducer import Transducer, TransducerGeometry, TransducerStack
|
|
13
|
+
from .transmit import Pulse
|
|
13
14
|
|
|
14
15
|
from .medium_builder import presets # isort:skip
|
|
15
16
|
|
|
@@ -35,11 +36,13 @@ __all__ = [
|
|
|
35
36
|
"MediumBuilder",
|
|
36
37
|
"MediumExponentialAttenuation",
|
|
37
38
|
"MediumRelaxationMaps",
|
|
39
|
+
"Pulse",
|
|
38
40
|
"Sensor",
|
|
39
41
|
"Solver",
|
|
40
42
|
"Source",
|
|
41
43
|
"Transducer",
|
|
42
44
|
"TransducerGeometry",
|
|
45
|
+
"TransducerStack",
|
|
43
46
|
"presets",
|
|
44
47
|
"utils",
|
|
45
48
|
]
|
|
@@ -60,7 +63,7 @@ try:
|
|
|
60
63
|
__version__ = version("fullwave")
|
|
61
64
|
except PackageNotFoundError:
|
|
62
65
|
# Update via bump-my-version, not manually
|
|
63
|
-
__version__ = "1.
|
|
66
|
+
__version__ = "1.3.0-dev0"
|
|
64
67
|
|
|
65
68
|
VERSION = __version__ # for convenience
|
|
66
69
|
logger.info("Fullwave version: %s", __version__)
|
|
@@ -14,10 +14,14 @@ import numexpr as ne
|
|
|
14
14
|
import numpy as np
|
|
15
15
|
|
|
16
16
|
from fullwave import Grid
|
|
17
|
+
from fullwave.solver.shipped_database import ShippedDatabase
|
|
17
18
|
from fullwave.solver.utils import initialize_relaxation_param_dict
|
|
18
19
|
from fullwave.utils import check_functions, plot_utils
|
|
19
20
|
from fullwave.utils.coordinates import coords_to_map, map_to_coords
|
|
20
|
-
from fullwave.utils.relaxation_parameters import
|
|
21
|
+
from fullwave.utils.relaxation_parameters import (
|
|
22
|
+
band_scaled_sound_speed,
|
|
23
|
+
generate_relaxation_params,
|
|
24
|
+
)
|
|
21
25
|
|
|
22
26
|
if TYPE_CHECKING:
|
|
23
27
|
from types import ModuleType
|
|
@@ -156,6 +160,87 @@ def _upload_or_convert_arrays(
|
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
|
|
163
|
+
def lossless_value_of(parameter_name: str) -> float:
|
|
164
|
+
"""Return what a lossless voxel holds for one relaxation parameter.
|
|
165
|
+
|
|
166
|
+
A stretching factor of 1 and a damping of 0 give a wavenumber of exactly
|
|
167
|
+
omega over c.
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
parameter_name : str
|
|
172
|
+
The name of the relaxation parameter.
|
|
173
|
+
|
|
174
|
+
Returns
|
|
175
|
+
-------
|
|
176
|
+
float
|
|
177
|
+
The value a lossless voxel holds.
|
|
178
|
+
|
|
179
|
+
"""
|
|
180
|
+
return 1.0 if parameter_name.startswith("kappa") else 0.0
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _make_the_lossless_voxels_lossless(
|
|
184
|
+
relaxation_param_dict: dict[str, NDArray[np.float64]],
|
|
185
|
+
alpha_coeff: NDArray[np.float64] | float,
|
|
186
|
+
) -> None:
|
|
187
|
+
"""Write the lossless values wherever the attenuation coefficient is zero.
|
|
188
|
+
|
|
189
|
+
Parameters
|
|
190
|
+
----------
|
|
191
|
+
relaxation_param_dict : dict[str, NDArray[np.float64]]
|
|
192
|
+
The parameters, changed in place.
|
|
193
|
+
alpha_coeff : NDArray[np.float64] | float
|
|
194
|
+
The attenuation coefficient of each voxel [dB/(MHz^y cm)].
|
|
195
|
+
|
|
196
|
+
Returns
|
|
197
|
+
-------
|
|
198
|
+
None
|
|
199
|
+
|
|
200
|
+
"""
|
|
201
|
+
if not relaxation_param_dict:
|
|
202
|
+
return
|
|
203
|
+
coefficient = np.asarray(alpha_coeff)
|
|
204
|
+
if coefficient.ndim == 0:
|
|
205
|
+
if float(coefficient) != 0.0:
|
|
206
|
+
return
|
|
207
|
+
for name, values in relaxation_param_dict.items():
|
|
208
|
+
values[...] = lossless_value_of(name)
|
|
209
|
+
return
|
|
210
|
+
lossless = coefficient == 0
|
|
211
|
+
if not bool(lossless.any()):
|
|
212
|
+
return
|
|
213
|
+
for name, values in relaxation_param_dict.items():
|
|
214
|
+
values[lossless] = lossless_value_of(name)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _resolve_lossless_marking(
|
|
218
|
+
alpha_coeff: NDArray[np.float64] | float | None,
|
|
219
|
+
lossless_coords: NDArray[np.int64] | None,
|
|
220
|
+
xp: ModuleType,
|
|
221
|
+
dtype: np.dtype,
|
|
222
|
+
) -> tuple[NDArray[np.float64] | float | None, NDArray[np.int64] | None]:
|
|
223
|
+
"""Return the stored `(alpha_coeff, lossless_coords)` pair.
|
|
224
|
+
|
|
225
|
+
A scalar stays a scalar and coordinates stay coordinates, so neither costs a
|
|
226
|
+
domain-sized array.
|
|
227
|
+
"""
|
|
228
|
+
if lossless_coords is not None and np.ndim(alpha_coeff) > 0:
|
|
229
|
+
message = (
|
|
230
|
+
"lossless_coords and an array alpha_coeff both mark the lossless voxels, "
|
|
231
|
+
"so give one or the other"
|
|
232
|
+
)
|
|
233
|
+
raise ValueError(message)
|
|
234
|
+
if alpha_coeff is None:
|
|
235
|
+
stored_coefficient = None
|
|
236
|
+
elif np.ndim(alpha_coeff) == 0:
|
|
237
|
+
stored_coefficient = float(alpha_coeff)
|
|
238
|
+
else:
|
|
239
|
+
stored_coefficient = xp.atleast_2d(xp.asarray(alpha_coeff)).astype(dtype, copy=False)
|
|
240
|
+
stored_coords = None if lossless_coords is None else np.asarray(lossless_coords, dtype=np.int64)
|
|
241
|
+
return stored_coefficient, stored_coords
|
|
242
|
+
|
|
243
|
+
|
|
159
244
|
@dataclass
|
|
160
245
|
class MediumRelaxationMaps:
|
|
161
246
|
"""Medium class for Fullwave."""
|
|
@@ -167,6 +252,8 @@ class MediumRelaxationMaps:
|
|
|
167
252
|
air_coords: NDArray[np.int64]
|
|
168
253
|
relaxation_param_dict: dict[str, NDArray[np.float64]]
|
|
169
254
|
relaxation_param_dict_for_fw2: dict[str, NDArray[np.float64]]
|
|
255
|
+
alpha_coeff: NDArray[np.float64] | float | None
|
|
256
|
+
lossless_coords: NDArray[np.int64] | None
|
|
170
257
|
use_regression: bool = False
|
|
171
258
|
|
|
172
259
|
def __init__(
|
|
@@ -177,9 +264,11 @@ class MediumRelaxationMaps:
|
|
|
177
264
|
beta: NDArray[np.float64],
|
|
178
265
|
relaxation_param_dict: dict[str, NDArray[np.float64]],
|
|
179
266
|
*,
|
|
267
|
+
alpha_coeff: NDArray[np.float64] | float | None = None,
|
|
268
|
+
lossless_coords: NDArray[np.int64] | None = None,
|
|
180
269
|
air_map: NDArray[np.int64] | None = None,
|
|
181
270
|
air_coords: NDArray[np.int64] | None = None,
|
|
182
|
-
n_relaxation_mechanisms: int =
|
|
271
|
+
n_relaxation_mechanisms: int = ShippedDatabase.mechanisms,
|
|
183
272
|
use_isotropic_relaxation: bool = True,
|
|
184
273
|
n_jobs: int = -1,
|
|
185
274
|
dtype: type = np.float64,
|
|
@@ -206,6 +295,16 @@ class MediumRelaxationMaps:
|
|
|
206
295
|
key: kappa_x1, kappa_x2, d_x1_nu{i}, alpha_x1_nu{i}, d_x2_nu{i}, alpha_x2_nu{i}
|
|
207
296
|
value.shape: [nx, ny] for 2D, [nx, ny, nz] for 3D for each value
|
|
208
297
|
see Pinton, G. (2021) http://arxiv.org/abs/2106.11476 for more detail.
|
|
298
|
+
alpha_coeff : float or NDArray[np.float64], optional
|
|
299
|
+
Attenuation coefficient the relaxation parameters were built for
|
|
300
|
+
[dB/(MHz^y cm)]. Marks a voxel lossless where it is exactly 0, which
|
|
301
|
+
the relaxation maps alone cannot express because the lookup clips a
|
|
302
|
+
smaller request to its minimum. Prefer a scalar, or lossless_coords.
|
|
303
|
+
None leaves the zero-attenuation gate a no-op for this medium.
|
|
304
|
+
lossless_coords : NDArray[np.int64], optional
|
|
305
|
+
Coordinates of the voxels that carry no attenuation, shape
|
|
306
|
+
[n_lossless, ndim], as air_coords does for air. Mutually exclusive
|
|
307
|
+
with an array alpha_coeff.
|
|
209
308
|
air_map: NDArray[np.int64], optional
|
|
210
309
|
Binary matrix where the medium is air.
|
|
211
310
|
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
@@ -235,8 +334,10 @@ class MediumRelaxationMaps:
|
|
|
235
334
|
"""
|
|
236
335
|
check_functions.check_compatible_value(
|
|
237
336
|
n_relaxation_mechanisms,
|
|
238
|
-
[2],
|
|
239
|
-
"
|
|
337
|
+
[1, 2, 3, 4, 5, 6],
|
|
338
|
+
"n_relaxation_mechanisms must be between 1 and 6. "
|
|
339
|
+
"A count other than 2 needs the n_relax solver kernel, "
|
|
340
|
+
"which reads the count from n_relax.dat.",
|
|
240
341
|
)
|
|
241
342
|
self.use_gpu = use_gpu
|
|
242
343
|
self.xp: ModuleType = _get_array_module(use_gpu=use_gpu)
|
|
@@ -261,6 +362,9 @@ class MediumRelaxationMaps:
|
|
|
261
362
|
self.sound_speed = xp.atleast_2d(xp.asarray(sound_speed)).astype(self.dtype, copy=False)
|
|
262
363
|
self.density = xp.atleast_2d(xp.asarray(density)).astype(self.dtype, copy=False)
|
|
263
364
|
self.beta = xp.atleast_2d(xp.asarray(beta)).astype(self.dtype, copy=False)
|
|
365
|
+
self.alpha_coeff, self.lossless_coords = _resolve_lossless_marking(
|
|
366
|
+
alpha_coeff, lossless_coords, xp, self.dtype
|
|
367
|
+
)
|
|
264
368
|
except Exception:
|
|
265
369
|
if xp is np:
|
|
266
370
|
raise
|
|
@@ -347,6 +451,8 @@ class MediumRelaxationMaps:
|
|
|
347
451
|
di, dj = d_arrays[i], d_arrays[j]
|
|
348
452
|
ai, aj = a_arrays[i], a_arrays[j]
|
|
349
453
|
swap = ne.evaluate("di / kappa + ai > dj / kappa + aj")
|
|
454
|
+
if not swap.any():
|
|
455
|
+
continue
|
|
350
456
|
d_arrays[i] = np.where(swap, dj, di)
|
|
351
457
|
d_arrays[j] = np.where(swap, di, dj)
|
|
352
458
|
a_arrays[i] = np.where(swap, aj, ai)
|
|
@@ -422,7 +528,7 @@ class MediumRelaxationMaps:
|
|
|
422
528
|
self,
|
|
423
529
|
relaxation_param_dict: dict[str, NDArray[np.float64]],
|
|
424
530
|
contents_shape: NDArray[np.int64] | tuple[int, ...],
|
|
425
|
-
n_relaxation_mechanisms: int =
|
|
531
|
+
n_relaxation_mechanisms: int = ShippedDatabase.mechanisms,
|
|
426
532
|
) -> None:
|
|
427
533
|
"""Check if the relaxation parameter updates have valid keys and matching shapes.
|
|
428
534
|
|
|
@@ -499,7 +605,6 @@ class MediumRelaxationMaps:
|
|
|
499
605
|
output_dtype: np.dtype | None = None,
|
|
500
606
|
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
|
|
501
607
|
xp = self.xp
|
|
502
|
-
use_gpu = xp is not np
|
|
503
608
|
|
|
504
609
|
dx = xp.asarray(dx, dtype=xp.float64)
|
|
505
610
|
kappa_x = xp.asarray(kappa_x, dtype=xp.float64)
|
|
@@ -507,19 +612,18 @@ class MediumRelaxationMaps:
|
|
|
507
612
|
dt = xp.asarray(dt, dtype=xp.float64)
|
|
508
613
|
|
|
509
614
|
eps = xp.finfo(xp.float64).eps
|
|
615
|
+
two_over_dt = 2.0 / dt
|
|
510
616
|
|
|
511
|
-
if
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
617
|
+
if xp is np:
|
|
618
|
+
rate = ne.evaluate("dx / kappa_x + alpha_x")
|
|
619
|
+
total = ne.evaluate("two_over_dt + rate")
|
|
620
|
+
b = ne.evaluate("(two_over_dt - rate) / total")
|
|
621
|
+
a = ne.evaluate("-(dx / (kappa_x ** 2 + eps)) / total")
|
|
515
622
|
else:
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
b =
|
|
519
|
-
|
|
520
|
-
denom = ne.evaluate("kappa_x*(dx + kappa_x*alpha_x) + eps_local")
|
|
521
|
-
# a = dx/denom*(b - 1)
|
|
522
|
-
a = ne.evaluate("dx/denom*(b - 1)")
|
|
623
|
+
rate = dx / kappa_x + alpha_x
|
|
624
|
+
total = two_over_dt + rate
|
|
625
|
+
b = (two_over_dt - rate) / total
|
|
626
|
+
a = -(dx / (kappa_x**2 + eps)) / total
|
|
523
627
|
|
|
524
628
|
if output_dtype is not None and output_dtype != xp.float64:
|
|
525
629
|
a = a.astype(output_dtype, copy=False)
|
|
@@ -1091,14 +1195,14 @@ class Medium:
|
|
|
1091
1195
|
*,
|
|
1092
1196
|
air_map: NDArray[np.int64] | None = None,
|
|
1093
1197
|
air_coords: NDArray[np.int64] | None = None,
|
|
1094
|
-
path_relaxation_parameters_database: Path =
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
/ "database"
|
|
1098
|
-
/ "relaxation_params_database_num_relax=2_20260113_0957.mat",
|
|
1099
|
-
n_relaxation_mechanisms: int = 2,
|
|
1198
|
+
path_relaxation_parameters_database: Path = ShippedDatabase.table,
|
|
1199
|
+
path_invalid_cells: Path | None = None,
|
|
1200
|
+
n_relaxation_mechanisms: int = ShippedDatabase.mechanisms,
|
|
1100
1201
|
attenuation_builder: str = "lookup",
|
|
1101
1202
|
use_isotropic_relaxation: bool = True,
|
|
1203
|
+
sound_speed_transfer: bool = True,
|
|
1204
|
+
band_scale: float = 1.0,
|
|
1205
|
+
scale_to_requested_alpha_coeff: bool = False,
|
|
1102
1206
|
n_jobs: int = -1,
|
|
1103
1207
|
dtype: type = np.float64,
|
|
1104
1208
|
use_gpu: bool = False,
|
|
@@ -1135,6 +1239,11 @@ class Medium:
|
|
|
1135
1239
|
Mutually exclusive with air_map.
|
|
1136
1240
|
path_relaxation_parameters_database : Path, optional
|
|
1137
1241
|
Path to the relaxation parameters database.
|
|
1242
|
+
path_invalid_cells : Path, optional
|
|
1243
|
+
Path to the JSON record an evaluation wrote, which names every
|
|
1244
|
+
invalid cell of the table and why it is invalid. A request that lands
|
|
1245
|
+
on one is warned about, and the lookup still serves it. Without it
|
|
1246
|
+
nothing is marked and the behaviour is unchanged.
|
|
1138
1247
|
n_relaxation_mechanisms : int, optional
|
|
1139
1248
|
Number of relaxation mechanisms, by default 4
|
|
1140
1249
|
attenuation_builder : str, optional
|
|
@@ -1148,6 +1257,33 @@ class Medium:
|
|
|
1148
1257
|
This option omits the anisotropic relaxation mechanisms to model the attenuation.
|
|
1149
1258
|
We usually recommend using isotropic relaxation mechanisms
|
|
1150
1259
|
unless the anisotropic attenuation is required for the simulation.
|
|
1260
|
+
sound_speed_transfer : bool, optional
|
|
1261
|
+
Correct the looked-up relaxation parameters for the medium's sound
|
|
1262
|
+
speed. The table was calibrated at 1540 m/s, where this is the
|
|
1263
|
+
identity. Elsewhere the uncorrected attenuation is wrong by
|
|
1264
|
+
1540/c, reaching 9.1% at a fat sound speed of 1412 m/s. Set False
|
|
1265
|
+
to reproduce a result produced before this existed.
|
|
1266
|
+
band_scale : float, optional
|
|
1267
|
+
Transfer the calibration to a frequency band scaled by this factor,
|
|
1268
|
+
so 0.1 moves the usable band from 1-20 MHz to 0.1-2 MHz. Give it
|
|
1269
|
+
explicitly rather than deriving it from the transmit frequency,
|
|
1270
|
+
which needs no transfer while it lies inside the calibrated band.
|
|
1271
|
+
A value other than 1.0 also moves the sound speed the built medium
|
|
1272
|
+
carries, by up to 0.5%, because the transfer re-anchors the
|
|
1273
|
+
Kramers-Kronig phase velocity. ``sound_speed`` is then the speed the
|
|
1274
|
+
medium carries at the calibration reference frequency of 5 MHz, and
|
|
1275
|
+
``MediumRelaxationMaps.sound_speed`` reports the base speed that
|
|
1276
|
+
gives it. See ``band_scaled_sound_speed``.
|
|
1277
|
+
scale_to_requested_alpha_coeff : bool, optional
|
|
1278
|
+
Give the requested attenuation coefficient rather than the
|
|
1279
|
+
calibrated level the lookup serves. The coefficient axis holds
|
|
1280
|
+
0.0022 and then 0.01 to 1.00 in absolute steps of 0.01, so a request
|
|
1281
|
+
between two levels is served the one above and a request past either
|
|
1282
|
+
end is clipped. Setting this True scales the relaxation departure by
|
|
1283
|
+
the shortfall instead. It matters most under a band transfer, which
|
|
1284
|
+
multiplies the request by a factor and often carries it off the
|
|
1285
|
+
axis. False, the default, reproduces every result produced before
|
|
1286
|
+
this existed.
|
|
1151
1287
|
n_jobs : int, optional
|
|
1152
1288
|
Number of parallel jobs for relaxation parameter calculation.
|
|
1153
1289
|
Default is -1, which uses all available CPUs.
|
|
@@ -1163,8 +1299,10 @@ class Medium:
|
|
|
1163
1299
|
"""
|
|
1164
1300
|
check_functions.check_compatible_value(
|
|
1165
1301
|
n_relaxation_mechanisms,
|
|
1166
|
-
[2],
|
|
1167
|
-
"
|
|
1302
|
+
[1, 2, 3, 4, 5, 6],
|
|
1303
|
+
"n_relaxation_mechanisms must be between 1 and 6. "
|
|
1304
|
+
"A count other than 2 needs the n_relax solver kernel, "
|
|
1305
|
+
"which reads the count from n_relax.dat.",
|
|
1168
1306
|
)
|
|
1169
1307
|
check_functions.check_instance(grid, Grid)
|
|
1170
1308
|
check_functions.check_path_exists(path_relaxation_parameters_database)
|
|
@@ -1215,19 +1353,14 @@ class Medium:
|
|
|
1215
1353
|
self.air_coords = np.empty((0, ndim), dtype=np.int64)
|
|
1216
1354
|
|
|
1217
1355
|
self.path_relaxation_parameters_database = path_relaxation_parameters_database
|
|
1356
|
+
self.path_invalid_cells = path_invalid_cells
|
|
1218
1357
|
self.n_relaxation_mechanisms = n_relaxation_mechanisms
|
|
1219
1358
|
self.use_isotropic_relaxation = use_isotropic_relaxation
|
|
1220
1359
|
|
|
1221
|
-
if self.n_relaxation_mechanisms != 2 and self.n_air > 0:
|
|
1222
|
-
warning_msg = (
|
|
1223
|
-
"Warning: Currently, only n_relaxation_mechanisms=2 supports air regions. "
|
|
1224
|
-
"Setting air regions to zero for other n_relaxation_mechanisms."
|
|
1225
|
-
)
|
|
1226
|
-
logger.warning(warning_msg)
|
|
1227
|
-
ndim = 3 if self.is_3d else 2
|
|
1228
|
-
self.air_coords = np.empty((0, ndim), dtype=np.int64)
|
|
1229
|
-
|
|
1230
1360
|
self.attenuation_builder = attenuation_builder
|
|
1361
|
+
self.sound_speed_transfer = sound_speed_transfer
|
|
1362
|
+
self.band_scale = band_scale
|
|
1363
|
+
self.scale_to_requested_alpha_coeff = scale_to_requested_alpha_coeff
|
|
1231
1364
|
self.n_jobs = n_jobs
|
|
1232
1365
|
self.check_fields()
|
|
1233
1366
|
logger.debug("Medium instance created.")
|
|
@@ -1412,48 +1545,125 @@ class Medium:
|
|
|
1412
1545
|
|
|
1413
1546
|
# ---
|
|
1414
1547
|
|
|
1415
|
-
def
|
|
1416
|
-
|
|
1548
|
+
def _relaxation_parameters_of(
|
|
1549
|
+
self,
|
|
1550
|
+
sound_speed: NDArray[np.float64],
|
|
1551
|
+
alpha_coeff: NDArray[np.float64],
|
|
1552
|
+
alpha_power: NDArray[np.float64],
|
|
1553
|
+
) -> dict[str, NDArray[np.float64]]:
|
|
1554
|
+
"""Look up the relaxation parameters of the given maps.
|
|
1417
1555
|
|
|
1418
|
-
|
|
1419
|
-
|
|
1556
|
+
Parameters
|
|
1557
|
+
----------
|
|
1558
|
+
sound_speed : NDArray[np.float64]
|
|
1559
|
+
The band scaled sound speed the parameters are built at [m/s].
|
|
1560
|
+
alpha_coeff : NDArray[np.float64]
|
|
1561
|
+
Attenuation coefficient [dB/cm/MHz^y].
|
|
1562
|
+
alpha_power : NDArray[np.float64]
|
|
1563
|
+
Attenuation power [-].
|
|
1420
1564
|
|
|
1421
1565
|
Returns
|
|
1422
1566
|
-------
|
|
1423
|
-
|
|
1424
|
-
|
|
1567
|
+
dict[str, NDArray[np.float64]]
|
|
1568
|
+
One entry for each relaxation parameter, of the shape given.
|
|
1425
1569
|
|
|
1426
1570
|
Raises
|
|
1427
1571
|
------
|
|
1428
|
-
|
|
1572
|
+
ValueError
|
|
1573
|
+
If the attenuation builder is not the lookup.
|
|
1429
1574
|
|
|
1430
1575
|
"""
|
|
1431
|
-
|
|
1432
|
-
if self.attenuation_builder == "lookup":
|
|
1433
|
-
relaxation_param_dict = generate_relaxation_params(
|
|
1434
|
-
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
1435
|
-
alpha_coeff=self.alpha_coeff,
|
|
1436
|
-
alpha_power=self.alpha_power,
|
|
1437
|
-
path_database=self.path_relaxation_parameters_database,
|
|
1438
|
-
)
|
|
1439
|
-
else:
|
|
1576
|
+
if self.attenuation_builder != "lookup":
|
|
1440
1577
|
error_msg = (
|
|
1441
1578
|
f"Unknown attenuation_builder: {self.attenuation_builder}. "
|
|
1442
1579
|
'Only "lookup" is supported currently.'
|
|
1443
1580
|
)
|
|
1444
1581
|
raise ValueError(error_msg)
|
|
1582
|
+
relaxation_param_dict = generate_relaxation_params(
|
|
1583
|
+
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
1584
|
+
alpha_coeff=alpha_coeff,
|
|
1585
|
+
alpha_power=alpha_power,
|
|
1586
|
+
path_database=self.path_relaxation_parameters_database,
|
|
1587
|
+
path_invalid_cells=self.path_invalid_cells,
|
|
1588
|
+
band_scale=self.band_scale,
|
|
1589
|
+
sound_speed=sound_speed if self.sound_speed_transfer else None,
|
|
1590
|
+
scale_to_requested_alpha_coeff=self.scale_to_requested_alpha_coeff,
|
|
1591
|
+
)
|
|
1592
|
+
_make_the_lossless_voxels_lossless(relaxation_param_dict, alpha_coeff)
|
|
1445
1593
|
if self.dtype != np.float64:
|
|
1446
1594
|
relaxation_param_dict = {
|
|
1447
|
-
|
|
1595
|
+
key: value.astype(self.dtype, copy=False)
|
|
1596
|
+
for key, value in relaxation_param_dict.items()
|
|
1448
1597
|
}
|
|
1598
|
+
return relaxation_param_dict
|
|
1599
|
+
|
|
1600
|
+
def relaxation_parameters_at(
|
|
1601
|
+
self,
|
|
1602
|
+
coords: NDArray[np.int64],
|
|
1603
|
+
) -> tuple[dict[str, NDArray[np.float64]], NDArray[np.float64]]:
|
|
1604
|
+
"""Return the relaxation parameters and the sound speed at the given positions.
|
|
1605
|
+
|
|
1606
|
+
Parameters
|
|
1607
|
+
----------
|
|
1608
|
+
coords : NDArray[np.int64]
|
|
1609
|
+
Positions, shape [n_positions, ndim].
|
|
1610
|
+
|
|
1611
|
+
Returns
|
|
1612
|
+
-------
|
|
1613
|
+
tuple[dict[str, NDArray[np.float64]], NDArray[np.float64]]
|
|
1614
|
+
One value for each relaxation parameter at each position, and the
|
|
1615
|
+
band scaled sound speed at each position [m/s].
|
|
1616
|
+
|
|
1617
|
+
"""
|
|
1618
|
+
index = tuple(np.asarray(coords).T)
|
|
1619
|
+
alpha_coeff = self._to_numpy(self.alpha_coeff[index])
|
|
1620
|
+
alpha_power = self._to_numpy(self.alpha_power[index])
|
|
1621
|
+
sound_speed = band_scaled_sound_speed(
|
|
1622
|
+
self._to_numpy(self.sound_speed[index]),
|
|
1623
|
+
alpha_coeff,
|
|
1624
|
+
alpha_power,
|
|
1625
|
+
self.band_scale,
|
|
1626
|
+
)
|
|
1627
|
+
parameters = self._relaxation_parameters_of(sound_speed, alpha_coeff, alpha_power)
|
|
1628
|
+
return parameters, sound_speed
|
|
1629
|
+
|
|
1630
|
+
def build(self) -> MediumRelaxationMaps:
|
|
1631
|
+
"""Retrieve the relaxation parameters from alpha and power maps.
|
|
1632
|
+
|
|
1633
|
+
it uses the relaxation parameters look up table
|
|
1634
|
+
to generate the relaxation parameters.
|
|
1635
|
+
|
|
1636
|
+
Returns
|
|
1637
|
+
-------
|
|
1638
|
+
MediumRelaxationMaps: An instance of MediumRelaxationMaps
|
|
1639
|
+
built from the retrieved relaxation parameters.
|
|
1640
|
+
|
|
1641
|
+
Raises
|
|
1642
|
+
------
|
|
1643
|
+
ValueError: If an unknown attenuation_builder is specified.
|
|
1644
|
+
|
|
1645
|
+
"""
|
|
1646
|
+
logger.debug("Building MediumRelaxationMaps from alpha and power maps.")
|
|
1647
|
+
sound_speed = band_scaled_sound_speed(
|
|
1648
|
+
self.sound_speed,
|
|
1649
|
+
self.alpha_coeff,
|
|
1650
|
+
self.alpha_power,
|
|
1651
|
+
self.band_scale,
|
|
1652
|
+
)
|
|
1653
|
+
relaxation_param_dict = self._relaxation_parameters_of(
|
|
1654
|
+
sound_speed,
|
|
1655
|
+
self.alpha_coeff,
|
|
1656
|
+
self.alpha_power,
|
|
1657
|
+
)
|
|
1449
1658
|
# Convert relaxation params to GPU if needed (MediumRelaxationMaps will
|
|
1450
1659
|
# call xp.asarray on them in __init__)
|
|
1451
1660
|
return MediumRelaxationMaps(
|
|
1452
1661
|
grid=self.grid,
|
|
1453
|
-
sound_speed=
|
|
1662
|
+
sound_speed=sound_speed,
|
|
1454
1663
|
density=self.density,
|
|
1455
1664
|
beta=self.beta,
|
|
1456
1665
|
relaxation_param_dict=relaxation_param_dict,
|
|
1666
|
+
alpha_coeff=self.alpha_coeff,
|
|
1457
1667
|
air_coords=self.air_coords,
|
|
1458
1668
|
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
1459
1669
|
use_isotropic_relaxation=self.use_isotropic_relaxation,
|
|
@@ -8,6 +8,7 @@ import numpy as np
|
|
|
8
8
|
from numpy.typing import NDArray
|
|
9
9
|
|
|
10
10
|
from fullwave import Grid, Medium
|
|
11
|
+
from fullwave.solver.shipped_database import ShippedDatabase
|
|
11
12
|
from fullwave.utils import check_functions
|
|
12
13
|
|
|
13
14
|
|
|
@@ -36,12 +37,8 @@ class Domain(ABC):
|
|
|
36
37
|
name: str,
|
|
37
38
|
grid: Grid,
|
|
38
39
|
*,
|
|
39
|
-
path_relaxation_parameters_database: Path =
|
|
40
|
-
|
|
41
|
-
/ "bins"
|
|
42
|
-
/ "database"
|
|
43
|
-
/ "relaxation_params_database_num_relax=2_20260113_0957.mat",
|
|
44
|
-
n_relaxation_mechanisms: int = 2,
|
|
40
|
+
path_relaxation_parameters_database: Path = ShippedDatabase.table,
|
|
41
|
+
n_relaxation_mechanisms: int = ShippedDatabase.mechanisms,
|
|
45
42
|
) -> None:
|
|
46
43
|
"""Initialize the Domain class.
|
|
47
44
|
|