Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anisotropic chi #9

Merged
merged 24 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
15b2bd1
update
fslanovc May 3, 2024
408dd58
update folder
fslanovc May 3, 2024
1acbf88
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 5, 2024
6840233
add __temp tp gitignore
OrtnerMichael May 5, 2024
9ea92ea
comment out tests
OrtnerMichael May 6, 2024
ae8667d
intermediate
OrtnerMichael May 6, 2024
3121949
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 6, 2024
cb442cf
remove test_demag
fslanovc May 6, 2024
82e4fa3
allow multiple susceptibility input formats
OrtnerMichael May 6, 2024
c227ed6
Merge branch 'anisotropic_chi' of https://github.com/magpylib/magpyli…
OrtnerMichael May 6, 2024
8dfbce0
Merge branch 'anisotropic_chi' of https://github.com/magpylib/magpyli…
fslanovc May 6, 2024
b6c7a20
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 6, 2024
5374617
add bad test
OrtnerMichael May 7, 2024
5d7cf0f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 7, 2024
627a2ce
test and example
fslanovc Aug 27, 2024
ee56ab3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 27, 2024
e666bb9
files for difference cell numbers
fslanovc Aug 27, 2024
668f955
Merge branch 'anisotropic_chi' of https://github.com/magpylib/magpyli…
fslanovc Aug 27, 2024
5d82b89
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 27, 2024
987eef7
remove example from main folder
OrtnerMichael Aug 28, 2024
dfed8ff
changelog
OrtnerMichael Aug 28, 2024
aa1e8ce
Merge branch 'main' of https://github.com/magpylib/magpylib-material-…
OrtnerMichael Aug 28, 2024
d1e788e
example with negative susceptibility
fslanovc Aug 28, 2024
e4321bb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
__temp*


# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@

# Unreleased
* Improve internals
* anisotropic susceptibilities are now allowed.
* Improve suszeptibility input possibilities:
- give susceptibility to parent collection
- if susceptiblity input is scalar, isotropic susceptibility is assumed, if it is a 3-vector it can be anisotropic
* Various tests included of interface and computation, isotropic and anisotropic tests confirm computaiton

# 0.2.1a0
* Fix null polarization for rotated objects ([#7](https://github.com/magpylib/magpylib-material-response/pull/7))
* Fix docs not building ([#6](https://github.com/magpylib/magpylib-material-response/pull/6))
Expand Down
2 changes: 1 addition & 1 deletion magpylib_material_response/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
analysis for soft materials and demagnetization of hard magnets. Leveraging the Method
of Moments, it calculates magnetic material response with high precision."""

__version__ = "0.2.1a0"
__version__ = "0.2.2"
87 changes: 70 additions & 17 deletions magpylib_material_response/demag.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,71 @@
logger.configure(**config)


def get_susceptibilities(*sources, susceptibility=None):
def get_susceptibilities(sources, susceptibility):
"""Return a list of length (len(sources)) with susceptibility values
Priority is given at the source level, hovever if value is not found, it is searched
up the parent tree, if available. Raises an error if no value is found when reached
the top level of the tree."""
susceptibilities = []
n = len(sources)

# susceptibilities from source attributes
if susceptibility is None:
susis = []
for src in sources:
susceptibility = getattr(src, "susceptibility", None)
if susceptibility is None:
if src.parent is None:
raise ValueError(
"No susceptibility defined in any parent collection"
)
susis.extend(get_susceptibilities(src.parent))
elif not hasattr(susceptibility, "__len__"):
susis.append((susceptibility, susceptibility, susceptibility))
elif len(susceptibility) == 3:
susis.append(susceptibility)
else:
raise ValueError("susceptibility is not scalar or array fo length 3")
else:
# susceptibilities as input to demag function
if np.isscalar(susceptibility):
susis = np.ones((n, 3)) * susceptibility
elif len(susceptibility) == 3:
susis = np.tile(susceptibility, (n, 1))
if n == 3:
raise ValueError(
"Apply_demag input susceptibility is ambiguous - either scalar list or vector single entry. "
"Please choose different means of input or change the number of cells in the Collection."
)
else:
if len(susceptibility) != n:
raise ValueError(
"Apply_demag input susceptibility must be scalar, 3-vector, or same length as input Collection."
)
susis = np.array(susceptibility)
if susis.ndim == 1:
susis = np.repeat(susis, 3).reshape(n, 3)

susis = np.reshape(susis, 3 * n, order="F")
return np.array(susis)


def get_H_ext(*sources, H_ext=None):
"""Return a list of length (len(sources)) with H_ext values
Priority is given at the source level, hovever if value is not found, it is searched up the
the parent tree, if available. Sets H_ext to zero if no value is found when reached the top
level of the tree"""
H_exts = []
for src in sources:
susceptibility = getattr(src, "susceptibility", None)
if susceptibility is None:
H_ext = getattr(src, "H_ext", None)
if H_ext is None:
if src.parent is None:
raise ValueError("No susceptibility defined in any parent collection")
susceptibilities.extend(get_susceptibilities(src.parent))
# print("Warning: No value for H_ext defined in any parent collection. H_ext set to zero.")
H_exts.append((0.0, 0.0, 0.0))
else:
H_exts.extend(get_H_ext(src.parent))
else:
susceptibilities.append(susceptibility)
return susceptibilities
H_exts.append(H_ext)
return H_exts


def demag_tensor(
Expand Down Expand Up @@ -341,14 +391,17 @@ def apply_demag(
) # shape ii = x1, ... xn, y1, ... yn, z1, ... zn

# set up S
if susceptibility is None:
susceptibility = get_susceptibilities(*magnets_list)
susceptibility = np.array(susceptibility)
if len(susceptibility) != n:
sus = get_susceptibilities(magnets_list, susceptibility)
S = np.diag(sus) # shape ii, jj

# set up H_ext
H_ext = get_H_ext(*magnets_list)
H_ext = np.array(H_ext)
if len(H_ext) != n:
raise ValueError(
"Apply_demag input collection and susceptibility must have same length."
"Apply_demag input collection and H_ext must have same length."
)
S = np.diag(np.tile(susceptibility, 3)) # shape ii, jj
H_ext = np.reshape(H_ext, (3 * n, 1), order="F")

# set up T (3 pol unit, n cells, n positions, 3 Bxyz)
with timelog("Demagnetization tensor calculation", min_log_time=min_log_time):
Expand All @@ -362,7 +415,7 @@ def apply_demag(
T *= magpy.mu_0
T = T.swapaxes(2, 3).reshape((3 * n, 3 * n)).T # shape ii, jj

pol_tolal = pol_magnets
pol_total = pol_magnets

if currents_list:
with timelog(
Expand All @@ -371,14 +424,14 @@ def apply_demag(
pos = np.array([src.position for src in magnets_list])
pol_currents = magpy.getB(currents_list, pos, sumup=True)
pol_currents = np.reshape(pol_currents, (3 * n, 1), order="F")
pol_tolal += np.matmul(S, pol_currents)
pol_total += np.matmul(S, pol_currents)

# set up Q
Q = np.eye(3 * n) - np.matmul(S, T)

# determine new polarization vectors
with timelog("Solving of linear system", min_log_time=1):
pol_new = np.linalg.solve(Q, pol_tolal)
pol_new = np.linalg.solve(Q, pol_total + np.matmul(S, H_ext))

pol_new = np.reshape(pol_new, (n, 3), order="F")
# pol_new *= .4*np.pi
Expand Down
Empty file added tests/__init__.py
Empty file.
43 changes: 43 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,48 @@
import magpylib as magpy
import numpy as np

import magpylib_material_response
from magpylib_material_response.demag import apply_demag
from magpylib_material_response.meshing import mesh_Cuboid


def test_version():
assert isinstance(magpylib_material_response.__version__, str)


def test_susceptibility_inputs():
"""
test if different xi inputs give the same result
"""

zone = magpy.magnet.Cuboid(
dimension=(1, 1, 1),
polarization=(0, 0, 1),
)
mesh = mesh_Cuboid(zone, (2, 2, 2))

dm1 = apply_demag(mesh, susceptibility=4)
dm2 = apply_demag(mesh, susceptibility=(4, 4, 4))
dm3 = apply_demag(mesh, susceptibility=[4] * 8)
dm4 = apply_demag(mesh, susceptibility=[(4, 4, 4)] * 8)

zone = magpy.magnet.Cuboid(
dimension=(1, 1, 1),
polarization=(0, 0, 1),
)
zone.susceptibility = 4
mesh = mesh_Cuboid(zone, (2, 2, 2))
dm5 = apply_demag(mesh)

zone = magpy.magnet.Cuboid(
dimension=(1, 1, 1),
polarization=(0, 0, 1),
)
zone.susceptibility = (4, 4, 4)
mesh = mesh_Cuboid(zone, (2, 2, 2))
dm6 = apply_demag(mesh)

b1 = dm1.getB((1, 2, 3))
for dm in [dm2, dm3, dm4, dm5, dm6]:
bb = dm.getB((1, 2, 3))
np.testing.assert_allclose(b1, bb)
68 changes: 68 additions & 0 deletions tests/test_isotropic_anisotropic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import magpylib as magpy
import numpy as np

from magpylib_material_response import demag, meshing


def test_isotropic_susceptibility():

cells = 1000 # should be >=1000, otherwise discretization error too large

magnet = magpy.magnet.Cuboid(dimension=(1e-3, 1e-3, 1e-3), polarization=(0, 0, 1.1))
grid = np.loadtxt("tests/testdata/grid_points.pts")
field_ansys = np.loadtxt("tests/testdata/isotropic_results_ansys.txt", skiprows=1)
field_ansys = field_ansys[:, 3:]

# isotropic
magnet.susceptibility = 0.1
magnet_meshed = meshing.mesh_Cuboid(magnet, cells)

demag.apply_demag(magnet_meshed, inplace=True)

field_magpylib = magnet_meshed.getB(grid)

np.testing.assert_allclose(field_ansys, field_magpylib, rtol=0, atol=0.0012)


def test_anisotropic_susceptibility():

cells = 1000 # should be >=1000, otherwise discretization error too large

magnet = magpy.magnet.Cuboid(dimension=(1e-3, 1e-3, 1e-3), polarization=(0, 0, 1.1))
grid = np.loadtxt("tests/testdata/grid_points.pts")
field_ansys = np.loadtxt("tests/testdata/anisotropic_results_ansys.txt", skiprows=1)
field_ansys = field_ansys[:, 3:]

# anisotropic
magnet.susceptibility = (0.3, 0.2, 0.1)
magnet_meshed = meshing.mesh_Cuboid(magnet, cells)

demag.apply_demag(magnet_meshed, inplace=True)

field_magpylib = magnet_meshed.getB(grid)

np.testing.assert_allclose(field_ansys, field_magpylib, rtol=0, atol=0.0012)


def test_negative_susceptibility():

cells = 1000 # should be >=1000, otherwise discretization error too large

magnet = magpy.magnet.Cuboid(
dimension=(1e-3, 1e-3, 1e-3), polarization=(0, 0, -0.1)
)
grid = np.loadtxt("tests/testdata/grid_points.pts")
field_ansys = np.loadtxt(
"tests/testdata/negative_susceptibility_ansys.txt", skiprows=1
)
field_ansys = field_ansys[:, 3:]

# isotropic
magnet.susceptibility = -1.1
magnet_meshed = meshing.mesh_Cuboid(magnet, cells)

demag.apply_demag(magnet_meshed, inplace=True)

field_magpylib = magnet_meshed.getB(grid)

np.testing.assert_allclose(field_ansys, field_magpylib, rtol=0, atol=0.0065)
Loading
Loading