1212from magpylib ._src .obj_classes .class_magnet_Cylinder import Cylinder
1313from magpylib ._src .obj_classes .class_magnet_CylinderSegment import CylinderSegment
1414from magpylib ._src .obj_classes .class_current_Circle import Circle
15+ from magpylib ._src .obj_classes .class_misc_Dipole import Dipole
1516
1617from magpylib_force .meshing import mesh_target
1718from magpylib_force .utility import check_input_anchor
@@ -35,8 +36,8 @@ def getFT(sources, targets, anchor=None, eps=1e-5, squeeze=True):
3536 or a 1D list of l sources and/or collection objects.
3637
3738 targets: single object or 1D list of t objects that are Sphere, Cuboid, Polyline,
38- Cylinder, or CylinderSegment . Force and Torque acting on targets in the magnetic
39- field generated by the sources will be computed. A target must have a valid
39+ Cylinder, CylinderSegment, or Dipole . Force and Torque acting on targets in the magnetic
40+ field generated by the sources will be computed. A target (except of Dipole) must have a valid
4041 `meshing` parameter.
4142
4243 anchor: array_like, default=None
@@ -66,10 +67,10 @@ def getFT(sources, targets, anchor=None, eps=1e-5, squeeze=True):
6667
6768 # split targets into lists of similar types
6869 TARGET_TYPES = [
69- Cuboid , Polyline , Sphere , Cylinder , CylinderSegment , Circle
70+ Cuboid , Polyline , Sphere , Cylinder , CylinderSegment , Circle , Dipole
7071 ]
7172 getFT_FUNCS = [
72- getFTmagnet , getFTcurrent , getFTmagnet , getFTmagnet , getFTmagnet , getFTcurrent_circ
73+ getFTmagnet , getFTcurrent , getFTmagnet , getFTmagnet , getFTmagnet , getFTcurrent_circ , getFTdipole
7374 ]
7475 objects = [[] for _ in TARGET_TYPES ]
7576 orders = [[] for _ in TARGET_TYPES ]
@@ -184,6 +185,8 @@ def getFTmagnet(sources, targets, eps=1e-5, anchor=None):
184185 POSS [insti [i ]:insti [i + 1 ],j ] = mesh + ev + tgt .position
185186
186187 BB = magpy .getB (sources , POSS , sumup = True )
188+ if BB .ndim == 2 :
189+ BB = np .expand_dims (BB , axis = 0 )
187190 gradB = (BB [:,1 ::2 ]- BB [:,2 ::2 ]) / (2 * eps )
188191 gradB = np .swapaxes (gradB ,0 ,1 )
189192
@@ -300,3 +303,61 @@ def getFTcurrent(sources, targets, anchor=None, eps=None):
300303 F = np .array ([np .sum (F [insti [i ]:insti [i + 1 ]],axis = 0 ) for i in range (tgt_number )])
301304
302305 return np .array ((F , - T ))
306+
307+
308+ def getFTdipole (sources , targets , anchor = None , eps = None ):
309+ """
310+ Compute force and torque acting on magnetic dipoles
311+
312+ Parameters
313+ ----------
314+ sources: source and collection objects or 1D list thereof
315+ Sources that generate the magnetic field. Can be a single source (or collection)
316+ or a 1D list of l sources and/or collection objects.
317+
318+ targets: Dipole object or 1D list of Dipole objects
319+ Force and Torque acting on targets in the magnetic field generated by the sources
320+ will be computed.
321+
322+ eps: float, default=1e-5
323+ The magnetic field gradient is computed using finite differences (FD). eps is
324+ the FD step size. A good value is 1e-5 * characteristic system size (magnet size,
325+ distance between sources and targets, ...).
326+
327+ anchor: array_like, default=None
328+ The Force adds to the Torque via the anchor point. For a freely floating magnet
329+ this would be the barycenter. If `anchor=None`, this part of the Torque computation
330+ is ommitted.
331+ """
332+ # number of magnets
333+ tgt_number = len (targets )
334+
335+ # field computation positions (1xfor B, 6x for gradB)
336+ POSS = np .zeros ((tgt_number ,7 ,3 ))
337+
338+ # moment of each instance
339+ MOM = np .zeros ((tgt_number ,3 ))
340+
341+ # MISSING: eps should be defined relative to the sizes of the objects
342+ eps_vec = np .array ([(0 ,0 ,0 ),(eps ,0 ,0 ),(- eps ,0 ,0 ),(0 ,eps ,0 ),(0 ,- eps ,0 ),(0 ,0 ,eps ),(0 ,0 ,- eps )])
343+
344+ for i ,tgt in enumerate (targets ):
345+ dipole_mom = tgt .orientation .apply (tgt .moment )
346+ MOM [i ] = dipole_mom
347+
348+ for j ,ev in enumerate (eps_vec ):
349+ POSS [i ,j ] = ev + tgt .position
350+
351+ BB = magpy .getB (sources , POSS , sumup = True )
352+ if BB .ndim == 2 :
353+ BB = np .expand_dims (BB , axis = 0 )
354+ gradB = (BB [:,1 ::2 ]- BB [:,2 ::2 ]) / (2 * eps )
355+ gradB = np .swapaxes (gradB ,0 ,1 )
356+
357+ F = np .sum ((gradB * MOM ),axis = 2 ).T
358+ #Ts = np.zeros((no_inst,3))
359+ T = np .cross (BB [:,0 ], MOM )
360+ if anchor is not None :
361+ T -= np .cross (POSS [:,0 ]- anchor , F )
362+
363+ return np .array ((F , - T ))
0 commit comments