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 13 14 15# def get_G_partial(points:Tensor, scatterer:Mesh, board:None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 16# ''' 17# Computes gradient of the G matrix in BEM \n 18# :param points: Points to propagate to 19# :param scatterer: The mesh used (as a `vedo` `mesh` object) 20# :param board: Ignored 21# :param return_components: if true will return the subparts used to compute 22# :return: Gradient of the G matrix in BEM 23# ''' 24# #Bk3. Pg. 26 25 26# areas = get_areas(scatterer) 27# centres = get_centres_as_points(scatterer) 28# normals = get_normals_as_points(scatterer) 29 30# N = points.shape[2] 31# M = centres.shape[2] 32 33# points = points.unsqueeze(3).expand(-1,-1,-1,M) 34# centres = centres.unsqueeze(2).expand(-1,-1,N,-1) 35 36# diff = centres - points 37# diff_square = diff**2 38# diff_square_sum = torch.sum(diff_square, 1) 39# distances = torch.sqrt(torch.sum(diff_square, 1)) 40# distances_expanded = distances.unsqueeze(1).expand((1,3,N,M)) 41# distances_expanded_square = distances_expanded**2 42# distances_expanded_cube = distances_expanded**3 43 44# # G = e^(ikd) / 4pi d 45# G = areas * torch.exp(1j * Constants.k * distances_expanded) / (4*3.1415*distances_expanded) 46 47# #Ga = [i*da * e^{ikd} * (kd+i) / 4pi d^2] 48 49# #d = distance 50# #da = -(at - a)^2 / d 51 52# da = -diff / distances_expanded 53# kd = Constants.k * distances_expanded 54# phase = torch.exp(1j*kd) 55# # Ga = areas * ( (1j*diff*phase * (kd - 1j))/ (4*3.1415*distances_expanded_cube)) 56# print(diff) 57# Ga = (areas * diff * phase * (1-1j*Constants.k*distances_expanded)) / (4*Constants.pi * distances_expanded_cube) 58 59# #P = (ik - 1/d) 60# P = (1j*Constants.k - 1/distances_expanded) 61# #Pa = da / d^2 62# Pa = -da / distances_expanded_cube 63 64# #C = (diff \cdot normals) / distances 65 66# nx = normals[:,0] 67# ny = normals[:,1] 68# nz = normals[:,2] 69 70# dx = diff[:,0,:] 71# dy = diff[:,1,:] 72# dz = diff[:,2,:] 73 74# C = (nx*dx + ny*dy + nz*dz) / distances 75 76 77# distances_cubed = distances**3 78# distance_square = distances**2 79 80# # Cx = (nx*(dy**2 + dz**2) - dx * (ny*dy + nz*dz)) / distances_cubed 81# # Cy = (ny*(dx**2 + dz**2) - dy * (nx*dx + nz*dz)) / distances_cubed 82# # Cz = (nz*(dx**2 + dy**2) - dz * (nx*dx + ny*dy)) / distances_cubed 83 84# Cx = (dx * (nx*dx + ny*dy + nz*dz) - nx*(diff_square_sum) ) / distances_cubed 85# Cy = (dy * (nx*dx + ny*dy + nz*dz) - ny*(diff_square_sum) ) / distances_cubed 86# Cz = (dz * (nx*dx + ny*dy + nz*dz) - nz*(diff_square_sum) ) / distances_cubed 87 88# Cx.unsqueeze_(1) 89# Cy.unsqueeze_(1) 90# Cz.unsqueeze_(1) 91 92# Ca = torch.cat([Cx, Cy, Cz],axis=1) 93 94# grad_G = Ga*P*C + G*P*Ca + G*Pa*C 95 96# grad_G = grad_G.to(DTYPE) 97 98# if return_components: 99# return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:], G,P,C,Ga,Pa,Ca 100 101# return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:] 102 103 104def BEM_forward_model_grad(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, 105 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 106 path:str="Media") -> tuple[Tensor, Tensor, Tensor] | tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]: 107 ''' 108 Computes the gradient of the forward propagation for BEM\n 109 :param scatterer: The mesh used (as a `vedo` `mesh` object) 110 :param transducers: Transducers to use, if `None` uses `acoustools.Utilities.TRANSDUCERS` 111 :param use_cache_H_grad: If true uses the cache system, otherwise computes `H` and does not save it 112 :param print_lines: if true prints messages detaling progress 113 :param H: Precomputed `H` - if `None` `H` will be computed 114 :param return_components: if true will return the subparts used to compute 115 :param path: path to folder containing `BEMCache/` 116 :return: Ex, Ey, Ez 117 ''' 118 if transducers is None: 119 transducers = TRANSDUCERS 120 121 B = points.shape[0] 122 if H is None: 123 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines) 124 125 Fx, Fy, Fz = forward_model_grad(points, transducers) 126 Gx, Gy, Gz = get_G_partial(points, scatterer, transducers) 127 128 129 Ex = Fx - Gx@H #Minus coming out of the PM grad -> Not entoerly sure where that comes from but seems to fix it? 130 Ey = Fy - Gy@H 131 Ez = Fz - Gz@H 132 133 134 if return_components: 135 return Ex.to(DTYPE), Ey.to(DTYPE), Ez.to(DTYPE), Fx, Fy, Fz, Gx, Gy, Gz, H 136 else: 137 return Ex.to(DTYPE), Ey.to(DTYPE), Ez.to(DTYPE) 138 139 140def get_G_second_unmixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 141 142 #Bk.3 Pg.80 143 #P is much higher than the others? 144 145 areas = get_areas(scatterer) 146 centres = get_centres_as_points(scatterer) 147 normals = get_normals_as_points(scatterer).unsqueeze(2) 148 149 N = points.shape[2] 150 M = centres.shape[2] 151 152 points.requires_grad_() 153 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True) 154 # exit() 155 156 points = points.unsqueeze(3) # [B, 3, N, 1] 157 centres = centres.unsqueeze(2) # [B, 3, 1, M] 158 159 160 diff = points - centres 161 diff_square = diff**2 162 diff_square_sum = torch.sum(diff_square, 1) 163 distances = torch.sqrt(diff_square_sum) 164 distances_square = distances ** 2 165 distances_cube = distances ** 3 166 distances_five = distances ** 5 167 168 distances_expanded = distances.unsqueeze(1).expand((1,3,N,M)) 169 distances_expanded_square = distances_expanded**2 170 distances_expanded_cube = distances_expanded**3 171 distances_expanded_four = distances_expanded**4 172 distances_expanded_five = distances_expanded**5 173 174 distance_xy = diff[:,0,:,:] **2 + diff[:,1,:,:] **2 175 distance_xz = diff[:,0,:,:] **2 + diff[:,2,:,:] **2 176 distance_yz = diff[:,1,:,:] **2 + diff[:,2,:,:] **2 177 178 179 da = diff / distances_expanded 180 distance_bs = torch.stack([distance_yz,distance_xz,distance_xy], dim =1) 181 daa = distance_bs / distances_expanded_cube 182 183 kd = Constants.k * distances_expanded 184 185 exp_ikd = torch.exp(1j*kd) 186 187 # G = e^(ikd) / 4pi d 188 # Gaa = (areas/4*Constants.pi) * (-1/distances_expanded_cube * torch.exp(1j*kd) * (da**2 * (kd**2 + 2*1j*kd - 2) + distances_expanded *daa * (1-1j * kd))) 189 # Gaa = -areas / (4*Constants.pi * distances_expanded_cube) * exp_ikd * (da**2 * (kd**2 + 2j * kd - 2) + distances_expanded *daa * (1-1j * kd)) 190 191 # Gaa = areas * ((-Constants.k**2 * diff_square * exp_ikd) / diff_square_sum + (1j*Constants.k * exp_ikd) / distances - (1j * Constants.k * diff_square * exp_ikd)/ distances_expanded_cube) / (4 * Constants.pi * distances) 192 # Gaa += areas * (((3*diff_square)/distances_expanded_five - 1/(distances_expanded_cube)) * exp_ikd) / (4 * Constants.pi) 193 # Gaa -= (1j * Constants.k * areas * diff_square * exp_ikd) / (2 * Constants.pi * distances_expanded_four) #Same as Gaa above 194 Gaa = areas/(4*Constants.pi * 1j) *exp_ikd * ((1j*Constants.k**2 * diff_square)/ distances_expanded_cube + (1j*Constants.k)/distances_expanded_square - 1/distances_expanded_cube - (3*1j*Constants.k*diff_square)/distances_expanded_four + (3*diff_square)/distances_expanded_five) 195 Gxx = Gaa[:,0] 196 Gyy = Gaa[:,1] 197 Gzz = Gaa[:,2] 198 199 #P = ik - 1/d 200 # Paa = (distances_expanded * daa - 2*da**2) / distances_expanded_cube 201 # Paa = (3 * diff_square - distances_expanded_square) / distances_expanded_five 202 Paa = 1/distances_expanded_cube - (3*diff_square) / distances_expanded_five #Equal to lines above 203 Pxx = Paa[:,0] 204 Pyy = Paa[:,1] 205 Pzz = Paa[:,2] 206 207 #C = (diff dot c )/ d 208 209 dx = diff[:,0,:,:] 210 dy = diff[:,1,:,:] 211 dz = diff[:,2,:,:] 212 213 214 nx = normals[:,0,:] 215 ny = normals[:,1,:] 216 nz = normals[:,2,:] 217 218 nd = nx * dx + ny * dy + nz * dz 219 220 Cxx = (2 * nx * dx)/distances_cube - nd/distances_cube + (3*nd*dx**2)/distances_five 221 Cyy = (2 * ny * dy)/distances_cube - nd/distances_cube + (3*nd*dy**2)/distances_five 222 Czz = (2 * nz * dz)/distances_cube - nd/distances_cube + (3*nd*dz**2)/distances_five 223 224 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 225 226 # Cxx = (((3 * dax**2)/distances_five) - (1/distances_cube)) * nd - (2*nx*dx) / distances_cube 227 # Cyy = (((3 * day**2)/distances_five) - (1/distances_cube)) * nd - (2*ny*dy) / distances_cube 228 # Czz = (((3 * daz**2)/distances_five) - (1/distances_cube)) * nd - (2*nz*dz) / distances_cube 229 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 230 231 # grad_2_G_unmixed_old = 2 * Ca * (Ga * P + G * Pa) + C * (2 * Ga*Pa + Gaa * P + G * Paa) + G*P*Caa 232 # grad_2_G_unmixed = C * (2*Ga * Pa + Gaa * P + G*Paa) + P * (2*Ga * Ca + G*Caa) + 2*G * Pa * Ca 233 234 Cx = Ca[:,0] 235 Cy = Ca[:,1] 236 Cz = Ca[:,2] 237 238 Px = Pa[:,0] 239 Py = Pa[:,1] 240 Pz = Pa[:,2] 241 242 Gx = Ga[:,0] 243 Gy = Ga[:,1] 244 Gz = Ga[:,2] 245 246 G = G[:,0,:] 247 P = P[:,0,:] 248 249 250 251 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 252 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 253 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 254 255 if return_components: 256 return grad_2_G_unmixed_xx, grad_2_G_unmixed_yy, grad_2_G_unmixed_zz, G,P,C,Ga,Pa,Ca 257 return grad_2_G_unmixed_xx, grad_2_G_unmixed_yy, grad_2_G_unmixed_zz 258 259 260def get_G_second_mixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 261 262 #Bk.3 Pg.81 263 264 areas = get_areas(scatterer).unsqueeze(1) 265 centres = get_centres_as_points(scatterer) 266 normals = get_normals_as_points(scatterer).unsqueeze(2) 267 268 N = points.shape[2] 269 M = centres.shape[2] 270 271 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True) 272 273 points = points.unsqueeze(3) # [B, 3, N, 1] 274 centres = centres.unsqueeze(2) # [B, 3, 1, M] 275 276 diff = points - centres 277 diff_square = diff**2 278 distances = torch.sqrt(torch.sum(diff_square, 1)) 279 distances_square = distances ** 2 280 distances_cube = distances ** 3 281 distances_four = distances ** 4 282 distances_five = distances ** 5 283 distances_six = distances ** 6 284 285 kd = Constants.k * distances 286 ikd = 1j * kd 287 288 dx = diff[:,0,:,:] 289 dy = diff[:,1,:,:] 290 dz = diff[:,2,:,:] 291 292 # print(dx.shape, dy.shape, dz.shape, distances_cube.shape) 293 dxy = -dx*dy / distances_cube 294 dxz = -dx*dz / distances_cube 295 dyz = -dy*dz / distances_cube 296 297 # print(dx.shape, distances.shape) 298 dax = dx / distances 299 day = dy / distances 300 daz = dz / distances 301 302 exp_ikd = torch.exp(ikd) 303 304 305 306 # print(areas.shape, exp_ikd.shape, day.shape, dax.shape, distances.shape, distances_cube.shape) 307 Gxy = (-areas * exp_ikd * (day * dax * (kd**2 + 2*ikd - 2) + distances * dxy * (1 - ikd))) / (4*Constants.pi * distances_cube) 308 Gxz = (-areas * exp_ikd * (daz * dax * (kd**2 + 2*ikd - 2) + distances * dxz * (1 - ikd))) / (4*Constants.pi * distances_cube) 309 Gyz = (-areas * exp_ikd * (day * daz * (kd**2 + 2*ikd - 2) + distances * dyz * (1 - ikd))) / (4*Constants.pi * distances_cube) 310 311 # Gab = (areas/(Constants.pi*4j)) * exp_ikd * ((-1*Constants.k)/distances_cube - (3j * Constants.k)/distances_four + 3/distances_five ) 312 313 # print(exp_ikd.shape, distances_six.shape, distances.shape, dx.shape,dy.shape,dz.shape) 314 # Gab = (areas/(Constants.pi*4j)) * exp_ikd * (1/distances_six * (3-1j*Constants.k*distances)) 315 # Gxy = (dx * dy) * Gab 316 # Gxz = (dx * dz) * Gab 317 # Gyz = (dz * dy) * Gab 318 319 320 nx = normals[:,0,:] 321 ny = normals[:,1,:] 322 nz = normals[:,2,:] 323 324 # print(nx.shape, dx.shape, ny.shape, dy.shape, nz.shape, dz.shape) 325 nd = nx * dx + ny * dy + nz * dz 326 327 # Cxy = (-ny*dx*distances_square - nx*dy*distances_square + 3 * dy*dx * nd) / distances_five 328 # Cxz = (-nz*dx*distances_square - nx*dz*distances_square + 3 * dz*dx * nd) / distances_five 329 # Cyz = (-ny*dz*distances_square - ny*dz*distances_square + 3 * dz*dy * nd) / distances_five 330 331 # print(nx.shape, dy.shape, ny.shape, dx.shape, distances_cube.shape,distances_square.shape ) 332 Cxy = (-nx*dy - ny*dx + (3*nd*dx*dy/distances_cube)) / distances_square 333 Cxz = (-nx*dz - nz*dx + (3*nd*dx*dz/distances_cube)) / distances_square 334 Cyz = (-nz*dy - ny*dz + (3*nd*dz*dy/distances_cube)) / distances_square 335 336 # Cxy = (2*ny*dx - nx*dy) / distances_cube - (3*(ny*distances_square - nd*dy)* dx) / distances_five 337 # Cxz = (2*nz*dx - nx*dz) / distances_cube - (3*(nz*distances_square - nd*dz)* dx) / distances_five 338 # Cyz = (2*ny*dz - nz*dy) / distances_cube - (3*(ny*distances_square - nd*dy)* dz) / distances_five 339 340 341 # Pxy = -3 * (dx * dy) / distances_five 342 # Pxz = -3 * (dx * dz) / distances_five 343 # Pyz = -3 * (dz * dy) / distances_five 344 345 Pxy = (distances * dxy - 2 * day * dax) / distances_cube 346 Pxz = (distances * dxz - 2 * daz * dax) / distances_cube 347 Pyz = (distances * dyz - 2 * day * daz) / distances_cube 348 349 350 G = G[:,0,:] 351 P = P[:,0,:] 352 # C = C.unsqueeze(1).expand(-1,3,-1,-1) 353 354 Gx = Ga[:,0,:] 355 Gy = Ga[:,1,:] 356 Gz = Ga[:,2,:] 357 358 Px = Pa[:,0,:] 359 Py = Pa[:,1,:] 360 Pz = Pa[:,2,:] 361 362 Cx = Ca[:,0,:] 363 Cy = Ca[:,1,:] 364 Cz = Ca[:,2,:] 365 366 367 # print(Gx*Py*C, G*Py*Cx) 368 # print(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, sep="\n\n") 369 # print(G.shape, Gx.shape, Gy.shape, Gz.shape,P.shape , Px.shape, Py.shape, Pz.shape, C.shape, Cx.shape, Cy.shape, Cz.shape ) 370 371 # 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 372 # 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 373 # 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 374 375 grad_2_G_mixed_xy = Gxy*P*C + Gx*Py*C + G*Pxy*C + G*Py*Cx + Gx*P*Cy + G*P*Cxy 376 grad_2_G_mixed_xz = Gxz*P*C + Gx*Pz*C + G*Pxz*C + G*Pz*Cx + Gx*P*Cz + G*P*Cxz 377 grad_2_G_mixed_yz = Gyz*P*C + Gz*Py*C + G*Pyz*C + G*Py*Cz + Gz*P*Cy + G*P*Cyz 378 379 380 381 return grad_2_G_mixed_xy, grad_2_G_mixed_xz, grad_2_G_mixed_yz 382 383 384def BEM_forward_model_second_derivative_unmixed(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, 385 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 386 path:str="Media"): 387 388 389 if transducers is None: 390 transducers = TRANSDUCERS 391 392 if H is None: 393 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines) 394 395 Fxx, Fyy, Fzz = forward_model_second_derivative_unmixed(points,transducers=transducers) 396 Gxx, Gyy, Gzz = get_G_second_unmixed(points, scatterer, transducers) 397 398 Exx = Fxx + Gxx@H 399 Eyy = Fyy + Gyy@H 400 Ezz = Fzz + Gzz@H 401 402 return Exx, Eyy, Ezz 403 404def BEM_forward_model_second_derivative_mixed(points:Tensor, scatterer:Mesh, transducers:Tensor|Mesh=None, use_cache_H:bool=True, 405 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 406 path:str="Media"): 407 408 409 if transducers is None: 410 transducers = TRANSDUCERS 411 412 if H is None: 413 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines) 414 415 Fxy, Fxz, Fyz = forward_model_second_derivative_mixed(points,transducers=transducers) 416 Gxy, Gxz, Gyz = get_G_second_mixed(points, scatterer, transducers) 417 418 419 Exy = Fxy + Gxy@H 420 Exz = Fxz + Gxz@H 421 Eyz = Fyz + Gyz@H 422 423 return Exy, Exz, Eyz 424 425 426 427 428 429# def get_G_second_mixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 430 431# #Bk.3 Pg.81 432 433# areas = get_areas(scatterer) 434# centres = get_centres_as_points(scatterer) 435# normals = get_normals_as_points(scatterer).unsqueeze(2) 436 437# N = points.shape[2] 438# M = centres.shape[2] 439 440# points = points.unsqueeze(3).expand(-1,-1,-1,M) 441# centres = centres.unsqueeze(2).expand(-1,-1,N,-1) 442 443# diff = points - centres 444# diff_square = diff**2 445# distances = torch.sqrt(torch.sum(diff_square, 1)) 446# distances_square = distances ** 2 447# distances_cube = distances ** 3 448# distances_four = distances ** 4 449# distances_five = distances ** 5 450 451 452# distances_expanded = distances.unsqueeze(1).expand((1,3,N,M)) 453 454# kd = Constants.k * distances 455# exp_ikd = torch.exp(1j*kd) 456 457 458# dx = diff[:,0,:,:] 459# dy = diff[:,1,:,:] 460# dz = diff[:,2,:,:] 461 462# dxy = -dx*dy / distances_cube 463# dxz = -dx*dz / distances_cube 464# dyz = -dy*dz / distances_cube 465 466# da = diff / distances_expanded 467# dax = da[:,0,:,:] 468# day = da[:,1,:,:] 469# daz = da[:,2,:,:] 470 471# F = (areas * 1j * Constants.k * exp_ikd) / ( 4 * Constants.pi * distances) 472# P = (-1 * areas * exp_ikd) / ( 4 * Constants.pi * distances_square) 473 474# Fa = (-1 * Constants.k * areas * da * exp_ikd * (kd + 1j)) / (Constants.pi * 4 * distances_square) 475# Pa = (areas * da * exp_ikd * (2 - 1j*kd)) / (Constants.pi * 4 * distances_cube) 476 477 478# Fxy = (Constants.k * areas * exp_ikd)/(4 * Constants.pi * distances_cube) * (day * dax * (-1j * kd**2 + 2*kd + 2j) - distances*dxy * (kd + 1j)) 479# Fxz = (Constants.k * areas * exp_ikd)/(4 * Constants.pi * distances_cube) * (daz * dax * (-1j * kd**2 + 2*kd + 2j) - distances*dxz * (kd + 1j)) 480# Fyz = (Constants.k * areas * exp_ikd)/(4 * Constants.pi * distances_cube) * (day * daz * (-1j * kd**2 + 2*kd + 2j) - distances*dyz * (kd + 1j)) 481 482# Pxy = (areas * exp_ikd)/(4 * Constants.pi * distances_four) * (day * dax * (kd**2 + 4j*kd -6) -distances*dxy * (2-1j*kd)) 483# Pxz = (areas * exp_ikd)/(4 * Constants.pi * distances_four) * (daz * dax * (kd**2 + 4j*kd -6) -distances*dxz * (2-1j*kd)) 484# Pyz = (areas * exp_ikd)/(4 * Constants.pi * distances_four) * (day * daz * (kd**2 + 4j*kd -6) -distances*dyz * (2-1j*kd)) 485 486 487# nx = normals[:,0,:] 488# ny = normals[:,1,:] 489# nz = normals[:,2,:] 490 491# nd = nx * dx + ny * dy + nz * dz 492 493# C = (diff * normals).sum(dim=1) / distances 494 495# Cxy = (-ny*dx*distances_square - nx*dy*distances_square - 3 * dy*dx * nd) / distances_five 496# Cxz = (-nz*dx*distances_square - nx*dz*distances_square - 3 * dz*dx * nd) / distances_five 497# Cyz = (-ny*dz*distances_square - ny*dz*distances_square - 3 * dz*dy * nd) / distances_five 498 499 500# Cx = (nx*(dx**2 +dy**2 + dz**2) - dx * (ny*dy + nz*dz)) / distances_cube 501# Cy = (ny*(dx**2 +dy**2 + dz**2) - dy * (nx*dx + nz*dz)) / distances_cube 502# Cz = (nz*(dx**2 +dy**2 + dz**2) - dz * (nx*dx + ny*dy)) / distances_cube 503 504# Fx = Fa[:,0,:] 505# Fy = Fa[:,1,:] 506# Fz = Fa[:,2,:] 507 508# Px = Pa[:,0,:] 509# Py = Pa[:,1,:] 510# Pz = Pa[:,2,:] 511 512# print(Fx.shape, Fxy.shape) 513# print(Px.shape, Pxy.shape ) 514# print(Cx.shape, Cxy.shape, C.shape) 515 516 517# grad_2_G_mixed_xy = Cy * (Fx + Px) + Cx * (Fy + Py) + C * (Fxy + Pxy) + Cxy * (F+P) 518# grad_2_G_mixed_xz = Cz * (Fx + Px) + Cx * (Fz + Pz) + C * (Fxz + Pxz) + Cxz * (F+P) 519# grad_2_G_mixed_yz = Cy * (Fz + Pz) + Cz * (Fy + Py) + C * (Fyz + Pyz) + Cyz * (F+P) 520 521 522 523# return grad_2_G_mixed_xy, grad_2_G_mixed_xz, grad_2_G_mixed_yz 524 525def get_G_partial(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 526 ''' 527 Computes gradient of the G matrix in BEM \n 528 :param points: Points to propagate to 529 :param scatterer: The mesh used (as a `vedo` `mesh` object) 530 :param board: Ignored 531 :param return_components: if true will return the subparts used to compute 532 :return: Gradient of the G matrix in BEM 533 ''' 534 #Bk3. Pg. 26 535 # if board is None: 536 # board = TRANSDUCERS 537 538 areas = get_areas(scatterer) 539 centres = get_centres_as_points(scatterer) 540 normals = get_normals_as_points(scatterer) 541 542 543 N = points.shape[2] 544 M = centres.shape[2] 545 546 547 # points = points.unsqueeze(3).expand(-1,-1,-1,M) 548 # centres = centres.unsqueeze(2).expand(-1,-1,N,-1) 549 points = points.unsqueeze(3) # [B, 3, N, 1] 550 centres = centres.unsqueeze(2) # [B, 3, 1, M] 551 552 diff = points - centres 553 diff_square = diff**2 554 distances = torch.sqrt(torch.sum(diff_square, 1)) 555 distances_expanded = distances.unsqueeze(1)#.expand((1,3,N,M)) 556 distances_expanded_square = distances_expanded**2 557 distances_expanded_cube = distances_expanded**3 558 559 # G = e^(ikd) / 4pi d 560 G = areas * torch.exp(1j * Constants.k * distances_expanded) / (4*3.1415*distances_expanded) 561 562 #Ga = [i*da * e^{ikd} * (kd+i) / 4pi d^2] 563 564 #d = distance 565 #da = -(at - a)^2 / d 566 da = diff / distances_expanded 567 kd = Constants.k * distances_expanded 568 phase = torch.exp(1j*kd) 569 Ga = areas * ( (1j*da*phase * (kd + 1j))/ (4*3.1415*distances_expanded_square)) 570 571 #P = (ik - 1/d) 572 P = (1j*Constants.k - 1/distances_expanded) 573 #Pa = da / d^2 574 # Pa = da / distances_expanded_square 575 Pa = diff / distances_expanded_cube 576 577 #C = (diff \cdot normals) / distances 578 579 nx = normals[:,0] 580 ny = normals[:,1] 581 nz = normals[:,2] 582 583 dx = diff[:,0,:] 584 dy = diff[:,1,:] 585 dz = diff[:,2,:] 586 587 n_dot_d = nx*dx + ny*dy + nz*dz 588 589 dax = da[:,0,:] 590 day = da[:,1,:] 591 daz = da[:,2,:] 592 593 C = (nx*dx + ny*dy + nz*dz) / distances 594 595 596 distances_cubed = distances**3 597 distance_square = distances**2 598 599 600 Cx = 1/distance_square * (nx * distances - (n_dot_d * dx) / distances) 601 Cy = 1/distance_square * (ny * distances - (n_dot_d * dy) / distances) 602 Cz = 1/distance_square * (nz * distances - (n_dot_d * dz) / distances) 603 604 Cx.unsqueeze_(1) 605 Cy.unsqueeze_(1) 606 Cz.unsqueeze_(1) 607 608 Ca = torch.cat([Cx, Cy, Cz],axis=1) 609 610 grad_G = Ga*P*C + G*P*Ca + G*Pa*C 611 612 grad_G = grad_G.to(DTYPE) 613 614 if return_components: 615 return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:], G,P,C,Ga,Pa, Ca 616 617 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, path: str = 'Media') -> 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]:
106def BEM_forward_model_grad(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, 107 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 108 path:str="Media") -> tuple[Tensor, Tensor, Tensor] | tuple[Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor]: 109 ''' 110 Computes the gradient of the forward propagation for BEM\n 111 :param scatterer: The mesh used (as a `vedo` `mesh` object) 112 :param transducers: Transducers to use, if `None` uses `acoustools.Utilities.TRANSDUCERS` 113 :param use_cache_H_grad: If true uses the cache system, otherwise computes `H` and does not save it 114 :param print_lines: if true prints messages detaling progress 115 :param H: Precomputed `H` - if `None` `H` will be computed 116 :param return_components: if true will return the subparts used to compute 117 :param path: path to folder containing `BEMCache/` 118 :return: Ex, Ey, Ez 119 ''' 120 if transducers is None: 121 transducers = TRANSDUCERS 122 123 B = points.shape[0] 124 if H is None: 125 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines) 126 127 Fx, Fy, Fz = forward_model_grad(points, transducers) 128 Gx, Gy, Gz = get_G_partial(points, scatterer, transducers) 129 130 131 Ex = Fx - Gx@H #Minus coming out of the PM grad -> Not entoerly sure where that comes from but seems to fix it? 132 Ey = Fy - Gy@H 133 Ez = Fz - Gz@H 134 135 136 if return_components: 137 return Ex.to(DTYPE), Ey.to(DTYPE), Ez.to(DTYPE), Fx, Fy, Fz, Gx, Gy, Gz, H 138 else: 139 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
vedo
mesh
object) - transducers: Transducers to use, if
None
usesacoustools.Utilities.TRANSDUCERS
- use_cache_H_grad: If true uses the cache system, otherwise computes
H
and does not save it - print_lines: if true prints messages detaling progress
- H: Precomputed
H
- ifNone
H
will 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) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
142def get_G_second_unmixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 143 144 #Bk.3 Pg.80 145 #P is much higher than the others? 146 147 areas = get_areas(scatterer) 148 centres = get_centres_as_points(scatterer) 149 normals = get_normals_as_points(scatterer).unsqueeze(2) 150 151 N = points.shape[2] 152 M = centres.shape[2] 153 154 points.requires_grad_() 155 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True) 156 # exit() 157 158 points = points.unsqueeze(3) # [B, 3, N, 1] 159 centres = centres.unsqueeze(2) # [B, 3, 1, M] 160 161 162 diff = points - centres 163 diff_square = diff**2 164 diff_square_sum = torch.sum(diff_square, 1) 165 distances = torch.sqrt(diff_square_sum) 166 distances_square = distances ** 2 167 distances_cube = distances ** 3 168 distances_five = distances ** 5 169 170 distances_expanded = distances.unsqueeze(1).expand((1,3,N,M)) 171 distances_expanded_square = distances_expanded**2 172 distances_expanded_cube = distances_expanded**3 173 distances_expanded_four = distances_expanded**4 174 distances_expanded_five = distances_expanded**5 175 176 distance_xy = diff[:,0,:,:] **2 + diff[:,1,:,:] **2 177 distance_xz = diff[:,0,:,:] **2 + diff[:,2,:,:] **2 178 distance_yz = diff[:,1,:,:] **2 + diff[:,2,:,:] **2 179 180 181 da = diff / distances_expanded 182 distance_bs = torch.stack([distance_yz,distance_xz,distance_xy], dim =1) 183 daa = distance_bs / distances_expanded_cube 184 185 kd = Constants.k * distances_expanded 186 187 exp_ikd = torch.exp(1j*kd) 188 189 # G = e^(ikd) / 4pi d 190 # Gaa = (areas/4*Constants.pi) * (-1/distances_expanded_cube * torch.exp(1j*kd) * (da**2 * (kd**2 + 2*1j*kd - 2) + distances_expanded *daa * (1-1j * kd))) 191 # Gaa = -areas / (4*Constants.pi * distances_expanded_cube) * exp_ikd * (da**2 * (kd**2 + 2j * kd - 2) + distances_expanded *daa * (1-1j * kd)) 192 193 # Gaa = areas * ((-Constants.k**2 * diff_square * exp_ikd) / diff_square_sum + (1j*Constants.k * exp_ikd) / distances - (1j * Constants.k * diff_square * exp_ikd)/ distances_expanded_cube) / (4 * Constants.pi * distances) 194 # Gaa += areas * (((3*diff_square)/distances_expanded_five - 1/(distances_expanded_cube)) * exp_ikd) / (4 * Constants.pi) 195 # Gaa -= (1j * Constants.k * areas * diff_square * exp_ikd) / (2 * Constants.pi * distances_expanded_four) #Same as Gaa above 196 Gaa = areas/(4*Constants.pi * 1j) *exp_ikd * ((1j*Constants.k**2 * diff_square)/ distances_expanded_cube + (1j*Constants.k)/distances_expanded_square - 1/distances_expanded_cube - (3*1j*Constants.k*diff_square)/distances_expanded_four + (3*diff_square)/distances_expanded_five) 197 Gxx = Gaa[:,0] 198 Gyy = Gaa[:,1] 199 Gzz = Gaa[:,2] 200 201 #P = ik - 1/d 202 # Paa = (distances_expanded * daa - 2*da**2) / distances_expanded_cube 203 # Paa = (3 * diff_square - distances_expanded_square) / distances_expanded_five 204 Paa = 1/distances_expanded_cube - (3*diff_square) / distances_expanded_five #Equal to lines above 205 Pxx = Paa[:,0] 206 Pyy = Paa[:,1] 207 Pzz = Paa[:,2] 208 209 #C = (diff dot c )/ d 210 211 dx = diff[:,0,:,:] 212 dy = diff[:,1,:,:] 213 dz = diff[:,2,:,:] 214 215 216 nx = normals[:,0,:] 217 ny = normals[:,1,:] 218 nz = normals[:,2,:] 219 220 nd = nx * dx + ny * dy + nz * dz 221 222 Cxx = (2 * nx * dx)/distances_cube - nd/distances_cube + (3*nd*dx**2)/distances_five 223 Cyy = (2 * ny * dy)/distances_cube - nd/distances_cube + (3*nd*dy**2)/distances_five 224 Czz = (2 * nz * dz)/distances_cube - nd/distances_cube + (3*nd*dz**2)/distances_five 225 226 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 227 228 # Cxx = (((3 * dax**2)/distances_five) - (1/distances_cube)) * nd - (2*nx*dx) / distances_cube 229 # Cyy = (((3 * day**2)/distances_five) - (1/distances_cube)) * nd - (2*ny*dy) / distances_cube 230 # Czz = (((3 * daz**2)/distances_five) - (1/distances_cube)) * nd - (2*nz*dz) / distances_cube 231 # Caa = torch.stack([Cxx, Cyy, Czz], dim=1) 232 233 # grad_2_G_unmixed_old = 2 * Ca * (Ga * P + G * Pa) + C * (2 * Ga*Pa + Gaa * P + G * Paa) + G*P*Caa 234 # grad_2_G_unmixed = C * (2*Ga * Pa + Gaa * P + G*Paa) + P * (2*Ga * Ca + G*Caa) + 2*G * Pa * Ca 235 236 Cx = Ca[:,0] 237 Cy = Ca[:,1] 238 Cz = Ca[:,2] 239 240 Px = Pa[:,0] 241 Py = Pa[:,1] 242 Pz = Pa[:,2] 243 244 Gx = Ga[:,0] 245 Gy = Ga[:,1] 246 Gz = Ga[:,2] 247 248 G = G[:,0,:] 249 P = P[:,0,:] 250 251 252 253 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 254 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 255 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 256 257 if return_components: 258 return grad_2_G_unmixed_xx, grad_2_G_unmixed_yy, grad_2_G_unmixed_zz, G,P,C,Ga,Pa,Ca 259 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) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
262def get_G_second_mixed(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 263 264 #Bk.3 Pg.81 265 266 areas = get_areas(scatterer).unsqueeze(1) 267 centres = get_centres_as_points(scatterer) 268 normals = get_normals_as_points(scatterer).unsqueeze(2) 269 270 N = points.shape[2] 271 M = centres.shape[2] 272 273 grad_Gx, grad_Gy, grad_Gz, G,P,C,Ga,Pa,Ca = get_G_partial(points, scatterer, board, True) 274 275 points = points.unsqueeze(3) # [B, 3, N, 1] 276 centres = centres.unsqueeze(2) # [B, 3, 1, M] 277 278 diff = points - centres 279 diff_square = diff**2 280 distances = torch.sqrt(torch.sum(diff_square, 1)) 281 distances_square = distances ** 2 282 distances_cube = distances ** 3 283 distances_four = distances ** 4 284 distances_five = distances ** 5 285 distances_six = distances ** 6 286 287 kd = Constants.k * distances 288 ikd = 1j * kd 289 290 dx = diff[:,0,:,:] 291 dy = diff[:,1,:,:] 292 dz = diff[:,2,:,:] 293 294 # print(dx.shape, dy.shape, dz.shape, distances_cube.shape) 295 dxy = -dx*dy / distances_cube 296 dxz = -dx*dz / distances_cube 297 dyz = -dy*dz / distances_cube 298 299 # print(dx.shape, distances.shape) 300 dax = dx / distances 301 day = dy / distances 302 daz = dz / distances 303 304 exp_ikd = torch.exp(ikd) 305 306 307 308 # print(areas.shape, exp_ikd.shape, day.shape, dax.shape, distances.shape, distances_cube.shape) 309 Gxy = (-areas * exp_ikd * (day * dax * (kd**2 + 2*ikd - 2) + distances * dxy * (1 - ikd))) / (4*Constants.pi * distances_cube) 310 Gxz = (-areas * exp_ikd * (daz * dax * (kd**2 + 2*ikd - 2) + distances * dxz * (1 - ikd))) / (4*Constants.pi * distances_cube) 311 Gyz = (-areas * exp_ikd * (day * daz * (kd**2 + 2*ikd - 2) + distances * dyz * (1 - ikd))) / (4*Constants.pi * distances_cube) 312 313 # Gab = (areas/(Constants.pi*4j)) * exp_ikd * ((-1*Constants.k)/distances_cube - (3j * Constants.k)/distances_four + 3/distances_five ) 314 315 # print(exp_ikd.shape, distances_six.shape, distances.shape, dx.shape,dy.shape,dz.shape) 316 # Gab = (areas/(Constants.pi*4j)) * exp_ikd * (1/distances_six * (3-1j*Constants.k*distances)) 317 # Gxy = (dx * dy) * Gab 318 # Gxz = (dx * dz) * Gab 319 # Gyz = (dz * dy) * Gab 320 321 322 nx = normals[:,0,:] 323 ny = normals[:,1,:] 324 nz = normals[:,2,:] 325 326 # print(nx.shape, dx.shape, ny.shape, dy.shape, nz.shape, dz.shape) 327 nd = nx * dx + ny * dy + nz * dz 328 329 # Cxy = (-ny*dx*distances_square - nx*dy*distances_square + 3 * dy*dx * nd) / distances_five 330 # Cxz = (-nz*dx*distances_square - nx*dz*distances_square + 3 * dz*dx * nd) / distances_five 331 # Cyz = (-ny*dz*distances_square - ny*dz*distances_square + 3 * dz*dy * nd) / distances_five 332 333 # print(nx.shape, dy.shape, ny.shape, dx.shape, distances_cube.shape,distances_square.shape ) 334 Cxy = (-nx*dy - ny*dx + (3*nd*dx*dy/distances_cube)) / distances_square 335 Cxz = (-nx*dz - nz*dx + (3*nd*dx*dz/distances_cube)) / distances_square 336 Cyz = (-nz*dy - ny*dz + (3*nd*dz*dy/distances_cube)) / distances_square 337 338 # Cxy = (2*ny*dx - nx*dy) / distances_cube - (3*(ny*distances_square - nd*dy)* dx) / distances_five 339 # Cxz = (2*nz*dx - nx*dz) / distances_cube - (3*(nz*distances_square - nd*dz)* dx) / distances_five 340 # Cyz = (2*ny*dz - nz*dy) / distances_cube - (3*(ny*distances_square - nd*dy)* dz) / distances_five 341 342 343 # Pxy = -3 * (dx * dy) / distances_five 344 # Pxz = -3 * (dx * dz) / distances_five 345 # Pyz = -3 * (dz * dy) / distances_five 346 347 Pxy = (distances * dxy - 2 * day * dax) / distances_cube 348 Pxz = (distances * dxz - 2 * daz * dax) / distances_cube 349 Pyz = (distances * dyz - 2 * day * daz) / distances_cube 350 351 352 G = G[:,0,:] 353 P = P[:,0,:] 354 # C = C.unsqueeze(1).expand(-1,3,-1,-1) 355 356 Gx = Ga[:,0,:] 357 Gy = Ga[:,1,:] 358 Gz = Ga[:,2,:] 359 360 Px = Pa[:,0,:] 361 Py = Pa[:,1,:] 362 Pz = Pa[:,2,:] 363 364 Cx = Ca[:,0,:] 365 Cy = Ca[:,1,:] 366 Cz = Ca[:,2,:] 367 368 369 # print(Gx*Py*C, G*Py*Cx) 370 # print(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, sep="\n\n") 371 # print(G.shape, Gx.shape, Gy.shape, Gz.shape,P.shape , Px.shape, Py.shape, Pz.shape, C.shape, Cx.shape, Cy.shape, Cz.shape ) 372 373 # 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 374 # 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 375 # 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 376 377 grad_2_G_mixed_xy = Gxy*P*C + Gx*Py*C + G*Pxy*C + G*Py*Cx + Gx*P*Cy + G*P*Cxy 378 grad_2_G_mixed_xz = Gxz*P*C + Gx*Pz*C + G*Pxz*C + G*Pz*Cx + Gx*P*Cz + G*P*Cxz 379 grad_2_G_mixed_yz = Gyz*P*C + Gz*Py*C + G*Pyz*C + G*Py*Cz + Gz*P*Cy + G*P*Cyz 380 381 382 383 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, print_lines: bool = False, H: torch.Tensor | None = None, return_components: bool = False, path: str = 'Media'):
386def BEM_forward_model_second_derivative_unmixed(points:Tensor, scatterer:Mesh, transducers:Tensor=None, use_cache_H:bool=True, 387 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 388 path:str="Media"): 389 390 391 if transducers is None: 392 transducers = TRANSDUCERS 393 394 if H is None: 395 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines) 396 397 Fxx, Fyy, Fzz = forward_model_second_derivative_unmixed(points,transducers=transducers) 398 Gxx, Gyy, Gzz = get_G_second_unmixed(points, scatterer, transducers) 399 400 Exx = Fxx + Gxx@H 401 Eyy = Fyy + Gyy@H 402 Ezz = Fzz + Gzz@H 403 404 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, print_lines: bool = False, H: torch.Tensor | None = None, return_components: bool = False, path: str = 'Media'):
406def BEM_forward_model_second_derivative_mixed(points:Tensor, scatterer:Mesh, transducers:Tensor|Mesh=None, use_cache_H:bool=True, 407 print_lines:bool=False, H:Tensor|None=None, return_components:bool=False, 408 path:str="Media"): 409 410 411 if transducers is None: 412 transducers = TRANSDUCERS 413 414 if H is None: 415 H = get_cache_or_compute_H(scatterer,transducers,use_cache_H, path, print_lines) 416 417 Fxy, Fxz, Fyz = forward_model_second_derivative_mixed(points,transducers=transducers) 418 Gxy, Gxz, Gyz = get_G_second_mixed(points, scatterer, transducers) 419 420 421 Exy = Fxy + Gxy@H 422 Exz = Fxz + Gxz@H 423 Eyz = Fyz + Gyz@H 424 425 return Exy, Exz, Eyz
def
get_G_partial( points: torch.Tensor, scatterer: vedo.mesh.Mesh, board: torch.Tensor | None = None, return_components: bool = False) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
527def get_G_partial(points:Tensor, scatterer:Mesh, board:Tensor|None=None, return_components:bool=False) -> tuple[Tensor, Tensor, Tensor]: 528 ''' 529 Computes gradient of the G matrix in BEM \n 530 :param points: Points to propagate to 531 :param scatterer: The mesh used (as a `vedo` `mesh` object) 532 :param board: Ignored 533 :param return_components: if true will return the subparts used to compute 534 :return: Gradient of the G matrix in BEM 535 ''' 536 #Bk3. Pg. 26 537 # if board is None: 538 # board = TRANSDUCERS 539 540 areas = get_areas(scatterer) 541 centres = get_centres_as_points(scatterer) 542 normals = get_normals_as_points(scatterer) 543 544 545 N = points.shape[2] 546 M = centres.shape[2] 547 548 549 # points = points.unsqueeze(3).expand(-1,-1,-1,M) 550 # centres = centres.unsqueeze(2).expand(-1,-1,N,-1) 551 points = points.unsqueeze(3) # [B, 3, N, 1] 552 centres = centres.unsqueeze(2) # [B, 3, 1, M] 553 554 diff = points - centres 555 diff_square = diff**2 556 distances = torch.sqrt(torch.sum(diff_square, 1)) 557 distances_expanded = distances.unsqueeze(1)#.expand((1,3,N,M)) 558 distances_expanded_square = distances_expanded**2 559 distances_expanded_cube = distances_expanded**3 560 561 # G = e^(ikd) / 4pi d 562 G = areas * torch.exp(1j * Constants.k * distances_expanded) / (4*3.1415*distances_expanded) 563 564 #Ga = [i*da * e^{ikd} * (kd+i) / 4pi d^2] 565 566 #d = distance 567 #da = -(at - a)^2 / d 568 da = diff / distances_expanded 569 kd = Constants.k * distances_expanded 570 phase = torch.exp(1j*kd) 571 Ga = areas * ( (1j*da*phase * (kd + 1j))/ (4*3.1415*distances_expanded_square)) 572 573 #P = (ik - 1/d) 574 P = (1j*Constants.k - 1/distances_expanded) 575 #Pa = da / d^2 576 # Pa = da / distances_expanded_square 577 Pa = diff / distances_expanded_cube 578 579 #C = (diff \cdot normals) / distances 580 581 nx = normals[:,0] 582 ny = normals[:,1] 583 nz = normals[:,2] 584 585 dx = diff[:,0,:] 586 dy = diff[:,1,:] 587 dz = diff[:,2,:] 588 589 n_dot_d = nx*dx + ny*dy + nz*dz 590 591 dax = da[:,0,:] 592 day = da[:,1,:] 593 daz = da[:,2,:] 594 595 C = (nx*dx + ny*dy + nz*dz) / distances 596 597 598 distances_cubed = distances**3 599 distance_square = distances**2 600 601 602 Cx = 1/distance_square * (nx * distances - (n_dot_d * dx) / distances) 603 Cy = 1/distance_square * (ny * distances - (n_dot_d * dy) / distances) 604 Cz = 1/distance_square * (nz * distances - (n_dot_d * dz) / distances) 605 606 Cx.unsqueeze_(1) 607 Cy.unsqueeze_(1) 608 Cz.unsqueeze_(1) 609 610 Ca = torch.cat([Cx, Cy, Cz],axis=1) 611 612 grad_G = Ga*P*C + G*P*Ca + G*Pa*C 613 614 grad_G = grad_G.to(DTYPE) 615 616 if return_components: 617 return grad_G[:,0,:], grad_G[:,1,:], grad_G[:,2,:], G,P,C,Ga,Pa, Ca 618 619 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
vedo
mesh
object) - board: Ignored
- return_components: if true will return the subparts used to compute
Returns
Gradient of the G matrix in BEM