fullwave25 1.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fullwave25 might be problematic. Click here for more details.
- fullwave/__init__.py +28 -0
- fullwave/constants/__init__.py +5 -0
- fullwave/constants/material_properties.py +112 -0
- fullwave/grid.py +222 -0
- fullwave/medium.py +1042 -0
- fullwave/medium_builder/__init__.py +12 -0
- fullwave/medium_builder/domain.py +151 -0
- fullwave/medium_builder/medium_builder.py +198 -0
- fullwave/medium_builder/presets/__init__.py +8 -0
- fullwave/medium_builder/presets/data/.keep +0 -0
- fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat +0 -0
- fullwave/medium_builder/presets/domain_abdominal_wall.py +293 -0
- fullwave/medium_builder/presets/domain_background.py +140 -0
- fullwave/medium_builder/presets/domain_scatterer.py +179 -0
- fullwave/medium_builder/presets/domain_simple.py +92 -0
- fullwave/medium_builder/presets/domain_water_gel.py +1 -0
- fullwave/sensor.py +161 -0
- fullwave/solver/__init__.py +1 -0
- fullwave/solver/bins/database/relaxation_params_database_num_relax=2_20251027_1437.mat +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenu +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_100_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_101_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_120_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_89_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_89_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_89_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_100_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_101_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_120_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda129 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda118 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda124 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda126 +0 -0
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_100_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_101_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_120_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_100_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_101_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_120_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda129 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda118 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda124 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda126 +0 -0
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_100_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_101_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_120_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_100_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_101_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_120_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda129 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda118 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda124 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda126 +0 -0
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda129 +0 -0
- fullwave/solver/cuda_utils.py +392 -0
- fullwave/solver/input_file_writer.py +853 -0
- fullwave/solver/launcher.py +134 -0
- fullwave/solver/pml_builder.py +1923 -0
- fullwave/solver/solver.py +750 -0
- fullwave/solver/utils.py +83 -0
- fullwave/source.py +173 -0
- fullwave/transducer.py +1003 -0
- fullwave/utils/__init__.py +12 -0
- fullwave/utils/check_functions.py +48 -0
- fullwave/utils/coordinates.py +155 -0
- fullwave/utils/memory_tempfile.py +439 -0
- fullwave/utils/numerical.py +111 -0
- fullwave/utils/plot_utils.py +1122 -0
- fullwave/utils/pulse.py +72 -0
- fullwave/utils/relaxation_parameters.py +212 -0
- fullwave/utils/signal_process.py +197 -0
- fullwave25-1.0.7.dist-info/METADATA +292 -0
- fullwave25-1.0.7.dist-info/RECORD +225 -0
- fullwave25-1.0.7.dist-info/WHEEL +4 -0
fullwave/medium.py
ADDED
|
@@ -0,0 +1,1042 @@
|
|
|
1
|
+
"""Medium class for Fullwave."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections import OrderedDict
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
import numpy as np
|
|
10
|
+
from numpy.typing import NDArray
|
|
11
|
+
|
|
12
|
+
from fullwave import Grid
|
|
13
|
+
from fullwave.solver.utils import initialize_relaxation_param_dict
|
|
14
|
+
from fullwave.utils import check_functions, plot_utils
|
|
15
|
+
from fullwave.utils.relaxation_parameters import generate_relaxation_params
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("__main__." + __name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class MediumRelaxationMaps:
|
|
22
|
+
"""Medium class for Fullwave."""
|
|
23
|
+
|
|
24
|
+
grid: Grid
|
|
25
|
+
sound_speed: NDArray[np.float64]
|
|
26
|
+
density: NDArray[np.float64]
|
|
27
|
+
beta: NDArray[np.float64]
|
|
28
|
+
air_map: NDArray[np.int64]
|
|
29
|
+
relaxation_param_dict: dict[str, NDArray[np.float64]]
|
|
30
|
+
relaxation_param_dict_for_fw2: dict[str, NDArray[np.float64]]
|
|
31
|
+
use_regression: bool = False
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
grid: Grid,
|
|
36
|
+
sound_speed: NDArray[np.float64],
|
|
37
|
+
density: NDArray[np.float64],
|
|
38
|
+
beta: NDArray[np.float64],
|
|
39
|
+
relaxation_param_dict: dict[str, NDArray[np.float64]],
|
|
40
|
+
*,
|
|
41
|
+
air_map: NDArray[np.int64] | None = None,
|
|
42
|
+
n_relaxation_mechanisms: int = 2,
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Medium class for Fullwave.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
grid : Grid
|
|
49
|
+
Grid instance.
|
|
50
|
+
sound_speed : NDArray[np.float64]
|
|
51
|
+
Sound speed in the medium [m/s].
|
|
52
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
53
|
+
density : NDArray[np.float64]
|
|
54
|
+
Density of the medium [kg/m^3].
|
|
55
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
56
|
+
beta : NDArray[np.float64]
|
|
57
|
+
nonlinearity [unitless].
|
|
58
|
+
beta = 1 + B/A / 2
|
|
59
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
60
|
+
relaxation_param_dict: dict[str, NDArray[np.float64]]
|
|
61
|
+
relaxation parameter map dict.
|
|
62
|
+
key: kappa_x1, kappa_x2, d_x1_nu{i}, alpha_x1_nu{i}, d_x2_nu{i}, alpha_x2_nu{i}
|
|
63
|
+
value.shape: [nx, ny] for 2D, [nx, ny, nz] for 3D for each value
|
|
64
|
+
see Pinton, G. (2021) http://arxiv.org/abs/2106.11476 for more detail.
|
|
65
|
+
air_map: NDArray[np.int64], optional
|
|
66
|
+
Binary matrix where the medium is air.
|
|
67
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
68
|
+
n_relaxation_mechanisms : int, optional
|
|
69
|
+
Number of relaxation mechanisms, by default 2
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
check_functions.check_compatible_value(
|
|
73
|
+
n_relaxation_mechanisms,
|
|
74
|
+
[2],
|
|
75
|
+
"Only n_relaxation_mechanisms=2 are supported currently.",
|
|
76
|
+
)
|
|
77
|
+
self.n_relaxation_mechanisms = n_relaxation_mechanisms
|
|
78
|
+
self.relaxation_param_dict = initialize_relaxation_param_dict(
|
|
79
|
+
n_relaxation_mechanisms=n_relaxation_mechanisms,
|
|
80
|
+
value=np.zeros_like(sound_speed),
|
|
81
|
+
)
|
|
82
|
+
self.grid = grid
|
|
83
|
+
self.is_3d = grid.is_3d
|
|
84
|
+
|
|
85
|
+
self.sound_speed = sound_speed
|
|
86
|
+
self.density = density
|
|
87
|
+
self.beta = beta
|
|
88
|
+
|
|
89
|
+
if air_map is None:
|
|
90
|
+
self.air_map = np.zeros_like(self.sound_speed, dtype=bool)
|
|
91
|
+
else:
|
|
92
|
+
self.air_map = air_map
|
|
93
|
+
|
|
94
|
+
self.__post_init__()
|
|
95
|
+
|
|
96
|
+
self._update_relaxation_param_dict(
|
|
97
|
+
relaxation_param_updates=relaxation_param_dict,
|
|
98
|
+
)
|
|
99
|
+
self.relaxation_param_dict_for_fw2 = self._calc_relaxation_param_dict_for_fw2()
|
|
100
|
+
self.check_fields()
|
|
101
|
+
|
|
102
|
+
def __post_init__(self) -> None:
|
|
103
|
+
"""Post-initialization processing for Medium."""
|
|
104
|
+
self.sound_speed = np.atleast_2d(self.sound_speed)
|
|
105
|
+
self.density = np.atleast_2d(self.density)
|
|
106
|
+
self.beta = np.atleast_2d(self.beta)
|
|
107
|
+
|
|
108
|
+
def _update_relaxation_param_dict(
|
|
109
|
+
self,
|
|
110
|
+
relaxation_param_updates: dict[str, NDArray[np.float64]],
|
|
111
|
+
) -> None:
|
|
112
|
+
self.check_relaxation_param_dict(
|
|
113
|
+
relaxation_param_dict=relaxation_param_updates,
|
|
114
|
+
contents_shape=self.sound_speed.shape,
|
|
115
|
+
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# nu should be sorted considering the values of the time constants. (for PML implementation)
|
|
119
|
+
# The sorting must be done between maps.
|
|
120
|
+
# The order of the nu has no meaning because of the summation feature of Fullwave2.
|
|
121
|
+
|
|
122
|
+
kappa_x1 = relaxation_param_updates["kappa_x1"]
|
|
123
|
+
kappa_x2 = relaxation_param_updates["kappa_x2"]
|
|
124
|
+
|
|
125
|
+
d_x1 = []
|
|
126
|
+
alpha_x1 = []
|
|
127
|
+
d_x2 = []
|
|
128
|
+
alpha_x2 = []
|
|
129
|
+
time_const_x1 = []
|
|
130
|
+
time_const_x2 = []
|
|
131
|
+
for nu in range(1, self.n_relaxation_mechanisms + 1):
|
|
132
|
+
d_x1_nu = relaxation_param_updates[f"d_x1_nu{nu}"]
|
|
133
|
+
alpha_x1_nu = relaxation_param_updates[f"alpha_x1_nu{nu}"]
|
|
134
|
+
d_x2_nu = relaxation_param_updates[f"d_x2_nu{nu}"]
|
|
135
|
+
alpha_x2_nu = relaxation_param_updates[f"alpha_x2_nu{nu}"]
|
|
136
|
+
|
|
137
|
+
d_x1.append(d_x1_nu)
|
|
138
|
+
alpha_x1.append(alpha_x1_nu)
|
|
139
|
+
d_x2.append(d_x2_nu)
|
|
140
|
+
alpha_x2.append(alpha_x2_nu)
|
|
141
|
+
|
|
142
|
+
time_const_x1_nu = self._calc_time_constants(
|
|
143
|
+
dx=d_x1_nu,
|
|
144
|
+
kappa=kappa_x1,
|
|
145
|
+
alpha=alpha_x1_nu,
|
|
146
|
+
)
|
|
147
|
+
time_const_x2_nu = self._calc_time_constants(
|
|
148
|
+
dx=d_x2_nu,
|
|
149
|
+
kappa=kappa_x2,
|
|
150
|
+
alpha=alpha_x2_nu,
|
|
151
|
+
)
|
|
152
|
+
time_const_x1.append(time_const_x1_nu)
|
|
153
|
+
time_const_x2.append(time_const_x2_nu)
|
|
154
|
+
|
|
155
|
+
time_const_x1 = np.stack(time_const_x1, axis=-1)
|
|
156
|
+
time_const_x2 = np.stack(time_const_x2, axis=-1)
|
|
157
|
+
d_x1 = np.stack(d_x1, axis=-1)
|
|
158
|
+
alpha_x1 = np.stack(alpha_x1, axis=-1)
|
|
159
|
+
d_x2 = np.stack(d_x2, axis=-1)
|
|
160
|
+
alpha_x2 = np.stack(alpha_x2, axis=-1)
|
|
161
|
+
|
|
162
|
+
# sort the nu values based on the time constants
|
|
163
|
+
sorted_indices_x1 = np.argsort(time_const_x1, axis=-1)
|
|
164
|
+
sorted_indices_x2 = np.argsort(time_const_x2, axis=-1)
|
|
165
|
+
self.relaxation_param_dict["kappa_x1"] = np.atleast_2d(kappa_x1)
|
|
166
|
+
self.relaxation_param_dict["kappa_x2"] = np.atleast_2d(kappa_x2)
|
|
167
|
+
|
|
168
|
+
for nu in range(1, self.n_relaxation_mechanisms + 1):
|
|
169
|
+
self.relaxation_param_dict[f"d_x1_nu{nu}"] = np.atleast_2d(
|
|
170
|
+
np.take_along_axis(
|
|
171
|
+
d_x1,
|
|
172
|
+
np.expand_dims(sorted_indices_x1[..., nu - 1], axis=-1),
|
|
173
|
+
axis=-1,
|
|
174
|
+
).squeeze(-1),
|
|
175
|
+
)
|
|
176
|
+
self.relaxation_param_dict[f"alpha_x1_nu{nu}"] = np.atleast_2d(
|
|
177
|
+
np.take_along_axis(
|
|
178
|
+
alpha_x1,
|
|
179
|
+
np.expand_dims(sorted_indices_x1[..., nu - 1], axis=-1),
|
|
180
|
+
axis=-1,
|
|
181
|
+
).squeeze(-1),
|
|
182
|
+
)
|
|
183
|
+
self.relaxation_param_dict[f"d_x2_nu{nu}"] = np.atleast_2d(
|
|
184
|
+
np.take_along_axis(
|
|
185
|
+
d_x2,
|
|
186
|
+
np.expand_dims(sorted_indices_x2[..., nu - 1], axis=-1),
|
|
187
|
+
axis=-1,
|
|
188
|
+
).squeeze(-1),
|
|
189
|
+
)
|
|
190
|
+
self.relaxation_param_dict[f"alpha_x2_nu{nu}"] = np.atleast_2d(
|
|
191
|
+
np.take_along_axis(
|
|
192
|
+
alpha_x2,
|
|
193
|
+
np.expand_dims(sorted_indices_x2[..., nu - 1], axis=-1),
|
|
194
|
+
axis=-1,
|
|
195
|
+
).squeeze(-1),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# check keys
|
|
199
|
+
desired_dict = initialize_relaxation_param_dict(
|
|
200
|
+
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
201
|
+
)
|
|
202
|
+
key_set = set(self.relaxation_param_dict.keys())
|
|
203
|
+
desired_key_set = set(desired_dict.keys())
|
|
204
|
+
if key_set != desired_key_set:
|
|
205
|
+
error_msg = f"Unknown relaxation parameter keys: {key_set - desired_key_set}"
|
|
206
|
+
raise ValueError(error_msg)
|
|
207
|
+
|
|
208
|
+
# for key, value in relaxation_param_updates.items():
|
|
209
|
+
# self.relaxation_param_dict[key] = np.atleast_2d(value)
|
|
210
|
+
|
|
211
|
+
def check_relaxation_param_dict(
|
|
212
|
+
self,
|
|
213
|
+
relaxation_param_dict: dict[str, NDArray[np.float64]],
|
|
214
|
+
contents_shape: NDArray[np.int64] | tuple[int, ...],
|
|
215
|
+
n_relaxation_mechanisms: int = 2,
|
|
216
|
+
) -> None:
|
|
217
|
+
"""Check if the relaxation parameter updates have valid keys and matching shapes.
|
|
218
|
+
|
|
219
|
+
Raises:
|
|
220
|
+
ValueError: If the keys do not match the desired keys or
|
|
221
|
+
if the shapes of the values do not match the domain shape.
|
|
222
|
+
|
|
223
|
+
"""
|
|
224
|
+
desired_dict = initialize_relaxation_param_dict(
|
|
225
|
+
n_relaxation_mechanisms=n_relaxation_mechanisms,
|
|
226
|
+
)
|
|
227
|
+
# key check
|
|
228
|
+
key_set = set(relaxation_param_dict.keys())
|
|
229
|
+
desired_key_set = set(desired_dict.keys())
|
|
230
|
+
if key_set != desired_key_set:
|
|
231
|
+
error_msg = f"Unknown relaxation parameter keys: {key_set - desired_key_set}"
|
|
232
|
+
raise ValueError(error_msg)
|
|
233
|
+
|
|
234
|
+
for value in relaxation_param_dict.values():
|
|
235
|
+
if value.shape != contents_shape:
|
|
236
|
+
error_msg = (
|
|
237
|
+
"Relaxation parameter map shape error: "
|
|
238
|
+
f"{value.shape} != {self.sound_speed.shape} (domain shape)"
|
|
239
|
+
)
|
|
240
|
+
raise ValueError(error_msg)
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def bulk_modulus(self) -> NDArray[np.float64]:
|
|
244
|
+
"""Return the bulk_modulus."""
|
|
245
|
+
return np.multiply(self.sound_speed**2, self.density)
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def n_coords_zero(self) -> int:
|
|
249
|
+
"""Return the number of air coordinates.
|
|
250
|
+
|
|
251
|
+
(alias for self.n_air)
|
|
252
|
+
"""
|
|
253
|
+
return self.n_air
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def n_air(self) -> int:
|
|
257
|
+
"""Return the number of air coordinates."""
|
|
258
|
+
return self.air_map.sum()
|
|
259
|
+
|
|
260
|
+
@staticmethod
|
|
261
|
+
def _calc_a_and_b(
|
|
262
|
+
dx: NDArray[np.float64] | float,
|
|
263
|
+
kappa_x: NDArray[np.float64] | float,
|
|
264
|
+
alpha_x: NDArray[np.float64] | float,
|
|
265
|
+
dt: NDArray[np.float64] | float,
|
|
266
|
+
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
|
|
267
|
+
# function [a b] = ab(dx,kappax,alphax,dT)
|
|
268
|
+
dx = np.array(dx)
|
|
269
|
+
kappa_x = np.array(kappa_x)
|
|
270
|
+
alpha_x = np.array(alpha_x)
|
|
271
|
+
dt = np.array(dt)
|
|
272
|
+
|
|
273
|
+
b = np.exp(-(dx / kappa_x + alpha_x) * dt)
|
|
274
|
+
eps = 1e-10
|
|
275
|
+
a = dx / (kappa_x * (dx + kappa_x * alpha_x) + eps) * (b - 1)
|
|
276
|
+
return a, b
|
|
277
|
+
|
|
278
|
+
@staticmethod
|
|
279
|
+
def _calc_time_constants(
|
|
280
|
+
dx: NDArray[np.float64],
|
|
281
|
+
kappa: NDArray[np.float64],
|
|
282
|
+
alpha: NDArray[np.float64],
|
|
283
|
+
) -> NDArray[np.float64]:
|
|
284
|
+
return dx / kappa + alpha
|
|
285
|
+
|
|
286
|
+
def _calc_relaxation_param_dict_for_fw2(self) -> dict[str, NDArray[np.float64]]:
|
|
287
|
+
"""Return the relaxation parameter dict for Fullwave2.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
dict[str, NDArray[np.float64]]: A dictionary with the calculated relaxation parameters
|
|
291
|
+
formatted for Fullwave2.
|
|
292
|
+
|
|
293
|
+
"""
|
|
294
|
+
rename_dict = {
|
|
295
|
+
"kappa_x": "kappa_x2",
|
|
296
|
+
"kappa_y": "kappa_x2",
|
|
297
|
+
"kappa_u": "kappa_x1",
|
|
298
|
+
"kappa_w": "kappa_x1",
|
|
299
|
+
}
|
|
300
|
+
if self.is_3d:
|
|
301
|
+
rename_dict["kappa_z"] = "kappa_x2"
|
|
302
|
+
rename_dict["kappa_v"] = "kappa_x1"
|
|
303
|
+
for nu in range(1, self.n_relaxation_mechanisms + 1):
|
|
304
|
+
rename_dict[f"a_pml_u{nu}"] = f"a_pml_x1_nu{nu}"
|
|
305
|
+
rename_dict[f"b_pml_u{nu}"] = f"b_pml_x1_nu{nu}"
|
|
306
|
+
rename_dict[f"a_pml_w{nu}"] = f"a_pml_x1_nu{nu}"
|
|
307
|
+
rename_dict[f"b_pml_w{nu}"] = f"b_pml_x1_nu{nu}"
|
|
308
|
+
if self.is_3d:
|
|
309
|
+
rename_dict[f"a_pml_v{nu}"] = f"a_pml_x1_nu{nu}"
|
|
310
|
+
rename_dict[f"b_pml_v{nu}"] = f"b_pml_x1_nu{nu}"
|
|
311
|
+
|
|
312
|
+
rename_dict[f"a_pml_x{nu}"] = f"a_pml_x2_nu{nu}"
|
|
313
|
+
rename_dict[f"b_pml_x{nu}"] = f"b_pml_x2_nu{nu}"
|
|
314
|
+
rename_dict[f"a_pml_y{nu}"] = f"a_pml_x2_nu{nu}"
|
|
315
|
+
rename_dict[f"b_pml_y{nu}"] = f"b_pml_x2_nu{nu}"
|
|
316
|
+
if self.is_3d:
|
|
317
|
+
rename_dict[f"a_pml_z{nu}"] = f"a_pml_x2_nu{nu}"
|
|
318
|
+
rename_dict[f"b_pml_z{nu}"] = f"b_pml_x2_nu{nu}"
|
|
319
|
+
|
|
320
|
+
relaxation_coefficients = {}
|
|
321
|
+
relaxation_coefficients["kappa_x1"] = self.relaxation_param_dict["kappa_x1"]
|
|
322
|
+
relaxation_coefficients["kappa_x2"] = self.relaxation_param_dict["kappa_x2"]
|
|
323
|
+
|
|
324
|
+
for nu in range(1, self.n_relaxation_mechanisms + 1):
|
|
325
|
+
(
|
|
326
|
+
relaxation_coefficients[f"a_pml_x1_nu{nu}"],
|
|
327
|
+
relaxation_coefficients[f"b_pml_x1_nu{nu}"],
|
|
328
|
+
) = self._calc_a_and_b(
|
|
329
|
+
dx=self.relaxation_param_dict[f"d_x1_nu{nu}"],
|
|
330
|
+
kappa_x=self.relaxation_param_dict["kappa_x1"],
|
|
331
|
+
alpha_x=self.relaxation_param_dict[f"alpha_x1_nu{nu}"],
|
|
332
|
+
dt=self.grid.dt,
|
|
333
|
+
)
|
|
334
|
+
(
|
|
335
|
+
relaxation_coefficients[f"a_pml_x2_nu{nu}"],
|
|
336
|
+
relaxation_coefficients[f"b_pml_x2_nu{nu}"],
|
|
337
|
+
) = self._calc_a_and_b(
|
|
338
|
+
dx=self.relaxation_param_dict[f"d_x2_nu{nu}"],
|
|
339
|
+
kappa_x=self.relaxation_param_dict["kappa_x2"],
|
|
340
|
+
alpha_x=self.relaxation_param_dict[f"alpha_x2_nu{nu}"],
|
|
341
|
+
dt=self.grid.dt,
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
# extend it to x and y directions and rename the keys to Fullwave2 format
|
|
345
|
+
out_dict = {}
|
|
346
|
+
for new_key, key in rename_dict.items():
|
|
347
|
+
out_dict[new_key] = relaxation_coefficients[key].copy()
|
|
348
|
+
return out_dict
|
|
349
|
+
|
|
350
|
+
def check_fields(self) -> None:
|
|
351
|
+
"""Check if the fields have the correct shape."""
|
|
352
|
+
grid_shape = (
|
|
353
|
+
(self.grid.nx, self.grid.ny, self.grid.nz)
|
|
354
|
+
if self.is_3d
|
|
355
|
+
else (self.grid.nx, self.grid.ny)
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
def _error_msg(
|
|
359
|
+
field: NDArray[np.float64 | np.int64],
|
|
360
|
+
grid_shape: NDArray[np.int64] | tuple[int, ...],
|
|
361
|
+
) -> str:
|
|
362
|
+
return f"map shape error: {field.shape} != {grid_shape}"
|
|
363
|
+
|
|
364
|
+
assert self.sound_speed.shape == grid_shape, _error_msg(self.sound_speed, grid_shape)
|
|
365
|
+
assert self.density.shape == grid_shape, _error_msg(self.density, grid_shape)
|
|
366
|
+
assert self.beta.shape == grid_shape, _error_msg(self.beta, grid_shape)
|
|
367
|
+
for value in self.relaxation_param_dict.values():
|
|
368
|
+
assert value.shape == grid_shape, _error_msg(value, grid_shape)
|
|
369
|
+
|
|
370
|
+
def plot(
|
|
371
|
+
self,
|
|
372
|
+
export_path: Path | str | None = Path("./temp/temp.png"),
|
|
373
|
+
*,
|
|
374
|
+
show: bool = False,
|
|
375
|
+
) -> None:
|
|
376
|
+
"""Plot the medium fields using matplotlib."""
|
|
377
|
+
if self.is_3d:
|
|
378
|
+
error_msg = "3D plotting is not implemented yet."
|
|
379
|
+
raise NotImplementedError(error_msg)
|
|
380
|
+
relaxation_param_dict_keys = initialize_relaxation_param_dict(
|
|
381
|
+
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
382
|
+
).keys()
|
|
383
|
+
|
|
384
|
+
target_map_dict: OrderedDict = OrderedDict(
|
|
385
|
+
[
|
|
386
|
+
("Sound speed", self.sound_speed),
|
|
387
|
+
("Density", self.density),
|
|
388
|
+
("Beta", self.beta),
|
|
389
|
+
("Air map", self.air_map),
|
|
390
|
+
],
|
|
391
|
+
)
|
|
392
|
+
for key in relaxation_param_dict_keys:
|
|
393
|
+
target_map_dict[key] = self.relaxation_param_dict[key]
|
|
394
|
+
|
|
395
|
+
num_plots = len(target_map_dict)
|
|
396
|
+
# calculate subplot shape to make a square
|
|
397
|
+
n_rows = int(np.sqrt(num_plots)) + 1
|
|
398
|
+
n_cols = int(np.ceil(num_plots / n_rows))
|
|
399
|
+
# adjust the fig size
|
|
400
|
+
fig_size = (n_cols * 5, n_rows * 5)
|
|
401
|
+
|
|
402
|
+
plt.close("all")
|
|
403
|
+
_, axes = plt.subplots(n_rows, n_cols, figsize=fig_size)
|
|
404
|
+
|
|
405
|
+
for ax, (title, map_data) in zip(
|
|
406
|
+
axes.flatten(),
|
|
407
|
+
target_map_dict.items(),
|
|
408
|
+
strict=False,
|
|
409
|
+
):
|
|
410
|
+
plot_utils.plot_array_on_ax(ax, map_data, title=title)
|
|
411
|
+
plt.tight_layout()
|
|
412
|
+
|
|
413
|
+
if export_path is not None:
|
|
414
|
+
export_path = Path(export_path)
|
|
415
|
+
export_path.parent.mkdir(parents=True, exist_ok=True)
|
|
416
|
+
plt.savefig(export_path, dpi=300)
|
|
417
|
+
if show:
|
|
418
|
+
plt.show()
|
|
419
|
+
plt.close("all")
|
|
420
|
+
|
|
421
|
+
def print_info(self) -> None:
|
|
422
|
+
"""Print grid information."""
|
|
423
|
+
print(str(self))
|
|
424
|
+
|
|
425
|
+
def summary(self) -> None:
|
|
426
|
+
"""Alias for print_info."""
|
|
427
|
+
self.print_info()
|
|
428
|
+
|
|
429
|
+
def __str__(self) -> str:
|
|
430
|
+
"""Return a string representation of the Medium.
|
|
431
|
+
|
|
432
|
+
Returns
|
|
433
|
+
-------
|
|
434
|
+
str
|
|
435
|
+
A string summarizing the Medium properties.
|
|
436
|
+
|
|
437
|
+
"""
|
|
438
|
+
return (
|
|
439
|
+
f"Relaxation Medium:\n"
|
|
440
|
+
f" Grid: {self.grid}\n"
|
|
441
|
+
"\n"
|
|
442
|
+
f" Sound speed: min {np.min(self.sound_speed):.2f} m/s, "
|
|
443
|
+
f"max {np.max(self.sound_speed):.2f} m/s\n"
|
|
444
|
+
f" Density: min {np.min(self.density):.2f} kg/m^3, "
|
|
445
|
+
f"max {np.max(self.density):.2f} kg/m^3\n"
|
|
446
|
+
f" Beta: min {np.min(self.beta):.2f}, max {np.max(self.beta):.2f}\n"
|
|
447
|
+
f" Number of air coordinates: {self.n_air}\n"
|
|
448
|
+
f" Number of relaxation mechanisms: {self.n_relaxation_mechanisms}\n"
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
def __repr__(self) -> str:
|
|
452
|
+
"""Return a detailed string representation of the Medium.
|
|
453
|
+
|
|
454
|
+
Returns
|
|
455
|
+
-------
|
|
456
|
+
str
|
|
457
|
+
A detailed string representation of the Medium instance.
|
|
458
|
+
|
|
459
|
+
"""
|
|
460
|
+
return str(self)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
@dataclass
|
|
464
|
+
class MediumExponentialAttenuation:
|
|
465
|
+
"""Medium class for Fullwave with exponential attenuation."""
|
|
466
|
+
|
|
467
|
+
grid: Grid
|
|
468
|
+
sound_speed: NDArray[np.float64]
|
|
469
|
+
density: NDArray[np.float64]
|
|
470
|
+
alpha_exp: NDArray[np.float64]
|
|
471
|
+
beta: NDArray[np.float64]
|
|
472
|
+
air_map: NDArray[np.int64]
|
|
473
|
+
|
|
474
|
+
def __init__(
|
|
475
|
+
self,
|
|
476
|
+
grid: Grid,
|
|
477
|
+
sound_speed: NDArray[np.float64],
|
|
478
|
+
density: NDArray[np.float64],
|
|
479
|
+
alpha_exp: NDArray[np.float64],
|
|
480
|
+
beta: NDArray[np.float64],
|
|
481
|
+
*,
|
|
482
|
+
air_map: NDArray[np.int64] | None = None,
|
|
483
|
+
) -> None:
|
|
484
|
+
"""Medium class for Fullwave.
|
|
485
|
+
|
|
486
|
+
Parameters
|
|
487
|
+
----------
|
|
488
|
+
grid: Grid
|
|
489
|
+
Grid instance.
|
|
490
|
+
sound_speed : NDArray[np.float64]
|
|
491
|
+
Sound speed in the medium [m/s].
|
|
492
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
493
|
+
density : NDArray[np.float64]
|
|
494
|
+
Density of the medium [kg/m^3].
|
|
495
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
496
|
+
alpha_exp : NDArray[np.float64]
|
|
497
|
+
Exponential attenuation coefficient converted from alpha coeff.
|
|
498
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
499
|
+
beta : NDArray[np.float64]
|
|
500
|
+
nonlinearity [unitless].
|
|
501
|
+
beta = 1 + B/A / 2
|
|
502
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
503
|
+
air_map: NDArray[np.int64], optional
|
|
504
|
+
Binary matrix where the medium is air.
|
|
505
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
506
|
+
|
|
507
|
+
"""
|
|
508
|
+
check_functions.check_instance(grid, Grid)
|
|
509
|
+
self.grid = grid
|
|
510
|
+
self.is_3d = grid.is_3d
|
|
511
|
+
|
|
512
|
+
self.sound_speed = sound_speed
|
|
513
|
+
self.density = density
|
|
514
|
+
self.alpha_exp = alpha_exp
|
|
515
|
+
self.beta = beta
|
|
516
|
+
|
|
517
|
+
if air_map is None:
|
|
518
|
+
self.air_map = np.zeros_like(self.sound_speed, dtype=bool)
|
|
519
|
+
else:
|
|
520
|
+
self.air_map = air_map
|
|
521
|
+
|
|
522
|
+
self.__post_init__()
|
|
523
|
+
self.check_fields()
|
|
524
|
+
|
|
525
|
+
def __post_init__(self) -> None:
|
|
526
|
+
"""Post-initialization processing for Medium."""
|
|
527
|
+
self.sound_speed = np.atleast_2d(self.sound_speed)
|
|
528
|
+
self.density = np.atleast_2d(self.density)
|
|
529
|
+
self.alpha_exp = np.atleast_2d(self.alpha_exp)
|
|
530
|
+
self.beta = np.atleast_2d(self.beta)
|
|
531
|
+
|
|
532
|
+
def check_fields(self) -> None:
|
|
533
|
+
"""Check if the fields have the correct shape."""
|
|
534
|
+
grid_shape: tuple[int, ...]
|
|
535
|
+
if self.is_3d:
|
|
536
|
+
grid_shape = (self.grid.nx, self.grid.ny, self.grid.nz)
|
|
537
|
+
else:
|
|
538
|
+
grid_shape = (self.grid.nx, self.grid.ny)
|
|
539
|
+
|
|
540
|
+
def _error_msg(
|
|
541
|
+
field: NDArray[np.float64 | np.int64],
|
|
542
|
+
grid_shape: NDArray[np.int64] | tuple[int, ...],
|
|
543
|
+
) -> str:
|
|
544
|
+
return f"map shape error: {field.shape} != {grid_shape}"
|
|
545
|
+
|
|
546
|
+
assert self.sound_speed.shape == grid_shape, _error_msg(self.sound_speed, grid_shape)
|
|
547
|
+
assert self.density.shape == grid_shape, _error_msg(self.density, grid_shape)
|
|
548
|
+
assert self.alpha_exp.shape == grid_shape, _error_msg(self.alpha_exp, grid_shape)
|
|
549
|
+
assert self.beta.shape == grid_shape, _error_msg(self.beta, grid_shape)
|
|
550
|
+
|
|
551
|
+
@property
|
|
552
|
+
def bulk_modulus(self) -> NDArray[np.float64]:
|
|
553
|
+
"""Return the bulk_modulus."""
|
|
554
|
+
return np.multiply(self.sound_speed**2, self.density)
|
|
555
|
+
|
|
556
|
+
@property
|
|
557
|
+
def n_coords_zero(self) -> int:
|
|
558
|
+
"""Return the number of air coordinates.
|
|
559
|
+
|
|
560
|
+
(alias for self.n_air)
|
|
561
|
+
"""
|
|
562
|
+
return self.n_air
|
|
563
|
+
|
|
564
|
+
@property
|
|
565
|
+
def n_air(self) -> int:
|
|
566
|
+
"""Return the number of air coordinates."""
|
|
567
|
+
return self.air_map.sum()
|
|
568
|
+
|
|
569
|
+
def plot(
|
|
570
|
+
self,
|
|
571
|
+
export_path: Path | str | None = Path("./temp/temp.png"),
|
|
572
|
+
*,
|
|
573
|
+
show: bool = False,
|
|
574
|
+
cmap: str = "turbo",
|
|
575
|
+
) -> None:
|
|
576
|
+
"""Plot the medium fields using matplotlib."""
|
|
577
|
+
if self.is_3d:
|
|
578
|
+
error_msg = "3D plotting is not implemented yet."
|
|
579
|
+
raise NotImplementedError(error_msg)
|
|
580
|
+
plt.close("all")
|
|
581
|
+
_, axes = plt.subplots(2, 3, figsize=(15, 10))
|
|
582
|
+
|
|
583
|
+
for ax, map_data, title in zip(
|
|
584
|
+
axes.flatten(),
|
|
585
|
+
[
|
|
586
|
+
self.sound_speed,
|
|
587
|
+
self.density,
|
|
588
|
+
self.alpha_exp,
|
|
589
|
+
self.beta,
|
|
590
|
+
self.air_map,
|
|
591
|
+
],
|
|
592
|
+
["Sound speed", "Density", "Alpha exp", "Beta", "Air map"],
|
|
593
|
+
strict=False,
|
|
594
|
+
):
|
|
595
|
+
plot_utils.plot_array_on_ax(
|
|
596
|
+
ax,
|
|
597
|
+
map_data,
|
|
598
|
+
title=title,
|
|
599
|
+
xlim=(0 - 10, self.grid.ny + 10),
|
|
600
|
+
ylim=(0 - 10, self.grid.nx + 10),
|
|
601
|
+
reverse_y_axis=True,
|
|
602
|
+
cmap=cmap,
|
|
603
|
+
)
|
|
604
|
+
plt.tight_layout()
|
|
605
|
+
|
|
606
|
+
if export_path is not None:
|
|
607
|
+
plt.savefig(export_path, dpi=300)
|
|
608
|
+
if show:
|
|
609
|
+
plt.show()
|
|
610
|
+
plt.close("all")
|
|
611
|
+
|
|
612
|
+
def print_info(self) -> None:
|
|
613
|
+
"""Print grid information."""
|
|
614
|
+
print(str(self))
|
|
615
|
+
|
|
616
|
+
def summary(self) -> None:
|
|
617
|
+
"""Alias for print_info."""
|
|
618
|
+
self.print_info()
|
|
619
|
+
|
|
620
|
+
def __str__(self) -> str:
|
|
621
|
+
"""Return a string representation of the Medium.
|
|
622
|
+
|
|
623
|
+
Returns
|
|
624
|
+
-------
|
|
625
|
+
str
|
|
626
|
+
A string summarizing the Medium properties.
|
|
627
|
+
|
|
628
|
+
"""
|
|
629
|
+
return (
|
|
630
|
+
f"Relaxation Medium:\n"
|
|
631
|
+
f" Grid: {self.grid}\n"
|
|
632
|
+
"\n"
|
|
633
|
+
f" Sound speed: min {np.min(self.sound_speed):.2f} m/s, "
|
|
634
|
+
f"max {np.max(self.sound_speed):.2f} m/s\n"
|
|
635
|
+
f" Density: min {np.min(self.density):.2f} kg/m^3, "
|
|
636
|
+
f"max {np.max(self.density):.2f} kg/m^3\n"
|
|
637
|
+
f" Beta: min {np.min(self.beta):.2f}, max {np.max(self.beta):.2f}\n"
|
|
638
|
+
f" Number of air coordinates: {self.n_air}\n"
|
|
639
|
+
f" Exponential attenuation coefficient: min {np.min(self.alpha_exp):.2f}, "
|
|
640
|
+
f"max {np.max(self.alpha_exp):.2f}\n"
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
def __repr__(self) -> str:
|
|
644
|
+
"""Return a detailed string representation of the Medium.
|
|
645
|
+
|
|
646
|
+
Returns
|
|
647
|
+
-------
|
|
648
|
+
str
|
|
649
|
+
A detailed string representation of the Medium instance.
|
|
650
|
+
|
|
651
|
+
"""
|
|
652
|
+
return str(self)
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
@dataclass
|
|
656
|
+
class Medium:
|
|
657
|
+
"""Medium class for Fullwave."""
|
|
658
|
+
|
|
659
|
+
grid: Grid
|
|
660
|
+
sound_speed: NDArray[np.float64]
|
|
661
|
+
density: NDArray[np.float64]
|
|
662
|
+
alpha_coeff: NDArray[np.float64]
|
|
663
|
+
alpha_power: NDArray[np.float64]
|
|
664
|
+
beta: NDArray[np.float64]
|
|
665
|
+
air_map: NDArray[np.int64]
|
|
666
|
+
attenuation_builder: str = "lookup"
|
|
667
|
+
|
|
668
|
+
def __init__(
|
|
669
|
+
self,
|
|
670
|
+
grid: Grid,
|
|
671
|
+
sound_speed: NDArray[np.float64],
|
|
672
|
+
density: NDArray[np.float64],
|
|
673
|
+
alpha_coeff: NDArray[np.float64],
|
|
674
|
+
alpha_power: NDArray[np.float64],
|
|
675
|
+
beta: NDArray[np.float64],
|
|
676
|
+
*,
|
|
677
|
+
air_map: NDArray[np.int64] | None = None,
|
|
678
|
+
path_relaxation_parameters_database: Path = Path(__file__).parent
|
|
679
|
+
/ "solver"
|
|
680
|
+
/ "bins"
|
|
681
|
+
/ "database"
|
|
682
|
+
/ "relaxation_params_database_num_relax=2_20251027_1437.mat",
|
|
683
|
+
n_relaxation_mechanisms: int = 2,
|
|
684
|
+
attenuation_builder: str = "lookup",
|
|
685
|
+
) -> None:
|
|
686
|
+
"""Medium class for Fullwave.
|
|
687
|
+
|
|
688
|
+
Parameters
|
|
689
|
+
----------
|
|
690
|
+
grid: Grid
|
|
691
|
+
Grid instance.
|
|
692
|
+
sound_speed : NDArray[np.float64]
|
|
693
|
+
Sound speed in the medium [m/s].
|
|
694
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
695
|
+
density : NDArray[np.float64]
|
|
696
|
+
Density of the medium [kg/m^3].
|
|
697
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
698
|
+
alpha_coeff : NDArray[np.float64]
|
|
699
|
+
Attenuation coefficient [dB/cm/MHz^gamma].
|
|
700
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
701
|
+
alpha_power : NDArray[np.float64]
|
|
702
|
+
Attenuation power [unitless].
|
|
703
|
+
gamma in the attenuation coefficient (power law)
|
|
704
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
705
|
+
beta : NDArray[np.float64]
|
|
706
|
+
nonlinearity [unitless].
|
|
707
|
+
beta = 1 + B/A / 2
|
|
708
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
709
|
+
air_map: NDArray[np.int64], optional
|
|
710
|
+
Binary matrix where the medium is air.
|
|
711
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
712
|
+
path_relaxation_parameters_database : Path, optional
|
|
713
|
+
Path to the relaxation parameters database.
|
|
714
|
+
n_relaxation_mechanisms : int, optional
|
|
715
|
+
Number of relaxation mechanisms, by default 4
|
|
716
|
+
attenuation_builder : str, optional
|
|
717
|
+
Attenuation builder method, by default "lookup".
|
|
718
|
+
Options are "lookup", "interpolation", and "regression".
|
|
719
|
+
|
|
720
|
+
"""
|
|
721
|
+
check_functions.check_compatible_value(
|
|
722
|
+
n_relaxation_mechanisms,
|
|
723
|
+
[2],
|
|
724
|
+
"Only n_relaxation_mechanisms=2 are supported currently.",
|
|
725
|
+
)
|
|
726
|
+
check_functions.check_instance(grid, Grid)
|
|
727
|
+
check_functions.check_path_exists(path_relaxation_parameters_database)
|
|
728
|
+
self.grid = grid
|
|
729
|
+
self.is_3d = grid.is_3d
|
|
730
|
+
|
|
731
|
+
self.sound_speed = sound_speed
|
|
732
|
+
self.density = density
|
|
733
|
+
self.alpha_coeff = alpha_coeff
|
|
734
|
+
self.alpha_power = alpha_power
|
|
735
|
+
self.beta = beta
|
|
736
|
+
if air_map is None:
|
|
737
|
+
self.air_map = np.zeros_like(self.sound_speed, dtype=bool)
|
|
738
|
+
else:
|
|
739
|
+
self.air_map = air_map
|
|
740
|
+
self.path_relaxation_parameters_database = path_relaxation_parameters_database
|
|
741
|
+
self.n_relaxation_mechanisms = n_relaxation_mechanisms
|
|
742
|
+
|
|
743
|
+
if self.n_relaxation_mechanisms != 2 and self.air_map.sum() > 0:
|
|
744
|
+
warning_msg = (
|
|
745
|
+
"Warning: Currently, only n_relaxation_mechanisms=2 supports air regions. "
|
|
746
|
+
"Setting air regions to zero for other n_relaxation_mechanisms."
|
|
747
|
+
)
|
|
748
|
+
logger.warning(warning_msg)
|
|
749
|
+
self.air_map = np.zeros_like(self.sound_speed, dtype=bool)
|
|
750
|
+
|
|
751
|
+
self.attenuation_builder = attenuation_builder
|
|
752
|
+
self.__post_init__()
|
|
753
|
+
self.check_fields()
|
|
754
|
+
|
|
755
|
+
def __post_init__(self) -> None:
|
|
756
|
+
"""Post-initialization processing for Medium."""
|
|
757
|
+
self.sound_speed = np.atleast_2d(self.sound_speed)
|
|
758
|
+
self.density = np.atleast_2d(self.density)
|
|
759
|
+
self.alpha_coeff = np.atleast_2d(self.alpha_coeff)
|
|
760
|
+
self.alpha_power = np.atleast_2d(self.alpha_power)
|
|
761
|
+
self.beta = np.atleast_2d(self.beta)
|
|
762
|
+
|
|
763
|
+
def check_fields(self) -> None:
|
|
764
|
+
"""Check if the fields have the correct shape."""
|
|
765
|
+
grid_shape: tuple[int, ...]
|
|
766
|
+
if self.is_3d:
|
|
767
|
+
grid_shape = (self.grid.nx, self.grid.ny, self.grid.nz)
|
|
768
|
+
else:
|
|
769
|
+
grid_shape = (self.grid.nx, self.grid.ny)
|
|
770
|
+
|
|
771
|
+
def _error_msg(
|
|
772
|
+
field: NDArray[np.float64 | np.int64],
|
|
773
|
+
grid_shape: NDArray[np.int64] | tuple[int, ...],
|
|
774
|
+
) -> str:
|
|
775
|
+
return f"map shape error: {field.shape} != {grid_shape}"
|
|
776
|
+
|
|
777
|
+
assert self.sound_speed.shape == grid_shape, _error_msg(self.sound_speed, grid_shape)
|
|
778
|
+
assert self.density.shape == grid_shape, _error_msg(self.density, grid_shape)
|
|
779
|
+
assert self.alpha_coeff.shape == grid_shape, _error_msg(self.alpha_coeff, grid_shape)
|
|
780
|
+
assert self.alpha_power.shape == grid_shape, _error_msg(self.alpha_power, grid_shape)
|
|
781
|
+
assert self.beta.shape == grid_shape, _error_msg(self.beta, grid_shape)
|
|
782
|
+
|
|
783
|
+
@property
|
|
784
|
+
def bulk_modulus(self) -> NDArray[np.float64]:
|
|
785
|
+
"""Return the bulk_modulus."""
|
|
786
|
+
return np.multiply(self.sound_speed**2, self.density)
|
|
787
|
+
|
|
788
|
+
@property
|
|
789
|
+
def n_coords_zero(self) -> int:
|
|
790
|
+
"""Return the number of air coordinates.
|
|
791
|
+
|
|
792
|
+
(alias for self.n_air)
|
|
793
|
+
"""
|
|
794
|
+
return self.n_air
|
|
795
|
+
|
|
796
|
+
@property
|
|
797
|
+
def n_air(self) -> int:
|
|
798
|
+
"""Return the number of air coordinates."""
|
|
799
|
+
return self.air_map.sum()
|
|
800
|
+
|
|
801
|
+
def plot(
|
|
802
|
+
self,
|
|
803
|
+
export_path: Path | str | None = Path("./temp/temp.png"),
|
|
804
|
+
*,
|
|
805
|
+
show: bool = False,
|
|
806
|
+
cmap: str = "turbo",
|
|
807
|
+
figsize: tuple = (20, 6),
|
|
808
|
+
fontsize_title: int = 20,
|
|
809
|
+
) -> None:
|
|
810
|
+
"""Plot the medium fields using matplotlib."""
|
|
811
|
+
if self.is_3d:
|
|
812
|
+
plt.close("all")
|
|
813
|
+
_, axes = plt.subplots(2, 6, figsize=figsize)
|
|
814
|
+
# plot the x-y axis and x-z axis slices
|
|
815
|
+
for ax, map_data, title in zip(
|
|
816
|
+
axes.flatten(),
|
|
817
|
+
[
|
|
818
|
+
self.sound_speed[:, :, self.grid.nz // 2],
|
|
819
|
+
self.sound_speed[:, self.grid.ny // 2, :],
|
|
820
|
+
self.density[:, :, self.grid.nz // 2],
|
|
821
|
+
self.density[:, self.grid.ny // 2, :],
|
|
822
|
+
self.alpha_coeff[:, :, self.grid.nz // 2],
|
|
823
|
+
self.alpha_coeff[:, self.grid.ny // 2, :],
|
|
824
|
+
self.alpha_power[:, :, self.grid.nz // 2],
|
|
825
|
+
self.alpha_power[:, self.grid.ny // 2, :],
|
|
826
|
+
self.beta[:, :, self.grid.nz // 2],
|
|
827
|
+
self.beta[:, self.grid.ny // 2, :],
|
|
828
|
+
self.air_map[:, :, self.grid.nz // 2],
|
|
829
|
+
self.air_map[:, self.grid.ny // 2, :],
|
|
830
|
+
],
|
|
831
|
+
[
|
|
832
|
+
"Sound speed (x-y slice)",
|
|
833
|
+
"Sound speed (x-z slice)",
|
|
834
|
+
"Density (x-y slice)",
|
|
835
|
+
"Density (x-z slice)",
|
|
836
|
+
"Alpha coeff (x-y slice)",
|
|
837
|
+
"Alpha coeff (x-z slice)",
|
|
838
|
+
"Alpha power (x-y slice)",
|
|
839
|
+
"Alpha power (x-z slice)",
|
|
840
|
+
"Beta (x-y slice)",
|
|
841
|
+
"Beta (x-z slice)",
|
|
842
|
+
"Air map (x-y slice)",
|
|
843
|
+
"Air map (x-z slice)",
|
|
844
|
+
],
|
|
845
|
+
strict=False,
|
|
846
|
+
):
|
|
847
|
+
plot_utils.plot_array_on_ax(
|
|
848
|
+
ax,
|
|
849
|
+
map_data,
|
|
850
|
+
title=title,
|
|
851
|
+
cmap=cmap,
|
|
852
|
+
)
|
|
853
|
+
plt.tight_layout()
|
|
854
|
+
if export_path is not None:
|
|
855
|
+
plt.savefig(export_path, dpi=300)
|
|
856
|
+
if show:
|
|
857
|
+
plt.show()
|
|
858
|
+
plt.close("all")
|
|
859
|
+
else:
|
|
860
|
+
plt.close("all")
|
|
861
|
+
_, axes = plt.subplots(2, 3, figsize=(15, 10))
|
|
862
|
+
|
|
863
|
+
for ax, map_data, title in zip(
|
|
864
|
+
axes.flatten(),
|
|
865
|
+
[
|
|
866
|
+
self.sound_speed,
|
|
867
|
+
self.density,
|
|
868
|
+
self.alpha_coeff,
|
|
869
|
+
self.alpha_power,
|
|
870
|
+
self.beta,
|
|
871
|
+
self.air_map,
|
|
872
|
+
],
|
|
873
|
+
[
|
|
874
|
+
(
|
|
875
|
+
"Sound speed\n"
|
|
876
|
+
r"$c$"
|
|
877
|
+
),
|
|
878
|
+
(
|
|
879
|
+
"Density\n"
|
|
880
|
+
r"$\rho$"
|
|
881
|
+
),
|
|
882
|
+
(
|
|
883
|
+
"Alpha coefficient\n"
|
|
884
|
+
r"$\alpha_0$"
|
|
885
|
+
),
|
|
886
|
+
(
|
|
887
|
+
"Power law exponent\n"
|
|
888
|
+
r"$\gamma$"
|
|
889
|
+
),
|
|
890
|
+
(
|
|
891
|
+
"Nonlinearity\n"
|
|
892
|
+
r"$\beta=1+\frac{B}{2A}$"
|
|
893
|
+
),
|
|
894
|
+
"Air map",
|
|
895
|
+
],
|
|
896
|
+
strict=False,
|
|
897
|
+
):
|
|
898
|
+
plot_utils.plot_array_on_ax(
|
|
899
|
+
ax,
|
|
900
|
+
map_data,
|
|
901
|
+
title=title,
|
|
902
|
+
xlim=(0 - 10, self.grid.ny + 10),
|
|
903
|
+
ylim=(0 - 10, self.grid.nx + 10),
|
|
904
|
+
reverse_y_axis=True,
|
|
905
|
+
cmap=cmap,
|
|
906
|
+
)
|
|
907
|
+
ax.title.set_fontsize(fontsize_title)
|
|
908
|
+
plt.tight_layout()
|
|
909
|
+
|
|
910
|
+
if export_path is not None:
|
|
911
|
+
plt.savefig(export_path, dpi=300)
|
|
912
|
+
if show:
|
|
913
|
+
plt.show()
|
|
914
|
+
plt.close("all")
|
|
915
|
+
|
|
916
|
+
# ---
|
|
917
|
+
|
|
918
|
+
def build(self) -> MediumRelaxationMaps:
|
|
919
|
+
"""Retrieve the relaxation parameters from alpha and power maps.
|
|
920
|
+
|
|
921
|
+
it uses the relaxation parameters look up table
|
|
922
|
+
to generate the relaxation parameters.
|
|
923
|
+
|
|
924
|
+
Returns:
|
|
925
|
+
MediumRelaxationMaps: An instance of MediumRelaxationMaps
|
|
926
|
+
built from the retrieved relaxation parameters.
|
|
927
|
+
|
|
928
|
+
Raises:
|
|
929
|
+
ValueError: If an unknown attenuation_builder is specified.
|
|
930
|
+
|
|
931
|
+
"""
|
|
932
|
+
if self.attenuation_builder == "lookup":
|
|
933
|
+
relaxation_param_dict = generate_relaxation_params(
|
|
934
|
+
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
935
|
+
alpha_coeff=self.alpha_coeff,
|
|
936
|
+
alpha_power=self.alpha_power,
|
|
937
|
+
path_database=self.path_relaxation_parameters_database,
|
|
938
|
+
)
|
|
939
|
+
else:
|
|
940
|
+
error_msg = (
|
|
941
|
+
f"Unknown attenuation_builder: {self.attenuation_builder}. "
|
|
942
|
+
'Only "lookup" is supported currently.'
|
|
943
|
+
)
|
|
944
|
+
raise ValueError(error_msg)
|
|
945
|
+
return MediumRelaxationMaps(
|
|
946
|
+
grid=self.grid,
|
|
947
|
+
sound_speed=self.sound_speed,
|
|
948
|
+
density=self.density,
|
|
949
|
+
beta=self.beta,
|
|
950
|
+
relaxation_param_dict=relaxation_param_dict,
|
|
951
|
+
air_map=self.air_map,
|
|
952
|
+
n_relaxation_mechanisms=self.n_relaxation_mechanisms,
|
|
953
|
+
)
|
|
954
|
+
|
|
955
|
+
def _db_mhz_cm_to_a_exp(
|
|
956
|
+
self,
|
|
957
|
+
alpha_coeff: np.ndarray,
|
|
958
|
+
) -> np.ndarray:
|
|
959
|
+
"""Convert alpha in [dB/cm/MHz] to a_exp for Fullwave.
|
|
960
|
+
|
|
961
|
+
Parameters
|
|
962
|
+
----------
|
|
963
|
+
alpha_coeff : np.ndarray
|
|
964
|
+
Attenuation coefficient [dB/cm/MHz].
|
|
965
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
966
|
+
|
|
967
|
+
Returns
|
|
968
|
+
-------
|
|
969
|
+
np.ndarray
|
|
970
|
+
a_exp for Fullwave.
|
|
971
|
+
shape: [nx, ny] for 2D, [nx, ny, nz] for 3D
|
|
972
|
+
|
|
973
|
+
"""
|
|
974
|
+
np_factor = -10 * np.log10(np.exp(-1)) # equivalent to -db(exp(-1)) in MATLAB
|
|
975
|
+
f0 = self.grid.omega / (2.0 * np.pi * 1e6)
|
|
976
|
+
texp = alpha_coeff / 2.0 * f0 * self.grid.c0 / (1e-2 * np_factor)
|
|
977
|
+
return np.exp(-self.grid.dt * texp)
|
|
978
|
+
|
|
979
|
+
def build_exponential(self) -> MediumExponentialAttenuation:
|
|
980
|
+
"""Build MediumExponentialAttenuation from alpha and power maps.
|
|
981
|
+
|
|
982
|
+
Returns:
|
|
983
|
+
MediumExponentialAttenuation: An instance of MediumExponentialAttenuation
|
|
984
|
+
built from the alpha and power maps.
|
|
985
|
+
|
|
986
|
+
"""
|
|
987
|
+
alpha_exp = self._db_mhz_cm_to_a_exp(
|
|
988
|
+
self.alpha_coeff,
|
|
989
|
+
)
|
|
990
|
+
return MediumExponentialAttenuation(
|
|
991
|
+
grid=self.grid,
|
|
992
|
+
sound_speed=self.sound_speed,
|
|
993
|
+
density=self.density,
|
|
994
|
+
alpha_exp=alpha_exp,
|
|
995
|
+
beta=self.beta,
|
|
996
|
+
air_map=self.air_map,
|
|
997
|
+
)
|
|
998
|
+
|
|
999
|
+
def print_info(self) -> None:
|
|
1000
|
+
"""Print grid information."""
|
|
1001
|
+
print(str(self))
|
|
1002
|
+
|
|
1003
|
+
def summary(self) -> None:
|
|
1004
|
+
"""Alias for print_info."""
|
|
1005
|
+
self.print_info()
|
|
1006
|
+
|
|
1007
|
+
def __str__(self) -> str:
|
|
1008
|
+
"""Return a string representation of the Medium.
|
|
1009
|
+
|
|
1010
|
+
Returns
|
|
1011
|
+
-------
|
|
1012
|
+
str
|
|
1013
|
+
A string summarizing the Medium properties.
|
|
1014
|
+
|
|
1015
|
+
"""
|
|
1016
|
+
return (
|
|
1017
|
+
f"Medium: \n"
|
|
1018
|
+
f" Grid: {self.grid}\n"
|
|
1019
|
+
"\n"
|
|
1020
|
+
f" Sound speed: min={np.min(self.sound_speed):.2f}, "
|
|
1021
|
+
f"max={np.max(self.sound_speed):.2f}\n"
|
|
1022
|
+
f" Density: min={np.min(self.density):.2f}, "
|
|
1023
|
+
f"max={np.max(self.density):.2f}\n"
|
|
1024
|
+
f" Alpha coeff: min={np.min(self.alpha_coeff):.2f}, "
|
|
1025
|
+
f"max={np.max(self.alpha_coeff):.2f}\n"
|
|
1026
|
+
f" Alpha power: min={np.min(self.alpha_power):.2f}, "
|
|
1027
|
+
f"max={np.max(self.alpha_power):.2f}\n"
|
|
1028
|
+
f" Beta: min={np.min(self.beta):.2f}, max={np.max(self.beta):.2f}\n"
|
|
1029
|
+
f" Number of air coords: {self.n_air}\n"
|
|
1030
|
+
f" Attenuation builder: {self.attenuation_builder}\n"
|
|
1031
|
+
)
|
|
1032
|
+
|
|
1033
|
+
def __repr__(self) -> str:
|
|
1034
|
+
"""Return a detailed string representation of the Medium.
|
|
1035
|
+
|
|
1036
|
+
Returns
|
|
1037
|
+
-------
|
|
1038
|
+
str
|
|
1039
|
+
A detailed string representation of the Medium instance.
|
|
1040
|
+
|
|
1041
|
+
"""
|
|
1042
|
+
return str(self)
|