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
|
@@ -0,0 +1,750 @@
|
|
|
1
|
+
"""solver module."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from numpy.typing import NDArray
|
|
8
|
+
|
|
9
|
+
import fullwave
|
|
10
|
+
from fullwave.solver.input_file_writer import InputFileWriter
|
|
11
|
+
from fullwave.solver.launcher import Launcher
|
|
12
|
+
from fullwave.solver.pml_builder import PMLBuilder, PMLBuilderExponentialAttenuation
|
|
13
|
+
from fullwave.utils import (
|
|
14
|
+
MemoryTempfile,
|
|
15
|
+
check_functions,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from .cuda_utils import get_cuda_architecture, retrieve_cuda_version
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger("__main__." + __name__)
|
|
21
|
+
|
|
22
|
+
COMPATIBLE_CUDA_ARCHITECTURES = [
|
|
23
|
+
"sm_61", # Pascal: GTX 10*0
|
|
24
|
+
"sm_70", # Volta: V100, GTX 1180
|
|
25
|
+
"sm_75", # Turing: RTX 20*0
|
|
26
|
+
"sm_80", # Ampere: A100
|
|
27
|
+
"sm_86", # Ampere: RTX 3080, RTX 3090, etc
|
|
28
|
+
"sm_89", # Ada: RTX 4090, L40, RTX6000
|
|
29
|
+
"sm_90", # Hopper: H100, H200
|
|
30
|
+
"sm_100", # Blackwell: RTX 50 series
|
|
31
|
+
"sm_101", # Blackwell: RTX 50 series
|
|
32
|
+
"sm_120", # Blackwell: RTX 50 series
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
VERIFIED_CUDA_ARCHITECTURES = [
|
|
36
|
+
"sm_80", # Ampere: A100
|
|
37
|
+
"sm_89", # Ada: RTX 4090, L40, RTX6000
|
|
38
|
+
"sm_120", # Blackwell: RTX 50 series
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
COMPATIBLE_CUDA_VERSIONS = [
|
|
42
|
+
11.8,
|
|
43
|
+
12.4,
|
|
44
|
+
12.6,
|
|
45
|
+
12.9,
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
COMPATIBLE_CUDA_RANGES = [
|
|
49
|
+
(11.8, 12.9),
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
VERIFIED_CUDA_VERSIONS = [
|
|
53
|
+
12.6,
|
|
54
|
+
12.9,
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
COMPATIBLE_CUDA_VERSIONS_ARCHITECTURES_set = {
|
|
58
|
+
(11.8, "sm_61"),
|
|
59
|
+
(11.8, "sm_70"),
|
|
60
|
+
(11.8, "sm_75"),
|
|
61
|
+
(11.8, "sm_80"),
|
|
62
|
+
(11.8, "sm_86"),
|
|
63
|
+
(11.8, "sm_89"),
|
|
64
|
+
(11.8, "sm_90"),
|
|
65
|
+
# ---
|
|
66
|
+
(12.4, "sm_61"),
|
|
67
|
+
(12.4, "sm_70"),
|
|
68
|
+
(12.4, "sm_75"),
|
|
69
|
+
(12.4, "sm_80"),
|
|
70
|
+
(12.4, "sm_86"),
|
|
71
|
+
(12.4, "sm_89"),
|
|
72
|
+
(12.4, "sm_90"),
|
|
73
|
+
# ---
|
|
74
|
+
(12.6, "sm_61"),
|
|
75
|
+
(12.6, "sm_70"),
|
|
76
|
+
(12.6, "sm_75"),
|
|
77
|
+
(12.6, "sm_80"),
|
|
78
|
+
(12.6, "sm_86"),
|
|
79
|
+
(12.6, "sm_89"),
|
|
80
|
+
(12.6, "sm_90"),
|
|
81
|
+
# ---
|
|
82
|
+
(12.9, "sm_61"),
|
|
83
|
+
(12.9, "sm_70"),
|
|
84
|
+
(12.9, "sm_75"),
|
|
85
|
+
(12.9, "sm_80"),
|
|
86
|
+
(12.9, "sm_86"),
|
|
87
|
+
(12.9, "sm_89"),
|
|
88
|
+
(12.9, "sm_90"),
|
|
89
|
+
(12.9, "sm_100"),
|
|
90
|
+
(12.9, "sm_101"),
|
|
91
|
+
(12.9, "sm_120"),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _make_cuda_arch_option(*, use_gpu: bool = True) -> str:
|
|
96
|
+
cuda_archtecture_dict = get_cuda_architecture()[0] # Get the first device's architecture
|
|
97
|
+
arch_option = (
|
|
98
|
+
"sm_"
|
|
99
|
+
+ str(cuda_archtecture_dict["compute_capability"][0])
|
|
100
|
+
+ str(cuda_archtecture_dict["compute_capability"][1])
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if use_gpu and arch_option not in COMPATIBLE_CUDA_ARCHITECTURES:
|
|
104
|
+
error_msg = (
|
|
105
|
+
f"CUDA architecture {arch_option} is not compatible. "
|
|
106
|
+
f"Please use one of the following architectures: "
|
|
107
|
+
f"{COMPATIBLE_CUDA_ARCHITECTURES}"
|
|
108
|
+
)
|
|
109
|
+
raise ValueError(error_msg)
|
|
110
|
+
if use_gpu and arch_option not in VERIFIED_CUDA_ARCHITECTURES:
|
|
111
|
+
warning_msg = (
|
|
112
|
+
f"Warning: CUDA architecture {arch_option} is not verified. "
|
|
113
|
+
f"Verified architectures are: {VERIFIED_CUDA_ARCHITECTURES}. "
|
|
114
|
+
"The simulation may not run correctly."
|
|
115
|
+
)
|
|
116
|
+
logger.warning(warning_msg)
|
|
117
|
+
return arch_option
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _make_cuda_version_option(*, use_gpu: bool = True) -> tuple[str, float]:
|
|
121
|
+
cuda_version: float = retrieve_cuda_version()
|
|
122
|
+
if use_gpu and cuda_version == -1:
|
|
123
|
+
error_msg = (
|
|
124
|
+
"Could not retrieve CUDA version. "
|
|
125
|
+
"Please ensure that the CUDA toolkit is properly installed."
|
|
126
|
+
)
|
|
127
|
+
raise ValueError(error_msg)
|
|
128
|
+
|
|
129
|
+
# range check
|
|
130
|
+
if use_gpu and not any(start <= cuda_version <= end for start, end in COMPATIBLE_CUDA_RANGES):
|
|
131
|
+
error_msg = (
|
|
132
|
+
f"CUDA version {cuda_version} is not in the compatible ranges: "
|
|
133
|
+
f"{COMPATIBLE_CUDA_RANGES}. Please install a compatible CUDA version."
|
|
134
|
+
)
|
|
135
|
+
raise ValueError(error_msg)
|
|
136
|
+
|
|
137
|
+
# find the a compatible cuda version below the system cuda
|
|
138
|
+
if use_gpu and cuda_version not in COMPATIBLE_CUDA_VERSIONS:
|
|
139
|
+
compatible_versions_below = [v for v in COMPATIBLE_CUDA_VERSIONS if v < cuda_version]
|
|
140
|
+
if compatible_versions_below:
|
|
141
|
+
closest_version = max(compatible_versions_below)
|
|
142
|
+
warning_msg = (
|
|
143
|
+
f"CUDA version {cuda_version} is not in the compatible versions: "
|
|
144
|
+
f"{COMPATIBLE_CUDA_VERSIONS}. "
|
|
145
|
+
f"Using the closest compatible version {closest_version} instead."
|
|
146
|
+
)
|
|
147
|
+
logger.warning(warning_msg)
|
|
148
|
+
cuda_version = closest_version
|
|
149
|
+
else:
|
|
150
|
+
error_msg = (
|
|
151
|
+
f"No compatible CUDA versions found below {cuda_version}. "
|
|
152
|
+
"Please install a compatible CUDA version."
|
|
153
|
+
)
|
|
154
|
+
raise ValueError(error_msg)
|
|
155
|
+
|
|
156
|
+
if use_gpu and cuda_version not in VERIFIED_CUDA_VERSIONS:
|
|
157
|
+
warning_msg = (
|
|
158
|
+
f"Warning: CUDA version {cuda_version} is not in the verified versions: "
|
|
159
|
+
f"{VERIFIED_CUDA_VERSIONS}. The simulation may not run correctly."
|
|
160
|
+
)
|
|
161
|
+
logger.warning(warning_msg)
|
|
162
|
+
|
|
163
|
+
return ("cuda" + str(cuda_version).replace(".", ""), cuda_version)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _check_compatible_set(cuda_version: float, cuda_arch: str) -> bool:
|
|
167
|
+
return (cuda_version, cuda_arch) in COMPATIBLE_CUDA_VERSIONS_ARCHITECTURES_set
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _retrieve_fullwave_simulation_path(
|
|
171
|
+
*,
|
|
172
|
+
use_gpu: bool = True,
|
|
173
|
+
is_3d: bool = False,
|
|
174
|
+
use_exponential_attenuation: bool = False,
|
|
175
|
+
use_isotropic_relaxation: bool = True,
|
|
176
|
+
n_relax_mechanisms: int = 2,
|
|
177
|
+
) -> Path:
|
|
178
|
+
arch_option = _make_cuda_arch_option(use_gpu=use_gpu)
|
|
179
|
+
cuda_version_option, cuda_version = _make_cuda_version_option(use_gpu=use_gpu)
|
|
180
|
+
isotropic_str = "_isotropic" if use_isotropic_relaxation else ""
|
|
181
|
+
|
|
182
|
+
_check_compatible_set(
|
|
183
|
+
cuda_version=cuda_version,
|
|
184
|
+
cuda_arch=arch_option,
|
|
185
|
+
)
|
|
186
|
+
if use_exponential_attenuation:
|
|
187
|
+
if is_3d and use_gpu:
|
|
188
|
+
path_fullwave_simulation_bin = (
|
|
189
|
+
Path(__file__).parent
|
|
190
|
+
/ "bins"
|
|
191
|
+
/ "exponential_attenuation"
|
|
192
|
+
/ "gpu"
|
|
193
|
+
/ "3d"
|
|
194
|
+
/ f"fullwave2_3d_exponential_attenuation_gpu_{arch_option}_{cuda_version_option}"
|
|
195
|
+
)
|
|
196
|
+
elif not is_3d and use_gpu:
|
|
197
|
+
path_fullwave_simulation_bin = (
|
|
198
|
+
Path(__file__).parent
|
|
199
|
+
/ "bins"
|
|
200
|
+
/ "exponential_attenuation"
|
|
201
|
+
/ "gpu"
|
|
202
|
+
/ "2d"
|
|
203
|
+
/ f"fullwave2_2d_exponential_attenuation_gpu_{arch_option}_{cuda_version_option}"
|
|
204
|
+
)
|
|
205
|
+
else:
|
|
206
|
+
error_msg = (
|
|
207
|
+
"Currently, exponential attenuation model is only supported in GPU mode. "
|
|
208
|
+
"Please use GPU mode for exponential attenuation simulations."
|
|
209
|
+
)
|
|
210
|
+
raise NotImplementedError(error_msg)
|
|
211
|
+
elif is_3d:
|
|
212
|
+
if use_gpu:
|
|
213
|
+
if n_relax_mechanisms != 2:
|
|
214
|
+
error_msg = (
|
|
215
|
+
"Currently, only 2 relaxation mechanisms are supported in 3D simulations. "
|
|
216
|
+
"Please set n_relax_mechanisms to 2 for 3D simulations."
|
|
217
|
+
)
|
|
218
|
+
raise NotImplementedError(error_msg)
|
|
219
|
+
|
|
220
|
+
path_fullwave_simulation_bin = (
|
|
221
|
+
Path(__file__).parent
|
|
222
|
+
/ "bins"
|
|
223
|
+
/ "gpu"
|
|
224
|
+
/ "3d"
|
|
225
|
+
/ f"num_relax={n_relax_mechanisms}"
|
|
226
|
+
/ (
|
|
227
|
+
f"fullwave2_3d_{n_relax_mechanisms}_relax{isotropic_str}"
|
|
228
|
+
f"_multi_gpu_{arch_option}_{cuda_version_option}"
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
else:
|
|
232
|
+
path_fullwave_simulation_bin = (
|
|
233
|
+
Path(__file__).parent / "bins" / "cpu" / "3d" / "fullwave2_3d_2_relax_multi_cpu"
|
|
234
|
+
)
|
|
235
|
+
error_msg = (
|
|
236
|
+
"Currently, 3D simulation is not supported in CPU mode. "
|
|
237
|
+
"Please use GPU mode for 3D simulations."
|
|
238
|
+
)
|
|
239
|
+
raise NotImplementedError(error_msg)
|
|
240
|
+
else: # noqa: PLR5501
|
|
241
|
+
if use_gpu:
|
|
242
|
+
path_fullwave_simulation_bin = (
|
|
243
|
+
Path(__file__).parent
|
|
244
|
+
/ "bins"
|
|
245
|
+
/ "gpu"
|
|
246
|
+
/ "2d"
|
|
247
|
+
/ f"num_relax={n_relax_mechanisms}"
|
|
248
|
+
/ (
|
|
249
|
+
f"fullwave2_2d_{n_relax_mechanisms}_relax{isotropic_str}"
|
|
250
|
+
f"_multi_gpu_{arch_option}_{cuda_version_option}"
|
|
251
|
+
)
|
|
252
|
+
)
|
|
253
|
+
else:
|
|
254
|
+
path_fullwave_simulation_bin = (
|
|
255
|
+
Path(__file__).parent / "bins" / "cpu" / "2d" / "fullwave2_2d_2_relax_multi_cpu"
|
|
256
|
+
)
|
|
257
|
+
error_msg = (
|
|
258
|
+
"Currently, 2D simulation is not supported in CPU mode. "
|
|
259
|
+
"Please use GPU mode for 3D simulations."
|
|
260
|
+
)
|
|
261
|
+
raise NotImplementedError(error_msg)
|
|
262
|
+
return path_fullwave_simulation_bin
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class Solver:
|
|
266
|
+
"""Solver for fullwave simulation tasks.
|
|
267
|
+
|
|
268
|
+
The Solver class manages the setup, input validation, and execution of a fullwave simulation.
|
|
269
|
+
It configures the simulation environment based on the provided
|
|
270
|
+
grid, medium, source, sensor, or transducer,
|
|
271
|
+
generates the required input files, and runs the simulation executable.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
def __init__( # noqa: PLR0912, PLR0915, C901
|
|
275
|
+
self,
|
|
276
|
+
work_dir: Path,
|
|
277
|
+
grid: fullwave.Grid,
|
|
278
|
+
medium: fullwave.Medium,
|
|
279
|
+
source: fullwave.Source | None = None,
|
|
280
|
+
sensor: fullwave.Sensor | None = None,
|
|
281
|
+
*,
|
|
282
|
+
transducer: fullwave.Transducer | None = None,
|
|
283
|
+
path_fullwave_simulation_bin: Path | None = None,
|
|
284
|
+
use_pml: bool = True,
|
|
285
|
+
m_spatial_order: int = 8,
|
|
286
|
+
pml_layer_thickness_px: int | None = None,
|
|
287
|
+
n_transition_layer: int | None = None,
|
|
288
|
+
run_on_memory: bool = False,
|
|
289
|
+
use_gpu: bool = True,
|
|
290
|
+
use_exponential_attenuation: bool = False,
|
|
291
|
+
use_isotropic_relaxation: bool = True,
|
|
292
|
+
) -> None:
|
|
293
|
+
"""Initialize a Solver instance for the fullwave simulation.
|
|
294
|
+
|
|
295
|
+
This initializer sets up the simulation
|
|
296
|
+
by assigning the provided grid, medium, source, sensor, and
|
|
297
|
+
transducer (if provided).
|
|
298
|
+
It validates input consistency, generates necessary working directories,
|
|
299
|
+
and prepares the input generator and simulation launcher.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
work_dir : (Path)
|
|
304
|
+
Directory to store simulation data and temporary files.
|
|
305
|
+
grid : (fullwave.Grid)
|
|
306
|
+
Instance representing the simulation computational grid.
|
|
307
|
+
medium : (fullwave.MediumRelaxationMaps)
|
|
308
|
+
Instance representing the physical medium where simulations occur.
|
|
309
|
+
source : (fullwave.Source, optional)
|
|
310
|
+
Source defining the simulation input. Optional if a transducer is given.
|
|
311
|
+
sensor : (fullwave.Sensor, optional)
|
|
312
|
+
Sensor defining the simulation output. Optional if a transducer is given.
|
|
313
|
+
transducer : (fullwave.Transducer, optional)
|
|
314
|
+
Transducer instance combining source and sensor information.
|
|
315
|
+
Must not be provided together with source or sensor.
|
|
316
|
+
path_fullwave_simulation_bin : (Path, optional):
|
|
317
|
+
Path to the fullwave simulation binary executable.
|
|
318
|
+
Defaults to a binary in the 'bins' directory relative to this file.
|
|
319
|
+
use_pml : (bool, optional)
|
|
320
|
+
Flag indicating whether to use Perfectly Matched Layer (PML) boundaries.
|
|
321
|
+
Defaults to True.
|
|
322
|
+
m_spatial_order : int, optional
|
|
323
|
+
fullwave simulation's spatial order (default is 8).
|
|
324
|
+
It depends on the fullwave simulation binary version.
|
|
325
|
+
Fullwave simulation has 2M th order spatial accuracy and fourth order accuracy in time.
|
|
326
|
+
see Pinton, G. (2021) http://arxiv.org/abs/2106.11476 for more detail.
|
|
327
|
+
pml_layer_thickness_px : int, optional
|
|
328
|
+
PML layer thickness (default is 3 ppw).
|
|
329
|
+
n_transition_layer : int, optional
|
|
330
|
+
Number of transition layers (default is 3 ppw).
|
|
331
|
+
run_on_memory : bool, optional
|
|
332
|
+
Flag indicating whether to run the simulation in memory.
|
|
333
|
+
If True, a temporary directory is created in memory.
|
|
334
|
+
it uses the /run/user/{uid} directory if available.
|
|
335
|
+
the maximum size depends on the system configuration.
|
|
336
|
+
if needed, increase the size of /run/user/{uid} using the following website:
|
|
337
|
+
https://wiki.archlinux.org/title/Profile-sync-daemon#Allocate_more_memory_to_accommodate_profiles_in_/run/user/xxxx
|
|
338
|
+
If False, a temporary directory is created on disk.
|
|
339
|
+
Defaults to False.
|
|
340
|
+
use_gpu : bool, optional
|
|
341
|
+
Whether to use GPU for the simulation.
|
|
342
|
+
Currently, only GPU version is supported.
|
|
343
|
+
Defaults to True.
|
|
344
|
+
In the future support the simulation will be run on multi-core CPU version if False.
|
|
345
|
+
use_exponential_attenuation : bool, optional
|
|
346
|
+
Whether to use exponential attenuation model.
|
|
347
|
+
Defaults to False. If True, the simulation will use exponential attenuation.
|
|
348
|
+
Exponential attenuation is memory efficient and faster
|
|
349
|
+
than the relaxation mechanism model at the cost of attenuation accuracy.
|
|
350
|
+
The exponential attenuation model does not use relaxation mechanisms
|
|
351
|
+
and does not supports frequency power law attenuation.
|
|
352
|
+
use_isotropic_relaxation : bool, optional
|
|
353
|
+
Whether to use isotropic relaxation mechanisms for attenuation modeling
|
|
354
|
+
to reduce memory usage while retaining accuracy.
|
|
355
|
+
For 2D it will reduce the GPU memory usage by approximately 15%.
|
|
356
|
+
For 3D it will reduce the GPU memory usage by approximately 30%
|
|
357
|
+
and CPU memory usage by approximately 20%.
|
|
358
|
+
This option omits the anisotropic relaxation mechanisms to model the attenuation.
|
|
359
|
+
We usually recommend using isotropic relaxation mechanisms
|
|
360
|
+
unless the anisotropic attenuation is required for the simulation.
|
|
361
|
+
|
|
362
|
+
Raises
|
|
363
|
+
------
|
|
364
|
+
ValueError:
|
|
365
|
+
If neither a source nor a transducer is provided,
|
|
366
|
+
if neither a sensor nor a transducer is provided,
|
|
367
|
+
or if both source and transducer (or sensor
|
|
368
|
+
and transducer) are defined simultaneously.
|
|
369
|
+
|
|
370
|
+
"""
|
|
371
|
+
# type hints
|
|
372
|
+
self.source: fullwave.Source
|
|
373
|
+
self.sensor: fullwave.Sensor
|
|
374
|
+
self.medium: fullwave.Medium
|
|
375
|
+
self.grid: fullwave.Grid
|
|
376
|
+
self.input_file_writer: InputFileWriter
|
|
377
|
+
|
|
378
|
+
if run_on_memory:
|
|
379
|
+
message = (
|
|
380
|
+
"\nrun_on_memory is set to True."
|
|
381
|
+
"\nThis simulation will be executed in RAM-based temporary directory. "
|
|
382
|
+
"\n"
|
|
383
|
+
"\nIt speeds up the simulation significantly, "
|
|
384
|
+
"\nhowever you need to ensure that sufficient memory"
|
|
385
|
+
"is available for the simulation. "
|
|
386
|
+
"\n"
|
|
387
|
+
"\nIf you encounter memory issues, consider setting run_on_memory to False. "
|
|
388
|
+
"\n"
|
|
389
|
+
"\nThe temporary directory will be created in /run/user/{uid} if available. "
|
|
390
|
+
f"\nThe simulation output will not be saved in {work_dir}. "
|
|
391
|
+
"\n"
|
|
392
|
+
"\nThe maximum size depends on the system configuration. "
|
|
393
|
+
"\nIf needed, increase the size of /run/user/{uid} using the following website: "
|
|
394
|
+
"\nhttps://wiki.archlinux.org/title/Profile-sync-daemon#Allocate_more_memory_to_accommodate_profiles_in_/run/user/xxxx"
|
|
395
|
+
"\n"
|
|
396
|
+
)
|
|
397
|
+
logger.warning(message)
|
|
398
|
+
self.tempfile = MemoryTempfile(
|
|
399
|
+
preferred_paths=["/run/user/{uid}"],
|
|
400
|
+
remove_paths=["/dev/shm", "/run/shm"], # noqa: S108
|
|
401
|
+
additional_paths=["/var/run"],
|
|
402
|
+
filesystem_types=["tmpfs"],
|
|
403
|
+
fallback=True,
|
|
404
|
+
)
|
|
405
|
+
self.tempdir = self.tempfile.TemporaryDirectory()
|
|
406
|
+
self.work_dir = Path(self.tempdir.name)
|
|
407
|
+
else:
|
|
408
|
+
self.work_dir = work_dir
|
|
409
|
+
self.work_dir.mkdir(exist_ok=True, parents=True)
|
|
410
|
+
|
|
411
|
+
self.grid = grid
|
|
412
|
+
self.is_3d = grid.is_3d
|
|
413
|
+
self.use_gpu = use_gpu
|
|
414
|
+
self.use_exponential_attenuation = use_exponential_attenuation
|
|
415
|
+
self.use_isotropic_relaxation = use_isotropic_relaxation
|
|
416
|
+
|
|
417
|
+
self.n_relax_mechanisms = medium.n_relaxation_mechanisms
|
|
418
|
+
|
|
419
|
+
if path_fullwave_simulation_bin is None:
|
|
420
|
+
path_fullwave_simulation_bin = _retrieve_fullwave_simulation_path(
|
|
421
|
+
use_gpu=use_gpu,
|
|
422
|
+
is_3d=self.is_3d,
|
|
423
|
+
use_exponential_attenuation=self.use_exponential_attenuation,
|
|
424
|
+
use_isotropic_relaxation=use_isotropic_relaxation,
|
|
425
|
+
n_relax_mechanisms=self.n_relax_mechanisms,
|
|
426
|
+
)
|
|
427
|
+
else:
|
|
428
|
+
check_functions.check_path_exists(path_fullwave_simulation_bin)
|
|
429
|
+
|
|
430
|
+
self._check_input(
|
|
431
|
+
grid,
|
|
432
|
+
medium,
|
|
433
|
+
source,
|
|
434
|
+
sensor,
|
|
435
|
+
transducer,
|
|
436
|
+
path_fullwave_simulation_bin,
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
self.medium = medium
|
|
440
|
+
self.use_pml = use_pml
|
|
441
|
+
if not use_pml:
|
|
442
|
+
pml_layer_thickness_px = 0
|
|
443
|
+
n_transition_layer = 0
|
|
444
|
+
|
|
445
|
+
if pml_layer_thickness_px is None:
|
|
446
|
+
pml_layer_thickness_px = self.grid.ppw * 3
|
|
447
|
+
if n_transition_layer is None:
|
|
448
|
+
n_transition_layer = self.grid.ppw * 3
|
|
449
|
+
|
|
450
|
+
if source is not None:
|
|
451
|
+
self.source = source
|
|
452
|
+
elif transducer is not None:
|
|
453
|
+
self.source = transducer.source
|
|
454
|
+
else:
|
|
455
|
+
error_msg = "source or transducer must be provided"
|
|
456
|
+
raise ValueError(error_msg)
|
|
457
|
+
|
|
458
|
+
if sensor is not None:
|
|
459
|
+
self.sensor = sensor
|
|
460
|
+
elif transducer is not None:
|
|
461
|
+
self.sensor = transducer.sensor
|
|
462
|
+
else:
|
|
463
|
+
error_msg = "sensor or transducer must be provided"
|
|
464
|
+
raise ValueError(error_msg)
|
|
465
|
+
|
|
466
|
+
self.transducer: fullwave.Transducer | None = transducer
|
|
467
|
+
|
|
468
|
+
self.path_fullwave_simulation_bin = path_fullwave_simulation_bin
|
|
469
|
+
|
|
470
|
+
self.fullwave_launcher = Launcher(
|
|
471
|
+
path_fullwave_simulation_bin,
|
|
472
|
+
is_3d=self.is_3d,
|
|
473
|
+
use_gpu=self.use_gpu,
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
if use_exponential_attenuation:
|
|
477
|
+
self.pml_builder = PMLBuilderExponentialAttenuation(
|
|
478
|
+
grid=self.grid,
|
|
479
|
+
medium=self.medium,
|
|
480
|
+
source=self.source,
|
|
481
|
+
sensor=self.sensor,
|
|
482
|
+
m_spatial_order=m_spatial_order,
|
|
483
|
+
n_pml_layer=pml_layer_thickness_px,
|
|
484
|
+
)
|
|
485
|
+
else:
|
|
486
|
+
self.pml_builder = PMLBuilder(
|
|
487
|
+
grid=self.grid,
|
|
488
|
+
medium=self.medium,
|
|
489
|
+
source=self.source,
|
|
490
|
+
sensor=self.sensor,
|
|
491
|
+
m_spatial_order=m_spatial_order,
|
|
492
|
+
n_pml_layer=pml_layer_thickness_px,
|
|
493
|
+
n_transition_layer=n_transition_layer,
|
|
494
|
+
use_isotropic_relaxation=use_isotropic_relaxation,
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
@staticmethod
|
|
498
|
+
def _check_input(
|
|
499
|
+
grid: fullwave.Grid,
|
|
500
|
+
medium: fullwave.Medium,
|
|
501
|
+
source: fullwave.Source | None,
|
|
502
|
+
sensor: fullwave.Sensor | None,
|
|
503
|
+
transducer: fullwave.Transducer | None,
|
|
504
|
+
path_fullwave_simulation_bin: Path,
|
|
505
|
+
) -> None:
|
|
506
|
+
"""Check the input values.
|
|
507
|
+
|
|
508
|
+
Raises
|
|
509
|
+
------
|
|
510
|
+
ValueError
|
|
511
|
+
If neither source nor transducer is defined,
|
|
512
|
+
if neither sensor nor transducer is defined,
|
|
513
|
+
or if both source and transducer (or sensor and transducer) are defined simultaneously.
|
|
514
|
+
|
|
515
|
+
"""
|
|
516
|
+
# check if the source and sensor have value or transducer has value
|
|
517
|
+
if source is None and transducer is None:
|
|
518
|
+
error_msg = "source or transducer must be defined"
|
|
519
|
+
raise ValueError(error_msg)
|
|
520
|
+
if sensor is None and transducer is None:
|
|
521
|
+
error_msg = "sensor or transducer must be defined"
|
|
522
|
+
raise ValueError(error_msg)
|
|
523
|
+
if transducer is not None and source is not None:
|
|
524
|
+
error_msg = "source and transducer cannot be defined at the same time"
|
|
525
|
+
raise ValueError(error_msg)
|
|
526
|
+
|
|
527
|
+
if transducer is not None and sensor is not None:
|
|
528
|
+
warning_msg = (
|
|
529
|
+
"sensor and transducer are defined at the same time. "
|
|
530
|
+
"It uses sensor instead of transducer.sensor."
|
|
531
|
+
)
|
|
532
|
+
logger.warning(warning_msg)
|
|
533
|
+
|
|
534
|
+
if source is not None and transducer is None:
|
|
535
|
+
check_functions.check_instance(source, fullwave.Source)
|
|
536
|
+
if sensor is not None and transducer is None:
|
|
537
|
+
check_functions.check_instance(sensor, fullwave.Sensor)
|
|
538
|
+
if transducer is not None:
|
|
539
|
+
check_functions.check_instance(transducer, fullwave.Transducer)
|
|
540
|
+
|
|
541
|
+
# validate the instances
|
|
542
|
+
check_functions.check_instance(grid, fullwave.Grid)
|
|
543
|
+
check_functions.check_instance(medium, fullwave.Medium)
|
|
544
|
+
|
|
545
|
+
if source is not None:
|
|
546
|
+
grid_shape = (grid.nx, grid.ny, grid.nz) if grid.is_3d else (grid.nx, grid.ny)
|
|
547
|
+
source.validate(grid_shape=grid_shape)
|
|
548
|
+
if sensor is not None:
|
|
549
|
+
grid_shape = (grid.nx, grid.ny, grid.nz) if grid.is_3d else (grid.nx, grid.ny)
|
|
550
|
+
sensor.validate(grid_shape=grid_shape)
|
|
551
|
+
|
|
552
|
+
error_msg = f"{path_fullwave_simulation_bin} does not exist"
|
|
553
|
+
assert path_fullwave_simulation_bin.exists(), error_msg
|
|
554
|
+
|
|
555
|
+
@staticmethod
|
|
556
|
+
def _reshape_sensor_data(
|
|
557
|
+
raw_sensor_output: NDArray[np.float64],
|
|
558
|
+
sensor: fullwave.Sensor,
|
|
559
|
+
) -> NDArray[np.float64]:
|
|
560
|
+
"""Reshape the raw sensor output data.
|
|
561
|
+
|
|
562
|
+
Parameters
|
|
563
|
+
----------
|
|
564
|
+
raw_sensor_output: NDArray[np.float64]
|
|
565
|
+
The raw sensor output data from the simulation. [nt*ncoordsout, 1]
|
|
566
|
+
sensor: fullwave.Sensor
|
|
567
|
+
The sensor object used in the simulation.
|
|
568
|
+
|
|
569
|
+
Returns
|
|
570
|
+
-------
|
|
571
|
+
NDArray[np.float64]: The reshaped sensor output data. [ncoordsout, nt]
|
|
572
|
+
|
|
573
|
+
"""
|
|
574
|
+
return raw_sensor_output.reshape(-1, sensor.n_sensors).T
|
|
575
|
+
|
|
576
|
+
def run(
|
|
577
|
+
self,
|
|
578
|
+
simulation_dir_name: str | Path = "txrx_0",
|
|
579
|
+
*,
|
|
580
|
+
is_static_map: bool = False,
|
|
581
|
+
recalculate_pml: bool = True,
|
|
582
|
+
record_whole_domain: bool = False,
|
|
583
|
+
sampling_modulus_time_whole_domain: int = 1,
|
|
584
|
+
load_results: bool = True,
|
|
585
|
+
) -> NDArray[np.float64] | Path:
|
|
586
|
+
r"""Run the fullwave simulation and return the result as a NumPy array.
|
|
587
|
+
|
|
588
|
+
This method generates the simulation input via the input generator,
|
|
589
|
+
launches the simulation through the external executable,
|
|
590
|
+
and retrieves the output data.
|
|
591
|
+
The simulation directory may be customized,
|
|
592
|
+
and additional parameters control the simulation behavior
|
|
593
|
+
such as static map generation
|
|
594
|
+
and recalculation of the Perfectly Matched Layer (PML).
|
|
595
|
+
|
|
596
|
+
Parameters
|
|
597
|
+
----------
|
|
598
|
+
simulation_dir_name : Path
|
|
599
|
+
The directory name where simulation files will be stored.
|
|
600
|
+
The directory will be created under the work directory.
|
|
601
|
+
This is the directory, where Fullwave2 will be executed
|
|
602
|
+
is_static_map : bool
|
|
603
|
+
Flag indicating if a static map is used.\n
|
|
604
|
+
static map is a map that does not change
|
|
605
|
+
during the transmission events such as plane wave and synthetic aperture sequence.\n
|
|
606
|
+
non-static map is a map that changes
|
|
607
|
+
during the transmission events such as walking aperture implementation
|
|
608
|
+
for focused transmit implementation.\n
|
|
609
|
+
if it is a static map, the input files are stored inside the work directory and
|
|
610
|
+
symbolic links are created in the simulation directory.\n
|
|
611
|
+
recalculate_pml : bool
|
|
612
|
+
Flag indicating whether to re-calculate PML parameters.
|
|
613
|
+
default is True.
|
|
614
|
+
you can store the value false
|
|
615
|
+
if you are using the same PML parameters in case of static map simulation.
|
|
616
|
+
set True if you are using different PML parameters for each transmit event
|
|
617
|
+
such as walking aperture.
|
|
618
|
+
set False if you are using the same PML parameters for each transmit event
|
|
619
|
+
such as plane wave
|
|
620
|
+
AND this is the second or later transmit event.
|
|
621
|
+
record_whole_domain : bool
|
|
622
|
+
Flag indicating whether to record the whole domain.
|
|
623
|
+
If True, the simulation will record data for the entire grid.
|
|
624
|
+
sampling_modulus_time_whole_domain : int
|
|
625
|
+
Sampling modulus in time. Default is 1 (record at every time step).
|
|
626
|
+
Changing this value to n will record the pressure every n time steps.
|
|
627
|
+
It reduces the size of the output data.
|
|
628
|
+
This will only change the sensor class if record_whole_domain is True.
|
|
629
|
+
If record_whole_domain is False,
|
|
630
|
+
the sampling sampling_modulus_time_whole_domain is ignored.
|
|
631
|
+
load_results : bool
|
|
632
|
+
Whether to load the results from genout.dat after the simulation.
|
|
633
|
+
Default is True. If set to False, it returns the genout.dat file path instead.
|
|
634
|
+
|
|
635
|
+
Returns
|
|
636
|
+
-------
|
|
637
|
+
NDArray[np.float64]: The simulation output data as a NumPy array.
|
|
638
|
+
|
|
639
|
+
"""
|
|
640
|
+
# self._save_data_for_beamforming()
|
|
641
|
+
|
|
642
|
+
# pml setup
|
|
643
|
+
extended_medium = self.pml_builder.run(use_pml=self.use_pml)
|
|
644
|
+
if sampling_modulus_time_whole_domain != 1 and record_whole_domain is False:
|
|
645
|
+
warning_msg = (
|
|
646
|
+
f"sampling_modulus_time_whole_domain value "
|
|
647
|
+
f"{sampling_modulus_time_whole_domain} is ignored "
|
|
648
|
+
"when record_whole_domain is False. "
|
|
649
|
+
f"The sampling_modulus_time {self.sensor.sampling_modulus_time} "
|
|
650
|
+
"in the sensor object is prioritized."
|
|
651
|
+
)
|
|
652
|
+
logger.warning(warning_msg)
|
|
653
|
+
|
|
654
|
+
sensor_mask: NDArray[np.bool_]
|
|
655
|
+
if record_whole_domain:
|
|
656
|
+
if self.is_3d:
|
|
657
|
+
sensor_mask = np.zeros(
|
|
658
|
+
(
|
|
659
|
+
self.pml_builder.extended_grid.nx,
|
|
660
|
+
self.pml_builder.extended_grid.ny,
|
|
661
|
+
self.pml_builder.extended_grid.nz,
|
|
662
|
+
),
|
|
663
|
+
dtype=bool,
|
|
664
|
+
)
|
|
665
|
+
else:
|
|
666
|
+
sensor_mask = np.zeros(
|
|
667
|
+
(self.pml_builder.extended_grid.nx, self.pml_builder.extended_grid.ny),
|
|
668
|
+
dtype=bool,
|
|
669
|
+
)
|
|
670
|
+
sensor_mask[:, :] = True
|
|
671
|
+
sensor = fullwave.Sensor(
|
|
672
|
+
mask=sensor_mask,
|
|
673
|
+
sampling_modulus_time=sampling_modulus_time_whole_domain,
|
|
674
|
+
)
|
|
675
|
+
else:
|
|
676
|
+
sensor = self.pml_builder.extended_sensor
|
|
677
|
+
|
|
678
|
+
input_file_writer = InputFileWriter(
|
|
679
|
+
work_dir=self.work_dir,
|
|
680
|
+
grid=self.pml_builder.extended_grid,
|
|
681
|
+
medium=extended_medium,
|
|
682
|
+
source=self.pml_builder.extended_source,
|
|
683
|
+
sensor=sensor,
|
|
684
|
+
path_fullwave_simulation_bin=self.path_fullwave_simulation_bin,
|
|
685
|
+
use_exponential_attenuation=self.use_exponential_attenuation,
|
|
686
|
+
use_isotropic_relaxation=self.use_isotropic_relaxation,
|
|
687
|
+
)
|
|
688
|
+
simulation_dir = input_file_writer.run(
|
|
689
|
+
simulation_dir_name,
|
|
690
|
+
is_static_map=is_static_map,
|
|
691
|
+
recalculate_pml=recalculate_pml,
|
|
692
|
+
)
|
|
693
|
+
sim_result = self.fullwave_launcher.run(
|
|
694
|
+
simulation_dir,
|
|
695
|
+
load_results=load_results,
|
|
696
|
+
)
|
|
697
|
+
if load_results:
|
|
698
|
+
return self._reshape_sensor_data(
|
|
699
|
+
sim_result,
|
|
700
|
+
sensor=sensor,
|
|
701
|
+
)
|
|
702
|
+
# if load_results is False, return the raw result
|
|
703
|
+
# which is a list of file names
|
|
704
|
+
return sim_result
|
|
705
|
+
|
|
706
|
+
def print_info(self) -> None:
|
|
707
|
+
"""Print the Solver instance information."""
|
|
708
|
+
print(str(self))
|
|
709
|
+
|
|
710
|
+
def summary(self) -> None:
|
|
711
|
+
"""Alias for print_info."""
|
|
712
|
+
self.print_info()
|
|
713
|
+
|
|
714
|
+
def __str__(self) -> str:
|
|
715
|
+
"""Return a string representation of the Solver instance.
|
|
716
|
+
|
|
717
|
+
Returns
|
|
718
|
+
-------
|
|
719
|
+
str
|
|
720
|
+
A formatted string containing the Solver's attributes.
|
|
721
|
+
|
|
722
|
+
"""
|
|
723
|
+
return (
|
|
724
|
+
f"\nSolver(\n"
|
|
725
|
+
f" work_dir={self.work_dir}\n\n"
|
|
726
|
+
f" medium={self.medium}\n"
|
|
727
|
+
f" source={self.source}\n"
|
|
728
|
+
f" sensor={self.sensor}\n"
|
|
729
|
+
f" transducer={self.transducer}\n\n"
|
|
730
|
+
f" path_fullwave_simulation_bin={self.path_fullwave_simulation_bin}\n"
|
|
731
|
+
f" use_pml={self.use_pml}\n"
|
|
732
|
+
f" pml_thickness_px={self.pml_builder.n_pml_layer}\n"
|
|
733
|
+
f" n_transition_layer={self.pml_builder.n_transition_layer}\n"
|
|
734
|
+
f" is_3d={self.is_3d}\n"
|
|
735
|
+
f" use_gpu={self.use_gpu}\n"
|
|
736
|
+
f" use_exponential_attenuation={self.use_exponential_attenuation}\n"
|
|
737
|
+
f" use_isotropic_relaxation={self.use_isotropic_relaxation}\n"
|
|
738
|
+
f")"
|
|
739
|
+
)
|
|
740
|
+
|
|
741
|
+
def __repr__(self) -> str:
|
|
742
|
+
"""Return a string representation of the Solver instance.
|
|
743
|
+
|
|
744
|
+
Returns
|
|
745
|
+
-------
|
|
746
|
+
str
|
|
747
|
+
A formatted string containing the Solver's attributes.
|
|
748
|
+
|
|
749
|
+
"""
|
|
750
|
+
return self.__str__()
|