fullwave25 1.2.3.dev1__tar.gz → 1.2.3rc1__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.3.dev1 → fullwave25-1.2.3rc1}/.bumpversion.toml +1 -1
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/PKG-INFO +1 -1
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/__init__.py +1 -1
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/grid.py +3 -3
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/binary_manager.py +1 -1
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/input_file_writer.py +12 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/launcher.py +20 -1
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/pml_builder.py +14 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/solver.py +14 -0
- fullwave25-1.2.3rc1/fullwave/source.py +326 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/pyproject.toml +1 -1
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/uv.lock +1 -1
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118 +0 -0
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda124 +0 -0
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda129 +0 -0
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda130 +0 -0
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda118 +0 -0
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda124 +0 -0
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda129 +0 -0
- fullwave25-1.2.3.dev1/fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda130 +0 -0
- fullwave25-1.2.3.dev1/fullwave/source.py +0 -206
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/.gitignore +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/.pre-commit-config.yaml +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/.python-version +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/20260120_0844.log +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/CITATION.cff +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/CLAUDE.md +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/CONTRIBUTING.md +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/LICENSE +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/Makefile +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/README.md +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/beamformer.m +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/experiments/__init__.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/experiments/exp_scatterer_diameter.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/beamformer/__init__.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/beamformer/beamformer.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/constants/__init__.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/constants/material_properties.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/__init__.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/domain.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/medium_builder.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/__init__.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/data/.keep +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_abdominal_wall.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_background.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_scatterer.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_simple.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_water_gel.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/sensor.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/__init__.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/bins/database/relaxation_params_database_num_relax=2_20260113_0957.mat +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/cuda_utils.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/solver/utils.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/transducer.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/__init__.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/check_functions.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/coordinates.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/memory_tempfile.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/numerical.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/plot_utils.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/pulse.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/relaxation_parameters.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/scatterer.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/utils/signal_process.py +0 -0
- {fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/ruff.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fullwave25
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3rc1
|
|
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
|
|
@@ -60,7 +60,7 @@ try:
|
|
|
60
60
|
__version__ = version("fullwave")
|
|
61
61
|
except PackageNotFoundError:
|
|
62
62
|
# Update via bump-my-version, not manually
|
|
63
|
-
__version__ = "1.2.3-
|
|
63
|
+
__version__ = "1.2.3-rc1"
|
|
64
64
|
|
|
65
65
|
VERSION = __version__ # for convenience
|
|
66
66
|
logger.info("Fullwave version: %s", __version__)
|
|
@@ -183,9 +183,9 @@ class Grid:
|
|
|
183
183
|
else " Grid spacing (grid.dx, grid.dy): "
|
|
184
184
|
)
|
|
185
185
|
grid_spacing_str = (
|
|
186
|
-
f"({self.dx * 1e3:.2e}
|
|
186
|
+
f"({self.dx * 1e3:.2e} mm, {self.dy * 1e3:.2e} mm, {self.dz * 1e3:.2e} mm)"
|
|
187
187
|
if self.is_3d
|
|
188
|
-
else f"({self.dx * 1e3:.2e}
|
|
188
|
+
else f"({self.dx * 1e3:.2e} mm, {self.dy * 1e3:.2e} mm)"
|
|
189
189
|
)
|
|
190
190
|
|
|
191
191
|
num_grid_points_str_desc = (
|
|
@@ -203,7 +203,7 @@ class Grid:
|
|
|
203
203
|
f" Speed of sound (grid.c0): {self.c0} m/s\n"
|
|
204
204
|
f" Points per wavelength (PPW) (grid.ppw): {self.ppw}\n"
|
|
205
205
|
f" Courant-Friedrichs-Lewy (CFL) number (grid.cfl): {self.cfl}\n"
|
|
206
|
-
f" Wavelength (grid.wavelength): {self.wavelength * 1e3:.2e}
|
|
206
|
+
f" Wavelength (grid.wavelength): {self.wavelength * 1e3:.2e} mm\n"
|
|
207
207
|
+ grid_spacing_str_desc
|
|
208
208
|
+ grid_spacing_str
|
|
209
209
|
+ "\n"
|
|
@@ -28,7 +28,7 @@ CACHE_DIR = Path.home() / ".cache" / "fullwave25" / "bins"
|
|
|
28
28
|
|
|
29
29
|
# Pinned release tag for the solver binaries.
|
|
30
30
|
# Update this only when new binaries are uploaded to a GitHub release.
|
|
31
|
-
BINARY_RELEASE_TAG = "
|
|
31
|
+
BINARY_RELEASE_TAG = "fullwave_bin_v1.1"
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def _download_url(filename: str, tag: str) -> str:
|
|
@@ -160,6 +160,15 @@ class InputFileWriter:
|
|
|
160
160
|
simulation_dir / "icmat.dat",
|
|
161
161
|
np.transpose(self.source.icmat),
|
|
162
162
|
)
|
|
163
|
+
p0_additive = getattr(self.source, "p0_additive", None)
|
|
164
|
+
incoords_add = getattr(self.source, "incoords_add", None)
|
|
165
|
+
if p0_additive is not None:
|
|
166
|
+
self._queue_ic_write(
|
|
167
|
+
simulation_dir / "icmat_add.dat",
|
|
168
|
+
np.transpose(p0_additive),
|
|
169
|
+
)
|
|
170
|
+
if incoords_add is not None:
|
|
171
|
+
self._queue_coords_write(simulation_dir / "icc_add.dat", incoords_add)
|
|
163
172
|
self._queue_coords_write(simulation_dir / "icc.dat", self.source.incoords)
|
|
164
173
|
self._copy_simulation_bin_file(simulation_dir)
|
|
165
174
|
|
|
@@ -1035,6 +1044,9 @@ class InputFileWriter:
|
|
|
1035
1044
|
("nTic", nt_ic),
|
|
1036
1045
|
("modT", self.sensor.sampling_modulus_time),
|
|
1037
1046
|
]
|
|
1047
|
+
n_sources_add = getattr(self.source, "n_sources_add", 0)
|
|
1048
|
+
if n_sources_add > 0:
|
|
1049
|
+
var_list.append(("ncoords_add", n_sources_add))
|
|
1038
1050
|
if self.is_3d:
|
|
1039
1051
|
var_list.extend(
|
|
1040
1052
|
[
|
|
@@ -30,6 +30,7 @@ class Launcher:
|
|
|
30
30
|
is_3d: bool = False,
|
|
31
31
|
use_gpu: bool = True,
|
|
32
32
|
cuda_device_id: str | int | list | None = None,
|
|
33
|
+
save_gpu_memory: bool = False,
|
|
33
34
|
) -> None:
|
|
34
35
|
"""Initialize a FullwaveLauncher instance.
|
|
35
36
|
|
|
@@ -50,6 +51,17 @@ class Launcher:
|
|
|
50
51
|
for multiple GPUs, provide a list of device IDs.
|
|
51
52
|
example 1: [0, 1] for using GPU 0 and GPU 1. or "0,1" as a string.
|
|
52
53
|
example 2: 2 for using GPU 2 or "2" as a string.
|
|
54
|
+
save_gpu_memory : bool, optional
|
|
55
|
+
Whether to save GPU memory by using ICMAT_MEMORY_SAVING flag in the simulation.
|
|
56
|
+
The simulation does not load initial conditions into GPU memory and
|
|
57
|
+
it loads the slice of the wavefield needed for the current time step
|
|
58
|
+
from CPU memory at each time step.
|
|
59
|
+
Defaults to False. If True, it may significantly reduce GPU memory usage,
|
|
60
|
+
but it may also increase the simulation time
|
|
61
|
+
due to the overhead of data transfer between CPU and GPU
|
|
62
|
+
depending on the hardware and the simulation settings.
|
|
63
|
+
useful in 3D simulations with large grid sizes
|
|
64
|
+
where GPU memory is a limiting factor.
|
|
53
65
|
|
|
54
66
|
"""
|
|
55
67
|
self._path_fullwave_simulation_bin = path_fullwave_simulation_bin
|
|
@@ -58,6 +70,7 @@ class Launcher:
|
|
|
58
70
|
self.is_3d = is_3d
|
|
59
71
|
self.use_gpu = use_gpu
|
|
60
72
|
self.cuda_device_id = self._configure_cuda_device_id(cuda_device_id)
|
|
73
|
+
self.save_gpu_memory = save_gpu_memory
|
|
61
74
|
logger.debug("Launcher instance created.")
|
|
62
75
|
|
|
63
76
|
@staticmethod
|
|
@@ -203,7 +216,12 @@ class Launcher:
|
|
|
203
216
|
logger.info("Running simulation...")
|
|
204
217
|
with (simulation_dir / "fw2_execution.log").open("w", encoding="utf-8") as file:
|
|
205
218
|
time_start = time()
|
|
206
|
-
|
|
219
|
+
env = os.environ.copy()
|
|
220
|
+
env["CUDA_VISIBLE_DEVICES"] = self.cuda_device_id
|
|
221
|
+
if self.save_gpu_memory:
|
|
222
|
+
env["ICMAT_MEMORY_SAVING"] = "1"
|
|
223
|
+
else:
|
|
224
|
+
env["ICMAT_MEMORY_SAVING"] = "0"
|
|
207
225
|
subprocess.run( # noqa: S603
|
|
208
226
|
command,
|
|
209
227
|
check=True,
|
|
@@ -211,6 +229,7 @@ class Launcher:
|
|
|
211
229
|
stdout=file,
|
|
212
230
|
stderr=file,
|
|
213
231
|
text=True,
|
|
232
|
+
env=env,
|
|
214
233
|
# check=False,
|
|
215
234
|
)
|
|
216
235
|
time_passed = time() - time_start
|
|
@@ -317,10 +317,17 @@ class PMLBuilder:
|
|
|
317
317
|
extended_grid_shape = tuple(
|
|
318
318
|
s + 2 * self.num_boundary_points for s in self.source_org.grid_shape
|
|
319
319
|
)
|
|
320
|
+
incoords_add_ext = (
|
|
321
|
+
self.source_org.incoords_add + self.num_boundary_points
|
|
322
|
+
if getattr(self.source_org, "incoords_add", None) is not None
|
|
323
|
+
else None
|
|
324
|
+
)
|
|
320
325
|
self.extended_source = fullwave.Source(
|
|
321
326
|
p0=self.source_org.p0,
|
|
322
327
|
coords=self.source_org.incoords + self.num_boundary_points,
|
|
323
328
|
grid_shape=extended_grid_shape,
|
|
329
|
+
p0_additive=self.source_org.p0_additive,
|
|
330
|
+
coords_additive=incoords_add_ext,
|
|
324
331
|
)
|
|
325
332
|
logger.debug("building extended source for pml...done")
|
|
326
333
|
|
|
@@ -1582,10 +1589,17 @@ class PMLBuilderExponentialAttenuation(PMLBuilder):
|
|
|
1582
1589
|
extended_grid_shape = tuple(
|
|
1583
1590
|
s + 2 * self.num_boundary_points for s in self.source_org.grid_shape
|
|
1584
1591
|
)
|
|
1592
|
+
incoords_add_ext = (
|
|
1593
|
+
self.source_org.incoords_add + self.num_boundary_points
|
|
1594
|
+
if getattr(self.source_org, "incoords_add", None) is not None
|
|
1595
|
+
else None
|
|
1596
|
+
)
|
|
1585
1597
|
self.extended_source = fullwave.Source(
|
|
1586
1598
|
p0=self.source_org.p0,
|
|
1587
1599
|
coords=self.source_org.incoords + self.num_boundary_points,
|
|
1588
1600
|
grid_shape=extended_grid_shape,
|
|
1601
|
+
p0_additive=self.source_org.p0_additive,
|
|
1602
|
+
coords_additive=incoords_add_ext,
|
|
1589
1603
|
)
|
|
1590
1604
|
extended_sensor_grid_shape = tuple(
|
|
1591
1605
|
s + 2 * self.num_boundary_points for s in self.sensor_org.grid_shape
|
|
@@ -327,6 +327,7 @@ class Solver:
|
|
|
327
327
|
use_exponential_attenuation: bool = False,
|
|
328
328
|
use_isotropic_relaxation: bool = True,
|
|
329
329
|
cuda_device_id: str | int | list | None = None,
|
|
330
|
+
save_gpu_memory: bool = False,
|
|
330
331
|
) -> None:
|
|
331
332
|
"""Initialize a Solver instance for the fullwave simulation.
|
|
332
333
|
|
|
@@ -402,6 +403,17 @@ class Solver:
|
|
|
402
403
|
for multiple GPUs, provide a list of device IDs.
|
|
403
404
|
example 1: [0, 1] for using GPU 0 and GPU 1. or "0,1" as a string.
|
|
404
405
|
example 2: 2 for using GPU 2 or "2" as a string.
|
|
406
|
+
save_gpu_memory : bool, optional
|
|
407
|
+
Whether to save GPU memory by using ICMAT_MEMORY_SAVING flag in the simulation.
|
|
408
|
+
The simulation does not load initial conditions into GPU memory and
|
|
409
|
+
it loads the slice of the wavefield needed for the current time step
|
|
410
|
+
from CPU memory at each time step.
|
|
411
|
+
Defaults to False. If True, it may significantly reduce GPU memory usage,
|
|
412
|
+
but it may also increase the simulation time
|
|
413
|
+
due to the overhead of data transfer between CPU and GPU
|
|
414
|
+
depending on the hardware and the simulation settings.
|
|
415
|
+
useful in 3D simulations with large grid sizes
|
|
416
|
+
where GPU memory is a limiting factor.
|
|
405
417
|
|
|
406
418
|
Raises
|
|
407
419
|
------
|
|
@@ -418,6 +430,7 @@ class Solver:
|
|
|
418
430
|
self.medium: fullwave.Medium
|
|
419
431
|
self.grid: fullwave.Grid
|
|
420
432
|
self.input_file_writer: InputFileWriter
|
|
433
|
+
self.save_gpu_memory = save_gpu_memory
|
|
421
434
|
|
|
422
435
|
self.run_on_memory = run_on_memory
|
|
423
436
|
if run_on_memory:
|
|
@@ -540,6 +553,7 @@ class Solver:
|
|
|
540
553
|
is_3d=self.is_3d,
|
|
541
554
|
use_gpu=self.use_gpu,
|
|
542
555
|
cuda_device_id=self.cuda_device_id,
|
|
556
|
+
save_gpu_memory=self.save_gpu_memory,
|
|
543
557
|
)
|
|
544
558
|
|
|
545
559
|
if use_exponential_attenuation:
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"""Source class for Fullwave."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from matplotlib import pyplot as plt
|
|
9
|
+
from numpy.typing import NDArray
|
|
10
|
+
|
|
11
|
+
from fullwave.utils import plot_utils
|
|
12
|
+
from fullwave.utils.coordinates import coords_to_map, map_to_coords
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger("__main__." + __name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class Source:
|
|
19
|
+
"""Source class for Fullwave."""
|
|
20
|
+
|
|
21
|
+
p0: NDArray[np.float64]
|
|
22
|
+
incoords: NDArray[np.int64]
|
|
23
|
+
grid_shape: tuple[int, ...]
|
|
24
|
+
p0_additive: NDArray[np.float64] | None = None
|
|
25
|
+
incoords_add: NDArray[np.int64] | None = None
|
|
26
|
+
|
|
27
|
+
def __init__( # noqa: C901 PLR0912 PLR0915
|
|
28
|
+
self,
|
|
29
|
+
p0: NDArray[np.float64] | None = None,
|
|
30
|
+
mask: NDArray[np.bool] | None = None,
|
|
31
|
+
*,
|
|
32
|
+
# ---
|
|
33
|
+
p0_additive: NDArray[np.float64] | None = None,
|
|
34
|
+
mask_additive: NDArray[np.bool] | None = None,
|
|
35
|
+
# ---
|
|
36
|
+
coords: NDArray[np.int64] | None = None,
|
|
37
|
+
coords_additive: NDArray[np.int64] | None = None,
|
|
38
|
+
# ---
|
|
39
|
+
grid_shape: tuple[int, ...] | None = None,
|
|
40
|
+
) -> None:
|
|
41
|
+
"""Source class for Fullwave.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
p0 : NDArray[np.float64] | None
|
|
46
|
+
Time-varying pressure at each source position; shape [n_sources, nt].
|
|
47
|
+
If None, p0_additive must be provided (additive-only / soft initial condition):
|
|
48
|
+
icmat is written as zeros and only the additive term drives the source.
|
|
49
|
+
mask : NDArray[np.bool] | None
|
|
50
|
+
binary matrix specifying the positions of the time varying pressure source distribution
|
|
51
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D.
|
|
52
|
+
Mutually exclusive with coords/grid_shape.
|
|
53
|
+
coords : NDArray[np.int64] | None
|
|
54
|
+
Coordinate array of source positions (hard source); shape [n_sources, ndim].
|
|
55
|
+
Must be provided together with grid_shape.
|
|
56
|
+
grid_shape : tuple[int, ...] | None
|
|
57
|
+
Shape of the computational grid. Required when using coords input.
|
|
58
|
+
p0_additive : NDArray[np.float64] | None
|
|
59
|
+
Optional additive (soft) source term; shape [n_sources_add, nt].
|
|
60
|
+
When provided, positions come from coords_additive or mask_additive,
|
|
61
|
+
or default to primary coords.
|
|
62
|
+
mask_additive : NDArray[np.bool] | None
|
|
63
|
+
Mask for additive source positions; shape matches grid_shape.
|
|
64
|
+
Mutually exclusive with coords_additive.
|
|
65
|
+
coords_additive : NDArray[np.int64] | None
|
|
66
|
+
Coordinates for the additive source; shape [n_sources_add, ndim].
|
|
67
|
+
If None and p0_additive is provided, defaults to primary incoords.
|
|
68
|
+
Mutually exclusive with mask_additive.
|
|
69
|
+
|
|
70
|
+
Raises
|
|
71
|
+
------
|
|
72
|
+
ValueError
|
|
73
|
+
If grid_shape is missing when using coords or additive-only.
|
|
74
|
+
If both mask and coords, or both coords_additive and mask_additive, are provided.
|
|
75
|
+
If primary source positions cannot be resolved (need coords+grid_shape,
|
|
76
|
+
or mask, or additive-only args).
|
|
77
|
+
If both p0 and p0_additive are None.
|
|
78
|
+
If p0 / p0_additive row counts do not match their coordinate arrays.
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
# --- Resolve primary source positions and grid_shape ---
|
|
82
|
+
if coords is not None:
|
|
83
|
+
if grid_shape is None:
|
|
84
|
+
error_msg = "grid_shape is required when using coords"
|
|
85
|
+
raise ValueError(error_msg)
|
|
86
|
+
if mask is not None:
|
|
87
|
+
error_msg = "mask and coords are mutually exclusive"
|
|
88
|
+
raise ValueError(error_msg)
|
|
89
|
+
self.incoords = np.atleast_2d(coords).astype(np.int64, copy=False)
|
|
90
|
+
self.grid_shape = tuple(grid_shape)
|
|
91
|
+
elif mask is not None:
|
|
92
|
+
mask = np.atleast_2d(mask)
|
|
93
|
+
self.grid_shape = mask.shape
|
|
94
|
+
self.incoords = map_to_coords(mask)
|
|
95
|
+
elif p0_additive is not None and (coords_additive is not None or mask_additive is not None):
|
|
96
|
+
# Additive-only: no primary mask/coords; use additive positions as primary
|
|
97
|
+
if coords_additive is not None:
|
|
98
|
+
if grid_shape is None:
|
|
99
|
+
error_msg = "grid_shape is required for additive-only with coords_additive"
|
|
100
|
+
raise ValueError(
|
|
101
|
+
error_msg,
|
|
102
|
+
)
|
|
103
|
+
self.incoords = np.atleast_2d(coords_additive).astype(
|
|
104
|
+
np.int64,
|
|
105
|
+
copy=False,
|
|
106
|
+
)
|
|
107
|
+
self.grid_shape = tuple(grid_shape)
|
|
108
|
+
else:
|
|
109
|
+
assert mask_additive is not None
|
|
110
|
+
mask_add = np.atleast_2d(mask_additive)
|
|
111
|
+
self.grid_shape = mask_add.shape
|
|
112
|
+
self.incoords = map_to_coords(mask_add)
|
|
113
|
+
else:
|
|
114
|
+
error_msg = (
|
|
115
|
+
"Provide (coords + grid_shape), or mask, or"
|
|
116
|
+
" (p0_additive + (coords_additive or mask_additive))"
|
|
117
|
+
)
|
|
118
|
+
raise ValueError(
|
|
119
|
+
error_msg,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
if p0 is None and p0_additive is None:
|
|
123
|
+
error_msg = "At least one of p0 or p0_additive must be provided"
|
|
124
|
+
raise ValueError(error_msg)
|
|
125
|
+
|
|
126
|
+
# --- Resolve additive coords (for later use) ---
|
|
127
|
+
if coords_additive is not None and mask_additive is not None:
|
|
128
|
+
error_msg = "coords_additive and mask_additive are mutually exclusive"
|
|
129
|
+
raise ValueError(error_msg)
|
|
130
|
+
if coords_additive is not None:
|
|
131
|
+
_coords_add = np.atleast_2d(coords_additive).astype(np.int64, copy=False)
|
|
132
|
+
elif mask_additive is not None:
|
|
133
|
+
mask_add = np.atleast_2d(mask_additive)
|
|
134
|
+
if mask_add.shape != self.grid_shape:
|
|
135
|
+
error_msg = "mask_additive shape must match grid_shape"
|
|
136
|
+
raise ValueError(error_msg)
|
|
137
|
+
_coords_add = map_to_coords(mask_add)
|
|
138
|
+
else:
|
|
139
|
+
_coords_add = None
|
|
140
|
+
|
|
141
|
+
# --- Set p0 and p0_additive ---
|
|
142
|
+
if p0 is not None:
|
|
143
|
+
self.p0 = np.atleast_2d(p0)
|
|
144
|
+
if self.p0.shape[0] != self.incoords.shape[0]:
|
|
145
|
+
error_msg = (
|
|
146
|
+
f"p0 has {self.p0.shape[0]} rows but "
|
|
147
|
+
f"incoords has {self.incoords.shape[0]} (must match)"
|
|
148
|
+
)
|
|
149
|
+
raise ValueError(error_msg)
|
|
150
|
+
self.p0_additive = np.atleast_2d(p0_additive) if p0_additive is not None else None
|
|
151
|
+
else:
|
|
152
|
+
# Additive-only: icmat written as zeros
|
|
153
|
+
p0_add = np.atleast_2d(p0_additive)
|
|
154
|
+
n_add = _coords_add.shape[0] if _coords_add is not None else self.incoords.shape[0]
|
|
155
|
+
if p0_add.shape[0] != n_add:
|
|
156
|
+
error_msg = (
|
|
157
|
+
f"p0_additive shape {p0_add.shape} must have {n_add} rows "
|
|
158
|
+
f"(coords_additive/mask_additive or primary coords)"
|
|
159
|
+
)
|
|
160
|
+
raise ValueError(error_msg)
|
|
161
|
+
if _coords_add is None:
|
|
162
|
+
self.p0 = np.zeros_like(p0_add, dtype=np.float64)
|
|
163
|
+
else:
|
|
164
|
+
self.p0 = np.zeros(
|
|
165
|
+
(self.incoords.shape[0], p0_add.shape[1]),
|
|
166
|
+
dtype=np.float64,
|
|
167
|
+
)
|
|
168
|
+
self.p0_additive = p0_add
|
|
169
|
+
|
|
170
|
+
# --- Set incoords_add for writer/binary ---
|
|
171
|
+
if self.p0_additive is not None:
|
|
172
|
+
self.incoords_add = _coords_add if _coords_add is not None else self.incoords
|
|
173
|
+
else:
|
|
174
|
+
self.incoords_add = None
|
|
175
|
+
|
|
176
|
+
self.is_3d = len(self.grid_shape) == 3
|
|
177
|
+
super().__init__()
|
|
178
|
+
self.__post_init__()
|
|
179
|
+
logger.debug("Source instance created.")
|
|
180
|
+
|
|
181
|
+
def __post_init__(self) -> None:
|
|
182
|
+
"""Post-initialization processing for Source.
|
|
183
|
+
|
|
184
|
+
Raises
|
|
185
|
+
------
|
|
186
|
+
ValueError
|
|
187
|
+
If the number of sources in the input signal
|
|
188
|
+
does not match the number of source coordinates.
|
|
189
|
+
If p0_additive length does not match incoords_add.
|
|
190
|
+
|
|
191
|
+
"""
|
|
192
|
+
self.p0 = np.atleast_2d(self.p0)
|
|
193
|
+
if self.p0.shape[0] != self.incoords.shape[0]:
|
|
194
|
+
error_msg = "Input signal has the wrong number of elements"
|
|
195
|
+
raise ValueError(error_msg)
|
|
196
|
+
if self.p0_additive is not None and self.incoords_add is not None:
|
|
197
|
+
self.p0_additive = np.atleast_2d(self.p0_additive)
|
|
198
|
+
if self.p0_additive.shape[0] != self.incoords_add.shape[0]:
|
|
199
|
+
error_msg = (
|
|
200
|
+
f"p0_additive shape {self.p0_additive.shape} must have "
|
|
201
|
+
f"{self.incoords_add.shape[0]} rows (incoords_add)"
|
|
202
|
+
)
|
|
203
|
+
raise ValueError(error_msg)
|
|
204
|
+
|
|
205
|
+
def validate(self, grid_shape: NDArray[np.int64] | tuple) -> None:
|
|
206
|
+
"""Check if the source coordinates are consistent with the grid shape."""
|
|
207
|
+
grid_shape = tuple(grid_shape) if isinstance(grid_shape, np.ndarray) else grid_shape
|
|
208
|
+
assert self.grid_shape == grid_shape, f"{self.grid_shape} != {grid_shape}"
|
|
209
|
+
assert self.n_sources > 0 or self.n_sources_add > 0, "No active source found."
|
|
210
|
+
logger.debug("Source validated against grid shape.")
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def icmat(self) -> NDArray[np.float64]:
|
|
214
|
+
"""Returns icmat for the compatibility with the fullwave code."""
|
|
215
|
+
return self.p0
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def mask(self) -> NDArray[np.int64]:
|
|
219
|
+
"""Returns the source mask.
|
|
220
|
+
|
|
221
|
+
it calculates the source mask from the source coordinates to reduce the memory usage.
|
|
222
|
+
"""
|
|
223
|
+
return coords_to_map(
|
|
224
|
+
self.incoords,
|
|
225
|
+
grid_shape=self.grid_shape,
|
|
226
|
+
is_3d=self.is_3d,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def ncoords(self) -> int:
|
|
231
|
+
"""Return the number of sources.
|
|
232
|
+
|
|
233
|
+
ailiased to n_sensors for the compatibility with matlab version
|
|
234
|
+
"""
|
|
235
|
+
return self.n_sources
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def n_sources(self) -> int:
|
|
239
|
+
"""Return the number of sources (hard / primary)."""
|
|
240
|
+
return self.incoords.shape[0]
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def n_sources_add(self) -> int:
|
|
244
|
+
"""Return the number of additive (soft) source positions."""
|
|
245
|
+
if self.incoords_add is None:
|
|
246
|
+
return 0
|
|
247
|
+
return self.incoords_add.shape[0]
|
|
248
|
+
|
|
249
|
+
def plot(
|
|
250
|
+
self,
|
|
251
|
+
export_path: Path | str | None = Path("./temp/temp.png"),
|
|
252
|
+
*,
|
|
253
|
+
show: bool = False,
|
|
254
|
+
dpi: int = 3000,
|
|
255
|
+
) -> None:
|
|
256
|
+
"""Plot the transducer mask, optionally exporting and displaying the figure.
|
|
257
|
+
|
|
258
|
+
Raises
|
|
259
|
+
------
|
|
260
|
+
ValueError
|
|
261
|
+
If 3D plotting is requested but not supported.
|
|
262
|
+
|
|
263
|
+
"""
|
|
264
|
+
if self.is_3d:
|
|
265
|
+
error_msg = "3D plotting is not supported yet."
|
|
266
|
+
raise ValueError(error_msg)
|
|
267
|
+
plt.close("all")
|
|
268
|
+
fig, _ = plt.subplots()
|
|
269
|
+
fig = plot_utils.plot_array(
|
|
270
|
+
self.mask,
|
|
271
|
+
xlim=[-10, self.mask.shape[1] + 10],
|
|
272
|
+
ylim=[-10, self.mask.shape[0] + 10],
|
|
273
|
+
reverse_y_axis=True,
|
|
274
|
+
save=False,
|
|
275
|
+
clear_all=False,
|
|
276
|
+
fig=fig,
|
|
277
|
+
colorbar=True,
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
if export_path is not None:
|
|
281
|
+
plt.savefig(export_path, dpi=dpi)
|
|
282
|
+
if show:
|
|
283
|
+
plt.show()
|
|
284
|
+
|
|
285
|
+
plt.close("all")
|
|
286
|
+
|
|
287
|
+
def print_info(self) -> None:
|
|
288
|
+
"""Print source information to the logger."""
|
|
289
|
+
print(str(self))
|
|
290
|
+
|
|
291
|
+
def summary(self) -> None:
|
|
292
|
+
"""Alias for print_info."""
|
|
293
|
+
self.print_info()
|
|
294
|
+
|
|
295
|
+
def __str__(self) -> str:
|
|
296
|
+
"""Show source information.
|
|
297
|
+
|
|
298
|
+
Returns
|
|
299
|
+
-------
|
|
300
|
+
str
|
|
301
|
+
Formatted string containing source information.
|
|
302
|
+
|
|
303
|
+
"""
|
|
304
|
+
lines = [
|
|
305
|
+
"Source:",
|
|
306
|
+
f" Number of sources: {self.n_sources}",
|
|
307
|
+
f" Grid shape: {self.grid_shape}",
|
|
308
|
+
f" Is 3D: {self.is_3d}",
|
|
309
|
+
f" p0 shape: {self.p0.shape}",
|
|
310
|
+
]
|
|
311
|
+
if self.p0_additive is not None:
|
|
312
|
+
lines.append(f" p0_additive shape: {self.p0_additive.shape}")
|
|
313
|
+
if self.incoords_add is not None:
|
|
314
|
+
lines.append(f" incoords_add: {self.incoords_add.shape[0]} points")
|
|
315
|
+
return "\n".join(lines) + "\n"
|
|
316
|
+
|
|
317
|
+
def __repr__(self) -> str:
|
|
318
|
+
"""Show source information.
|
|
319
|
+
|
|
320
|
+
Returns
|
|
321
|
+
-------
|
|
322
|
+
str
|
|
323
|
+
Formatted string containing source information.
|
|
324
|
+
|
|
325
|
+
"""
|
|
326
|
+
return self.__str__()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "fullwave25"
|
|
3
|
-
version = "1.2.3-
|
|
3
|
+
version = "1.2.3-rc1" # Update via bump-my-version, not manually
|
|
4
4
|
description = "Fullwave 2.5: Ultrasound wave propagation simulation with heterogeneous power law attenuation modelling capabilities"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
"""Source class for Fullwave."""
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
import numpy as np
|
|
8
|
-
from matplotlib import pyplot as plt
|
|
9
|
-
from numpy.typing import NDArray
|
|
10
|
-
|
|
11
|
-
from fullwave.utils import plot_utils
|
|
12
|
-
from fullwave.utils.coordinates import coords_to_map, map_to_coords
|
|
13
|
-
|
|
14
|
-
logger = logging.getLogger("__main__." + __name__)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
@dataclass
|
|
18
|
-
class Source:
|
|
19
|
-
"""Source class for Fullwave."""
|
|
20
|
-
|
|
21
|
-
p0: NDArray[np.float64]
|
|
22
|
-
incoords: NDArray[np.int64]
|
|
23
|
-
grid_shape: tuple[int, ...]
|
|
24
|
-
|
|
25
|
-
def __init__(
|
|
26
|
-
self,
|
|
27
|
-
p0: NDArray[np.float64],
|
|
28
|
-
mask: NDArray[np.bool] | None = None,
|
|
29
|
-
*,
|
|
30
|
-
coords: NDArray[np.int64] | None = None,
|
|
31
|
-
grid_shape: tuple[int, ...] | None = None,
|
|
32
|
-
) -> None:
|
|
33
|
-
"""Source class for Fullwave.
|
|
34
|
-
|
|
35
|
-
Parameters
|
|
36
|
-
----------
|
|
37
|
-
p0 : NDArray[np.float64]
|
|
38
|
-
time varying pressure at each of the source positions given by source.p_mask
|
|
39
|
-
shape: [n_sources, nt]
|
|
40
|
-
mask : NDArray[np.bool] | None
|
|
41
|
-
binary matrix specifying the positions of the time varying pressure source distribution
|
|
42
|
-
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D.
|
|
43
|
-
Mutually exclusive with coords/grid_shape.
|
|
44
|
-
coords : NDArray[np.int64] | None
|
|
45
|
-
Coordinate array of source positions, shape [n_sources, ndim].
|
|
46
|
-
Must be provided together with grid_shape.
|
|
47
|
-
grid_shape : tuple[int, ...] | None
|
|
48
|
-
Shape of the computational grid. Required when using coords input.
|
|
49
|
-
|
|
50
|
-
Raises
|
|
51
|
-
------
|
|
52
|
-
ValueError
|
|
53
|
-
If grid_shape is not provided when using coords input.
|
|
54
|
-
If both mask and coords are provided (mutually exclusive).
|
|
55
|
-
If neither mask nor coords (with grid_shape) are provided.
|
|
56
|
-
|
|
57
|
-
"""
|
|
58
|
-
self.p0 = np.atleast_2d(p0)
|
|
59
|
-
|
|
60
|
-
if coords is not None:
|
|
61
|
-
if grid_shape is None:
|
|
62
|
-
msg = "grid_shape is required when using coords input"
|
|
63
|
-
raise ValueError(msg)
|
|
64
|
-
if mask is not None:
|
|
65
|
-
msg = "mask and coords are mutually exclusive"
|
|
66
|
-
raise ValueError(msg)
|
|
67
|
-
self.incoords = np.atleast_2d(coords).astype(np.int64, copy=False)
|
|
68
|
-
self.grid_shape = tuple(grid_shape)
|
|
69
|
-
elif mask is not None:
|
|
70
|
-
mask = np.atleast_2d(mask)
|
|
71
|
-
self.grid_shape = mask.shape
|
|
72
|
-
self.incoords = map_to_coords(mask)
|
|
73
|
-
else:
|
|
74
|
-
msg = "Either mask or coords (with grid_shape) must be provided"
|
|
75
|
-
raise ValueError(msg)
|
|
76
|
-
|
|
77
|
-
self.is_3d = len(self.grid_shape) == 3
|
|
78
|
-
super().__init__()
|
|
79
|
-
self.__post_init__()
|
|
80
|
-
logger.debug("Source instance created.")
|
|
81
|
-
|
|
82
|
-
def __post_init__(self) -> None:
|
|
83
|
-
"""Post-initialization processing for Source.
|
|
84
|
-
|
|
85
|
-
Raises
|
|
86
|
-
------
|
|
87
|
-
ValueError
|
|
88
|
-
If the number of sources in the input signal
|
|
89
|
-
does not match the number of source coordinates.
|
|
90
|
-
|
|
91
|
-
"""
|
|
92
|
-
self.p0 = np.atleast_2d(self.p0)
|
|
93
|
-
if self.p0.shape[0] != self.incoords.shape[0]:
|
|
94
|
-
error_msg = "Input signal has the wrong number of elements"
|
|
95
|
-
raise ValueError(error_msg)
|
|
96
|
-
|
|
97
|
-
def validate(self, grid_shape: NDArray[np.int64] | tuple) -> None:
|
|
98
|
-
"""Check if the source coordinates are consistent with the grid shape."""
|
|
99
|
-
grid_shape = tuple(grid_shape) if isinstance(grid_shape, np.ndarray) else grid_shape
|
|
100
|
-
assert self.grid_shape == grid_shape, f"{self.grid_shape} != {grid_shape}"
|
|
101
|
-
assert self.n_sources > 0, "No active source found."
|
|
102
|
-
logger.debug("Source validated against grid shape.")
|
|
103
|
-
|
|
104
|
-
@property
|
|
105
|
-
def icmat(self) -> NDArray[np.float64]:
|
|
106
|
-
"""Returns icmat for the compatibility with the fullwave code."""
|
|
107
|
-
return self.p0
|
|
108
|
-
|
|
109
|
-
@property
|
|
110
|
-
def mask(self) -> NDArray[np.int64]:
|
|
111
|
-
"""Returns the source mask.
|
|
112
|
-
|
|
113
|
-
it calculates the source mask from the source coordinates to reduce the memory usage.
|
|
114
|
-
"""
|
|
115
|
-
return coords_to_map(
|
|
116
|
-
self.incoords,
|
|
117
|
-
grid_shape=self.grid_shape,
|
|
118
|
-
is_3d=self.is_3d,
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
@property
|
|
122
|
-
def ncoords(self) -> int:
|
|
123
|
-
"""Return the number of sources.
|
|
124
|
-
|
|
125
|
-
ailiased to n_sensors for the compatibility with matlab version
|
|
126
|
-
"""
|
|
127
|
-
return self.n_sources
|
|
128
|
-
|
|
129
|
-
@property
|
|
130
|
-
def n_sources(self) -> int:
|
|
131
|
-
"""Return the number of sources."""
|
|
132
|
-
return self.incoords.shape[0]
|
|
133
|
-
|
|
134
|
-
def plot(
|
|
135
|
-
self,
|
|
136
|
-
export_path: Path | str | None = Path("./temp/temp.png"),
|
|
137
|
-
*,
|
|
138
|
-
show: bool = False,
|
|
139
|
-
dpi: int = 3000,
|
|
140
|
-
) -> None:
|
|
141
|
-
"""Plot the transducer mask, optionally exporting and displaying the figure.
|
|
142
|
-
|
|
143
|
-
Raises
|
|
144
|
-
------
|
|
145
|
-
ValueError
|
|
146
|
-
If 3D plotting is requested but not supported.
|
|
147
|
-
|
|
148
|
-
"""
|
|
149
|
-
if self.is_3d:
|
|
150
|
-
error_msg = "3D plotting is not supported yet."
|
|
151
|
-
raise ValueError(error_msg)
|
|
152
|
-
plt.close("all")
|
|
153
|
-
fig, _ = plt.subplots()
|
|
154
|
-
fig = plot_utils.plot_array(
|
|
155
|
-
self.mask,
|
|
156
|
-
xlim=[-10, self.mask.shape[1] + 10],
|
|
157
|
-
ylim=[-10, self.mask.shape[0] + 10],
|
|
158
|
-
reverse_y_axis=True,
|
|
159
|
-
save=False,
|
|
160
|
-
clear_all=False,
|
|
161
|
-
fig=fig,
|
|
162
|
-
colorbar=True,
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
if export_path is not None:
|
|
166
|
-
plt.savefig(export_path, dpi=dpi)
|
|
167
|
-
if show:
|
|
168
|
-
plt.show()
|
|
169
|
-
|
|
170
|
-
plt.close("all")
|
|
171
|
-
|
|
172
|
-
def print_info(self) -> None:
|
|
173
|
-
"""Print source information to the logger."""
|
|
174
|
-
print(str(self))
|
|
175
|
-
|
|
176
|
-
def summary(self) -> None:
|
|
177
|
-
"""Alias for print_info."""
|
|
178
|
-
self.print_info()
|
|
179
|
-
|
|
180
|
-
def __str__(self) -> str:
|
|
181
|
-
"""Show source information.
|
|
182
|
-
|
|
183
|
-
Returns
|
|
184
|
-
-------
|
|
185
|
-
str
|
|
186
|
-
Formatted string containing source information.
|
|
187
|
-
|
|
188
|
-
"""
|
|
189
|
-
return (
|
|
190
|
-
f"Source: \n"
|
|
191
|
-
f" Number of sources: {self.n_sources}\n"
|
|
192
|
-
f" Grid shape: {self.grid_shape}\n"
|
|
193
|
-
f" Is 3D: {self.is_3d}\n"
|
|
194
|
-
f" p0 shape: {self.p0.shape}\n"
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
def __repr__(self) -> str:
|
|
198
|
-
"""Show source information.
|
|
199
|
-
|
|
200
|
-
Returns
|
|
201
|
-
-------
|
|
202
|
-
str
|
|
203
|
-
Formatted string containing source information.
|
|
204
|
-
|
|
205
|
-
"""
|
|
206
|
-
return self.__str__()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_background.py
RENAMED
|
File without changes
|
{fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_scatterer.py
RENAMED
|
File without changes
|
{fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_simple.py
RENAMED
|
File without changes
|
{fullwave25-1.2.3.dev1 → fullwave25-1.2.3rc1}/fullwave/medium_builder/presets/domain_water_gel.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|