Skip to content

Commit 9f8cc41

Browse files
Improve meshing parameter (#12)
* improve meshing * changelog * version bump to 031 * remove Dipole for now
1 parent 7300481 commit 9f8cc41

File tree

5 files changed

+39
-117
lines changed

5 files changed

+39
-117
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Unpublished
22

3+
# v0.3.1 (2024/10/30)
4+
- Improved Mesing to accept simimal scalar value for all classes except Polyline and Dipole
5+
- Include warning when meshing is low
6+
- Improve physics tests
7+
38
# v0.3.0 (2024/10/29)
49
- Added the current.Cicle class to the force computation
510
- Improved warning msg when meshing parameter not given

magpylib_force/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from magpylib_force.force import getFT
88

99
# module level dunders
10-
__version__ = "0.3.0"
10+
__version__ = "0.3.1"
1111
__author__ = "The Magpylib Team"
1212
__all__ = [
1313
"getFT",

magpylib_force/meshing.py

+8-5
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@ def mesh_sphere(obj):
3232
"""
3333
create sphere mesh from object meshing parameter
3434
"""
35-
n = obj.meshing
35+
n = obj.meshing # target number of elements
36+
n /= np.pi/6 # sphere volume VS cube volume ratio
37+
n_grid = int(n**(1/3)) # splitting of cube sides
38+
3639
dia = obj.diameter
37-
a = -dia/2+dia/(2*n)
38-
b = dia/2-dia/(2*n)
39-
c = n*1j
40-
mesh = np.mgrid[a:b:c, a:b:c, a:b:c].T.reshape(n**3,3)
40+
a = -dia/2+dia/(2*n_grid)
41+
b = dia/2-dia/(2*n_grid)
42+
c = n_grid*1j
43+
mesh = np.mgrid[a:b:c, a:b:c, a:b:c].T.reshape(n_grid**3,3)
4144
return mesh[np.linalg.norm(mesh, axis=1)<dia/2]
4245

4346

magpylib_force/utility.py

+7
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,11 @@ def check_input_targets(targets):
4747
"Missing input for getFT `targets`."
4848
" `targets` must have the `meshing` parameter set."
4949
)
50+
if not isinstance(t, (Polyline, )):
51+
if np.isscalar(t.meshing):
52+
if t.meshing<20:
53+
warnings.warn(
54+
"Input parameter `meshing` is set to a low value which will result in "
55+
"inaccurate computation of force and torque."
56+
)
5057
return targets

tests/test_physics.py

+18-111
Original file line numberDiff line numberDiff line change
@@ -6,60 +6,6 @@
66
from scipy.special import ellipk
77

88

9-
# def test_physics_loop_torque():
10-
# """
11-
# for a current loop in a homogeneous field the following holds
12-
# F = 0
13-
# T = current * loop_surface * field_normal_component
14-
# """
15-
# # circular loop
16-
# ts = np.linspace(0,2*np.pi,300)
17-
# verts = [(np.sin(t), np.cos(t), 0) for t in ts]
18-
# cloop = magpy.current.Polyline(
19-
# current=(1, "A"),
20-
# vertices=(verts, "m"),
21-
# )
22-
# cloop.meshing = 1
23-
24-
# # homogeneous field
25-
# def func(field, observers):
26-
# return np.zeros_like(observers, dtype=float) + np.array((1,0,0))
27-
# hom = magpy.misc.CustomSource(field_func=func)
28-
29-
# # without anchor
30-
# F,T = getFT(hom, cloop, Tanch=None)
31-
# assert np.amax(F.magnitude) < 1e-14
32-
# assert T.magnitude == 0
33-
34-
# # with anchor
35-
# F,T = getFT(hom, cloop, Tanch=cloop.position)
36-
# assert np.amax(abs(F.magnitude)) < 1e-14
37-
# assert abs(T[0].magnitude) < 1e-14
38-
# assert abs(T[1].magnitude - np.pi ) < 1e-3
39-
# assert abs(T[2].magnitude) < 1e-14
40-
41-
# ##############################################################
42-
43-
# # rectangular loop
44-
# verts = [(-1,-1,0), (1,-1,0), (1,1,0), (-1,1,0), (-1,-1,0)]
45-
# rloop = magpy.current.Polyline(
46-
# current=(1, "A"),
47-
# vertices=(verts, "m"),
48-
# )
49-
# rloop.meshing = 10
50-
51-
# # without anchor
52-
# F,T = getFT(hom, rloop, Tanch=None)
53-
# assert np.amax(F.magnitude) < 1e-14
54-
# assert T.magnitude == 0
55-
56-
# # with anchor
57-
# F,T = getFT(hom, rloop, Tanch=rloop.position)
58-
# assert np.amax(abs(F.magnitude)) < 1e-14
59-
# assert abs(T[0].magnitude) < 1e-14
60-
# assert abs(T[1].magnitude + 4 ) < 1e-3
61-
# assert abs(T[2].magnitude) < 1e-14
62-
639
def test_physics_loop_torque():
6410
"""
6511
for a current loop in a homogeneous field the following holds
@@ -121,30 +67,6 @@ def func(field, observers):
12167
assert abs(T[2]) < 1e-14
12268

12369

124-
# def test_physics_parallel_wires():
125-
# """
126-
# The force between straight infinite parallel wires is
127-
# F = 2*mu0/4/pi * i1*i2/r
128-
# """
129-
# src = magpy.current.Polyline(
130-
# current=(1, "A"),
131-
# vertices=([(-1000,0,0),(1000,0,0)], "m"),
132-
# )
133-
# tgt = magpy.current.Polyline(
134-
# current=(1, "A"),
135-
# vertices=([(-1000,0,0),(0,0,0),(1000,0,0)], "m"),
136-
# position=((0,0,1), "m"),
137-
# )
138-
# tgt.meshing = 1000
139-
140-
# F,_ = getFT(src, tgt)
141-
142-
# Fanalytic = 2*magpy.mu_0/4/np.pi*2000
143-
144-
# assert abs(F[0].magnitude) < 1e-14
145-
# assert abs(F[1].magnitude) < 1e-14
146-
# assert abs((F[2].magnitude + Fanalytic)/Fanalytic) < 1e-3
147-
14870
def test_physics_parallel_wires():
14971
"""
15072
The force between straight infinite parallel wires is
@@ -168,28 +90,6 @@ def test_physics_parallel_wires():
16890
assert abs((F[2]+Fanalytic)/Fanalytic) < 1e-3
16991

17092

171-
# def test_physics_perpendicular_wires():
172-
# """
173-
# The force between straight infinite perpendicular wires is 0
174-
# """
175-
# src = magpy.current.Polyline(
176-
# current=(1, "A"),
177-
# vertices=([(-1000,0,0),(1000,0,0)], "m"),
178-
# )
179-
# tgt = magpy.current.Polyline(
180-
# current=(1, "A"),
181-
# vertices=([(0,-1000,0),(0,0,0),(0,1000,0)], "m"),
182-
# position=((0,0,1), "m"),
183-
# )
184-
# tgt.meshing = 1000
185-
186-
# ureg=src.current._REGISTRY
187-
# F,T = getFT(src, tgt)
188-
189-
# assert np.max(abs(F.magnitude)) < 1e-14
190-
191-
192-
19393
def test_physics_perpendicular_wires():
19494
"""
19595
The force between straight infinite perpendicular wires is 0
@@ -244,7 +144,7 @@ def test_cube_loop_replacement():
244144
assert np.amax(abs((T1-T2)/(T1+T2)*2))<1e-2
245145

246146

247-
def test_sphere_cube_at_distance():
147+
def test_physics_at_distance():
248148
"""
249149
A sphere and a cuboid with similar volume should see a similar torque and force
250150
at a distance
@@ -259,25 +159,33 @@ def test_sphere_cube_at_distance():
259159
polarization=J,
260160
position=pos
261161
)
262-
cube.meshing = (2,2,2)
162+
cube.meshing = 100
263163

264164
sphere = magpy.magnet.Sphere(
265165
diameter=(6/np.pi)**(1/3),
266166
polarization=J,
267167
position=pos,
268168
)
269-
sphere.meshing=2
169+
sphere.meshing=100
270170

271-
FT = getFT(source, [cube, sphere], anchor=(0,0,0))
171+
cyl = magpy.magnet.Cylinder(
172+
dimension=(2*np.sqrt(1/np.pi),1),
173+
polarization=J,
174+
position=pos,
175+
)
176+
cyl.meshing=100
272177

273-
errF = (FT[0,0]-FT[1,0])/np.linalg.norm(FT[0,0])
274-
errT = (FT[0,1]-FT[1,1])/np.linalg.norm(FT[0,1])
178+
FT = getFT(source, [cube, sphere, cyl], anchor=(0,0,0))
179+
print(FT.shape)
275180

276-
assert max(abs(errF)) < 1e-5
277-
assert max(abs(errT)) < 1e-5
181+
for i in range(1,3):
182+
errF = abs(np.linalg.norm(FT[0,0]-FT[i,0]) / np.linalg.norm(FT[0,0]+FT[i,0]))
183+
errT = abs(np.linalg.norm(FT[0,1]-FT[i,1]) / np.linalg.norm(FT[0,1]+FT[i,1]))
184+
assert errF<1e-4
185+
assert errF<1e-4
278186

279187

280-
def test_torque_sign():
188+
def test_physics_torque_sign():
281189
""" make sure that torque sign is in the right direction"""
282190

283191
# Cuboid -> Cuboid
@@ -308,7 +216,7 @@ def test_torque_sign():
308216
assert T[1] < 0
309217

310218

311-
def test_force_between_cocentric_loops():
219+
def test_physics_force_between_cocentric_loops():
312220
"""
313221
compare the numerical solution against the analytical solution of the force between two
314222
cocentric current loops.
@@ -331,4 +239,3 @@ def test_force_between_cocentric_loops():
331239
F_ana = pf*( (2-k2)/(1-k2)*ellipe(k**2) - 2*ellipk(k**2) )
332240

333241
assert abs((F_num - F_ana)/(F_num + F_ana)) < 1e-5
334-

0 commit comments

Comments
 (0)