src.acoustools.BEM.Gradients.E_Gradient
1import torch 2from torch import Tensor 3 4from vedo import Mesh 5 6import hashlib, pickle 7 8from acoustools.Utilities import DTYPE, forward_model_grad, forward_model_second_derivative_unmixed, forward_model_second_derivative_mixed 9from acoustools.BEM.Forward_models import get_cache_or_compute_H 10from acoustools.Mesh import get_areas, get_centres_as_points, get_normals_as_points 11import acoustools.Constants as Constants 12 13def BEM_forward_model_grad(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, 14 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False,k=Constants.k, 15 path:str="Media", p_ref=Constants.P_ref, internal_points = None, transducer_radius=Constants.radius) -> tuple[Tensor, Tensor, Tensor] | tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]: 16 ''' 17 Computes the gradient of the forward propagation for BEM\n 18 :param scatterer: The mesh used (as a `vedo` `mesh` object) 19 :param transducers: Transducers to use, if `None` uses `acoustools.Utilities.TRANSDUCERS` 20 :param use_cache_H_grad: If true uses the cache system, otherwise computes `H` and does not save it 21 :param print_lines: if true prints messages detaling progress 22 :param H: Precomputed `H` - if `None` `H` will be computed 23 :param return_components: if true will return the subparts used to compute 24 :param path: path to folder containing `BEMCache/` 25 :return: Ex, Ey, Ez 26 ''' 27 if transducers is None: 28 transducers = TRANSDUCERS 29 30 B = points.shape[0] 31 if H is None: 32 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines,p_ref=p_ref, k=k, internal_points=internal_points, transducer_radius=transducer_radius) 33 34 Fx, Fy, Fz = forward_model_grad(points, transducers,p_ref=p_ref, k=k, transducer_radius=transducer_radius) 35 Gx, Gy, Gz = get_G_partial(points, scatterer, transducers, k=k) 36 37 38 Ex = Fx + Gx@H 39 Ey = Fy + Gy@H 40 Ez = Fz + Gz@H 41 42 43 if return_components: 44 return Ex.to(DTYPE), Ey.to(DTYPE), Ez.to(DTYPE), Fx, Fy, Fz, Gx, Gy, Gz, H 45 else: 46 return Ex.to(DTYPE), Ey.to(DTYPE), Ez.to(DTYPE) 47 48 49def get_G_second_unmixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False, k=Constants.k) -> tuple[Tensor, Tensor, Tensor]: 50 51 #Bk.3 Pg.80 52 #P is much higher than the others? 53 54 areas = get_areas(scatterer) 55 centres = get_centres_as_points(scatterer) 56 normals = get_normals_as_points(scatterer).unsqueeze(2) 57 58 N = points.shape[2] 59 M = centres.shape[2] 60 61 points.requires_grad_() 62 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True, k=k) 63 # exit() 64 65 points = points.unsqueeze(3) # [B, 3, N, 1] 66 centres = centres.unsqueeze(2) # [B, 3, 1, M] 67 68 69 diff = points - centres 70 diff_square = diff**2 71 diff_square_sum = torch.sum(diff_square, 1) 72 distances = torch.sqrt(diff_square_sum) 73 distances_cube = distances ** 3 74 distances_five = distances ** 5 75 76 distances_expanded = distances.unsqueeze(1).expand((1,3,N,M)) 77 distances_expanded_square = distances_expanded**2 78 distances_expanded_cube = distances_expanded**3 79 distances_expanded_four = distances_expanded**4 80 distances_expanded_five = distances_expanded**5 81 82 kd = k * distances_expanded 83 84 exp_ikd = torch.exp(1j*kd) 85 86 Gaa = areas/(4*Constants.pi * 1j) *exp_ikd * ((1j*k**2 * diff_square)/ distances_expanded_cube + (1j*k)/distances_expanded_square - 1/distances_expanded_cube - (3*1j*k*diff_square)/distances_expanded_four + (3*diff_square)/distances_expanded_five) 87 Gxx = Gaa[:,0] 88 Gyy = Gaa[:,1] 89 Gzz = Gaa[:,2] 90 91 #P = ik - 1/d 92 # Paa = (distances_expanded * daa - 2*da**2) / distances_expanded_cube 93 # Paa = (3 * diff_square - distances_expanded_square) / distances_expanded_five 94 Paa = 1/distances_expanded_cube - (3*diff_square) / distances_expanded_five #Equal to lines above 95 Pxx = Paa[:,0] 96 Pyy = Paa[:,1] 97 Pzz = Paa[:,2] 98 99 #C = (diff dot c )/ d 100 101 dx = diff[:,0,:,:] 102 dy = diff[:,1,:,:] 103 dz = diff[:,2,:,:] 104 105 106 nx = normals[:,0,:] 107 ny = normals[:,1,:] 108 nz = normals[:,2,:] 109 110 nd = nx * dx + ny * dy + nz * dz 111 112 Cxx = (2 * nx * dx)/distances_cube - nd/distances_cube + (3*nd*dx**2)/distances_five 113 Cyy = (2 * ny * dy)/distances_cube - nd/distances_cube + (3*nd*dy**2)/distances_five 114 Czz = (2 * nz * dz)/distances_cube - nd/distances_cube + (3*nd*dz**2)/distances_five 115 116 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 117 118 # Cxx = (((3 * dax**2)/distances_five) - (1/distances_cube)) * nd - (2*nx*dx) / distances_cube 119 # Cyy = (((3 * day**2)/distances_five) - (1/distances_cube)) * nd - (2*ny*dy) / distances_cube 120 # Czz = (((3 * daz**2)/distances_five) - (1/distances_cube)) * nd - (2*nz*dz) / distances_cube 121 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 122 123 # grad_2_G_unmixed_old = 2 * Ca * (Ga * P + G * Pa) + C * (2 * Ga*Pa + Gaa * P + G * Paa) + G*P*Caa 124 # grad_2_G_unmixed = C * (2*Ga * Pa + Gaa * P + G*Paa) + P * (2*Ga * Ca + G*Caa) + 2*G * Pa * Ca 125 126 Cx = Ca[:,0] 127 Cy = Ca[:,1] 128 Cz = Ca[:,2] 129 130 Px = Pa[:,0] 131 Py = Pa[:,1] 132 Pz = Pa[:,2] 133 134 Gx = Ga[:,0] 135 Gy = Ga[:,1] 136 Gz = Ga[:,2] 137 138 G = G[:,0,:] 139 P = P[:,0,:] 140 141 142 143 grad_2_G_unmixed_xx = Gxx * P * C + G*Pxx*C + G*P*Cxx+ 2*Gx*Px*C + 2*Gx*P*Cx + 2*G*Px*Cx 144 grad_2_G_unmixed_yy = Gyy * P * C + G*Pyy*C + G*P*Cyy+ 2*Gy*Py*C + 2*Gy*P*Cy + 2*G*Py*Cy 145 grad_2_G_unmixed_zz = Gzz * P * C + G*Pzz*C + G*P*Czz+ 2*Gz*Pz*C + 2*Gz*P*Cz + 2*G*Pz*Cz 146 147 if return_components: 148 return grad_2_G_unmixed_xx, grad_2_G_unmixed_yy, grad_2_G_unmixed_zz, G,P,C,Ga,Pa,Ca 149 return grad_2_G_unmixed_xx, grad_2_G_unmixed_yy, grad_2_G_unmixed_zz 150 151 152def get_G_second_mixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False, k=Constants.k) -> tuple[Tensor, Tensor, Tensor]: 153 154 #Bk.3 Pg.81 155 156 areas = get_areas(scatterer).unsqueeze(1) 157 centres = get_centres_as_points(scatterer) 158 normals = get_normals_as_points(scatterer).unsqueeze(2) 159 160 161 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True, k=k) 162 163 points = points.unsqueeze(3) # [B, 3, N, 1] 164 centres = centres.unsqueeze(2) # [B, 3, 1, M] 165 166 diff = points - centres 167 diff_square = diff**2 168 distances = torch.sqrt(torch.sum(diff_square, 1)) 169 distances_square = distances ** 2 170 distances_cube = distances ** 3 171 172 kd = k * distances 173 ikd = 1j * kd 174 175 dx = diff[:,0,:,:] 176 dy = diff[:,1,:,:] 177 dz = diff[:,2,:,:] 178 179 # print(dx.shape, dy.shape, dz.shape, distances_cube.shape) 180 dxy = -dx*dy / distances_cube 181 dxz = -dx*dz / distances_cube 182 dyz = -dy*dz / distances_cube 183 184 # print(dx.shape, distances.shape) 185 dax = dx / distances 186 day = dy / distances 187 daz = dz / distances 188 189 exp_ikd = torch.exp(ikd) 190 191 192 193 # print(areas.shape, exp_ikd.shape, day.shape, dax.shape, distances.shape, distances_cube.shape) 194 Gxy = (-areas * exp_ikd * (day * dax * (kd**2 + 2*ikd - 2) + distances * dxy * (1 - ikd))) / (4*Constants.pi * distances_cube) 195 Gxz = (-areas * exp_ikd * (daz * dax * (kd**2 + 2*ikd - 2) + distances * dxz * (1 - ikd))) / (4*Constants.pi * distances_cube) 196 Gyz = (-areas * exp_ikd * (day * daz * (kd**2 + 2*ikd - 2) + distances * dyz * (1 - ikd))) / (4*Constants.pi * distances_cube) 197 198 nx = normals[:,0,:] 199 ny = normals[:,1,:] 200 nz = normals[:,2,:] 201 202 # print(nx.shape, dx.shape, ny.shape, dy.shape, nz.shape, dz.shape) 203 nd = nx * dx + ny * dy + nz * dz 204 205 Cxy = (-nx*dy - ny*dx + (3*nd*dx*dy/distances_cube)) / distances_square 206 Cxz = (-nx*dz - nz*dx + (3*nd*dx*dz/distances_cube)) / distances_square 207 Cyz = (-nz*dy - ny*dz + (3*nd*dz*dy/distances_cube)) / distances_square 208 209 210 Pxy = (distances * dxy - 2 * day * dax) / distances_cube 211 Pxz = (distances * dxz - 2 * daz * dax) / distances_cube 212 Pyz = (distances * dyz - 2 * day * daz) / distances_cube 213 214 215 G = G[:,0,:] 216 P = P[:,0,:] 217 # C = C.unsqueeze(1).expand(-1,3,-1,-1) 218 219 Gx = Ga[:,0,:] 220 Gy = Ga[:,1,:] 221 Gz = Ga[:,2,:] 222 223 Px = Pa[:,0,:] 224 Py = Pa[:,1,:] 225 Pz = Pa[:,2,:] 226 227 Cx = Ca[:,0,:] 228 Cy = Ca[:,1,:] 229 Cz = Ca[:,2,:] 230 231 # grad_2_G_mixed_xy = Gxy*P*C + Gy*Px*C + Gy*P*Cx + Gx*Py*C + G*Pxy*C + G*Py*Cx + Gx*P*Cy + G*Px*Cy + G*P*Cxy 232 # grad_2_G_mixed_xz = Gxz*P*C + Gz*Px*C + Gz*P*Cx + Gx*Pz*C + G*Pxz*C + G*Pz*Cx + Gx*P*Cz + G*Px*Cz + G*P*Cxz 233 # grad_2_G_mixed_yz = Gyz*P*C + Gy*Pz*C + Gy*P*Cz + Gz*Py*C + G*Pyz*C + G*Py*Cz + Gz*P*Cy + G*Pz*Cy + G*P*Cyz 234 235 236 grad_2_G_mixed_xy = Gxy*P*C + Gx*Py*C + G*Pxy*C + G*Py*Cx + Gx*P*Cy + G*P*Cxy 237 grad_2_G_mixed_xz = Gxz*P*C + Gx*Pz*C + G*Pxz*C + G*Pz*Cx + Gx*P*Cz + G*P*Cxz 238 grad_2_G_mixed_yz = Gyz*P*C + Gz*Py*C + G*Pyz*C + G*Py*Cz + Gz*P*Cy + G*P*Cyz 239 240 241 242 return grad_2_G_mixed_xy, grad_2_G_mixed_xz, grad_2_G_mixed_yz 243 244 245def BEM_forward_model_second_derivative_unmixed(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, k=Constants.k, 246 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 247 path:str="Media", p_ref=Constants.P_ref,internal_points = None, transducer_radius=Constants.radius): 248 249 250 251 if transducers is None: 252 transducers = TRANSDUCERS 253 254 if H is None: 255 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines,p_ref=p_ref, k=k, internal_points=internal_points, transducer_radius=transducer_radius) 256 257 Fxx, Fyy, Fzz = forward_model_second_derivative_unmixed(points,transducers=transducers,p_ref=p_ref, k=k, transducer_radius=transducer_radius) 258 Gxx, Gyy, Gzz = get_G_second_unmixed(points, scatterer, transducers, k=k) 259 260 Exx = Fxx + Gxx@H 261 Eyy = Fyy + Gyy@H 262 Ezz = Fzz + Gzz@H 263 264 return Exx, Eyy, Ezz 265 266def BEM_forward_model_second_derivative_mixed(points:Tensor, scatterer:Mesh, transducers:Tensor|Mesh=None, use_cache_H:bool=True, k=Constants.k, 267 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 268 path:str="Media", p_ref=Constants.P_ref,internal_points = None, transducer_radius=Constants.radius): 269 270 271 if transducers is None: 272 transducers = TRANSDUCERS 273 274 if H is None: 275 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines,p_ref=p_ref, k=k, internal_points=internal_points, transducer_radius=transducer_radius) 276 277 Fxy, Fxz, Fyz = forward_model_second_derivative_mixed(points,transducers=transducers, k=k, transducer_radius=transducer_radius, p_ref=p_ref) 278 Gxy, Gxz, Gyz = get_G_second_mixed(points, scatterer, transducers, k=k) 279 280 281 Exy = Fxy + Gxy@H 282 Exz = Fxz + Gxz@H 283 Eyz = Fyz + Gyz@H 284 285 return Exy, Exz, Eyz 286 287def BEM_laplacian(points:Tensor, scatterer:Mesh, transducers:Tensor|Mesh=None, use_cache_H:bool=True, k=Constants.k, 288 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 289 path:str="Media", p_ref=Constants.P_ref,internal_points = None, transducer_radius=Constants.radius): 290 291 ''' 292 Computes the laplacian of pressure at points given a hologram 293 294 :param activations: Transducer hologram 295 :param points: Points to propagate to 296 :param scatterer: The mesh used (as a `vedo` `mesh` object) 297 :param board: Transducers to use, if `None` then uses `acoustools.Utilities.TOP_BOARD` 298 :param H: Precomputed H - if None H will be computed 299 :param E: Precomputed E - if None E will be computed 300 :param path: path to folder containing `BEMCache/ ` 301 :param use_cache_H: If True uses the cache system to load and save the H matrix. Default `True` 302 :param print_lines: if true prints messages detaling progress 303 :param k: wavenumber 304 :param internal_points: The internal points to use for CHIEF based BEM 305 306 :return pressure: laplacian at points 307 ''' 308 309 Exx, Eyy, Ezz = BEM_forward_model_second_derivative_unmixed(points=points, scatterer=scatterer, transducers=transducers, use_cache_H=use_cache_H, k=k, print_lines=print_lines, H=H, return_components=return_components, path=path, p_ref=p_ref, internal_points=internal_points, transducer_radius=transducer_radius) 310 311 return Exx + Eyy + Ezz 312 313 314 315def get_G_partial(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False, k=Constants.k) -> tuple[Tensor, Tensor, Tensor]: 316 ''' 317 Computes gradient of the G matrix in BEM \n 318 :param points: Points to propagate to 319 :param scatterer: The mesh used (as a `vedo` `mesh` object) 320 :param board: Ignored 321 :param return_components: if true will return the subparts used to compute 322 :return: Gradient of the G matrix in BEM 323 ''' 324 #Bk3. Pg. 26 325 # if board is None: 326 # board = TRANSDUCERS 327 328 areas = get_areas(scatterer) 329 centres = get_centres_as_points(scatterer) 330 normals = get_normals_as_points(scatterer) 331 332 333 N = points.shape[2] 334 M = centres.shape[2] 335 336 337 # points = points.unsqueeze(3).expand(-1,-1,-1,M) 338 # centres = centres.unsqueeze(2).expand(-1,-1,N,-1) 339 points = points.unsqueeze(3) # [B, 3, N, 1] 340 centres = centres.unsqueeze(2) # [B, 3, 1, M] 341 342 diff = (points - centres) 343 diff_square = diff**2 344 distances = torch.sqrt(torch.sum(diff_square, 1)) 345 distances_expanded = distances.unsqueeze(1)#.expand((1,3,N,M)) 346 distances_expanded_square = distances_expanded**2 347 distances_expanded_cube = distances_expanded**3 348 349 # G = e^(ikd) / 4pi d 350 G = areas * torch.exp(1j * k * distances_expanded) / (4*3.1415*distances_expanded) 351 352 #Ga = [i*da * e^{ikd} * (kd+i) / 4pi d^2] 353 354 #d = distance 355 #da = -(at - a)^2 / d 356 da = diff / distances_expanded 357 kd = k * distances_expanded 358 phase = torch.exp(1j*kd) 359 Ga = areas * ( (1j*da*phase * (kd + 1j))/ (4*3.1415*distances_expanded_square)) 360 361 #P = (ik - 1/d) 362 P = (1j*k - 1/distances_expanded) 363 #Pa = da / d^2 = (diff / d^2) /d 364 Pa = diff / distances_expanded_cube 365 366 #C = (diff \cdot normals) / distances 367 368 nx = normals[:,0] 369 ny = normals[:,1] 370 nz = normals[:,2] 371 372 dx = diff[:,0,:] 373 dy = diff[:,1,:] 374 dz = diff[:,2,:] 375 376 n_dot_d = nx*dx + ny*dy + nz*dz 377 378 C = (n_dot_d) / distances 379 380 381 distance_square = distances**2 382 383 384 Cx = 1/distance_square * (nx * distances - (n_dot_d * dx) / distances) 385 Cy = 1/distance_square * (ny * distances - (n_dot_d * dy) / distances) 386 Cz = 1/distance_square * (nz * distances - (n_dot_d * dz) / distances) 387 388 Cx.unsqueeze_(1) 389 Cy.unsqueeze_(1) 390 Cz.unsqueeze_(1) 391 392 Ca = torch.cat([Cx, Cy, Cz],axis=1) 393 394 grad_G = Ga*P*C + G*P*Ca + G*Pa*C 395 396 grad_G = -grad_G.to(DTYPE) 397 398 if return_components: 399 return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:], G,P,C,Ga,Pa, Ca 400 401 return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:]
def
BEM_forward_model_grad( points: torch.Tensor, scatterer: vedo.mesh.Mesh, transducers: torch.Tensor = None, use_cache_H: bool = True, print_lines: bool = False, H: torch.Tensor | None = None, return_components: bool = False, k=732.7329804081634, path: str = 'Media', p_ref=3.4000000000000004, internal_points=None, transducer_radius=0.0045) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor] | tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
15def BEM_forward_model_grad(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, 16 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False,k=Constants.k, 17 path:str="Media", p_ref=Constants.P_ref, internal_points = None, transducer_radius=Constants.radius) -> tuple[Tensor, Tensor, Tensor] | tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]: 18 ''' 19 Computes the gradient of the forward propagation for BEM\n 20 :param scatterer: The mesh used (as a `vedo` `mesh` object) 21 :param transducers: Transducers to use, if `None` uses `acoustools.Utilities.TRANSDUCERS` 22 :param use_cache_H_grad: If true uses the cache system, otherwise computes `H` and does not save it 23 :param print_lines: if true prints messages detaling progress 24 :param H: Precomputed `H` - if `None` `H` will be computed 25 :param return_components: if true will return the subparts used to compute 26 :param path: path to folder containing `BEMCache/` 27 :return: Ex, Ey, Ez 28 ''' 29 if transducers is None: 30 transducers = TRANSDUCERS 31 32 B = points.shape[0] 33 if H is None: 34 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines,p_ref=p_ref, k=k, internal_points=internal_points, transducer_radius=transducer_radius) 35 36 Fx, Fy, Fz = forward_model_grad(points, transducers,p_ref=p_ref, k=k, transducer_radius=transducer_radius) 37 Gx, Gy, Gz = get_G_partial(points, scatterer, transducers, k=k) 38 39 40 Ex = Fx + Gx@H 41 Ey = Fy + Gy@H 42 Ez = Fz + Gz@H 43 44 45 if return_components: 46 return Ex.to(DTYPE), Ey.to(DTYPE), Ez.to(DTYPE), Fx, Fy, Fz, Gx, Gy, Gz, H 47 else: 48 return Ex.to(DTYPE), Ey.to(DTYPE), Ez.to(DTYPE)
Computes the gradient of the forward propagation for BEM
Parameters
- scatterer: The mesh used (as a
vedomeshobject) - transducers: Transducers to use, if
Noneusesacoustools.Utilities.TRANSDUCERS - use_cache_H_grad: If true uses the cache system, otherwise computes
Hand does not save it - print_lines: if true prints messages detaling progress
- H: Precomputed
H- ifNoneHwill be computed - return_components: if true will return the subparts used to compute
- path: path to folder containing
BEMCache/
Returns
Ex, Ey, Ez
def
get_G_second_unmixed( points: torch.Tensor, scatterer: vedo.mesh.Mesh, board: torch.Tensor | None = None, return_components: bool = False, k=732.7329804081634) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
51def get_G_second_unmixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False, k=Constants.k) -> tuple[Tensor, Tensor, Tensor]: 52 53 #Bk.3 Pg.80 54 #P is much higher than the others? 55 56 areas = get_areas(scatterer) 57 centres = get_centres_as_points(scatterer) 58 normals = get_normals_as_points(scatterer).unsqueeze(2) 59 60 N = points.shape[2] 61 M = centres.shape[2] 62 63 points.requires_grad_() 64 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True, k=k) 65 # exit() 66 67 points = points.unsqueeze(3) # [B, 3, N, 1] 68 centres = centres.unsqueeze(2) # [B, 3, 1, M] 69 70 71 diff = points - centres 72 diff_square = diff**2 73 diff_square_sum = torch.sum(diff_square, 1) 74 distances = torch.sqrt(diff_square_sum) 75 distances_cube = distances ** 3 76 distances_five = distances ** 5 77 78 distances_expanded = distances.unsqueeze(1).expand((1,3,N,M)) 79 distances_expanded_square = distances_expanded**2 80 distances_expanded_cube = distances_expanded**3 81 distances_expanded_four = distances_expanded**4 82 distances_expanded_five = distances_expanded**5 83 84 kd = k * distances_expanded 85 86 exp_ikd = torch.exp(1j*kd) 87 88 Gaa = areas/(4*Constants.pi * 1j) *exp_ikd * ((1j*k**2 * diff_square)/ distances_expanded_cube + (1j*k)/distances_expanded_square - 1/distances_expanded_cube - (3*1j*k*diff_square)/distances_expanded_four + (3*diff_square)/distances_expanded_five) 89 Gxx = Gaa[:,0] 90 Gyy = Gaa[:,1] 91 Gzz = Gaa[:,2] 92 93 #P = ik - 1/d 94 # Paa = (distances_expanded * daa - 2*da**2) / distances_expanded_cube 95 # Paa = (3 * diff_square - distances_expanded_square) / distances_expanded_five 96 Paa = 1/distances_expanded_cube - (3*diff_square) / distances_expanded_five #Equal to lines above 97 Pxx = Paa[:,0] 98 Pyy = Paa[:,1] 99 Pzz = Paa[:,2] 100 101 #C = (diff dot c )/ d 102 103 dx = diff[:,0,:,:] 104 dy = diff[:,1,:,:] 105 dz = diff[:,2,:,:] 106 107 108 nx = normals[:,0,:] 109 ny = normals[:,1,:] 110 nz = normals[:,2,:] 111 112 nd = nx * dx + ny * dy + nz * dz 113 114 Cxx = (2 * nx * dx)/distances_cube - nd/distances_cube + (3*nd*dx**2)/distances_five 115 Cyy = (2 * ny * dy)/distances_cube - nd/distances_cube + (3*nd*dy**2)/distances_five 116 Czz = (2 * nz * dz)/distances_cube - nd/distances_cube + (3*nd*dz**2)/distances_five 117 118 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 119 120 # Cxx = (((3 * dax**2)/distances_five) - (1/distances_cube)) * nd - (2*nx*dx) / distances_cube 121 # Cyy = (((3 * day**2)/distances_five) - (1/distances_cube)) * nd - (2*ny*dy) / distances_cube 122 # Czz = (((3 * daz**2)/distances_five) - (1/distances_cube)) * nd - (2*nz*dz) / distances_cube 123 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 124 125 # grad_2_G_unmixed_old = 2 * Ca * (Ga * P + G * Pa) + C * (2 * Ga*Pa + Gaa * P + G * Paa) + G*P*Caa 126 # grad_2_G_unmixed = C * (2*Ga * Pa + Gaa * P + G*Paa) + P * (2*Ga * Ca + G*Caa) + 2*G * Pa * Ca 127 128 Cx = Ca[:,0] 129 Cy = Ca[:,1] 130 Cz = Ca[:,2] 131 132 Px = Pa[:,0] 133 Py = Pa[:,1] 134 Pz = Pa[:,2] 135 136 Gx = Ga[:,0] 137 Gy = Ga[:,1] 138 Gz = Ga[:,2] 139 140 G = G[:,0,:] 141 P = P[:,0,:] 142 143 144 145 grad_2_G_unmixed_xx = Gxx * P * C + G*Pxx*C + G*P*Cxx+ 2*Gx*Px*C + 2*Gx*P*Cx + 2*G*Px*Cx 146 grad_2_G_unmixed_yy = Gyy * P * C + G*Pyy*C + G*P*Cyy+ 2*Gy*Py*C + 2*Gy*P*Cy + 2*G*Py*Cy 147 grad_2_G_unmixed_zz = Gzz * P * C + G*Pzz*C + G*P*Czz+ 2*Gz*Pz*C + 2*Gz*P*Cz + 2*G*Pz*Cz 148 149 if return_components: 150 return grad_2_G_unmixed_xx, grad_2_G_unmixed_yy, grad_2_G_unmixed_zz, G,P,C,Ga,Pa,Ca 151 return grad_2_G_unmixed_xx, grad_2_G_unmixed_yy, grad_2_G_unmixed_zz
def
get_G_second_mixed( points: torch.Tensor, scatterer: vedo.mesh.Mesh, board: torch.Tensor | None = None, return_components: bool = False, k=732.7329804081634) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
154def get_G_second_mixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False, k=Constants.k) -> tuple[Tensor, Tensor, Tensor]: 155 156 #Bk.3 Pg.81 157 158 areas = get_areas(scatterer).unsqueeze(1) 159 centres = get_centres_as_points(scatterer) 160 normals = get_normals_as_points(scatterer).unsqueeze(2) 161 162 163 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True, k=k) 164 165 points = points.unsqueeze(3) # [B, 3, N, 1] 166 centres = centres.unsqueeze(2) # [B, 3, 1, M] 167 168 diff = points - centres 169 diff_square = diff**2 170 distances = torch.sqrt(torch.sum(diff_square, 1)) 171 distances_square = distances ** 2 172 distances_cube = distances ** 3 173 174 kd = k * distances 175 ikd = 1j * kd 176 177 dx = diff[:,0,:,:] 178 dy = diff[:,1,:,:] 179 dz = diff[:,2,:,:] 180 181 # print(dx.shape, dy.shape, dz.shape, distances_cube.shape) 182 dxy = -dx*dy / distances_cube 183 dxz = -dx*dz / distances_cube 184 dyz = -dy*dz / distances_cube 185 186 # print(dx.shape, distances.shape) 187 dax = dx / distances 188 day = dy / distances 189 daz = dz / distances 190 191 exp_ikd = torch.exp(ikd) 192 193 194 195 # print(areas.shape, exp_ikd.shape, day.shape, dax.shape, distances.shape, distances_cube.shape) 196 Gxy = (-areas * exp_ikd * (day * dax * (kd**2 + 2*ikd - 2) + distances * dxy * (1 - ikd))) / (4*Constants.pi * distances_cube) 197 Gxz = (-areas * exp_ikd * (daz * dax * (kd**2 + 2*ikd - 2) + distances * dxz * (1 - ikd))) / (4*Constants.pi * distances_cube) 198 Gyz = (-areas * exp_ikd * (day * daz * (kd**2 + 2*ikd - 2) + distances * dyz * (1 - ikd))) / (4*Constants.pi * distances_cube) 199 200 nx = normals[:,0,:] 201 ny = normals[:,1,:] 202 nz = normals[:,2,:] 203 204 # print(nx.shape, dx.shape, ny.shape, dy.shape, nz.shape, dz.shape) 205 nd = nx * dx + ny * dy + nz * dz 206 207 Cxy = (-nx*dy - ny*dx + (3*nd*dx*dy/distances_cube)) / distances_square 208 Cxz = (-nx*dz - nz*dx + (3*nd*dx*dz/distances_cube)) / distances_square 209 Cyz = (-nz*dy - ny*dz + (3*nd*dz*dy/distances_cube)) / distances_square 210 211 212 Pxy = (distances * dxy - 2 * day * dax) / distances_cube 213 Pxz = (distances * dxz - 2 * daz * dax) / distances_cube 214 Pyz = (distances * dyz - 2 * day * daz) / distances_cube 215 216 217 G = G[:,0,:] 218 P = P[:,0,:] 219 # C = C.unsqueeze(1).expand(-1,3,-1,-1) 220 221 Gx = Ga[:,0,:] 222 Gy = Ga[:,1,:] 223 Gz = Ga[:,2,:] 224 225 Px = Pa[:,0,:] 226 Py = Pa[:,1,:] 227 Pz = Pa[:,2,:] 228 229 Cx = Ca[:,0,:] 230 Cy = Ca[:,1,:] 231 Cz = Ca[:,2,:] 232 233 # grad_2_G_mixed_xy = Gxy*P*C + Gy*Px*C + Gy*P*Cx + Gx*Py*C + G*Pxy*C + G*Py*Cx + Gx*P*Cy + G*Px*Cy + G*P*Cxy 234 # grad_2_G_mixed_xz = Gxz*P*C + Gz*Px*C + Gz*P*Cx + Gx*Pz*C + G*Pxz*C + G*Pz*Cx + Gx*P*Cz + G*Px*Cz + G*P*Cxz 235 # grad_2_G_mixed_yz = Gyz*P*C + Gy*Pz*C + Gy*P*Cz + Gz*Py*C + G*Pyz*C + G*Py*Cz + Gz*P*Cy + G*Pz*Cy + G*P*Cyz 236 237 238 grad_2_G_mixed_xy = Gxy*P*C + Gx*Py*C + G*Pxy*C + G*Py*Cx + Gx*P*Cy + G*P*Cxy 239 grad_2_G_mixed_xz = Gxz*P*C + Gx*Pz*C + G*Pxz*C + G*Pz*Cx + Gx*P*Cz + G*P*Cxz 240 grad_2_G_mixed_yz = Gyz*P*C + Gz*Py*C + G*Pyz*C + G*Py*Cz + Gz*P*Cy + G*P*Cyz 241 242 243 244 return grad_2_G_mixed_xy, grad_2_G_mixed_xz, grad_2_G_mixed_yz
def
BEM_forward_model_second_derivative_unmixed( points: torch.Tensor, scatterer: vedo.mesh.Mesh, transducers: torch.Tensor = None, use_cache_H: bool = True, k=732.7329804081634, print_lines: bool = False, H: torch.Tensor | None = None, return_components: bool = False, path: str = 'Media', p_ref=3.4000000000000004, internal_points=None, transducer_radius=0.0045):
247def BEM_forward_model_second_derivative_unmixed(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, k=Constants.k, 248 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 249 path:str="Media", p_ref=Constants.P_ref,internal_points = None, transducer_radius=Constants.radius): 250 251 252 253 if transducers is None: 254 transducers = TRANSDUCERS 255 256 if H is None: 257 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines,p_ref=p_ref, k=k, internal_points=internal_points, transducer_radius=transducer_radius) 258 259 Fxx, Fyy, Fzz = forward_model_second_derivative_unmixed(points,transducers=transducers,p_ref=p_ref, k=k, transducer_radius=transducer_radius) 260 Gxx, Gyy, Gzz = get_G_second_unmixed(points, scatterer, transducers, k=k) 261 262 Exx = Fxx + Gxx@H 263 Eyy = Fyy + Gyy@H 264 Ezz = Fzz + Gzz@H 265 266 return Exx, Eyy, Ezz
def
BEM_forward_model_second_derivative_mixed( points: torch.Tensor, scatterer: vedo.mesh.Mesh, transducers: torch.Tensor | vedo.mesh.Mesh = None, use_cache_H: bool = True, k=732.7329804081634, print_lines: bool = False, H: torch.Tensor | None = None, return_components: bool = False, path: str = 'Media', p_ref=3.4000000000000004, internal_points=None, transducer_radius=0.0045):
268def BEM_forward_model_second_derivative_mixed(points:Tensor, scatterer:Mesh, transducers:Tensor|Mesh=None, use_cache_H:bool=True, k=Constants.k, 269 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 270 path:str="Media", p_ref=Constants.P_ref,internal_points = None, transducer_radius=Constants.radius): 271 272 273 if transducers is None: 274 transducers = TRANSDUCERS 275 276 if H is None: 277 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines,p_ref=p_ref, k=k, internal_points=internal_points, transducer_radius=transducer_radius) 278 279 Fxy, Fxz, Fyz = forward_model_second_derivative_mixed(points,transducers=transducers, k=k, transducer_radius=transducer_radius, p_ref=p_ref) 280 Gxy, Gxz, Gyz = get_G_second_mixed(points, scatterer, transducers, k=k) 281 282 283 Exy = Fxy + Gxy@H 284 Exz = Fxz + Gxz@H 285 Eyz = Fyz + Gyz@H 286 287 return Exy, Exz, Eyz
def
BEM_laplacian( points: torch.Tensor, scatterer: vedo.mesh.Mesh, transducers: torch.Tensor | vedo.mesh.Mesh = None, use_cache_H: bool = True, k=732.7329804081634, print_lines: bool = False, H: torch.Tensor | None = None, return_components: bool = False, path: str = 'Media', p_ref=3.4000000000000004, internal_points=None, transducer_radius=0.0045):
289def BEM_laplacian(points:Tensor, scatterer:Mesh, transducers:Tensor|Mesh=None, use_cache_H:bool=True, k=Constants.k, 290 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 291 path:str="Media", p_ref=Constants.P_ref,internal_points = None, transducer_radius=Constants.radius): 292 293 ''' 294 Computes the laplacian of pressure at points given a hologram 295 296 :param activations: Transducer hologram 297 :param points: Points to propagate to 298 :param scatterer: The mesh used (as a `vedo` `mesh` object) 299 :param board: Transducers to use, if `None` then uses `acoustools.Utilities.TOP_BOARD` 300 :param H: Precomputed H - if None H will be computed 301 :param E: Precomputed E - if None E will be computed 302 :param path: path to folder containing `BEMCache/ ` 303 :param use_cache_H: If True uses the cache system to load and save the H matrix. Default `True` 304 :param print_lines: if true prints messages detaling progress 305 :param k: wavenumber 306 :param internal_points: The internal points to use for CHIEF based BEM 307 308 :return pressure: laplacian at points 309 ''' 310 311 Exx, Eyy, Ezz = BEM_forward_model_second_derivative_unmixed(points=points, scatterer=scatterer, transducers=transducers, use_cache_H=use_cache_H, k=k, print_lines=print_lines, H=H, return_components=return_components, path=path, p_ref=p_ref, internal_points=internal_points, transducer_radius=transducer_radius) 312 313 return Exx + Eyy + Ezz
Computes the laplacian of pressure at points given a hologram
Parameters
- activations: Transducer hologram
- points: Points to propagate to
- scatterer: The mesh used (as a
vedomeshobject) - board: Transducers to use, if
Nonethen usesacoustools.Utilities.TOP_BOARD - H: Precomputed H - if None H will be computed
- E: Precomputed E - if None E will be computed
- path: path to folder containing
BEMCache/ - use_cache_H: If True uses the cache system to load and save the H matrix. Default
True - print_lines: if true prints messages detaling progress
- k: wavenumber
- internal_points: The internal points to use for CHIEF based BEM
Returns
laplacian at points
def
get_G_partial( points: torch.Tensor, scatterer: vedo.mesh.Mesh, board: torch.Tensor | None = None, return_components: bool = False, k=732.7329804081634) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
317def get_G_partial(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False, k=Constants.k) -> tuple[Tensor, Tensor, Tensor]: 318 ''' 319 Computes gradient of the G matrix in BEM \n 320 :param points: Points to propagate to 321 :param scatterer: The mesh used (as a `vedo` `mesh` object) 322 :param board: Ignored 323 :param return_components: if true will return the subparts used to compute 324 :return: Gradient of the G matrix in BEM 325 ''' 326 #Bk3. Pg. 26 327 # if board is None: 328 # board = TRANSDUCERS 329 330 areas = get_areas(scatterer) 331 centres = get_centres_as_points(scatterer) 332 normals = get_normals_as_points(scatterer) 333 334 335 N = points.shape[2] 336 M = centres.shape[2] 337 338 339 # points = points.unsqueeze(3).expand(-1,-1,-1,M) 340 # centres = centres.unsqueeze(2).expand(-1,-1,N,-1) 341 points = points.unsqueeze(3) # [B, 3, N, 1] 342 centres = centres.unsqueeze(2) # [B, 3, 1, M] 343 344 diff = (points - centres) 345 diff_square = diff**2 346 distances = torch.sqrt(torch.sum(diff_square, 1)) 347 distances_expanded = distances.unsqueeze(1)#.expand((1,3,N,M)) 348 distances_expanded_square = distances_expanded**2 349 distances_expanded_cube = distances_expanded**3 350 351 # G = e^(ikd) / 4pi d 352 G = areas * torch.exp(1j * k * distances_expanded) / (4*3.1415*distances_expanded) 353 354 #Ga = [i*da * e^{ikd} * (kd+i) / 4pi d^2] 355 356 #d = distance 357 #da = -(at - a)^2 / d 358 da = diff / distances_expanded 359 kd = k * distances_expanded 360 phase = torch.exp(1j*kd) 361 Ga = areas * ( (1j*da*phase * (kd + 1j))/ (4*3.1415*distances_expanded_square)) 362 363 #P = (ik - 1/d) 364 P = (1j*k - 1/distances_expanded) 365 #Pa = da / d^2 = (diff / d^2) /d 366 Pa = diff / distances_expanded_cube 367 368 #C = (diff \cdot normals) / distances 369 370 nx = normals[:,0] 371 ny = normals[:,1] 372 nz = normals[:,2] 373 374 dx = diff[:,0,:] 375 dy = diff[:,1,:] 376 dz = diff[:,2,:] 377 378 n_dot_d = nx*dx + ny*dy + nz*dz 379 380 C = (n_dot_d) / distances 381 382 383 distance_square = distances**2 384 385 386 Cx = 1/distance_square * (nx * distances - (n_dot_d * dx) / distances) 387 Cy = 1/distance_square * (ny * distances - (n_dot_d * dy) / distances) 388 Cz = 1/distance_square * (nz * distances - (n_dot_d * dz) / distances) 389 390 Cx.unsqueeze_(1) 391 Cy.unsqueeze_(1) 392 Cz.unsqueeze_(1) 393 394 Ca = torch.cat([Cx, Cy, Cz],axis=1) 395 396 grad_G = Ga*P*C + G*P*Ca + G*Pa*C 397 398 grad_G = -grad_G.to(DTYPE) 399 400 if return_components: 401 return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:], G,P,C,Ga,Pa, Ca 402 403 return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:]
Computes gradient of the G matrix in BEM
Parameters
- points: Points to propagate to
- scatterer: The mesh used (as a
vedomeshobject) - board: Ignored
- return_components: if true will return the subparts used to compute
Returns
Gradient of the G matrix in BEM