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.

Files changed (225) hide show
  1. fullwave/__init__.py +28 -0
  2. fullwave/constants/__init__.py +5 -0
  3. fullwave/constants/material_properties.py +112 -0
  4. fullwave/grid.py +222 -0
  5. fullwave/medium.py +1042 -0
  6. fullwave/medium_builder/__init__.py +12 -0
  7. fullwave/medium_builder/domain.py +151 -0
  8. fullwave/medium_builder/medium_builder.py +198 -0
  9. fullwave/medium_builder/presets/__init__.py +8 -0
  10. fullwave/medium_builder/presets/data/.keep +0 -0
  11. fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat +0 -0
  12. fullwave/medium_builder/presets/domain_abdominal_wall.py +293 -0
  13. fullwave/medium_builder/presets/domain_background.py +140 -0
  14. fullwave/medium_builder/presets/domain_scatterer.py +179 -0
  15. fullwave/medium_builder/presets/domain_simple.py +92 -0
  16. fullwave/medium_builder/presets/domain_water_gel.py +1 -0
  17. fullwave/sensor.py +161 -0
  18. fullwave/solver/__init__.py +1 -0
  19. fullwave/solver/bins/database/relaxation_params_database_num_relax=2_20251027_1437.mat +0 -0
  20. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenu +0 -0
  21. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_100_cuda129 +0 -0
  22. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_101_cuda129 +0 -0
  23. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_120_cuda129 +0 -0
  24. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda118 +0 -0
  25. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda124 +0 -0
  26. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda126 +0 -0
  27. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_61_cuda129 +0 -0
  28. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda118 +0 -0
  29. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda124 +0 -0
  30. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda126 +0 -0
  31. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_70_cuda129 +0 -0
  32. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda118 +0 -0
  33. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda124 +0 -0
  34. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda126 +0 -0
  35. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_75_cuda129 +0 -0
  36. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda118 +0 -0
  37. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda124 +0 -0
  38. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda126 +0 -0
  39. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_80_cuda129 +0 -0
  40. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda118 +0 -0
  41. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda124 +0 -0
  42. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda126 +0 -0
  43. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_86_cuda129 +0 -0
  44. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_89_cuda118 +0 -0
  45. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_89_cuda126 +0 -0
  46. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_89_cuda129 +0 -0
  47. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda118 +0 -0
  48. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda124 +0 -0
  49. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda126 +0 -0
  50. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_gpu_sm_90_cuda129 +0 -0
  51. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_100_cuda129 +0 -0
  52. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_101_cuda129 +0 -0
  53. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_120_cuda129 +0 -0
  54. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda118 +0 -0
  55. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda124 +0 -0
  56. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda126 +0 -0
  57. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_61_cuda129 +0 -0
  58. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda118 +0 -0
  59. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda124 +0 -0
  60. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda126 +0 -0
  61. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_70_cuda129 +0 -0
  62. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda118 +0 -0
  63. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda124 +0 -0
  64. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda126 +0 -0
  65. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_75_cuda129 +0 -0
  66. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda118 +0 -0
  67. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda124 +0 -0
  68. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda126 +0 -0
  69. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_80_cuda129 +0 -0
  70. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda118 +0 -0
  71. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda124 +0 -0
  72. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda126 +0 -0
  73. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_86_cuda129 +0 -0
  74. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda118 +0 -0
  75. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda124 +0 -0
  76. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda126 +0 -0
  77. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_89_cuda129 +0 -0
  78. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda118 +0 -0
  79. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda124 +0 -0
  80. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda126 +0 -0
  81. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_gpu_sm_90_cuda129 +0 -0
  82. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_100_cuda129 +0 -0
  83. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_101_cuda129 +0 -0
  84. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_120_cuda129 +0 -0
  85. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda118 +0 -0
  86. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda124 +0 -0
  87. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda126 +0 -0
  88. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_61_cuda129 +0 -0
  89. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda118 +0 -0
  90. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda124 +0 -0
  91. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda126 +0 -0
  92. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_70_cuda129 +0 -0
  93. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda118 +0 -0
  94. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda124 +0 -0
  95. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda126 +0 -0
  96. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_75_cuda129 +0 -0
  97. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda118 +0 -0
  98. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda124 +0 -0
  99. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda126 +0 -0
  100. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_80_cuda129 +0 -0
  101. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda118 +0 -0
  102. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda124 +0 -0
  103. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda126 +0 -0
  104. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_86_cuda129 +0 -0
  105. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda118 +0 -0
  106. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda124 +0 -0
  107. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda126 +0 -0
  108. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_89_cuda129 +0 -0
  109. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda118 +0 -0
  110. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda124 +0 -0
  111. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda126 +0 -0
  112. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_isotropic_multi_gpu_sm_90_cuda129 +0 -0
  113. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_100_cuda129 +0 -0
  114. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_101_cuda129 +0 -0
  115. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_120_cuda129 +0 -0
  116. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda118 +0 -0
  117. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda124 +0 -0
  118. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda126 +0 -0
  119. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_61_cuda129 +0 -0
  120. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda118 +0 -0
  121. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda124 +0 -0
  122. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda126 +0 -0
  123. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_70_cuda129 +0 -0
  124. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda118 +0 -0
  125. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda124 +0 -0
  126. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda126 +0 -0
  127. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_75_cuda129 +0 -0
  128. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda118 +0 -0
  129. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda124 +0 -0
  130. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda126 +0 -0
  131. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_80_cuda129 +0 -0
  132. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda118 +0 -0
  133. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda124 +0 -0
  134. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda126 +0 -0
  135. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_86_cuda129 +0 -0
  136. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda118 +0 -0
  137. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda124 +0 -0
  138. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda126 +0 -0
  139. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_89_cuda129 +0 -0
  140. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda118 +0 -0
  141. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda124 +0 -0
  142. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda126 +0 -0
  143. fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_sm_90_cuda129 +0 -0
  144. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_100_cuda129 +0 -0
  145. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_101_cuda129 +0 -0
  146. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_120_cuda129 +0 -0
  147. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda118 +0 -0
  148. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda124 +0 -0
  149. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda126 +0 -0
  150. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_61_cuda129 +0 -0
  151. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda118 +0 -0
  152. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda124 +0 -0
  153. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda126 +0 -0
  154. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_70_cuda129 +0 -0
  155. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda118 +0 -0
  156. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda124 +0 -0
  157. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda126 +0 -0
  158. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_75_cuda129 +0 -0
  159. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda118 +0 -0
  160. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda124 +0 -0
  161. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda126 +0 -0
  162. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_80_cuda129 +0 -0
  163. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda118 +0 -0
  164. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda124 +0 -0
  165. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda126 +0 -0
  166. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_86_cuda129 +0 -0
  167. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda118 +0 -0
  168. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda124 +0 -0
  169. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda126 +0 -0
  170. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_89_cuda129 +0 -0
  171. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda118 +0 -0
  172. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda124 +0 -0
  173. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda126 +0 -0
  174. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_isotropic_multi_gpu_sm_90_cuda129 +0 -0
  175. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_100_cuda129 +0 -0
  176. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_101_cuda129 +0 -0
  177. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_120_cuda129 +0 -0
  178. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda118 +0 -0
  179. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda124 +0 -0
  180. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda126 +0 -0
  181. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_61_cuda129 +0 -0
  182. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda118 +0 -0
  183. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda124 +0 -0
  184. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda126 +0 -0
  185. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_70_cuda129 +0 -0
  186. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda118 +0 -0
  187. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda124 +0 -0
  188. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda126 +0 -0
  189. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_75_cuda129 +0 -0
  190. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda118 +0 -0
  191. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda124 +0 -0
  192. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda126 +0 -0
  193. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_80_cuda129 +0 -0
  194. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda118 +0 -0
  195. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda124 +0 -0
  196. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda126 +0 -0
  197. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_86_cuda129 +0 -0
  198. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda118 +0 -0
  199. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda124 +0 -0
  200. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda126 +0 -0
  201. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_89_cuda129 +0 -0
  202. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda118 +0 -0
  203. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda124 +0 -0
  204. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda126 +0 -0
  205. fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_sm_90_cuda129 +0 -0
  206. fullwave/solver/cuda_utils.py +392 -0
  207. fullwave/solver/input_file_writer.py +853 -0
  208. fullwave/solver/launcher.py +134 -0
  209. fullwave/solver/pml_builder.py +1923 -0
  210. fullwave/solver/solver.py +750 -0
  211. fullwave/solver/utils.py +83 -0
  212. fullwave/source.py +173 -0
  213. fullwave/transducer.py +1003 -0
  214. fullwave/utils/__init__.py +12 -0
  215. fullwave/utils/check_functions.py +48 -0
  216. fullwave/utils/coordinates.py +155 -0
  217. fullwave/utils/memory_tempfile.py +439 -0
  218. fullwave/utils/numerical.py +111 -0
  219. fullwave/utils/plot_utils.py +1122 -0
  220. fullwave/utils/pulse.py +72 -0
  221. fullwave/utils/relaxation_parameters.py +212 -0
  222. fullwave/utils/signal_process.py +197 -0
  223. fullwave25-1.0.7.dist-info/METADATA +292 -0
  224. fullwave25-1.0.7.dist-info/RECORD +225 -0
  225. 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)