src.acoustools.BEM.Gradients.H_Gradient

  1import torch
  2from torch import Tensor
  3
  4from vedo import Mesh
  5
  6import hashlib, pickle
  7
  8from acoustools.Utilities import device, DTYPE, forward_model_batched, forward_model_grad, forward_model_second_derivative_unmixed
  9from acoustools.BEM.Forward_models import compute_bs, compute_A, get_cache_or_compute_H
 10from acoustools.Mesh import get_centres_as_points, get_normals_as_points, board_name
 11import acoustools.Constants as Constants
 12
 13from acoustools.BEM.Gradients.E_Gradient import get_G_partial
 14
 15
 16 
 17def grad_H(points: Tensor, scatterer: Mesh, transducers: Tensor, return_components:bool = False, 
 18           path:str='', H:Tensor=None, use_cache_H:bool=True) ->tuple[Tensor,Tensor, Tensor] | tuple[Tensor,Tensor, Tensor, Tensor,Tensor, Tensor, Tensor]:
 19    '''
 20    Computes the gradient of H wrt scatterer centres\n
 21    Ignores `points` - for compatability with other gradient functions, takes centres of the scatterers
 22    :param scatterer: The mesh used (as a `vedo` `mesh` object)
 23    :param transducers: Transducers to use 
 24    :param return_components: if true will return the subparts used to compute the derivative
 25    :return grad_H: The gradient of the H matrix wrt the position of the mesh
 26    '''
 27
 28    if H is None:
 29        H = get_cache_or_compute_H(scatterer, transducers, use_cache_H, path)
 30    
 31    
 32    # centres = torch.tensor(scatterer.cell_centers().points).to(device).T.unsqueeze_(0)
 33    centres = get_centres_as_points(scatterer)
 34
 35
 36    M = centres.shape[2]
 37
 38    B = compute_bs(scatterer,transducers)
 39    A = compute_A(scatterer)
 40    A_inv = torch.inverse(A).to(DTYPE)
 41
 42    
 43    Bx, By, Bz = forward_model_grad(centres, transducers)
 44    Bx = Bx.to(DTYPE) 
 45    By = By.to(DTYPE)
 46    Bz = Bz.to(DTYPE)
 47
 48
 49    Ax, Ay, Az =  get_G_partial(centres,scatterer,transducers)
 50    # Ax *= -1
 51    # Ay *= -1
 52    # Az *= -1
 53    
 54    Ax = (-1* Ax)
 55    Ay = (-1* Ay)
 56    Az = (-1* Az)
 57
 58
 59    
 60    eye = torch.eye(M).to(bool)
 61    Ax[:,eye] = 0
 62    Ay[:,eye] = 0
 63    Az[:,eye] = 0
 64    
 65    # A_inv_x = (-1*A_inv @ Ax @ A_inv).to(DTYPE)
 66    # A_inv_y = (-1*A_inv @ Ay @ A_inv).to(DTYPE)
 67    # A_inv_z = (-1*A_inv @ Az @ A_inv).to(DTYPE)
 68
 69    # Hx_old = (A_inv_x@B) + (A_inv@Bx)
 70    # Hy_old = (A_inv_y@B) + (A_inv@By)
 71    # Hz_old = (A_inv_z@B) + (A_inv@Bz)
 72
 73
 74    Hx = A_inv @ (Bx - Ax @ H)
 75    Hy = A_inv @ (By - Ay @ H)
 76    Hz = A_inv @ (Bz - Az @ H)
 77
 78
 79    Hx = Hx.to(DTYPE)
 80    Hy = Hy.to(DTYPE)
 81    Hz = Hz.to(DTYPE)
 82
 83    if return_components:
 84        return Hx, Hy, Hz, A, A_inv, Ax, Ay, Az
 85    else:
 86        return Hx, Hy, Hz
 87
 88 
 89def grad_2_H(points: Tensor, scatterer: Mesh, transducers: Tensor, A:Tensor|None = None, 
 90             A_inv:Tensor|None = None, Ax:Tensor|None = None, Ay:Tensor|None = None, Az:Tensor|None = None) -> Tensor:
 91    '''
 92    Computes the second derivative of H wrt scatterer centres\n
 93    Ignores `points` - for compatability with other gradient functions, takes centres of the scatterers
 94    :param scatterer: The mesh used (as a `vedo` `mesh` object)
 95    :param transducers: Transducers to use 
 96    :param A: The result of a call to `compute_A`
 97    :param A_inv: The inverse of `A`
 98    :param Ax: The gradient of A wrt the x position of scatterer centres
 99    :param Ay: The gradient of A wrt the y position of scatterer centres
100    :param Az: The gradient of A wrt the z position of scatterer centres
101    :return Haa: second order unmixed gradient of H wrt scatterer positions
102    '''
103
104    centres = get_centres_as_points(scatterer)
105    M = centres.shape[2]
106
107    B = compute_bs(scatterer,transducers)
108
109    Fx, Fy, Fz = forward_model_grad(centres, transducers)
110    Fx = Fx.to(DTYPE)
111    Fy = Fy.to(DTYPE)
112    Fz = Fz.to(DTYPE)
113    Fa = torch.stack([Fx,Fy,Fz],dim=3)
114
115    Fxx, Fyy, Fzz = forward_model_second_derivative_unmixed(centres, transducers)
116    Faa = torch.stack([Fxx,Fyy,Fzz],dim=3)
117
118    F = forward_model_batched(centres, transducers)
119    
120    if A is None:
121        A = compute_A(scatterer)
122    
123    if A_inv is None:
124        A_inv = torch.inverse(A)
125    
126    if Ax is None or Ay is None or Az is None:
127        Ax, Ay, Az = get_G_partial(centres,scatterer,transducers)
128        eye = torch.eye(M).to(bool)
129        Ax[:,eye] = 0
130        Ay[:,eye] = 0
131        Az[:,eye] = 0
132        Ax = Ax.to(DTYPE)
133        Ay = Ay.to(DTYPE)
134        Az = Az.to(DTYPE)
135    Aa = torch.stack([Ax,Ay,Az],dim=3)
136
137    
138    A_inv_x = (-1*A_inv @ Ax @ A_inv).to(DTYPE)
139    A_inv_y = (-1*A_inv @ Ay @ A_inv).to(DTYPE)
140    A_inv_z = (-1*A_inv @ Az @ A_inv).to(DTYPE)
141
142
143    A_inv_a = torch.stack([A_inv_x,A_inv_y,A_inv_z],dim=3)
144
145    m = centres.permute(0,2,1)
146    m = m.expand((M,M,3))
147
148    m_prime = m.clone()
149    m_prime = m_prime.permute((1,0,2))
150
151    vecs = m - m_prime
152    vecs = vecs.unsqueeze(0)
153    
154
155    # norms = torch.tensor(scatterer.cell_normals).to(device)
156    norms = get_normals_as_points(scatterer,permute_to_points=False)
157    norms = norms.expand(1,M,-1,-1)
158
159    norm_norms = torch.norm(norms,2,dim=3)
160    vec_norms = torch.norm(vecs,2,dim=3)
161    vec_norms_cube = vec_norms**3
162    vec_norms_five = vec_norms**5
163
164    distance = torch.sqrt(torch.sum(vecs**2,dim=3))
165    vecs_square = vecs **2
166    distance_exp = torch.unsqueeze(distance,3)
167    distance_exp = distance_exp.expand(-1,-1,-1,3)
168    
169    distance_exp_cube = distance_exp**3
170
171    distaa = torch.zeros_like(distance_exp)
172    distaa[:,:,:,0] = (vecs_square[:,:,:,1] + vecs_square[:,:,:,2]) 
173    distaa[:,:,:,1] = (vecs_square[:,:,:,0] + vecs_square[:,:,:,2]) 
174    distaa[:,:,:,2] = (vecs_square[:,:,:,1] + vecs_square[:,:,:,0])
175    distaa = distaa / distance_exp_cube
176
177    dista = vecs / distance_exp
178
179    Aaa = (-1 * torch.exp(1j*Constants.k * distance_exp) * (distance_exp*(1-1j*Constants.k*distance_exp))*distaa + dista*(Constants.k**2 * distance_exp**2 + 2*1j*Constants.k * distance_exp -2)) / (4*torch.pi * distance_exp_cube)
180    
181    Baa = (distance_exp * distaa - 2*dista**2) / distance_exp_cube
182
183    Caa = torch.zeros_like(distance_exp).to(device)
184
185    vec_dot_norm = vecs[:,:,:,0]*norms[:,:,:,0]+vecs[:,:,:,1]*norms[:,:,:,1]+vecs[:,:,:,2]*norms[:,:,:,2]
186
187    Caa[:,:,:,0] = ((( (3 * vecs[:,:,:,0]**2) / (vec_norms_five) - (1)/(vec_norms_cube))*(vec_dot_norm)) / norm_norms) - ((2*vecs[:,:,:,0]*norms[:,:,:,0]) / (norm_norms*vec_norms_cube**3))
188    Caa[:,:,:,1] = ((( (3 * vecs[:,:,:,1]**2) / (vec_norms_five) - (1)/(vec_norms_cube))*(vec_dot_norm)) / norm_norms) - ((2*vecs[:,:,:,1]*norms[:,:,:,1]) / (norm_norms*vec_norms_cube**3))
189    Caa[:,:,:,2] = ((( (3 * vecs[:,:,:,2]**2) / (vec_norms_five) - (1)/(vec_norms_cube))*(vec_dot_norm)) / norm_norms) - ((2*vecs[:,:,:,2]*norms[:,:,:,2]) / (norm_norms*vec_norms_cube**3))
190    
191    Gx, Gy, Gz, A_green, B_green, C_green, Aa_green, Ba_green, Ca_green = get_G_partial(centres, scatterer, transducers, return_components=True)
192
193    Gaa = 2*Ca_green*(B_green*Aa_green + A_green*Ba_green) + C_green*(B_green*Aaa + 2*Aa_green*Ba_green + A_green*Baa)+ A_green*B_green*Caa
194    Gaa = Gaa.to(DTYPE)
195
196    areas = torch.Tensor(scatterer.celldata["Area"]).to(device)
197    areas = torch.unsqueeze(areas,0)
198    areas = torch.unsqueeze(areas,0)
199    areas = torch.unsqueeze(areas,3)
200
201    Gaa = Gaa * areas
202    # Gaa = torch.nan_to_num(Gaa)
203    eye = torch.eye(Gaa.shape[2]).to(bool)
204    Gaa[:,eye] = 0
205    
206    
207    A_inv_a = A_inv_a.permute(0,3,2,1)
208    Fa = Fa.permute(0,3,1,2)
209
210    A_inv = A_inv.unsqueeze(1).expand(-1,3,-1,-1)
211    Faa = Faa.permute(0,3,1,2)
212
213    Fa = Fa.to(DTYPE)
214    Faa = Faa.to(DTYPE)
215
216    Gaa = Gaa.permute(0,3,2,1)
217    Aa = Aa.permute(0,3,2,1)
218    Aa = Aa.to(DTYPE)
219
220    X1 = A_inv_a @ Fa + A_inv @ Faa
221    X2 = (A_inv @ (Aa @ A_inv @ Aa - Gaa)@A_inv) @ F
222    X3 = A_inv_a@Fa
223
224
225    Haa = X1 + X2 + X3
226    
227    return Haa
228
229 
230def get_cache_or_compute_H_2_gradients(scatterer:Mesh,board:Tensor,use_cache_H_grad:bool=True, path:str="Media", print_lines:bool=False) -> Tensor:
231    '''
232    Get second derivatives of H using cache system. Expects a folder named BEMCache in `path`\n
233    :param scatterer: The mesh used (as a `vedo` `mesh` object)
234    :param board: Transducers to use 
235    :param use_cache_H_grad: If true uses the cache system, otherwise computes H and does not save it
236    :param path: path to folder containing `BEMCache/ `
237    :param print_lines: if true prints messages detaling progress
238    :return: second derivatives of H
239    '''
240    if use_cache_H_grad:
241        
242        f_name = scatterer.filename+"--"+ board_name(board)
243        f_name = hashlib.md5(f_name.encode()).hexdigest()
244        f_name = path+"/BEMCache/"  +  f_name +"_2grad"+ ".bin"
245
246        try:
247            if print_lines: print("Trying to load H 2 grads at", f_name ,"...")
248            Haa = pickle.load(open(f_name,"rb"))
249            Haa = Haa.to(device)
250        except FileNotFoundError: 
251            if print_lines: print("Not found, computing H grad 2...")
252            Haa = grad_2_H(None, transducers=board, **{"scatterer":scatterer })
253            f = open(f_name,"wb")
254            pickle.dump(Haa,f)
255            f.close()
256    else:
257        if print_lines: print("Computing H grad 2...")
258        Haa = grad_2_H(None, transducers=board, **{"scatterer":scatterer })
259
260    return Haa
261
262 
263def get_cache_or_compute_H_gradients(scatterer,board,use_cache_H_grad=True, path="Media", print_lines=False) -> tuple[Tensor, Tensor, Tensor]:
264    '''
265    Get derivatives of H using cache system. Expects a folder named BEMCache in `path`\\
266    :param scatterer: The mesh used (as a `vedo` `mesh` object)\\
267    :param board: Transducers to use \\
268    :param use_cache_H_grad: If true uses the cache system, otherwise computes H and does not save it\\
269    :param path: path to folder containing BEMCache/ \\
270    :param print_lines: if true prints messages detaling progress\\
271    Returns derivatives of H
272    '''
273
274    if use_cache_H_grad:
275        
276        f_name = scatterer.filename +"--"+ board_name(board)
277        f_name = hashlib.md5(f_name.encode()).hexdigest()
278        f_name = path+"/BEMCache/"  +  f_name +"_grad"+ ".bin"
279
280        try:
281            if print_lines: print("Trying to load H grads at", f_name ,"...")
282            Hx, Hy, Hz = pickle.load(open(f_name,"rb"))
283            Hx = Hx.to(device)
284            Hy = Hy.to(device)
285            Hz = Hz.to(device)
286        except FileNotFoundError: 
287            if print_lines: print("Not found, computing H Grads...")
288            Hx, Hy, Hz = grad_H(None, transducers=board, **{"scatterer":scatterer }, path=path)
289            f = open(f_name,"wb")
290            pickle.dump((Hx, Hy, Hz),f)
291            f.close()
292    else:
293        if print_lines: print("Computing H Grad...")
294        Hx, Hy, Hz = grad_H(None, transducers=board, **{"scatterer":scatterer }, path=path)
295
296    return Hx, Hy, Hz
def grad_H( points: torch.Tensor, scatterer: vedo.mesh.Mesh, transducers: torch.Tensor, return_components: bool = False, path: str = '', H: torch.Tensor = None, use_cache_H: bool = True) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor] | tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
18def grad_H(points: Tensor, scatterer: Mesh, transducers: Tensor, return_components:bool = False, 
19           path:str='', H:Tensor=None, use_cache_H:bool=True) ->tuple[Tensor,Tensor, Tensor] | tuple[Tensor,Tensor, Tensor, Tensor,Tensor, Tensor, Tensor]:
20    '''
21    Computes the gradient of H wrt scatterer centres\n
22    Ignores `points` - for compatability with other gradient functions, takes centres of the scatterers
23    :param scatterer: The mesh used (as a `vedo` `mesh` object)
24    :param transducers: Transducers to use 
25    :param return_components: if true will return the subparts used to compute the derivative
26    :return grad_H: The gradient of the H matrix wrt the position of the mesh
27    '''
28
29    if H is None:
30        H = get_cache_or_compute_H(scatterer, transducers, use_cache_H, path)
31    
32    
33    # centres = torch.tensor(scatterer.cell_centers().points).to(device).T.unsqueeze_(0)
34    centres = get_centres_as_points(scatterer)
35
36
37    M = centres.shape[2]
38
39    B = compute_bs(scatterer,transducers)
40    A = compute_A(scatterer)
41    A_inv = torch.inverse(A).to(DTYPE)
42
43    
44    Bx, By, Bz = forward_model_grad(centres, transducers)
45    Bx = Bx.to(DTYPE) 
46    By = By.to(DTYPE)
47    Bz = Bz.to(DTYPE)
48
49
50    Ax, Ay, Az =  get_G_partial(centres,scatterer,transducers)
51    # Ax *= -1
52    # Ay *= -1
53    # Az *= -1
54    
55    Ax = (-1* Ax)
56    Ay = (-1* Ay)
57    Az = (-1* Az)
58
59
60    
61    eye = torch.eye(M).to(bool)
62    Ax[:,eye] = 0
63    Ay[:,eye] = 0
64    Az[:,eye] = 0
65    
66    # A_inv_x = (-1*A_inv @ Ax @ A_inv).to(DTYPE)
67    # A_inv_y = (-1*A_inv @ Ay @ A_inv).to(DTYPE)
68    # A_inv_z = (-1*A_inv @ Az @ A_inv).to(DTYPE)
69
70    # Hx_old = (A_inv_x@B) + (A_inv@Bx)
71    # Hy_old = (A_inv_y@B) + (A_inv@By)
72    # Hz_old = (A_inv_z@B) + (A_inv@Bz)
73
74
75    Hx = A_inv @ (Bx - Ax @ H)
76    Hy = A_inv @ (By - Ay @ H)
77    Hz = A_inv @ (Bz - Az @ H)
78
79
80    Hx = Hx.to(DTYPE)
81    Hy = Hy.to(DTYPE)
82    Hz = Hz.to(DTYPE)
83
84    if return_components:
85        return Hx, Hy, Hz, A, A_inv, Ax, Ay, Az
86    else:
87        return Hx, Hy, Hz

Computes the gradient of H wrt scatterer centres

Ignores points - for compatability with other gradient functions, takes centres of the scatterers

Parameters
  • scatterer: The mesh used (as a vedo mesh object)
  • transducers: Transducers to use
  • return_components: if true will return the subparts used to compute the derivative
Returns

The gradient of the H matrix wrt the position of the mesh

def grad_2_H( points: torch.Tensor, scatterer: vedo.mesh.Mesh, transducers: torch.Tensor, A: torch.Tensor | None = None, A_inv: torch.Tensor | None = None, Ax: torch.Tensor | None = None, Ay: torch.Tensor | None = None, Az: torch.Tensor | None = None) -> torch.Tensor:
 90def grad_2_H(points: Tensor, scatterer: Mesh, transducers: Tensor, A:Tensor|None = None, 
 91             A_inv:Tensor|None = None, Ax:Tensor|None = None, Ay:Tensor|None = None, Az:Tensor|None = None) -> Tensor:
 92    '''
 93    Computes the second derivative of H wrt scatterer centres\n
 94    Ignores `points` - for compatability with other gradient functions, takes centres of the scatterers
 95    :param scatterer: The mesh used (as a `vedo` `mesh` object)
 96    :param transducers: Transducers to use 
 97    :param A: The result of a call to `compute_A`
 98    :param A_inv: The inverse of `A`
 99    :param Ax: The gradient of A wrt the x position of scatterer centres
100    :param Ay: The gradient of A wrt the y position of scatterer centres
101    :param Az: The gradient of A wrt the z position of scatterer centres
102    :return Haa: second order unmixed gradient of H wrt scatterer positions
103    '''
104
105    centres = get_centres_as_points(scatterer)
106    M = centres.shape[2]
107
108    B = compute_bs(scatterer,transducers)
109
110    Fx, Fy, Fz = forward_model_grad(centres, transducers)
111    Fx = Fx.to(DTYPE)
112    Fy = Fy.to(DTYPE)
113    Fz = Fz.to(DTYPE)
114    Fa = torch.stack([Fx,Fy,Fz],dim=3)
115
116    Fxx, Fyy, Fzz = forward_model_second_derivative_unmixed(centres, transducers)
117    Faa = torch.stack([Fxx,Fyy,Fzz],dim=3)
118
119    F = forward_model_batched(centres, transducers)
120    
121    if A is None:
122        A = compute_A(scatterer)
123    
124    if A_inv is None:
125        A_inv = torch.inverse(A)
126    
127    if Ax is None or Ay is None or Az is None:
128        Ax, Ay, Az = get_G_partial(centres,scatterer,transducers)
129        eye = torch.eye(M).to(bool)
130        Ax[:,eye] = 0
131        Ay[:,eye] = 0
132        Az[:,eye] = 0
133        Ax = Ax.to(DTYPE)
134        Ay = Ay.to(DTYPE)
135        Az = Az.to(DTYPE)
136    Aa = torch.stack([Ax,Ay,Az],dim=3)
137
138    
139    A_inv_x = (-1*A_inv @ Ax @ A_inv).to(DTYPE)
140    A_inv_y = (-1*A_inv @ Ay @ A_inv).to(DTYPE)
141    A_inv_z = (-1*A_inv @ Az @ A_inv).to(DTYPE)
142
143
144    A_inv_a = torch.stack([A_inv_x,A_inv_y,A_inv_z],dim=3)
145
146    m = centres.permute(0,2,1)
147    m = m.expand((M,M,3))
148
149    m_prime = m.clone()
150    m_prime = m_prime.permute((1,0,2))
151
152    vecs = m - m_prime
153    vecs = vecs.unsqueeze(0)
154    
155
156    # norms = torch.tensor(scatterer.cell_normals).to(device)
157    norms = get_normals_as_points(scatterer,permute_to_points=False)
158    norms = norms.expand(1,M,-1,-1)
159
160    norm_norms = torch.norm(norms,2,dim=3)
161    vec_norms = torch.norm(vecs,2,dim=3)
162    vec_norms_cube = vec_norms**3
163    vec_norms_five = vec_norms**5
164
165    distance = torch.sqrt(torch.sum(vecs**2,dim=3))
166    vecs_square = vecs **2
167    distance_exp = torch.unsqueeze(distance,3)
168    distance_exp = distance_exp.expand(-1,-1,-1,3)
169    
170    distance_exp_cube = distance_exp**3
171
172    distaa = torch.zeros_like(distance_exp)
173    distaa[:,:,:,0] = (vecs_square[:,:,:,1] + vecs_square[:,:,:,2]) 
174    distaa[:,:,:,1] = (vecs_square[:,:,:,0] + vecs_square[:,:,:,2]) 
175    distaa[:,:,:,2] = (vecs_square[:,:,:,1] + vecs_square[:,:,:,0])
176    distaa = distaa / distance_exp_cube
177
178    dista = vecs / distance_exp
179
180    Aaa = (-1 * torch.exp(1j*Constants.k * distance_exp) * (distance_exp*(1-1j*Constants.k*distance_exp))*distaa + dista*(Constants.k**2 * distance_exp**2 + 2*1j*Constants.k * distance_exp -2)) / (4*torch.pi * distance_exp_cube)
181    
182    Baa = (distance_exp * distaa - 2*dista**2) / distance_exp_cube
183
184    Caa = torch.zeros_like(distance_exp).to(device)
185
186    vec_dot_norm = vecs[:,:,:,0]*norms[:,:,:,0]+vecs[:,:,:,1]*norms[:,:,:,1]+vecs[:,:,:,2]*norms[:,:,:,2]
187
188    Caa[:,:,:,0] = ((( (3 * vecs[:,:,:,0]**2) / (vec_norms_five) - (1)/(vec_norms_cube))*(vec_dot_norm)) / norm_norms) - ((2*vecs[:,:,:,0]*norms[:,:,:,0]) / (norm_norms*vec_norms_cube**3))
189    Caa[:,:,:,1] = ((( (3 * vecs[:,:,:,1]**2) / (vec_norms_five) - (1)/(vec_norms_cube))*(vec_dot_norm)) / norm_norms) - ((2*vecs[:,:,:,1]*norms[:,:,:,1]) / (norm_norms*vec_norms_cube**3))
190    Caa[:,:,:,2] = ((( (3 * vecs[:,:,:,2]**2) / (vec_norms_five) - (1)/(vec_norms_cube))*(vec_dot_norm)) / norm_norms) - ((2*vecs[:,:,:,2]*norms[:,:,:,2]) / (norm_norms*vec_norms_cube**3))
191    
192    Gx, Gy, Gz, A_green, B_green, C_green, Aa_green, Ba_green, Ca_green = get_G_partial(centres, scatterer, transducers, return_components=True)
193
194    Gaa = 2*Ca_green*(B_green*Aa_green + A_green*Ba_green) + C_green*(B_green*Aaa + 2*Aa_green*Ba_green + A_green*Baa)+ A_green*B_green*Caa
195    Gaa = Gaa.to(DTYPE)
196
197    areas = torch.Tensor(scatterer.celldata["Area"]).to(device)
198    areas = torch.unsqueeze(areas,0)
199    areas = torch.unsqueeze(areas,0)
200    areas = torch.unsqueeze(areas,3)
201
202    Gaa = Gaa * areas
203    # Gaa = torch.nan_to_num(Gaa)
204    eye = torch.eye(Gaa.shape[2]).to(bool)
205    Gaa[:,eye] = 0
206    
207    
208    A_inv_a = A_inv_a.permute(0,3,2,1)
209    Fa = Fa.permute(0,3,1,2)
210
211    A_inv = A_inv.unsqueeze(1).expand(-1,3,-1,-1)
212    Faa = Faa.permute(0,3,1,2)
213
214    Fa = Fa.to(DTYPE)
215    Faa = Faa.to(DTYPE)
216
217    Gaa = Gaa.permute(0,3,2,1)
218    Aa = Aa.permute(0,3,2,1)
219    Aa = Aa.to(DTYPE)
220
221    X1 = A_inv_a @ Fa + A_inv @ Faa
222    X2 = (A_inv @ (Aa @ A_inv @ Aa - Gaa)@A_inv) @ F
223    X3 = A_inv_a@Fa
224
225
226    Haa = X1 + X2 + X3
227    
228    return Haa

Computes the second derivative of H wrt scatterer centres

Ignores points - for compatability with other gradient functions, takes centres of the scatterers

Parameters
  • scatterer: The mesh used (as a vedo mesh object)
  • transducers: Transducers to use
  • A: The result of a call to compute_A
  • A_inv: The inverse of A
  • Ax: The gradient of A wrt the x position of scatterer centres
  • Ay: The gradient of A wrt the y position of scatterer centres
  • Az: The gradient of A wrt the z position of scatterer centres
Returns

second order unmixed gradient of H wrt scatterer positions

def get_cache_or_compute_H_2_gradients( scatterer: vedo.mesh.Mesh, board: torch.Tensor, use_cache_H_grad: bool = True, path: str = 'Media', print_lines: bool = False) -> torch.Tensor:
231def get_cache_or_compute_H_2_gradients(scatterer:Mesh,board:Tensor,use_cache_H_grad:bool=True, path:str="Media", print_lines:bool=False) -> Tensor:
232    '''
233    Get second derivatives of H using cache system. Expects a folder named BEMCache in `path`\n
234    :param scatterer: The mesh used (as a `vedo` `mesh` object)
235    :param board: Transducers to use 
236    :param use_cache_H_grad: If true uses the cache system, otherwise computes H and does not save it
237    :param path: path to folder containing `BEMCache/ `
238    :param print_lines: if true prints messages detaling progress
239    :return: second derivatives of H
240    '''
241    if use_cache_H_grad:
242        
243        f_name = scatterer.filename+"--"+ board_name(board)
244        f_name = hashlib.md5(f_name.encode()).hexdigest()
245        f_name = path+"/BEMCache/"  +  f_name +"_2grad"+ ".bin"
246
247        try:
248            if print_lines: print("Trying to load H 2 grads at", f_name ,"...")
249            Haa = pickle.load(open(f_name,"rb"))
250            Haa = Haa.to(device)
251        except FileNotFoundError: 
252            if print_lines: print("Not found, computing H grad 2...")
253            Haa = grad_2_H(None, transducers=board, **{"scatterer":scatterer })
254            f = open(f_name,"wb")
255            pickle.dump(Haa,f)
256            f.close()
257    else:
258        if print_lines: print("Computing H grad 2...")
259        Haa = grad_2_H(None, transducers=board, **{"scatterer":scatterer })
260
261    return Haa

Get second derivatives of H using cache system. Expects a folder named BEMCache in path

Parameters
  • scatterer: The mesh used (as a vedo mesh object)
  • board: Transducers to use
  • use_cache_H_grad: If true uses the cache system, otherwise computes H and does not save it
  • path: path to folder containing BEMCache/
  • print_lines: if true prints messages detaling progress
Returns

second derivatives of H

def get_cache_or_compute_H_gradients( scatterer, board, use_cache_H_grad=True, path='Media', print_lines=False) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
264def get_cache_or_compute_H_gradients(scatterer,board,use_cache_H_grad=True, path="Media", print_lines=False) -> tuple[Tensor, Tensor, Tensor]:
265    '''
266    Get derivatives of H using cache system. Expects a folder named BEMCache in `path`\\
267    :param scatterer: The mesh used (as a `vedo` `mesh` object)\\
268    :param board: Transducers to use \\
269    :param use_cache_H_grad: If true uses the cache system, otherwise computes H and does not save it\\
270    :param path: path to folder containing BEMCache/ \\
271    :param print_lines: if true prints messages detaling progress\\
272    Returns derivatives of H
273    '''
274
275    if use_cache_H_grad:
276        
277        f_name = scatterer.filename +"--"+ board_name(board)
278        f_name = hashlib.md5(f_name.encode()).hexdigest()
279        f_name = path+"/BEMCache/"  +  f_name +"_grad"+ ".bin"
280
281        try:
282            if print_lines: print("Trying to load H grads at", f_name ,"...")
283            Hx, Hy, Hz = pickle.load(open(f_name,"rb"))
284            Hx = Hx.to(device)
285            Hy = Hy.to(device)
286            Hz = Hz.to(device)
287        except FileNotFoundError: 
288            if print_lines: print("Not found, computing H Grads...")
289            Hx, Hy, Hz = grad_H(None, transducers=board, **{"scatterer":scatterer }, path=path)
290            f = open(f_name,"wb")
291            pickle.dump((Hx, Hy, Hz),f)
292            f.close()
293    else:
294        if print_lines: print("Computing H Grad...")
295        Hx, Hy, Hz = grad_H(None, transducers=board, **{"scatterer":scatterer }, path=path)
296
297    return Hx, Hy, Hz

Get derivatives of H using cache system. Expects a folder named BEMCache in path\

Parameters
  • scatterer: The mesh used (as a vedo mesh object)\
  • board: Transducers to use \
  • use_cache_H_grad: If true uses the cache system, otherwise computes H and does not save it\
  • path: path to folder containing BEMCache/ \
  • print_lines: if true prints messages detaling progress\ Returns derivatives of H