src.acoustools.BEM.Force
1from acoustools.BEM import BEM_forward_model_second_derivative_mixed, BEM_forward_model_second_derivative_unmixed, BEM_forward_model_grad, compute_E, get_cache_or_compute_H, get_cache_or_compute_H_gradients 2from acoustools.Utilities import TRANSDUCERS, propagate 3from acoustools.Force import force_mesh 4from acoustools.Mesh import load_scatterer, get_centres_as_points, get_normals_as_points, get_areas, scale_to_diameter,\ 5 centre_scatterer, translate, merge_scatterers, get_centre_of_mass_as_points, get_volume 6from acoustools.Gorkov import get_gorkov_constants 7 8 9import acoustools.Constants as c 10 11from torch import Tensor 12import torch 13 14from vedo import Mesh 15 16 17def BEM_compute_force(activations:Tensor, points:Tensor,board:Tensor|None=None,return_components:bool=False, V:float=c.V, scatterer:Mesh=None, 18 H:Tensor=None, path:str="Media", k=c.k, transducer_radius=c.radius, p_ref=c.P_ref, 19 medium_density=c.p_0, medium_speed = c.c_0, particle_density = c.p_p, particle_speed = c.c_p, transucer_norms=None) -> Tensor | tuple[Tensor, Tensor, Tensor]: 20 ''' 21 Returns the force on a particle using the analytical derivative of the Gor'kov potential and BEM\n 22 :param activations: Transducer hologram 23 :param points: Points to propagate to 24 :param board: Transducers to use, if `None` uses `acoustools.Utilities.TRANSDUCERS` 25 :param return_components: If true returns force as one tensor otherwise returns Fx, Fy, Fz 26 :param V: Particle volume 27 :param scatterer: Scatterer to use 28 :param H: H to use, will load/compute if None 29 :param path: Path to folder containing BEMCache 30 :return: force 31 ''' 32 33 #Bk.2 Pg.319 34 35 if board is None: 36 board = TRANSDUCERS 37 38 F = compute_E(scatterer=scatterer,points=points,board=board,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, norms=transucer_norms) 39 Fx, Fy, Fz = BEM_forward_model_grad(points,transducers=board,scatterer=scatterer,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, transducer_norms=transucer_norms) 40 Fxx, Fyy, Fzz = BEM_forward_model_second_derivative_unmixed(points,transducers=board,scatterer=scatterer,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, transducer_norms=transucer_norms) 41 Fxy, Fxz, Fyz = BEM_forward_model_second_derivative_mixed(points,transducers=board,scatterer=scatterer,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, transducer_norms=transucer_norms) 42 43 p = (F@activations) 44 Px = (Fx@activations) 45 Py = (Fy@activations) 46 Pz = (Fz@activations) 47 Pxx = (Fxx@activations) 48 Pyy = (Fyy@activations) 49 Pzz = (Fzz@activations) 50 Pxy = (Fxy@activations) 51 Pxz = (Fxz@activations) 52 Pyz = (Fyz@activations) 53 54 55 grad_p = torch.stack([Px,Py,Pz]) 56 grad_px = torch.stack([Pxx,Pxy,Pxz]) 57 grad_py = torch.stack([Pxy,Pyy,Pyz]) 58 grad_pz = torch.stack([Pxz,Pyz,Pzz]) 59 60 61 p_term = p*grad_p.conj() + p.conj()*grad_p 62 63 px_term = Px*grad_px.conj() + Px.conj()*grad_px 64 py_term = Py*grad_py.conj() + Py.conj()*grad_py 65 pz_term = Pz*grad_pz.conj() + Pz.conj()*grad_pz 66 67 K1, K2 = get_gorkov_constants(V=V, c_0=medium_speed, c_p=particle_speed, p_0=medium_density, p_p=particle_density) 68 69 grad_U = K1 * p_term - K2 * (px_term + py_term + pz_term) 70 force = -1*(grad_U).squeeze().real 71 72 if return_components: 73 return force[0], force[1], force[2] 74 else: 75 return force 76 77def torque_mesh_surface(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, sum_elements = True, use_pressure:bool=False, 78 H:Tensor=None, diameter=c.wavelength*2, p_ref = c.P_ref, 79 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 80 surface:Mesh|None=None, use_cache_H:bool=True, 81 E:Tensor|None=None, Ex:Tensor|None=None, Ey:Tensor|None=None, Ez:Tensor|None=None, 82 internal_points=None, transducer_norms=None, transducer_radius=c.radius ) -> Tensor | tuple[Tensor, Tensor, Tensor]: 83 ''' 84 Computes the force on a scattering obejct by computing thr force on a far field surface\\ 85 :param activations: Hologram 86 :param scatterer: Object to compute force on 87 :param board: Transducers 88 :param sum_elements: if True will call sum across mesh elements 89 :param H: H matrix to use for BEM, if None will be computed 90 :param diameter: diameter of surfac to use 91 :param path: path to BEMCache 92 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 93 :param surface: Surface to use, if None will be laoded from surface_path 94 :param use_cache_H: If true use BEM cache system 95 :param E: E matrix to use for BEM, if None will be computed 96 :param Ex: Grad E wrt x matrix to use for BEM, if None will be computed 97 :param Ey: Grad E wrt y matrix to use for BEM, if None will be computed 98 :param Ey: Grad E wrt z matrix to use for BEM, if None will be computed 99 :returns torque: 100 ''' 101 102 object_com = get_centre_of_mass_as_points(scatterer) 103 104 if surface is None: 105 surface = load_scatterer(path+surface_path) 106 scale_to_diameter(surface,diameter, reset=False, origin=True) 107 centre_scatterer(surface) 108 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 109 110 111 112 points = get_centres_as_points(surface) 113 norms = get_normals_as_points(surface) 114 areas = get_areas(surface) 115 surface_com = get_centre_of_mass_as_points(surface) 116 r = points - surface_com 117 # print('dot',torch.sum(r * norms, dim=1) / torch.norm(r,2, dim=1)) 118 119 if use_pressure: 120 if E is None: 121 E = compute_E(scatterer, points, board, use_cache_H=use_cache_H, path=path, H=H,internal_points=internal_points, p_ref=p_ref, norms=transducer_norms, transducer_radius=transducer_radius) 122 p = propagate(activations,points,board,A=E, p_ref=p_ref) 123 pressure_square = torch.abs(p)**2 124 pressure_time_average = 1/2 * pressure_square 125 126 r_cross_n = torch.cross(r,norms, dim=1) 127 pressure_term = pressure_time_average * r_cross_n * areas 128 if sum_elements: pressure_term = torch.sum(pressure_term, dim=2) 129 else: 130 pressure_term = 0 131 132 if Ex is None or Ey is None or Ez is None: 133 Ex, Ey, Ez = BEM_forward_model_grad(points, scatterer, board, use_cache_H=use_cache_H, H=H, path=path,internal_points=internal_points, p_ref=p_ref, transducer_norms=transducer_norms, transducer_radius=transducer_radius) 134 135 px = (Ex@activations).squeeze(2).unsqueeze(0) 136 py = (Ey@activations).squeeze(2).unsqueeze(0) 137 pz = (Ez@activations).squeeze(2).unsqueeze(0) 138 139 grad = torch.cat((px,py,pz),dim=1) 140 velocity = grad /( 1j * c.p_0 * c.angular_frequency) 141 # return torch.sum(velocity,dim=2) 142 # r_cross_outer_conj = torch.cross(r, outer_conj) 143 144 # time_average_outer_v = 1/2 * torch.einsum('bin,bjn -> bijn', r_cross_v, velocity.conj().resolve_conj()) #Takes two (B,3,N) vectors and computes the outer product on them - i think... 145 vconj_dot_n = torch.sum(velocity.conj() * norms, dim=1, keepdim=True) 146 time_average_velocity = 1/2 *(torch.cross((vconj_dot_n * r), velocity, dim=1)).real * areas 147 if sum_elements: time_average_velocity = torch.sum(time_average_velocity, dim=2) 148 torque = - pressure_term - c.p_0 * time_average_velocity 149 150 return torque 151 152 153 154def force_mesh_surface(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, 155 return_components:bool=False, sum_elements:bool = True, return_momentum:bool = False, 156 H:Tensor=None, diameter:float=c.wavelength*2, 157 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 158 surface:Mesh|None=None, use_cache_H:bool=True, 159 E:Tensor|None=None, Ex:Tensor|None=None, Ey:Tensor|None=None, Ez:Tensor|None=None, 160 use_momentum:float=True, p_ref:float=c.P_ref, internal_points=None, k=c.k, transducer_radius=c.radius, transducer_norms=None) -> Tensor | tuple[Tensor, Tensor, Tensor]: 161 ''' 162 Computes the torque on a scattering obejct by computing thr force on a far field surface\\ 163 :param activations: Hologram 164 :param scatterer: Object to compute force on 165 :param board: Transducers 166 :param return_components: if True will return Fx,Fy,Fz else returns force 167 :param sum_elements: if True will call sum across mesh elements 168 :param return_momentum: if True will return total force and the momentum flux term 169 :param H: H matrix to use for BEM, if None will be computed 170 :param diameter: diameter of surface to use 171 :param path: path to BEMCache 172 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 173 :param surface: Surface to use, if None will be laoded from surface_path 174 :param use_cache_H: If true use BEM cache system 175 :param E: E matrix to use for BEM, if None will be computed 176 :param Ex: Grad E wrt x matrix to use for BEM, if None will be computed 177 :param Ey: Grad E wrt y matrix to use for BEM, if None will be computed 178 :param Ey: Grad E wrt z matrix to use for BEM, if None will be computed 179 :use_momentum: If true will use momentum flux terms 180 :returns force: 181 ''' 182 183 if surface is None: 184 surface = load_scatterer(path+surface_path) 185 scale_to_diameter(surface,diameter, reset=False, origin=True) 186 centre_scatterer(surface) 187 object_com = get_centre_of_mass_as_points(scatterer) 188 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 189 190 191 points = get_centres_as_points(surface) 192 norms = get_normals_as_points(surface) 193 areas = get_areas(surface) 194 195 if E is None: 196 E,F,G,H = compute_E(scatterer, points, board,path=path, H=H, return_components=True, use_cache_H=use_cache_H, p_ref=p_ref,internal_points=internal_points, k=k, transducer_radius=transducer_radius, norms=transducer_norms) 197 198 force, momentum = force_mesh(activations, points,norms,areas,board=board,F=E, use_momentum=use_momentum, p_ref=p_ref, k=k, transducer_radius=transducer_radius, 199 grad_function=BEM_forward_model_grad, grad_function_args={'scatterer':scatterer, 200 'H':H, 201 'path':path, 202 "internal_points":internal_points, 203 }, 204 return_components=True, 205 Ax = Ex, Ay=Ey, Az=Ez) 206 207 208 209 if sum_elements: force=torch.sum(force, dim=2) 210 211 if return_components: 212 if not return_momentum: 213 return (force[:,0]), (force[:,1]), (force[:,2]) 214 else: 215 return (force[:,0]), (force[:,1]), (force[:,2]), momentum 216 217 if return_momentum: return force, momentum 218 return force 219 220def force_mesh_surface_divergance(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, 221 sum_elements:bool = True, H:Tensor=None, diameter:float=c.wavelength*2, 222 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 223 surface:Mesh|None=None, use_cache_H:bool=True, force:Tensor|None=None, norms:Tensor|None=None, p_ref=c.P_ref, k=c.k, transducer_radius=c.radius,transducer_norms=None) -> Tensor: 224 ''' 225 Computes the divergance force (the dot product of the force and normals on the surface) on a scattering obejct by computing thr force on a far field surface\\ 226 :param activations: Hologram 227 :param scatterer: Object to compute force on 228 :param board: Transducers 229 :param sum_elements: if True will call sum across mesh elements 230 :param H: H matrix to use for BEM, if None will be computed 231 :param diameter: diameter of surfac to use 232 :param path: path to BEMCache 233 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 234 :param surface: Surface to use, if None will be laoded from surface_path 235 :param use_cache_H: If true use BEM cache system 236 :param force: Precomputed force, if non is computed using `force_mesh_surface` 237 :param norms: Precomputed norms, if non is found from surface 238 :returns divergance of force: 239 ''' 240 241 242 if surface is None: 243 surface = load_scatterer(path+surface_path) 244 scale_to_diameter(surface,diameter, reset=False, origin=True) 245 centre_scatterer(surface) 246 object_com = get_centre_of_mass_as_points(scatterer) 247 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 248 249 if force is None: 250 force = force_mesh_surface(activations, scatterer, board, H=H, diameter=diameter, path=path, 251 surface_path=surface_path, surface=surface, use_cache_H=use_cache_H, sum_elements=False, use_momentum=True, k=k, p_ref=p_ref, transducer_radius=transducer_radius, transducer_norms=transducer_norms) 252 253 if norms is None: norms = get_normals_as_points(surface) 254 areas = get_areas(surface) 255 256 div = (torch.sum(norms * force, dim=1) * areas ) 257 258 if sum_elements: div = torch.sum(div, dim=1) 259 260 v = get_volume(surface) 261 262 return div / v 263 264 265def force_mesh_surface_curl(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, 266 sum_elements:bool = True, H:Tensor=None, diameter:float=c.wavelength*2, 267 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 268 surface:Mesh|None=None, use_cache_H:bool=True, magnitude:Tensor|None = False, force:Tensor|None=None, p_ref=c.P_ref, k=c.k, transducer_radius=c.radius,transducer_norms=None) -> Tensor: 269 ''' 270 Computes the curl force (the cross product of the force and normals on the surface) on a scattering obejct by computing thr force on a far field surface\\ 271 :param activations: Hologram 272 :param scatterer: Object to compute force on 273 :param board: Transducers 274 :param sum_elements: if True will call sum across mesh elements 275 :param H: H matrix to use for BEM, if None will be computed 276 :param diameter: diameter of surfac to use 277 :param path: path to BEMCache 278 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 279 :param surface: Surface to use, if None will be laoded from surface_path 280 :param use_cache_H: If true use BEM cache system 281 :param force: Precomputed force, if non is computed using `force_mesh_surface` 282 :param magnitude: If true will call `torch.norm` on the curl vectors 283 :returns curl of force: 284 ''' 285 286 if force is None: force = force_mesh_surface(activations, scatterer, board, H=H, diameter=diameter, path=path, 287 surface_path=surface_path, surface=surface, use_cache_H=use_cache_H, sum_elements=False, k=k, p_ref=p_ref, transducer_radius=transducer_radius, transducer_norms=transducer_norms) 288 289 if surface is None: 290 surface = load_scatterer(path+surface_path) 291 scale_to_diameter(surface,diameter, reset=False, origin=True) 292 centre_scatterer(surface) 293 object_com = get_centre_of_mass_as_points(scatterer) 294 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 295 296 norms = get_normals_as_points(surface).real 297 areas = get_areas(surface) 298 299 curl = torch.cross(force, norms, dim=1) * areas 300 301 if sum_elements: curl = torch.sum(curl, dim=2) 302 303 v = get_volume(surface) 304 305 curl = curl/v 306 307 if magnitude: return torch.norm(curl, dim=1) 308 309 return curl 310 311 312def get_force_mesh_along_axis(start:Tensor,end:Tensor, activations:Tensor, scatterers:list[Mesh], board:Tensor, mask:Tensor|None=None, steps:int=200, 313 path:str="Media",print_lines:bool=False, use_cache:bool=True, 314 Hs:Tensor|None = None, Hxs:Tensor|None=None, Hys:Tensor|None=None, Hzs:Tensor|None=None, p_ref=c.P_ref, k=c.k, transducer_radius=c.radius,transducer_norms=None) -> tuple[list[Tensor],list[Tensor],list[Tensor]]: 315 ''' 316 @private 317 Computes the force on a mesh at each point from `start` to `end` with number of samples = `steps` \n 318 :param start: The starting position 319 :param end: The ending position 320 :param activations: Transducer hologram 321 :param scatterers: First element is the mesh to move, rest is considered static reflectors 322 :param board: Transducers to use 323 :param mask: The mask to apply to filter force for only the mesh to move 324 :param steps: Number of steps to take from start to end 325 :param path: path to folder containing BEMCache/ 326 :param print_lines: if true prints messages detaling progress 327 :param use_cache: If true uses the cache system, otherwise computes H and does not save it 328 :param Hs: List of precomputed forward propagation matricies 329 :param Hxs: List of precomputed derivative of forward propagation matricies wrt x 330 :param Hys: List of precomputed derivative of forward propagation matricies wrt y 331 :param Hzs: List of precomputed derivative of forward propagation matricies wrt z 332 :return: list for each axis of the force at each position 333 ''' 334 335 print("get_force_mesh_along_axis - implementation H grad incorrect - do not use") 336 # if Ax is None or Ay is None or Az is None: 337 # Ax, Ay, Az = grad_function(points=points, transducers=board, **grad_function_args) 338 direction = (end - start) / steps 339 340 translate(scatterers[0], start[0].item() - direction[0].item(), start[1].item() - direction[1].item(), start[2].item() - direction[2].item()) 341 scatterer = merge_scatterers(*scatterers) 342 343 points = get_centres_as_points(scatterer) 344 if mask is None: 345 mask = torch.ones(points.shape[2]).to(bool) 346 347 Fxs = [] 348 Fys = [] 349 Fzs = [] 350 351 for i in range(steps+1): 352 if print_lines: 353 print(i) 354 355 356 translate(scatterers[0], direction[0].item(), direction[1].item(), direction[2].item()) 357 scatterer = merge_scatterers(*scatterers) 358 359 points = get_centres_as_points(scatterer) 360 areas = get_areas(scatterer) 361 norms = get_normals_as_points(scatterer) 362 363 if Hs is None: 364 H = get_cache_or_compute_H(scatterer, board, path=path, print_lines=print_lines, use_cache_H=use_cache, k=k, p_ref=p_ref, transducer_radius=transducer_radius, norms=transducer_norms) 365 else: 366 H = Hs[i] 367 368 if Hxs is None or Hys is None or Hzs is None: 369 Hx, Hy, Hz = get_cache_or_compute_H_gradients(scatterer, board, path=path, print_lines=print_lines, use_cache_H_grad=use_cache) 370 else: 371 Hx = Hxs[i] 372 Hy = Hys[i] 373 Hz = Hzs[i] 374 375 376 force = force_mesh(activations, points, norms, areas, board, F=H, Ax=Hx, Ay=Hy, Az=Hz) 377 378 force = torch.sum(force[:,:,mask],dim=2).squeeze() 379 Fxs.append(force[0]) 380 Fys.append(force[1]) 381 Fzs.append(force[2]) 382 383 # print(i, force[0].item(), force[1].item(),force[2].item()) 384 return Fxs, Fys, Fzs
def
BEM_compute_force( activations: torch.Tensor, points: torch.Tensor, board: torch.Tensor | None = None, return_components: bool = False, V: float = 4.188790204666667e-09, scatterer: vedo.mesh.core.Mesh = None, H: torch.Tensor = None, path: str = 'Media', k=732.7329804081634, transducer_radius=0.0045, p_ref=3.4000000000000004, medium_density=1.2, medium_speed=343, particle_density=29.36, particle_speed=1052, transucer_norms=None) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
19def BEM_compute_force(activations:Tensor, points:Tensor,board:Tensor|None=None,return_components:bool=False, V:float=c.V, scatterer:Mesh=None, 20 H:Tensor=None, path:str="Media", k=c.k, transducer_radius=c.radius, p_ref=c.P_ref, 21 medium_density=c.p_0, medium_speed = c.c_0, particle_density = c.p_p, particle_speed = c.c_p, transucer_norms=None) -> Tensor | tuple[Tensor, Tensor, Tensor]: 22 ''' 23 Returns the force on a particle using the analytical derivative of the Gor'kov potential and BEM\n 24 :param activations: Transducer hologram 25 :param points: Points to propagate to 26 :param board: Transducers to use, if `None` uses `acoustools.Utilities.TRANSDUCERS` 27 :param return_components: If true returns force as one tensor otherwise returns Fx, Fy, Fz 28 :param V: Particle volume 29 :param scatterer: Scatterer to use 30 :param H: H to use, will load/compute if None 31 :param path: Path to folder containing BEMCache 32 :return: force 33 ''' 34 35 #Bk.2 Pg.319 36 37 if board is None: 38 board = TRANSDUCERS 39 40 F = compute_E(scatterer=scatterer,points=points,board=board,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, norms=transucer_norms) 41 Fx, Fy, Fz = BEM_forward_model_grad(points,transducers=board,scatterer=scatterer,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, transducer_norms=transucer_norms) 42 Fxx, Fyy, Fzz = BEM_forward_model_second_derivative_unmixed(points,transducers=board,scatterer=scatterer,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, transducer_norms=transucer_norms) 43 Fxy, Fxz, Fyz = BEM_forward_model_second_derivative_mixed(points,transducers=board,scatterer=scatterer,H=H, path=path, k=k, transducer_radius=transducer_radius, p_ref=p_ref, transducer_norms=transucer_norms) 44 45 p = (F@activations) 46 Px = (Fx@activations) 47 Py = (Fy@activations) 48 Pz = (Fz@activations) 49 Pxx = (Fxx@activations) 50 Pyy = (Fyy@activations) 51 Pzz = (Fzz@activations) 52 Pxy = (Fxy@activations) 53 Pxz = (Fxz@activations) 54 Pyz = (Fyz@activations) 55 56 57 grad_p = torch.stack([Px,Py,Pz]) 58 grad_px = torch.stack([Pxx,Pxy,Pxz]) 59 grad_py = torch.stack([Pxy,Pyy,Pyz]) 60 grad_pz = torch.stack([Pxz,Pyz,Pzz]) 61 62 63 p_term = p*grad_p.conj() + p.conj()*grad_p 64 65 px_term = Px*grad_px.conj() + Px.conj()*grad_px 66 py_term = Py*grad_py.conj() + Py.conj()*grad_py 67 pz_term = Pz*grad_pz.conj() + Pz.conj()*grad_pz 68 69 K1, K2 = get_gorkov_constants(V=V, c_0=medium_speed, c_p=particle_speed, p_0=medium_density, p_p=particle_density) 70 71 grad_U = K1 * p_term - K2 * (px_term + py_term + pz_term) 72 force = -1*(grad_U).squeeze().real 73 74 if return_components: 75 return force[0], force[1], force[2] 76 else: 77 return force
Returns the force on a particle using the analytical derivative of the Gor'kov potential and BEM
Parameters
- activations: Transducer hologram
- points: Points to propagate to
- board: Transducers to use, if
Noneusesacoustools.Utilities.TRANSDUCERS - return_components: If true returns force as one tensor otherwise returns Fx, Fy, Fz
- V: Particle volume
- scatterer: Scatterer to use
- H: H to use, will load/compute if None
- path: Path to folder containing BEMCache
Returns
force
def
torque_mesh_surface( activations: torch.Tensor, scatterer: vedo.mesh.core.Mesh = None, board: torch.Tensor | None = None, sum_elements=True, use_pressure: bool = False, H: torch.Tensor = None, diameter=0.01715, p_ref=3.4000000000000004, path: str = 'Media', surface_path: str = '/Sphere-solidworks-lam2.stl', surface: vedo.mesh.core.Mesh | None = None, use_cache_H: bool = True, E: torch.Tensor | None = None, Ex: torch.Tensor | None = None, Ey: torch.Tensor | None = None, Ez: torch.Tensor | None = None, internal_points=None, transducer_norms=None, transducer_radius=0.0045) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
79def torque_mesh_surface(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, sum_elements = True, use_pressure:bool=False, 80 H:Tensor=None, diameter=c.wavelength*2, p_ref = c.P_ref, 81 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 82 surface:Mesh|None=None, use_cache_H:bool=True, 83 E:Tensor|None=None, Ex:Tensor|None=None, Ey:Tensor|None=None, Ez:Tensor|None=None, 84 internal_points=None, transducer_norms=None, transducer_radius=c.radius ) -> Tensor | tuple[Tensor, Tensor, Tensor]: 85 ''' 86 Computes the force on a scattering obejct by computing thr force on a far field surface\\ 87 :param activations: Hologram 88 :param scatterer: Object to compute force on 89 :param board: Transducers 90 :param sum_elements: if True will call sum across mesh elements 91 :param H: H matrix to use for BEM, if None will be computed 92 :param diameter: diameter of surfac to use 93 :param path: path to BEMCache 94 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 95 :param surface: Surface to use, if None will be laoded from surface_path 96 :param use_cache_H: If true use BEM cache system 97 :param E: E matrix to use for BEM, if None will be computed 98 :param Ex: Grad E wrt x matrix to use for BEM, if None will be computed 99 :param Ey: Grad E wrt y matrix to use for BEM, if None will be computed 100 :param Ey: Grad E wrt z matrix to use for BEM, if None will be computed 101 :returns torque: 102 ''' 103 104 object_com = get_centre_of_mass_as_points(scatterer) 105 106 if surface is None: 107 surface = load_scatterer(path+surface_path) 108 scale_to_diameter(surface,diameter, reset=False, origin=True) 109 centre_scatterer(surface) 110 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 111 112 113 114 points = get_centres_as_points(surface) 115 norms = get_normals_as_points(surface) 116 areas = get_areas(surface) 117 surface_com = get_centre_of_mass_as_points(surface) 118 r = points - surface_com 119 # print('dot',torch.sum(r * norms, dim=1) / torch.norm(r,2, dim=1)) 120 121 if use_pressure: 122 if E is None: 123 E = compute_E(scatterer, points, board, use_cache_H=use_cache_H, path=path, H=H,internal_points=internal_points, p_ref=p_ref, norms=transducer_norms, transducer_radius=transducer_radius) 124 p = propagate(activations,points,board,A=E, p_ref=p_ref) 125 pressure_square = torch.abs(p)**2 126 pressure_time_average = 1/2 * pressure_square 127 128 r_cross_n = torch.cross(r,norms, dim=1) 129 pressure_term = pressure_time_average * r_cross_n * areas 130 if sum_elements: pressure_term = torch.sum(pressure_term, dim=2) 131 else: 132 pressure_term = 0 133 134 if Ex is None or Ey is None or Ez is None: 135 Ex, Ey, Ez = BEM_forward_model_grad(points, scatterer, board, use_cache_H=use_cache_H, H=H, path=path,internal_points=internal_points, p_ref=p_ref, transducer_norms=transducer_norms, transducer_radius=transducer_radius) 136 137 px = (Ex@activations).squeeze(2).unsqueeze(0) 138 py = (Ey@activations).squeeze(2).unsqueeze(0) 139 pz = (Ez@activations).squeeze(2).unsqueeze(0) 140 141 grad = torch.cat((px,py,pz),dim=1) 142 velocity = grad /( 1j * c.p_0 * c.angular_frequency) 143 # return torch.sum(velocity,dim=2) 144 # r_cross_outer_conj = torch.cross(r, outer_conj) 145 146 # time_average_outer_v = 1/2 * torch.einsum('bin,bjn -> bijn', r_cross_v, velocity.conj().resolve_conj()) #Takes two (B,3,N) vectors and computes the outer product on them - i think... 147 vconj_dot_n = torch.sum(velocity.conj() * norms, dim=1, keepdim=True) 148 time_average_velocity = 1/2 *(torch.cross((vconj_dot_n * r), velocity, dim=1)).real * areas 149 if sum_elements: time_average_velocity = torch.sum(time_average_velocity, dim=2) 150 torque = - pressure_term - c.p_0 * time_average_velocity 151 152 return torque
Computes the force on a scattering obejct by computing thr force on a far field surface\
Parameters
- activations: Hologram
- scatterer: Object to compute force on
- board: Transducers
- sum_elements: if True will call sum across mesh elements
- H: H matrix to use for BEM, if None will be computed
- diameter: diameter of surfac to use
- path: path to BEMCache
- surface_path: Name of stl to use for surface such that path + surface path is the full address
- surface: Surface to use, if None will be laoded from surface_path
- use_cache_H: If true use BEM cache system
- E: E matrix to use for BEM, if None will be computed
- Ex: Grad E wrt x matrix to use for BEM, if None will be computed
- Ey: Grad E wrt y matrix to use for BEM, if None will be computed
- Ey: Grad E wrt z matrix to use for BEM, if None will be computed :returns torque:
def
force_mesh_surface( activations: torch.Tensor, scatterer: vedo.mesh.core.Mesh = None, board: torch.Tensor | None = None, return_components: bool = False, sum_elements: bool = True, return_momentum: bool = False, H: torch.Tensor = None, diameter: float = 0.01715, path: str = 'Media', surface_path: str = '/Sphere-solidworks-lam2.stl', surface: vedo.mesh.core.Mesh | None = None, use_cache_H: bool = True, E: torch.Tensor | None = None, Ex: torch.Tensor | None = None, Ey: torch.Tensor | None = None, Ez: torch.Tensor | None = None, use_momentum: float = True, p_ref: float = 3.4000000000000004, internal_points=None, k=732.7329804081634, transducer_radius=0.0045, transducer_norms=None) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
156def force_mesh_surface(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, 157 return_components:bool=False, sum_elements:bool = True, return_momentum:bool = False, 158 H:Tensor=None, diameter:float=c.wavelength*2, 159 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 160 surface:Mesh|None=None, use_cache_H:bool=True, 161 E:Tensor|None=None, Ex:Tensor|None=None, Ey:Tensor|None=None, Ez:Tensor|None=None, 162 use_momentum:float=True, p_ref:float=c.P_ref, internal_points=None, k=c.k, transducer_radius=c.radius, transducer_norms=None) -> Tensor | tuple[Tensor, Tensor, Tensor]: 163 ''' 164 Computes the torque on a scattering obejct by computing thr force on a far field surface\\ 165 :param activations: Hologram 166 :param scatterer: Object to compute force on 167 :param board: Transducers 168 :param return_components: if True will return Fx,Fy,Fz else returns force 169 :param sum_elements: if True will call sum across mesh elements 170 :param return_momentum: if True will return total force and the momentum flux term 171 :param H: H matrix to use for BEM, if None will be computed 172 :param diameter: diameter of surface to use 173 :param path: path to BEMCache 174 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 175 :param surface: Surface to use, if None will be laoded from surface_path 176 :param use_cache_H: If true use BEM cache system 177 :param E: E matrix to use for BEM, if None will be computed 178 :param Ex: Grad E wrt x matrix to use for BEM, if None will be computed 179 :param Ey: Grad E wrt y matrix to use for BEM, if None will be computed 180 :param Ey: Grad E wrt z matrix to use for BEM, if None will be computed 181 :use_momentum: If true will use momentum flux terms 182 :returns force: 183 ''' 184 185 if surface is None: 186 surface = load_scatterer(path+surface_path) 187 scale_to_diameter(surface,diameter, reset=False, origin=True) 188 centre_scatterer(surface) 189 object_com = get_centre_of_mass_as_points(scatterer) 190 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 191 192 193 points = get_centres_as_points(surface) 194 norms = get_normals_as_points(surface) 195 areas = get_areas(surface) 196 197 if E is None: 198 E,F,G,H = compute_E(scatterer, points, board,path=path, H=H, return_components=True, use_cache_H=use_cache_H, p_ref=p_ref,internal_points=internal_points, k=k, transducer_radius=transducer_radius, norms=transducer_norms) 199 200 force, momentum = force_mesh(activations, points,norms,areas,board=board,F=E, use_momentum=use_momentum, p_ref=p_ref, k=k, transducer_radius=transducer_radius, 201 grad_function=BEM_forward_model_grad, grad_function_args={'scatterer':scatterer, 202 'H':H, 203 'path':path, 204 "internal_points":internal_points, 205 }, 206 return_components=True, 207 Ax = Ex, Ay=Ey, Az=Ez) 208 209 210 211 if sum_elements: force=torch.sum(force, dim=2) 212 213 if return_components: 214 if not return_momentum: 215 return (force[:,0]), (force[:,1]), (force[:,2]) 216 else: 217 return (force[:,0]), (force[:,1]), (force[:,2]), momentum 218 219 if return_momentum: return force, momentum 220 return force
Computes the torque on a scattering obejct by computing thr force on a far field surface\
Parameters
- activations: Hologram
- scatterer: Object to compute force on
- board: Transducers
- return_components: if True will return Fx,Fy,Fz else returns force
- sum_elements: if True will call sum across mesh elements
- return_momentum: if True will return total force and the momentum flux term
- H: H matrix to use for BEM, if None will be computed
- diameter: diameter of surface to use
- path: path to BEMCache
- surface_path: Name of stl to use for surface such that path + surface path is the full address
- surface: Surface to use, if None will be laoded from surface_path
- use_cache_H: If true use BEM cache system
- E: E matrix to use for BEM, if None will be computed
- Ex: Grad E wrt x matrix to use for BEM, if None will be computed
- Ey: Grad E wrt y matrix to use for BEM, if None will be computed
- Ey: Grad E wrt z matrix to use for BEM, if None will be computed :use_momentum: If true will use momentum flux terms :returns force:
def
force_mesh_surface_divergance( activations: torch.Tensor, scatterer: vedo.mesh.core.Mesh = None, board: torch.Tensor | None = None, sum_elements: bool = True, H: torch.Tensor = None, diameter: float = 0.01715, path: str = 'Media', surface_path: str = '/Sphere-solidworks-lam2.stl', surface: vedo.mesh.core.Mesh | None = None, use_cache_H: bool = True, force: torch.Tensor | None = None, norms: torch.Tensor | None = None, p_ref=3.4000000000000004, k=732.7329804081634, transducer_radius=0.0045, transducer_norms=None) -> torch.Tensor:
222def force_mesh_surface_divergance(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, 223 sum_elements:bool = True, H:Tensor=None, diameter:float=c.wavelength*2, 224 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 225 surface:Mesh|None=None, use_cache_H:bool=True, force:Tensor|None=None, norms:Tensor|None=None, p_ref=c.P_ref, k=c.k, transducer_radius=c.radius,transducer_norms=None) -> Tensor: 226 ''' 227 Computes the divergance force (the dot product of the force and normals on the surface) on a scattering obejct by computing thr force on a far field surface\\ 228 :param activations: Hologram 229 :param scatterer: Object to compute force on 230 :param board: Transducers 231 :param sum_elements: if True will call sum across mesh elements 232 :param H: H matrix to use for BEM, if None will be computed 233 :param diameter: diameter of surfac to use 234 :param path: path to BEMCache 235 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 236 :param surface: Surface to use, if None will be laoded from surface_path 237 :param use_cache_H: If true use BEM cache system 238 :param force: Precomputed force, if non is computed using `force_mesh_surface` 239 :param norms: Precomputed norms, if non is found from surface 240 :returns divergance of force: 241 ''' 242 243 244 if surface is None: 245 surface = load_scatterer(path+surface_path) 246 scale_to_diameter(surface,diameter, reset=False, origin=True) 247 centre_scatterer(surface) 248 object_com = get_centre_of_mass_as_points(scatterer) 249 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 250 251 if force is None: 252 force = force_mesh_surface(activations, scatterer, board, H=H, diameter=diameter, path=path, 253 surface_path=surface_path, surface=surface, use_cache_H=use_cache_H, sum_elements=False, use_momentum=True, k=k, p_ref=p_ref, transducer_radius=transducer_radius, transducer_norms=transducer_norms) 254 255 if norms is None: norms = get_normals_as_points(surface) 256 areas = get_areas(surface) 257 258 div = (torch.sum(norms * force, dim=1) * areas ) 259 260 if sum_elements: div = torch.sum(div, dim=1) 261 262 v = get_volume(surface) 263 264 return div / v
Computes the divergance force (the dot product of the force and normals on the surface) on a scattering obejct by computing thr force on a far field surface\
Parameters
- activations: Hologram
- scatterer: Object to compute force on
- board: Transducers
- sum_elements: if True will call sum across mesh elements
- H: H matrix to use for BEM, if None will be computed
- diameter: diameter of surfac to use
- path: path to BEMCache
- surface_path: Name of stl to use for surface such that path + surface path is the full address
- surface: Surface to use, if None will be laoded from surface_path
- use_cache_H: If true use BEM cache system
- force: Precomputed force, if non is computed using
force_mesh_surface - norms: Precomputed norms, if non is found from surface :returns divergance of force:
def
force_mesh_surface_curl( activations: torch.Tensor, scatterer: vedo.mesh.core.Mesh = None, board: torch.Tensor | None = None, sum_elements: bool = True, H: torch.Tensor = None, diameter: float = 0.01715, path: str = 'Media', surface_path: str = '/Sphere-solidworks-lam2.stl', surface: vedo.mesh.core.Mesh | None = None, use_cache_H: bool = True, magnitude: torch.Tensor | None = False, force: torch.Tensor | None = None, p_ref=3.4000000000000004, k=732.7329804081634, transducer_radius=0.0045, transducer_norms=None) -> torch.Tensor:
267def force_mesh_surface_curl(activations:Tensor, scatterer:Mesh=None, board:Tensor|None=None, 268 sum_elements:bool = True, H:Tensor=None, diameter:float=c.wavelength*2, 269 path:str="Media", surface_path:str = "/Sphere-solidworks-lam2.stl", 270 surface:Mesh|None=None, use_cache_H:bool=True, magnitude:Tensor|None = False, force:Tensor|None=None, p_ref=c.P_ref, k=c.k, transducer_radius=c.radius,transducer_norms=None) -> Tensor: 271 ''' 272 Computes the curl force (the cross product of the force and normals on the surface) on a scattering obejct by computing thr force on a far field surface\\ 273 :param activations: Hologram 274 :param scatterer: Object to compute force on 275 :param board: Transducers 276 :param sum_elements: if True will call sum across mesh elements 277 :param H: H matrix to use for BEM, if None will be computed 278 :param diameter: diameter of surfac to use 279 :param path: path to BEMCache 280 :param surface_path: Name of stl to use for surface such that path + surface path is the full address 281 :param surface: Surface to use, if None will be laoded from surface_path 282 :param use_cache_H: If true use BEM cache system 283 :param force: Precomputed force, if non is computed using `force_mesh_surface` 284 :param magnitude: If true will call `torch.norm` on the curl vectors 285 :returns curl of force: 286 ''' 287 288 if force is None: force = force_mesh_surface(activations, scatterer, board, H=H, diameter=diameter, path=path, 289 surface_path=surface_path, surface=surface, use_cache_H=use_cache_H, sum_elements=False, k=k, p_ref=p_ref, transducer_radius=transducer_radius, transducer_norms=transducer_norms) 290 291 if surface is None: 292 surface = load_scatterer(path+surface_path) 293 scale_to_diameter(surface,diameter, reset=False, origin=True) 294 centre_scatterer(surface) 295 object_com = get_centre_of_mass_as_points(scatterer) 296 translate(surface, dx = object_com[:,0].item(), dy=object_com[:,1].item(), dz = object_com[:,2].item()) 297 298 norms = get_normals_as_points(surface).real 299 areas = get_areas(surface) 300 301 curl = torch.cross(force, norms, dim=1) * areas 302 303 if sum_elements: curl = torch.sum(curl, dim=2) 304 305 v = get_volume(surface) 306 307 curl = curl/v 308 309 if magnitude: return torch.norm(curl, dim=1) 310 311 return curl
Computes the curl force (the cross product of the force and normals on the surface) on a scattering obejct by computing thr force on a far field surface\
Parameters
- activations: Hologram
- scatterer: Object to compute force on
- board: Transducers
- sum_elements: if True will call sum across mesh elements
- H: H matrix to use for BEM, if None will be computed
- diameter: diameter of surfac to use
- path: path to BEMCache
- surface_path: Name of stl to use for surface such that path + surface path is the full address
- surface: Surface to use, if None will be laoded from surface_path
- use_cache_H: If true use BEM cache system
- force: Precomputed force, if non is computed using
force_mesh_surface - magnitude: If true will call
torch.normon the curl vectors :returns curl of force: