Soft Magnets#

This code demonstrates demagnetization calculations for a hard and a soft cuboid magnet using the Magpylib library. Demagnetization is applied using varying numbers of cells for the mesh and compared to the computed magnetic fields from Magpylib withoug demagnetization and with FEM analysis data obtained from an external dataset.

Define magnetic sources with their susceptibilities#

import json

import magpylib as magpy
import numpy as np
import pandas as pd
import plotly.express as px
from loguru import logger
from magpylib_material_response.demag import apply_demag
from magpylib_material_response.meshing import mesh_all

magpy.defaults.display.backend = "plotly"

# hard magnet
cube1 = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(0.001, 0.001, 0.002))
cube1.move((0, 0, 0.0005))
cube1.susceptibility = 0.5  # µr=1.5
cube1.style.label = f"Hard cuboid magnet, susceptibility={cube1.susceptibility}"

# soft magnet
cube2 = magpy.magnet.Cuboid(polarization=(0, 0, 0), dimension=(0.001, 0.001, 0.001))
cube2.rotate_from_angax(angle=45, axis="y").move((0.0015, 0, 0))
cube2.susceptibility = 3999  # µr=4000
cube2.style.label = f"Soft cuboid magnet, susceptibility={cube2.susceptibility}"

# collection of all cells
coll = magpy.Collection(cube1, cube2, style_label="No demag")

# add sensors
sensors = [
    magpy.Sensor(
        position=np.linspace((-0.004, 0, z), (0.006, 0, z), 1001),
        style_label=f"Sensor, z={z}m",
    )
    for z in (-0.001, -0.003, -0.005)
]

magpy.show(*coll, *sensors)
# example of meshed Collection
coll_meshed = mesh_all(
    coll, target_elems=50, per_child_elems=False, style_label="No demag - meshed"
)
magpy.show(*coll_meshed)

Compute material response - demagnetization#

# apply demagnetization with varying number of cells
colls = [coll]
for target_elems in [1, 2, 8, 16, 32, 64, 128, 256]:
    with logger.contextualize(target_elems=target_elems):
        coll_meshed = mesh_all(
            coll, target_elems=target_elems, per_child_elems=True, min_elems=1
        )
        coll_demag = apply_demag(
            coll_meshed,
            style={"label": f"Coll_demag ({len(coll_meshed.sources_all):3d} cells)"},
        )
        colls.append(coll_demag)
2024-04-21 at 10:19:06 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag (  2 cells) with 2 cells - Counter({'Cuboid': 2})
2024-04-21 at 10:19:06 | SUCCESS  | timelog | {'target_elems': 1} ✅  Demagnetization of Coll_demag (  2 cells) with 2 cells - Counter({'Cuboid': 2}) done 🕑 1.002sec
2024-04-21 at 10:19:07 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag (  4 cells) with 4 cells - Counter({'Cuboid': 4})
2024-04-21 at 10:19:07 | SUCCESS  | timelog | {'target_elems': 2} ✅  Demagnetization of Coll_demag (  4 cells) with 4 cells - Counter({'Cuboid': 4}) done 🕑 1.002sec
2024-04-21 at 10:19:08 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag ( 16 cells) with 16 cells - Counter({'Cuboid': 16})
2024-04-21 at 10:19:08 | SUCCESS  | timelog | {'target_elems': 8} ✅  Demagnetization of Coll_demag ( 16 cells) with 16 cells - Counter({'Cuboid': 16}) done 🕑 1.003sec
2024-04-21 at 10:19:09 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag ( 34 cells) with 34 cells - Counter({'Cuboid': 34})
2024-04-21 at 10:19:10 | SUCCESS  | timelog | {'target_elems': 16} ✅  Demagnetization of Coll_demag ( 34 cells) with 34 cells - Counter({'Cuboid': 34}) done 🕑 1.017sec
2024-04-21 at 10:19:11 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag ( 66 cells) with 66 cells - Counter({'Cuboid': 66})
2024-04-21 at 10:19:11 | SUCCESS  | timelog | {'target_elems': 32} ✅  Demagnetization of Coll_demag ( 66 cells) with 66 cells - Counter({'Cuboid': 66}) done 🕑 1.007sec
2024-04-21 at 10:19:12 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag (127 cells) with 127 cells - Counter({'Cuboid': 127})
2024-04-21 at 10:19:12 | SUCCESS  | timelog | {'target_elems': 64} ✅  Demagnetization of Coll_demag (127 cells) with 127 cells - Counter({'Cuboid': 127}) done 🕑 1.016sec
2024-04-21 at 10:19:13 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag (253 cells) with 253 cells - Counter({'Cuboid': 253})
2024-04-21 at 10:19:13 | SUCCESS  | timelog | {'target_elems': 128} ✅  Demagnetization of Coll_demag (253 cells) with 253 cells - Counter({'Cuboid': 253}) done 🕑 1.039sec
2024-04-21 at 10:19:14 |   INFO   | run | {} ℹ️ Start Demagnetization of Coll_demag (502 cells) with 502 cells - Counter({'Cuboid': 502})
2024-04-21 at 10:19:15 |   INFO   | run | {} ℹ️ Start Demagnetization tensor calculation
2024-04-21 at 10:19:15 | SUCCESS  | timelog | {'target_elems': 256} ✅  Demagnetization tensor calculation done 🕑 1.216sec
2024-04-21 at 10:19:15 | SUCCESS  | timelog | {'target_elems': 256} ✅  Demagnetization of Coll_demag (502 cells) with 502 cells - Counter({'Cuboid': 502}) done 🕑 1.755sec

Compare with FEM analysis#

# compute field before demag
B_no_demag_df = magpy.getB(coll_meshed, sensors, output="dataframe")

B_cols = ["Bx", "Bz"]


def get_FEM_dataframe(sim):
    res = sim["results"][0]
    df = B_no_demag_df.copy()
    for Bk in B_cols:
        df[Bk] = res["value"].get(Bk, np.nan)
    df["computation"] = res["computation"]
    return df


def get_magpylib_dataframe(collection, sensors):
    df = magpy.getB(collection, sensors, output="dataframe")
    df["computation"] = collection.style.label
    return df


from magpylib_material_response.data import get_dataset

sim_ANSYS = get_dataset("FEMdata_test_softmag")  # FEM dataset has only Bx and Bz

df = pd.concat(
    [
        get_FEM_dataframe(sim_ANSYS),
        *[get_magpylib_dataframe(c, sensors) for c in colls],
    ]
).sort_values(["computation", "path"])


df["Distance [m]"] = sensors[0].position[df["path"]][:, 0]
df["Distance [m]"] -= df["Distance [m]"].min()
px_kwargs = dict(
    x="path",
    y=B_cols,
    facet_row="variable",
    facet_col="sensor",
    color="computation",
    line_dash="computation",
    height=600,
    facet_col_spacing=0.05,
    labels={**{Bk: f"{Bk} [T]" for Bk in B_cols}, "value": "value [T]"},
)
fig1 = px.line(
    df,
    title="Methods comparison",
    **px_kwargs,
)
fig1.update_yaxes(matches=None, showticklabels=True)

df_diff = df.copy()
ref = sim_ANSYS["results"][0]["computation"]

for st in df_diff["computation"].unique():
    df_diff.loc[df_diff["computation"] == st, B_cols] -= df.loc[
        df["computation"] == ref, B_cols
    ].values

fig2 = px.line(
    df_diff,
    title=f"Methods comparison - diff vs {ref}",
    **px_kwargs,
)
fig2.update_yaxes(matches=None, showticklabels=True)
display(fig1, fig2)

As shown above, the demagnetized collection outputs are approaching the reference FEM values while refining the mesh.