Skip to content

Commit f14cc02

Browse files
committedDec 31, 2019
vector Line code, replaces also Line classic
1 parent e4802a0 commit f14cc02

File tree

4 files changed

+134
-16
lines changed

4 files changed

+134
-16
lines changed
 

‎magpylib/_lib/classes/currents.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
from numpy import array, float64, ndarray
2626
from magpylib._lib.mathLib import angleAxisRotation_priv
27-
from magpylib._lib.fields.Current_Line import Bfield_CurrentLine
27+
from magpylib._lib.fields.Current_Line_vector import Bfield_CurrentLineV
2828
from magpylib._lib.fields.Current_CircularLoop import Bfield_CircularCurrentLoop
2929
from magpylib._lib.classes.base import LineCurrent
3030

@@ -238,7 +238,7 @@ def getB(self, pos): # Particular Line current B field calculation. Check RCS f
238238
# rotate this vector into the CS of the magnet (inverse rotation)
239239
rotatedPos = angleAxisRotation_priv(self.angle, -self.axis, posRel) # pylint: disable=invalid-unary-operand-type
240240
# rotate field vector back
241-
BCm = angleAxisRotation_priv(self.angle, self.axis, Bfield_CurrentLine(rotatedPos, self.vertices, self.current))
241+
BCm = angleAxisRotation_priv(self.angle, self.axis, Bfield_CurrentLineV(self.vertices, self.current,rotatedPos))
242242
# BCm is the obtained magnetic field in Cm
243243
# the field is well known in the magnet coordinates.
244244
return BCm

‎magpylib/_lib/fields/Current_Line.py renamed to ‎magpylib/_lib/fields/Current_Line_vector.py

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
from numpy import array, NaN
2626
from magpylib._lib.mathLib import fastSum3D, fastNorm3D, fastCross3D
2727
from warnings import warn
28+
import numpy as np
29+
from numpy.linalg import norm
2830

2931
# %% CURRENT LINE
3032
# Describes the magnetic field of a line current. The line is given by a set of
@@ -38,6 +40,96 @@
3840
# source: http://www.phys.uri.edu/gerhard/PHY204/tsl216.pdf
3941
# FieldOfLineCurrent
4042

43+
# VECTORIZED VERSION
44+
# here we only use vectorized code as this function will primarily be
45+
# used to call on multiple line segments. The vectorized code was
46+
# developed based on the depreciated version below.
47+
48+
def Bfield_LineSegmentV(p0, p1, p2, I0):
49+
''' private
50+
base function determines the fields of given line segments
51+
p0 = observer position
52+
p1->p2 = current flows from vertex p1 to vertex p2
53+
I0 = current in [A]
54+
'''
55+
56+
N = len(p0)
57+
fields = np.zeros((N,3)) # default values for mask0 and mask1
58+
59+
# Check for zero-length segment
60+
mask0 = np.all(p1==p2,axis=1)
61+
62+
# projection of p0 onto line p1-p2
63+
nm0 = np.invert(mask0)
64+
p1p2 = (p1[nm0]-p2[nm0])
65+
p4 = p1[nm0]+(p1p2.T*np.sum((p0[nm0]-p1[nm0])*p1p2,axis=1)/np.sum(p1p2**2,axis=1)).T
66+
67+
# determine anchorrect normal vector to surface spanned by triangle
68+
cross0 = np.cross(-p1p2, p0[nm0]-p4)
69+
norm_cross0 = norm(cross0,axis=1)
70+
71+
# on-line cases (include when position is on current path)
72+
mask1 = (norm_cross0 == 0)
73+
74+
# normal cases
75+
nm1 = np.invert(mask1)
76+
eB = (cross0[nm1].T/norm_cross0[nm1]) #field direction
77+
78+
# not mask0 and not mask1
79+
NM = np.copy(nm0)
80+
NM[NM==True] = nm1
81+
82+
norm_04 = norm(p0[NM] -p4[nm1],axis=1)
83+
norm_01 = norm(p0[NM] -p1[NM],axis=1)
84+
norm_02 = norm(p0[NM] -p2[NM],axis=1)
85+
norm_12 = norm(p1[NM] -p2[NM],axis=1)
86+
norm_41 = norm(p4[nm1]-p1[NM],axis=1)
87+
norm_42 = norm(p4[nm1]-p2[NM],axis=1)
88+
89+
sinTh1 = norm_41/norm_01
90+
sinTh2 = norm_42/norm_02
91+
92+
deltaSin = np.empty((N))[NM]
93+
94+
# determine how p1,p2,p4 are sorted on the line (to get sinTH signs)
95+
# both points below
96+
mask2 = ((norm_41>norm_12) * (norm_41>norm_42))
97+
deltaSin[mask2] = abs(sinTh1[mask2]-sinTh2[mask2])
98+
# both points above
99+
mask3 = ((norm_42>norm_12) * (norm_42>norm_41))
100+
deltaSin[mask3] = abs(sinTh2[mask3]-sinTh1[mask3])
101+
# one above one below or one equals p4
102+
mask4 = np.invert(mask2)*np.invert(mask3)
103+
deltaSin[mask4] = abs(sinTh1[mask4]+sinTh2[mask4])
104+
105+
# missing 10**-6 from m->mm conversion #T->mT conversion
106+
fields[NM] = (I0[NM]*deltaSin/norm_04*eB).T/10
107+
108+
return fields
109+
110+
111+
112+
def Bfield_CurrentLineV(VERT,i0,poso):
113+
''' private
114+
determine total field from a multi-segment line current
115+
'''
116+
117+
N = len(VERT)-1
118+
P0 = np.outer(np.ones((N)),poso)
119+
P1 = VERT[:-1]
120+
P2 = VERT[1:]
121+
I0 = np.ones((N))*i0
122+
123+
Bv = Bfield_LineSegmentV(P0,P1,P2,I0)
124+
125+
return np.sum(Bv,axis=0)
126+
127+
128+
129+
130+
131+
''' DEPRECHIATED VERSION (non-vectorized)
132+
41133
# observer at p0
42134
# current I0 flows in straight line from p1 to p2
43135
def Bfield_LineSegment(p0, p1, p2, I0):
@@ -90,15 +182,4 @@ def Bfield_LineSegment(p0, p1, p2, I0):
90182
B = I0*deltaSin/norm_04*eB/10
91183
92184
return B
93-
94-
# determine total field from multiple segments
95-
96-
97-
def Bfield_CurrentLine(p0, possis, I0):
98-
99-
B = array([0., 0., 0.])
100-
for i in range(len(possis)-1):
101-
p1 = possis[i]
102-
p2 = possis[i+1]
103-
B += Bfield_LineSegment(p0, p1, p2, I0)
104-
return B
185+
'''

‎magpylib/_lib/getBvector.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from magpylib._lib.fields.PM_Sphere_vector import Bfield_SphereV
2727
from magpylib._lib.fields.Moment_Dipole_vector import Bfield_DipoleV
2828
from magpylib._lib.fields.Current_CircularLoop_vector import Bfield_CircularCurrentLoopV
29+
from magpylib._lib.fields.Current_Line_vector import Bfield_LineSegmentV
2930
from magpylib._lib.mathLib_vector import QconjV, QrotationV, QmultV, getRotQuatV, angleAxisRotationV_priv
3031
import numpy as np
3132

@@ -121,7 +122,7 @@ def getBv_current(type,CURR,DIM,POSm,POSo,ANG=[],AX=[],ANCH=[]):
121122
122123
DIM : NxY numpy array float [mm]
123124
vector of N dimensions for each evaluation. The form of this vector depends
124-
on the source type. Y=3/2/1 for box/cylinder/sphere
125+
on the source type. Y=1/3x3 for circular/line.
125126
126127
POSo : Nx3 numpy array float [mm]
127128
vector of N positions of the observer.
@@ -162,6 +163,8 @@ def getBv_current(type,CURR,DIM,POSm,POSo,ANG=[],AX=[],ANCH=[]):
162163
# calculate field
163164
if type == 'circular':
164165
Brot = Bfield_CircularCurrentLoopV(CURR, DIM, POSrot)
166+
elif type == 'line':
167+
Brot = Bfield_LineSegmentV(POSrot,DIM[:,0],DIM[:,1],CURR)
165168
else:
166169
print('Bad type')
167170
return 0

‎tests/test_magpyVector.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import numpy as np
44
from magpylib.source.magnet import Box, Cylinder, Sphere
55
from magpylib.source.moment import Dipole
6-
from magpylib.source.current import Circular
6+
from magpylib.source.current import Circular, Line
77
from magpylib.vector import getBv_magnet, getBv_current, getBv_moment
88
from magpylib.math import axisFromAngles
99
from magpylib.math import angleAxisRotationV
@@ -156,3 +156,37 @@ def test_vectorCurrentCircular():
156156
Bv = getBv_current('circular',I,D,Pm,Po)
157157

158158
assert np.amax(abs(Bc-Bv))<1e-10
159+
160+
161+
def test_vectorLine():
162+
163+
#general cases
164+
NN=100
165+
V = np.random.rand(NN,3)-.5
166+
V1 = V[:-1]
167+
V2 = V[1:]
168+
DIM = np.array([[v1,v2] for v1,v2 in zip(V1,V2)])
169+
I0 = np.ones([NN-1])
170+
Po = np.ones((NN-1,3))
171+
Pm = np.zeros((NN-1,3))
172+
173+
Bc = []
174+
for dim,i0,po in zip(DIM,I0,Po):
175+
s = Line(curr=i0,vertices=dim)
176+
Bc += [s.getB(po)]
177+
Bc = np.array(Bc)
178+
179+
Bv = getBv_current('line',I0,DIM,Pm,Po)
180+
assert np.amax(abs(Bc-Bv))<1e-12
181+
182+
#special cases
183+
V = np.array([[0,0,0],[1,2,3],[1,2,3],[3,3,3],[1,1,1],[1,1,2],[1,1,0]])
184+
V1 = V[:-1]
185+
V2 = V[1:]
186+
DIM = np.array([[v1,v2] for v1,v2 in zip(V1,V2)])
187+
I0 = np.ones([6])
188+
Po = np.ones((6,3))
189+
Pm = np.zeros((6,3))
190+
191+
Bv = getBv_current('line',I0,DIM,Pm,Po)
192+
assert [all(b == 0) for b in Bv] == [False, True, False, True, True, True]

0 commit comments

Comments
 (0)