Repository: magpylib/magpylib (language: python)

Issue:
Add `getM` and `getJ` + `in_out`  inside/ouside parameter
### Related Issues
- Implements #608
- Needs #712


### Notes
This PR implements the `getM` and `getJ` respectively for the `magnetization` and the `polarization` similarly to `getB` and `getH`. 

The inside/outside checks are now also separated from the field calculation of magnets. By introducing the `in_out` parameter to the core functions as well as for all `getH`, `getB`, `getM`, `getJ` functions it allows the user to specify the location of the observers relative to the magnet body, affecting the calculation of the magnetic field and optimizing performance. This is especially relevant for `Triangularmesh` for which this check is especially computationally intensive. The following options are in use:
- `'auto'` (default): The location (inside or outside the cuboid) is determined automatically for each observer.
- `'inside'`: All observers are considered to be inside the cuboid; use this for performance optimization if applicable.
- `'outside'`: All observers are considered to be outside the cuboid; use this for performance optimization if applicable.
Choosing 'auto' is fail-safe but may be computationally intensive if the mix of observer locations is unknown.



The following code is for performance comparison of the parameter combinations for each magnet type


```python
from time import perf_counter

import magpylib as magpy
import numpy as np
import pandas as pd
import plotly.express as px

objs_params = {
    "Cuboid": {
        "dimension": [1, 1, 1],
        "func": magpy.core.magnet_cuboid_field,
    },
    "Cylinder": {
        "dimension": [1, 1],
        "func": magpy.core.magnet_cylinder_field,
    },
    "Sphere": {
        "diameter": 1,
        "func": magpy.core.magnet_sphere_field,
    },
    "CylinderSegment": {
        "dimension": [0.25, 0.5, 1, 120, 420],
        "func": magpy.core.magnet_cylinder_segment_field,
    },
    "Tetrahedron": {
        "vertices": [(-1, 0, 0), (1, -1, 0), (1, 1, 0), (0, 0, 1)],
        "func": magpy.core.magnet_tetrahedron_field,
    },
}


def get_time(obj_type, field, in_out, N):
    kw = objs_params[obj_type].copy()
    func = kw.pop("func")
    kw["polarization"] = [1, 1, 1]
    kw = {k: np.repeat([v], N, axis=0) for k, v in kw.items()}
    kw["observers"] = np.linspace((-1, 0, 0), (1, 0, 0), N)
    if in_out is not None:
        kw["in_out"] = in_out
    tic = perf_counter()
    func(field=field, **kw)
    return perf_counter() - tic


def get_time_avg(obj_type, field, in_out, N, max_time=.1):
    t = get_time(obj_type, field, in_out, N)
    runs = 1
    if t > max_time:
        t, runs
    runs = max(2, int(max_time / t))
    t = np.mean([get_time(obj_type, field, in_out, N) for _ in range(runs)])
    return t, runs

def calc_res(in_outs):
    res = []
    for in_out in in_outs:
        for num_of_observers in [1, 10, 100, 1000, 10000]:
            for field in "BH":
                for obj_type in objs_params:
                    t, runs = get_time_avg(obj_type, field, in_out, num_of_observers)
                    d = {
                        "obj_type": obj_type,
                        "num_of_observers": num_of_observers,
                        "field": field,
                        "time": t,
                        "runs": runs,
                        "in_out": in_out,
                    }
                    print(f"{str(d):1000}", end="\r")
                    res.append(d)
    df = pd.DataFrame(res)
    df.to_csv(f"res_{'_'.join(str(v) for v in in_outs)}.csv", index=False)

# calc_res(in_outs=[None]) # magnetization-polarization branch

# calc_res(in_outs = ["auto", "inside", "outside"]) # inside-outside-getM-getJ

df1 = pd.read_csv("res_None.csv")
df2 = pd.read_csv("res_auto_inside_outside.csv")
df = pd.concat([df1, df2])
df["in_out"] = df["in_out"].astype(str)

px.line(
    df,
    x="num_of_observers",
    y="time",
    facet_col="obj_type",
    facet_row="field",
    color="in_out",
    line_dash="in_out",
    log_x=True,
    log_y=True,
    height=600
)
```

![image](https://github.com/magpylib/magpylib/assets/29252289/ebf968ad-cf42-4308-9866-1048ae17035c)

Display option for multi-pixel sensors
![image](https://user-images.githubusercontent.com/47384012/112679222-33b45300-8e6c-11eb-8da0-9c23676d7a30.png)



Discussion / hints:

Fix patch:
diff --git a/docs/_pages/docu/docu_magpylib_api.md b/docs/_pages/docu/docu_magpylib_api.md
index 36e546ed..e537c4ca 100644
--- a/docs/_pages/docu/docu_magpylib_api.md
+++ b/docs/_pages/docu/docu_magpylib_api.md
@@ -649,7 +649,7 @@ print(B)
 #  --> [0.         0.         0.00125664]
 ```
 
-By default, `getB` returns the B-field in units of T, `getH` the H-field in units of A/m, `getJ` the magnetic polarization in T and, `getM` the magnetization in A/m, assuming that all inputs are given in SI units. 
+By default, `getB` returns the B-field in units of T, `getH` the H-field in units of A/m, `getJ` the magnetic polarization in T and, `getM` the magnetization in A/m, assuming that all inputs are given in SI units.
 
 ```{note}
 In reality, `getB` returns the same unit as given by the `polarization` input. For example, with polarization input in mT, getB will return mT as well. At the same time when the `magnetization` input is kA/m, then `getH` returns kA/m as well. The B/H-field outputs are related to a M/J-inputs via a factor of $µ_0$.


Test patch:
diff --git a/tests/test_BaseTransform.py b/tests/test_BaseTransform.py
index dcf1bef1..b96908c9 100644
--- a/tests/test_BaseTransform.py
+++ b/tests/test_BaseTransform.py
@@ -85,7 +85,7 @@ def test_apply_move(description, old_position, displacement, new_position, start
     print(description)
     s = magpy.Sensor(position=old_position)
     apply_move(s, displacement, start=start)
-    assert np.all(s.position == np.array(new_position))
+    np.testing.assert_array_equal(s.position, np.array(new_position))
 
 
 @pytest.mark.parametrize(
@@ -255,7 +255,13 @@ def test_apply_rotation(
         position=old_position, orientation=R.from_rotvec(old_orientation_rotvec)
     )
     apply_rotation(s, R.from_rotvec(rotvec_to_apply), start=start, anchor=anchor)
-    assert np.allclose(s.position, np.array(new_position))
-    assert np.allclose(
-        s.orientation.as_matrix(), R.from_rotvec(new_orientation_rotvec).as_matrix()
+
+    np.testing.assert_allclose(
+        s.position, np.array(new_position), rtol=1e-05, atol=1e-08
+    )
+    np.testing.assert_allclose(
+        s.orientation.as_matrix(),
+        R.from_rotvec(new_orientation_rotvec).as_matrix(),
+        rtol=1e-05,
+        atol=1e-08,
     )
diff --git a/tests/test_elliptics.py b/tests/test_elliptics.py
index c849c8aa..d6bbb9c9 100644
--- a/tests/test_elliptics.py
+++ b/tests/test_elliptics.py
@@ -56,11 +56,11 @@ def test_el3_vs_original():
 
     # compare to vectorized
     resv = el3v(x11, kc11, p11)
-    assert np.allclose(res0, resv)
+    np.testing.assert_allclose(res0, resv)
 
     # compare to modified original
     res1 = np.array([el30(x, kc, p) for x, kc, p in zip(x11, kc11, p11)])
-    assert np.allclose(res0, res1)
+    np.testing.assert_allclose(res0, res1)
 
 
 def test_el3_angle_vs_original():
@@ -81,7 +81,7 @@ def test_el3_angle_vs_original():
 
     # compare to vectorized
     resv = el3_angle(phis, ns, ms)
-    assert np.allclose(res0, resv)
+    np.testing.assert_allclose(res0, resv)
 
 
 def test_el3s():
@@ -97,8 +97,8 @@ def test_el3s():
     res1 = el3v(xs, kcs, ps)
     res2 = el3(xs, kcs, ps)
 
-    assert np.allclose(res0, res1)
-    assert np.allclose(res1, res2)
+    np.testing.assert_allclose(res0, res1)
+    np.testing.assert_allclose(res1, res2)
 
 
 def test_cels():
@@ -116,5 +116,5 @@ def test_cels():
     res1 = celv(kcc, pp, cc, ss)
     res2 = cel(kcc, pp, cc, ss)
 
-    assert np.allclose(res0, res1)
-    assert np.allclose(res1, res2)
+    np.testing.assert_allclose(res0, res1)
+    np.testing.assert_allclose(res1, res2)
diff --git a/tests/test_field_cylinder.py b/tests/test_field_cylinder.py
index b634feeb..c85ca4d6 100644
--- a/tests/test_field_cylinder.py
+++ b/tests/test_field_cylinder.py
@@ -224,7 +224,7 @@ def test_cylinder_field1():
         field="B", observers=poso, polarization=magg, dimension=dim5
     )
 
-    assert np.allclose(B1, B0)
+    np.testing.assert_allclose(B1, B0)
 
 
 def test_cylinder_slanovc_field2():
@@ -244,37 +244,37 @@ def test_cylinder_slanovc_field2():
     # only inside
     btest = np.array([b_in] * 3)
     B = src.getB([r_in] * 3)
-    assert np.allclose(B, btest)
+    np.testing.assert_allclose(B, btest)
 
     # only edge
     btest = np.array([b_corn] * 3)
     B = src.getB([r_corn] * 3)
-    assert np.allclose(B, btest)
+    np.testing.assert_allclose(B, btest)
 
     # only outside
     btest = np.array([b_out] * 3)
     B = src.getB([r_out] * 3)
-    assert np.allclose(B, btest)
+    np.testing.assert_allclose(B, btest, rtol=1e-05, atol=1e-08)
 
     # edge + out
     btest = np.array([b_corn, b_corn, b_out])
     B = src.getB([r_corn, r_corn, r_out])
-    assert np.allclose(B, btest)
+    np.testing.assert_allclose(B, btest, rtol=1e-05, atol=1e-08)
 
     # surf + in
     btest = np.array([b_corn, b_corn, b_in])
     B = src.getB(r_corn, r_corn, r_in)
-    assert np.allclose(B, btest)
+    np.testing.assert_allclose(B, btest)
 
     # in + out
     btest = np.array([b_out, b_in])
     B = src.getB(r_out, r_in)
-    assert np.allclose(B, btest)
+    np.testing.assert_allclose(B, btest, rtol=1e-05, atol=1e-08)
 
     # in + out + surf
     btest = np.array([b_corn, b_corn, b_in, b_out, b_corn, b_corn])
     B = src.getB([r_corn, r_corn, r_in, r_out, r_corn, r_corn])
-    assert np.allclose(B, btest)
+    np.testing.assert_allclose(B, btest, rtol=1e-05, atol=1e-08)
 
 
 def test_cylinder_slanovc_field3():
@@ -290,32 +290,32 @@ def test_cylinder_slanovc_field3():
     # only inside
     htest = np.array([hinn] * 3)
     H = src.getH([[0.5, 0.6, 0.3]] * 3)
-    assert np.allclose(H, htest)
+    np.testing.assert_allclose(H, htest)
 
     # only surf
     htest = np.array([nulll] * 3)
     H = src.getH([[1, 0, 0]] * 3)
-    assert np.allclose(H, htest)
+    np.testing.assert_allclose(H, htest)
 
     # only outside
     htest = np.array([hout] * 3)
     H = src.getH([[1, 2, 3]] * 3)
-    assert np.allclose(H, htest)
+    np.testing.assert_allclose(H, htest)
 
     # surf + out
     htest = np.array([nulll, nulll, hout])
     H = src.getH([0.6, 0, 1], [1, 0, 0.5], [1, 2, 3])
-    assert np.allclose(H, htest)
+    np.testing.assert_allclose(H, htest)
 
     # surf + in
     htest = np.array([nulll, nulll, hinn])
     H = src.getH([0, 0.5, 1], [1, 0, 0.5], [0.5, 0.6, 0.3])
-    assert np.allclose(H, htest)
+    np.testing.assert_allclose(H, htest)
 
     # in + out
     htest = np.array([hout, hinn])
     H = src.getH([1, 2, 3], [0.5, 0.6, 0.3])
-    assert np.allclose(H, htest)
+    np.testing.assert_allclose(H, htest)
 
     # in + out + surf
     htest = np.array([nulll, nulll, hinn, hout, nulll, nulll])
@@ -327,7 +327,7 @@ def test_cylinder_slanovc_field3():
         [0.5, 0.6, -1],
         [0, 1, -0.3],
     )
-    assert np.allclose(H, htest)
+    np.testing.assert_allclose(H, htest)
 
 
 def test_cylinder_rauber_field4():
@@ -353,7 +353,7 @@ def test_cylinder_tile_negative_phi():
     )
     B1 = src1.getB((1, 0.5, 0.1))
     B2 = src2.getB((1, 0.5, 0.1))
-    assert np.allclose(B1, B2)
+    np.testing.assert_allclose(B1, B2)
 
 
 def test_cylinder_tile_vs_fem():
diff --git a/tests/test_getBH_dict.py b/tests/test_getBH_dict.py
index 17f44107..4c8998fe 100644
--- a/tests/test_getBH_dict.py
+++ b/tests/test_getBH_dict.py
@@ -25,7 +25,7 @@ def test_getB_dict1():
     dic = {"polarization": mag, "dimension": dim, "position": pos, "orientation": rot}
     B1 = magpy.getB("Cylinder", pos_obs, **dic)
 
-    assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
+    np.testing.assert_allclose(B1, B2, rtol=1e-12, atol=1e-12)
 
 
 def test_getB_dict2():
@@ -41,7 +41,7 @@ def test_getB_dict2():
     pm = magpy.magnet.Cylinder(polarization=mag, dimension=dim, position=pos)
     B2 = magpy.getB([pm], pos_obs)
 
-    assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
+    np.testing.assert_allclose(B1, B2, rtol=1e-12, atol=1e-12)
 
 
 def test_getH_dict1():
@@ -56,7 +56,7 @@ def test_getH_dict1():
     pm = magpy.magnet.Cylinder(polarization=mag, dimension=dim)
     B2 = pm.getH(pos_obs)
 
-    assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
+    np.testing.assert_allclose(B1, B2, rtol=1e-12, atol=1e-12)
 
 
 def test_getB_dict3():
@@ -81,7 +81,7 @@ def test_getB_dict3():
         B2 += [pm.getB(pos_obs)]
     B2 = np.array(B2)
     print(B1 - B2)
-    assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
+    np.testing.assert_allclose(B1, B2, rtol=1e-12, atol=1e-12)
 
 
 def test_getH_dict3():
@@ -99,7 +99,7 @@ def test_getH_dict3():
         B2 += [magpy.getH([pm], pos_obs)]
     B2 = np.array(B2)
 
-    assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
+    np.testing.assert_allclose(B1, B2, rtol=1e-12, atol=1e-12)
 
 
 def test_getB_dict4():
@@ -124,33 +124,33 @@ def test_getB_dict4():
         B2 += [pm.getB(pos_obs)]
     B2 = np.array(B2)
     print(B1 - B2)
-    assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
+    np.testing.assert_allclose(B1, B2, rtol=1e-12, atol=1e-12)
 
 
 def test_getBH_dipole():
     """test if Dipole implementation gives correct output"""
     B = magpy.getB("Dipole", (1, 1, 1), moment=(1, 2, 3))
     Btest = np.array([9.62250449e-08, 7.69800359e-08, 5.77350269e-08])
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
     H = magpy.getH("Dipole", (1, 1, 1), moment=(1, 2, 3))
     Htest = np.array([0.07657346, 0.06125877, 0.04594407])
-    assert np.allclose(H, Htest)
+    np.testing.assert_allclose(H, Htest, rtol=1e-05, atol=1e-08)
 
 
 def test_getBH_circle():
     """test if Circle implementation gives correct output"""
     B = magpy.getB("Circle", (0, 0, 0), current=1, diameter=2)
     Btest = np.array([0, 0, 0.6283185307179586 * 1e-6])
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
     H = magpy.getH("Circle", (0, 0, 0), current=1, diameter=2)
     Htest = np.array([0, 0, 0.6283185307179586 * 10 / 4 / np.pi])
-    assert np.allclose(H, Htest)
+    np.testing.assert_allclose(H, Htest)
 
     with pytest.warns(MagpylibDeprecationWarning):
         B = magpy.getB("Loop", (0, 0, 0), current=1, diameter=2)
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
 
 def test_getBH_squeeze():
@@ -181,7 +181,7 @@ def test_getBH_polyline():
         / 4
         / np.pi
     )
-    assert np.allclose(x, H)
+    np.testing.assert_allclose(x, H, rtol=1e-05, atol=1e-08)
 
 
 def test_getBH_polyline2():
@@ -200,11 +200,11 @@ def getB_line(name):
 
     B1 = getB_line("Polyline")
     expected = np.array([0, -x, 0])
-    assert np.allclose(B1, expected)
+    np.testing.assert_allclose(B1, expected, rtol=1e-05, atol=1e-08)
 
     with pytest.warns(MagpylibDeprecationWarning):
         B1 = getB_line("Line")
-    assert np.allclose(B1, expected)
+    np.testing.assert_allclose(B1, expected, rtol=1e-05, atol=1e-08)
 
     # move z-line to x=-1
     B2 = magpy.getB(
@@ -215,7 +215,7 @@ def getB_line(name):
         segment_start=(1, 0, -1),
         segment_end=(1, 0, 1),
     )
-    assert np.allclose(B2, np.array([0, x, 0]))
+    np.testing.assert_allclose(B2, np.array([0, x, 0]), rtol=1e-05, atol=1e-08)
 
     # rotate 1
     rot = R.from_euler("z", 90, degrees=True)
@@ -227,7 +227,7 @@ def getB_line(name):
         segment_start=(1, 0, -1),
         segment_end=(1, 0, 1),
     )
-    assert np.allclose(B3, np.array([x, 0, 0]))
+    np.testing.assert_allclose(B3, np.array([x, 0, 0]), rtol=1e-05, atol=1e-08)
 
     # rotate 2
     rot = R.from_euler("x", 90, degrees=True)
@@ -239,7 +239,7 @@ def getB_line(name):
         segment_start=(1, 0, -1),
         segment_end=(1, 0, 1),
     )
-    assert np.allclose(B4, np.array([0, 0, -x]))
+    np.testing.assert_allclose(B4, np.array([0, 0, -x]), rtol=1e-05, atol=1e-08)
 
     # rotate 3
     rot = R.from_euler("y", 90, degrees=True)
@@ -251,7 +251,7 @@ def getB_line(name):
         segment_start=(1, 0, -1),
         segment_end=(1, 0, 1),
     )
-    assert np.allclose(B5, np.array([0, -x, 0]))
+    np.testing.assert_allclose(B5, np.array([0, -x, 0]), rtol=1e-05, atol=1e-08)
 
     # "scalar" vertices tiling
     B = magpy.getB(
@@ -374,8 +374,8 @@ def test_getBH_solid_cylinder():
         polarization=(22, 33, 44),
     )
 
-    assert np.allclose(B1, B2)
-    assert np.allclose(B1, B3)
+    np.testing.assert_allclose(B1, B2)
+    np.testing.assert_allclose(B1, B3)
 
 
 def test_getB_dict_over_getB():
@@ -403,7 +403,7 @@ def test_getB_dict_over_getB():
     }
     B1 = magpy.getB(**dic)
 
-    assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
+    np.testing.assert_allclose(B1, B2, rtol=1e-12, atol=1e-12)
 
     # test for kwargs if sources is not a string
     dic["sources"] = pm
diff --git a/tests/test_getBH_interfaces.py b/tests/test_getBH_interfaces.py
index 89c0473e..8f6231f3 100644
--- a/tests/test_getBH_interfaces.py
+++ b/tests/test_getBH_interfaces.py
@@ -361,3 +361,24 @@ def test_getB_on_missing_excitations(module, class_, missing_arg, kwargs):
         match=rf"Parameter `{missing_arg}` of .* must be set.",
     ):
         getattr(getattr(magpy, module), class_)(**kwargs).getB([0, 0, 0])
+
+
+@pytest.mark.parametrize("field", ("H", "B", "M", "J"))
+@pytest.mark.parametrize("in_out", ("auto", "inside", "outside"))
+def test_getHBMJ_self_consistency(field, in_out):
+    """test getHBMJ self consistency"""
+    sources = [
+        magpy.magnet.Cuboid(dimension=(1, 1, 1), polarization=(0, 0, 1)),
+        magpy.current.Circle(diameter=1, current=1),
+    ]
+    sens = magpy.Sensor(position=np.linspace((-1, 0, 0), (1, 0, 0), 10))
+    src = sources[0]
+
+    F1 = getattr(magpy, f"get{field}")(src, sens, in_out=in_out)
+    F2 = getattr(sens, f"get{field}")(src, in_out=in_out)
+    F3 = getattr(src, f"get{field}")(sens, in_out=in_out)
+    F4 = getattr(magpy.Collection(src, sens), f"get{field}")(in_out=in_out)
+
+    np.testing.assert_allclose(F1, F2)
+    np.testing.assert_allclose(F1, F3)
+    np.testing.assert_allclose(F1, F4)
diff --git a/tests/test_getBH_level2.py b/tests/test_getBH_level2.py
index d34e0707..79de8a1f 100644
--- a/tests/test_getBH_level2.py
+++ b/tests/test_getBH_level2.py
@@ -56,8 +56,7 @@ def test_getB_level2_input_simple():
             result = np.array(result)
 
             B = magpy.getB(sources, observers)
-            assert B.shape == result.shape, "FAILOR shape"
-            assert np.allclose(B, result), "FAILOR values"
+            np.testing.assert_allclose(B, result)
 
 
 def test_getB_level2_input_shape22():
@@ -118,8 +117,7 @@ def pm4():
             sources, observers, result = sor
             result = np.array(result)
             B = magpy.getB(sources, observers)
-            assert B.shape == result.shape, "FAILOR2 shape"
-            assert np.allclose(B, result), "FAILOR2 values"
+            np.testing.assert_allclose(B, result)
 
 
 def test_getB_level2_input_path():
@@ -139,32 +137,27 @@ def test_getB_level2_input_path():
     pm1.move(possis)
     B = magpy.getB(pm1, (0, 0, 0))
     result = fb
-    assert B.shape == result.shape, "FAILOR3a shape"
-    assert np.allclose(B, result), "FAILOR3a values"
+    np.testing.assert_allclose(B, result)
 
     B = magpy.getB(pm1, sens1)
     result = fb
-    assert B.shape == result.shape, "FAILOR3b shape"
-    assert np.allclose(B, result), "FAILOR3b values"
+    np.testing.assert_allclose(B, result)
 
     B = magpy.getB([pm1, pm1], sens1)
     result = np.array([fb, fb])
-    assert B.shape == result.shape, "FAILOR3c shape"
-    assert np.allclose(B, result), "FAILOR3c values"
+    np.testing.assert_allclose(B, result)
 
     fb = pm2.getB([[(x, 0, 0), (x, 0, 0)] for x in np.linspace(0, -1, 11)])
     B = magpy.getB([pm1, pm1], [sens1, sens1])
     result = np.array([fb, fb])
-    assert B.shape == result.shape, "FAILOR3d shape"
-    assert np.allclose(B, result), "FAILOR3d values"
+    np.testing.assert_allclose(B, result)
 
     fb = pm2.getB(
         [[[(x, 0, 0), (x, 0, 1), (x, 0, 2)]] * 2 for x in np.linspace(0, -1, 11)]
     )
     B = magpy.getB([pm1, pm1], [sens2, sens2])
     result = np.array([fb, fb])
-    assert B.shape == result.shape, "FAILOR3e shape"
-    assert np.allclose(B, result), "FAILOR3e values"
+    np.testing.assert_allclose(B, result)
 
 
 def test_path_tile():
@@ -184,14 +177,26 @@ def test_path_tile():
 
     _ = magpy.getB([pm1, pm2], [0, 0, 0])
 
-    assert np.all(path1p == pm1.position), "FAILED: getB modified object path"
-    assert np.all(
-        path1r.as_quat() == pm1.orientation.as_quat()
-    ), "FAILED: getB modified object path"
-    assert np.all(path2p == pm2.position), "FAILED: getB modified object path"
-    assert np.all(
-        path2r.as_quat() == pm2.orientation.as_quat()
-    ), "FAILED: getB modified object path"
+    np.testing.assert_array_equal(
+        path1p,
+        pm1.position,
+        err_msg="FAILED: getB modified object path",
+    )
+    np.testing.assert_array_equal(
+        path1r.as_quat(),
+        pm1.orientation.as_quat(),
+        err_msg="FAILED: getB modified object path",
+    )
+    np.testing.assert_array_equal(
+        path2p,
+        pm2.position,
+        err_msg="FAILED: getB modified object path",
+    )
+    np.testing.assert_array_equal(
+        path2r.as_quat(),
+        pm2.orientation.as_quat(),
+        err_msg="FAILED: getB modified object path",
+    )
 
 
 def test_sensor_rotation1():
@@ -209,7 +214,7 @@ def test_sensor_rotation1():
         ]
     )
 
-    assert np.allclose(B, Brot)
+    np.testing.assert_allclose(B, Brot, rtol=1e-05, atol=1e-08)
 
 
 def test_sensor_rotation2():
@@ -238,25 +243,37 @@ def test_sensor_rotation2():
 
     B = magpy.getB(src, poss, squeeze=True)
     Btest = x1
-    assert np.allclose(np.around(B, decimals=5), Btest), "FAIL: mag  +  pos"
+    np.testing.assert_allclose(
+        np.around(B, decimals=5),
+        Btest,
+        err_msg="FAIL: mag  +  pos",
+    )
 
     B = magpy.getB([src], [sens], squeeze=True)
     Btest = np.array([x1, x2, x3])
-    assert np.allclose(np.around(B, decimals=5), Btest), "FAIL: mag  +  sens_rot_path"
+    np.testing.assert_allclose(
+        np.around(B, decimals=5),
+        Btest,
+        err_msg="FAIL: mag  +  sens_rot_path",
+    )
 
     B = magpy.getB([src], [sens, poss], squeeze=True)
     Btest = np.array([[x1, x1], [x2, x1], [x3, x1]])
-    assert np.allclose(
-        np.around(B, decimals=5), Btest
-    ), "FAIL: mag  +  sens_rot_path, pos"
+    np.testing.assert_allclose(
+        np.around(B, decimals=5),
+        Btest,
+        err_msg="FAIL: mag  +  sens_rot_path, pos",
+    )
 
     B = magpy.getB([src, col], [sens, poss], squeeze=True)
     Btest = np.array(
         [[[x1, x1], [x2, x1], [x3, x1]], [[x1b, x1b], [x2b, x1b], [x3b, x1b]]]
     )
-    assert np.allclose(
-        np.around(B, decimals=5), Btest
-    ), "FAIL: mag,col  +  sens_rot_path, pos"
+    np.testing.assert_allclose(
+        np.around(B, decimals=5),
+        Btest,
+        err_msg="FAIL: mag,col  +  sens_rot_path, pos",
+    )
 
 
 def test_sensor_rotation3():
@@ -271,7 +288,7 @@ def test_sensor_rotation3():
     sens.move([(0, 0, 0)] * 12, start=-1)
     Bpath = magpy.getB(src, sens)
 
-    assert np.allclose(B0t, Bpath)
+    np.testing.assert_allclose(B0t, Bpath)
 
 
 def test_object_tiling():
diff --git a/tests/test_numerical_stability.py b/tests/test_numerical_stability.py
index 7ef03fb2..ef225d6e 100644
--- a/tests/test_numerical_stability.py
+++ b/tests/test_numerical_stability.py
@@ -23,4 +23,4 @@ def test_loop_field():
     normB = np.linalg.norm(B, axis=1)
     norms = normB / normB[0]
 
-    assert np.allclose(norms, np.ones(1000))
+    np.testing.assert_allclose(norms, np.ones(1000))
diff --git a/tests/test_obj_BaseGeo.py b/tests/test_obj_BaseGeo.py
index a31d91f4..e6707cb4 100644
--- a/tests/test_obj_BaseGeo.py
+++ b/tests/test_obj_BaseGeo.py
@@ -74,8 +74,8 @@ def test_BaseGeo_basics():
     poss = np.array(poss)
     rots = np.array(rots)
 
-    assert np.allclose(poss, ptest), "test_BaseGeo bad position"
-    assert np.allclose(rots, otest), "test_BaseGeo bad orientation"
+    np.testing.assert_allclose(poss, ptest, err_msg="test_BaseGeo bad position")
+    np.testing.assert_allclose(rots, otest, err_msg="test_BaseGeo bad orientation")
 
 
 def test_rotate_vs_rotate_from():
@@ -103,8 +103,8 @@ def test_rotate_vs_rotate_from():
     pos2 = bg2.position
     ori2 = bg2.orientation.as_quat()
 
-    assert np.allclose(pos1, pos2)
-    assert np.allclose(ori1, ori2)
+    np.testing.assert_allclose(pos1, pos2)
+    np.testing.assert_allclose(ori1, ori2)
 
 
 def test_BaseGeo_reset_path():
@@ -127,10 +127,16 @@ def test_BaseGeo_anchor_None():
 
     pos3 = np.array([pos] * 3)
     rot3 = np.array([(0, 0, 0), (0.1, 0.2, 0.3), (0.2, 0.4, 0.6)])
-    assert np.allclose(bg.position, pos3), "None rotation changed position"
-    assert np.allclose(
-        bg.orientation.as_rotvec(), rot3
-    ), "None rotation did not adjust rot"
+    np.testing.assert_allclose(
+        bg.position,
+        pos3,
+        err_msg="None rotation changed position",
+    )
+    np.testing.assert_allclose(
+        bg.orientation.as_rotvec(),
+        rot3,
+        err_msg="None rotation did not adjust rot",
+    )
 
 
 def evall(obj):
@@ -153,8 +159,16 @@ def test_attach():
     for _ in range(10):
         bg2.rotate(roto)
 
-    assert np.allclose(bg.position, bg2.position), "attach p"
-    assert np.allclose(bg.orientation.as_quat(), bg2.orientation.as_quat()), "attach o"
+    np.testing.assert_allclose(
+        bg.position,
+        bg2.position,
+        err_msg="attach p",
+    )
+    np.testing.assert_allclose(
+        bg.orientation.as_quat(),
+        bg2.orientation.as_quat(),
+        err_msg="attach o",
+    )
 
 
 def test_path_functionality1():
@@ -174,26 +188,26 @@ def test_path_functionality1():
     pos, ori = evall(BaseGeo(pos0, rot0))
     P = np.array([b1, b2, b3, b4, b5])
     Q = np.array([q1, q2, q3, q4, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath, start=0))
     P = np.array([b1 + c1, b2 + c2, b3 + c3, b4, b5])
     Q = np.array([q1, q2, q3, q4, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath, start=1))
     P = np.array([b1, b2 + c1, b3 + c2, b4 + c3, b5])
     Q = np.array([q1, q2, q3, q4, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath, start=2))
     P = np.array([b1, b2, b3 + c1, b4 + c2, b5 + c3])
     Q = np.array([q1, q2, q3, q4, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
 
 def test_path_functionality2():
@@ -213,32 +227,32 @@ def test_path_functionality2():
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath, start=3))
     P = np.array([b1, b2, b3, b4 + c1, b5 + c2, b5 + c3])
     Q = np.array([q1, q2, q3, q4, q5, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath, start=4))
     P = np.array([b1, b2, b3, b4, b5 + c1, b5 + c2, b5 + c3])
     Q = np.array([q1, q2, q3, q4, q5, q5, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath, start=5))
     P = np.array([b1, b2, b3, b4, b5, b5 + c1, b5 + c2, b5 + c3])
     Q = np.array([q1, q2, q3, q4, q5, q5, q5, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath, start=5))
     P = np.array([b1, b2, b3, b4, b5, b5 + c1, b5 + c2, b5 + c3])
     Q = np.array([q1, q2, q3, q4, q5, q5, q5, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
     pos, ori = evall(BaseGeo(pos0, rot0).move(inpath))
     P = np.array([b1, b2, b3, b4, b5, b5 + c1, b5 + c2, b5 + c3])
     Q = np.array([q1, q2, q3, q4, q5, q5, q5, q5])
-    assert np.allclose(pos, P)
-    assert np.allclose(ori, Q)
+    np.testing.assert_allclose(pos, P)
+    np.testing.assert_allclose(ori, Q)
 
 
 def test_path_functionality3():
@@ -251,28 +265,28 @@ def test_path_functionality3():
 
     pos1, ori1 = evall(BaseGeo(pos0, rot0).move(inpath, start=4))
     pos2, ori2 = evall(BaseGeo(pos0, rot0).move(inpath, start=-1))
-    assert np.allclose(pos1, pos2)
-    assert np.allclose(ori1, ori2)
+    np.testing.assert_allclose(pos1, pos2)
+    np.testing.assert_allclose(ori1, ori2)
 
     pos1, ori1 = evall(BaseGeo(pos0, rot0).move(inpath, start=3))
     pos2, ori2 = evall(BaseGeo(pos0, rot0).move(inpath, start=-2))
-    assert np.allclose(pos1, pos2)
-    assert np.allclose(ori1, ori2)
+    np.testing.assert_allclose(pos1, pos2)
+    np.testing.assert_allclose(ori1, ori2)
 
     pos1, ori1 = evall(BaseGeo(pos0, rot0).move(inpath, start=2))
     pos2, ori2 = evall(BaseGeo(pos0, rot0).move(inpath, start=-3))
-    assert np.allclose(pos1, pos2)
-    assert np.allclose(ori1, ori2)
+    np.testing.assert_allclose(pos1, pos2)
+    np.testing.assert_allclose(ori1, ori2)
 
     pos1, ori1 = evall(BaseGeo(pos0, rot0).move(inpath, start=1))
     pos2, ori2 = evall(BaseGeo(pos0, rot0).move(inpath, start=-4))
-    assert np.allclose(pos1, pos2)
-    assert np.allclose(ori1, ori2)
+    np.testing.assert_allclose(pos1, pos2)
+    np.testing.assert_allclose(ori1, ori2)
 
     pos1, ori1 = evall(BaseGeo(pos0, rot0).move(inpath, start=0))
     pos2, ori2 = evall(BaseGeo(pos0, rot0).move(inpath, start=-5))
-    assert np.allclose(pos1, pos2)
-    assert np.allclose(ori1, ori2)
+    np.testing.assert_allclose(pos1, pos2)
+    np.testing.assert_allclose(ori1, ori2)
 
 
 def test_scipy_from_methods():
@@ -290,50 +304,86 @@ def cube():
     from_rotvec = cube().rotate_from_rotvec(
         rot.as_rotvec(degrees=True), anchor=anchor, degrees=True
     )
-    assert np.allclose(
-        cube0.position, from_rotvec.position
-    ), "from_rotvec failed on position"
-    assert np.allclose(
-        cube0.orientation.as_rotvec(), from_rotvec.orientation.as_rotvec()
-    ), "from_rotvec failed on orientation"
+    np.testing.assert_allclose(
+        cube0.position,
+        from_rotvec.position,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg="from_rotvec failed on position",
+    )
+    np.testing.assert_allclose(
+        cube0.orientation.as_rotvec(),
+        from_rotvec.orientation.as_rotvec(),
+        err_msg="from_rotvec failed on orientation",
+    )
 
     from_angax = cube().rotate_from_angax(angs_deg, "z", anchor=anchor, degrees=True)
-    assert np.allclose(
-        cube0.position, from_angax.position
-    ), "from_angax failed on position"
-    assert np.allclose(
-        cube0.orientation.as_rotvec(), from_angax.orientation.as_rotvec()
-    ), "from_rotvec failed on orientation"
+    np.testing.assert_allclose(
+        cube0.position,
+        from_angax.position,
+        err_msg="from_angax failed on position",
+    )
+    np.testing.assert_allclose(
+        cube0.orientation.as_rotvec(),
+        from_angax.orientation.as_rotvec(),
+        err_msg="from_rotvec failed on orientation",
+    )
 
     from_euler = cube().rotate_from_euler(angs_deg, "z", anchor=anchor, degrees=True)
-    assert np.allclose(
-        cube0.position, from_euler.position
-    ), "from_euler failed on position"
-    assert np.allclose(
-        cube0.orientation.as_rotvec(), from_euler.orientation.as_rotvec()
-    ), "from_rotvec failed on orientation"
+    np.testing.assert_allclose(
+        cube0.position,
+        from_euler.position,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg="from_euler failed on position",
+    )
+    np.testing.assert_allclose(
+        cube0.orientation.as_rotvec(),
+        from_euler.orientation.as_rotvec(),
+        err_msg="from_rotvec failed on orientation",
+    )
 
     from_matrix = cube().rotate_from_matrix(rot.as_matrix(), anchor=anchor)
-    assert np.allclose(
-        cube0.position, from_matrix.position
-    ), "from_matrix failed on position"
-    assert np.allclose(
-        cube0.orientation.as_rotvec(), from_matrix.orientation.as_rotvec()
-    ), "from_rotvec failed on orientation"
+    np.testing.assert_allclose(
+        cube0.position,
+        from_matrix.position,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg="from_matrix failed on position",
+    )
+    np.testing.assert_allclose(
+        cube0.orientation.as_rotvec(),
+        from_matrix.orientation.as_rotvec(),
+        err_msg="from_rotvec failed on orientation",
+    )
 
     from_mrp = cube().rotate_from_mrp(rot.as_mrp(), anchor=anchor)
-    assert np.allclose(cube0.position, from_mrp.position), "from_mrp failed on position"
-    assert np.allclose(
-        cube0.orientation.as_rotvec(), from_mrp.orientation.as_rotvec()
-    ), "from_rotvec failed on orientation"
+    np.testing.assert_allclose(
+        cube0.position,
+        from_mrp.position,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg="from_mrp failed on position",
+    )
+    np.testing.assert_allclose(
+        cube0.orientation.as_rotvec(),
+        from_mrp.orientation.as_rotvec(),
+        err_msg="from_rotvec failed on orientation",
+    )
 
     from_quat = cube().rotate_from_quat(rot.as_quat(), anchor=anchor)
-    assert np.allclose(
-        cube0.position, from_quat.position
-    ), "from_quat failed on position"
-    assert np.allclose(
-        cube0.orientation.as_rotvec(), from_quat.orientation.as_rotvec()
-    ), "from_rotvec failed on orientation"
+    np.testing.assert_allclose(
+        cube0.position,
+        from_quat.position,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg="from_quat failed on position",
+    )
+    np.testing.assert_allclose(
+        cube0.orientation.as_rotvec(),
+        from_quat.orientation.as_rotvec(),
+        err_msg="from_rotvec failed on orientation",
+    )
 
 
 def test_style():
diff --git a/tests/test_obj_BaseGeo_v4motion.py b/tests/test_obj_BaseGeo_v4motion.py
index 6a5939e0..6bb86177 100644
--- a/tests/test_obj_BaseGeo_v4motion.py
+++ b/tests/test_obj_BaseGeo_v4motion.py
@@ -15,20 +15,22 @@ def validate_pos_orient(obj, ppath, opath_as_rotvec):
     so = obj.orientation
     ppath = np.array(ppath)
     opath = R.from_rotvec(opath_as_rotvec)
-    assert ppath.shape == sp.shape, (
-        "position shapes do not match"
-        f"\n object has {sp.shape} instead of {ppath.shape}"
+    np.testing.assert_allclose(
+        sp,
+        ppath,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg=f"position validation failed with ({sp})" f"\n expected {ppath}",
     )
-    assert opath.as_rotvec().shape == so.as_rotvec().shape, (
-        "orientation as_rotvec shapes do not match"
-        f"\n object has {so.as_rotvec().shape} instead of {opath.as_rotvec().shape}"
-    )
-    assert np.allclose(sp, ppath), (
-        f"position validation failed with ({sp})" f"\n expected {ppath}"
-    )
-    assert np.allclose(so.as_matrix(), opath.as_matrix()), (
-        f"orientation validation failed with ({so.as_rotvec()})"
-        f"\n expected {opath_as_rotvec}"
+    np.testing.assert_allclose(
+        so.as_matrix(),
+        opath.as_matrix(),
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg=(
+            f"orientation validation failed with ({so.as_rotvec()})"
+            f"\n expected {opath_as_rotvec}"
+        ),
     )
 
 
diff --git a/tests/test_obj_Circle.py b/tests/test_obj_Circle.py
index 5875560f..d81ecd2a 100644
--- a/tests/test_obj_Circle.py
+++ b/tests/test_obj_Circle.py
@@ -12,7 +12,7 @@ def test_Circle_basic_B():
 
     B = src.getB(sens)
     Btest = np.array([0.44179833, 0.88359665, 0.71546231]) * 1e-6
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
 
 def test_BHJM_circle():
@@ -44,7 +44,7 @@ def test_Circle_basic_H():
 
     H = src.getH(sens)
     Htest = np.array([0.44179833, 0.88359665, 0.71546231]) * 10 / 4 / np.pi
-    assert np.allclose(H, Htest)
+    np.testing.assert_allclose(H, Htest)
 
 
 # def test_Circular_problem_positions():
@@ -56,7 +56,7 @@ def test_Circle_basic_H():
 
 #     B = src.getB(sens)
 #     Btest = np.array([[0,0,0.6283185307179586], [0,0,0], [0,0,0]])
-#     assert np.allclose(B, Btest)
+#     np.testing.assert_allclose(B, Btest)
 
 
 def test_repr():
diff --git a/tests/test_obj_Collection.py b/tests/test_obj_Collection.py
index 8db0a32b..9a4156f4 100644
--- a/tests/test_obj_Collection.py
+++ b/tests/test_obj_Collection.py
@@ -244,7 +244,7 @@ def test_col_getH():
     col = magpy.Collection(pm1, pm2)
     H = col.getH((0, 0, 0))
     H1 = pm1.getH((0, 0, 0))
-    assert np.all(H == 2 * H1), "col getH fail"
+    np.testing.assert_array_equal(H, 2 * H1, err_msg="col getH fail")
 
 
 def test_col_reset_path():
@@ -285,7 +285,7 @@ def test_Collection_with_Dipole():
 
     B = magpy.getB(col, sens)
     Btest = np.array([3.81801774e-09, 7.63603548e-09, 1.14540532e-08])
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
 
 def test_adding_sources():
diff --git a/tests/test_obj_Collection_v4motion.py b/tests/test_obj_Collection_v4motion.py
index 5518b05f..7e978464 100644
--- a/tests/test_obj_Collection_v4motion.py
+++ b/tests/test_obj_Collection_v4motion.py
@@ -24,12 +24,22 @@ def validate_pos_orient(obj, ppath, opath_as_rotvec):
         "orientation as_rotvec shapes do not match"
         f"\n object has {so.as_rotvec().shape} instead of {opath.as_rotvec().shape}"
     )
-    assert np.allclose(sp, ppath), (
-        f"position validation failed with ({sp})" f"\n expected {ppath}"
+    np.testing.assert_allclose(
+        sp,
+        ppath,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg=f"position validation failed with ({sp}) expected {ppath}",
     )
-    assert np.allclose(so.as_matrix(), opath.as_matrix()), (
-        f"orientation validation failed with ({so.as_rotvec()})"
-        f"\n expected {opath_as_rotvec}"
+    np.testing.assert_allclose(
+        so.as_matrix(),
+        opath.as_matrix(),
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg=(
+            f"orientation validation failed with ({so.as_rotvec()})"
+            f"\n expected {opath_as_rotvec}"
+        ),
     )
 
 
@@ -282,8 +292,8 @@ def test_Collection_setter():
 
     test_POS, test_ORI = np.load("tests/testdata/testdata_Collection_setter.npy")
 
-    assert np.allclose(POS, test_POS)
-    assert np.allclose(ORI, test_ORI)
+    np.testing.assert_allclose(POS, test_POS)
+    np.testing.assert_allclose(ORI, test_ORI)
 
 
 ############################################################################
diff --git a/tests/test_obj_Cylinder.py b/tests/test_obj_Cylinder.py
index 93adb6e6..d73f8152 100644
--- a/tests/test_obj_Cylinder.py
+++ b/tests/test_obj_Cylinder.py
@@ -103,13 +103,13 @@ def test_Cylinder_getBH():
             dimension=d5,
         )
 
-        assert np.allclose(B1, B2)
-        assert np.allclose(B1, B3)
-        assert np.allclose(B1, B0)
+        np.testing.assert_allclose(B1, B2)
+        np.testing.assert_allclose(B1, B3)
+        np.testing.assert_allclose(B1, B0)
 
-        assert np.allclose(H1, H2)
-        assert np.allclose(H1, H3)
-        assert np.allclose(H1, H0)
+        np.testing.assert_allclose(H1, H2)
+        np.testing.assert_allclose(H1, H3)
+        np.testing.assert_allclose(H1, H0)
 
 
 def test_getM():
diff --git a/tests/test_obj_Dipole.py b/tests/test_obj_Dipole.py
index 8c4c725c..e27483f2 100644
--- a/tests/test_obj_Dipole.py
+++ b/tests/test_obj_Dipole.py
@@ -10,7 +10,7 @@ def test_Dipole_basicB():
 
     B = src.getB(sens)
     Btest = np.array([3.81801774e-09, 7.63603548e-09, 1.14540532e-08])
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
 
 def test_Dipole_basicH():
@@ -19,7 +19,7 @@ def test_Dipole_basicH():
     sens = magpy.Sensor()
     H = src.getH(sens)
     Htest = np.array([0.00303828, 0.00607656, 0.00911485])
-    assert np.allclose(H, Htest)
+    np.testing.assert_allclose(H, Htest, rtol=1e-05, atol=1e-08)
 
 
 def test_Dipole_zero_position():
diff --git a/tests/test_obj_Polyline.py b/tests/test_obj_Polyline.py
index ce734ad3..66bea15c 100644
--- a/tests/test_obj_Polyline.py
+++ b/tests/test_obj_Polyline.py
@@ -14,7 +14,7 @@ def test_Polyline_basic1():
     x = 5.77350269 * 1e-6
     Btest = np.array([x, -x, 0])
 
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
 
 def test_Polyline_basic2():
@@ -26,7 +26,7 @@ def test_Polyline_basic2():
     x = 5.77350269 / 4 / np.pi * 10
     Htest = np.array([-x, x, 0])
 
-    assert np.allclose(H, Htest)
+    np.testing.assert_allclose(H, Htest)
 
 
 def test_Polyline_basic3():
@@ -41,7 +41,7 @@ def test_Polyline_basic3():
     x = 5.77350269 * 1e-6
     Btest = np.array([(x, -x, 0)] * 2)
 
-    assert np.allclose(B, Btest)
+    np.testing.assert_allclose(B, Btest)
 
 
 def test_Polyline_repr():
@@ -54,15 +54,15 @@ def test_Polyline_specials():
     """Polyline specials tests"""
     line = magpy.current.Polyline(current=100, vertices=[(0, 0, 0), (1, 1, 1)])
     b = line.getB([0, 0, 0])
-    assert np.allclose(b, np.zeros(3))
+    np.testing.assert_allclose(b, np.zeros(3))
 
     line = magpy.current.Polyline(current=100, vertices=[(0, 0, 0), (0, 0, 0)])
     b = line.getB([1, 2, 3])
-    assert np.allclose(b, np.zeros(3))
+    np.testing.assert_allclose(b, np.zeros(3))
 
     line = magpy.current.Polyline(current=0, vertices=[(1, 2, 3), (3, 2, 1)])
     b = line.getB([0, 0, 0])
-    assert np.allclose(b, np.zeros(3))
+    np.testing.assert_allclose(b, np.zeros(3))
 
 
 def test_line_position_bug():
@@ -84,7 +84,7 @@ def test_line_position_bug():
     # B2 = col.getB([(0,.99,.5), (0,.99,-.5)])
     B2 = col.getB(poso)
 
-    assert np.allclose(B1, B2)
+    np.testing.assert_allclose(B1, B2)
 
 
 def test_discontinous_line():
diff --git a/tests/test_obj_Sensor.py b/tests/test_obj_Sensor.py
index 9be750f9..80d930db 100644
--- a/tests/test_obj_Sensor.py
+++ b/tests/test_obj_Sensor.py
@@ -18,8 +18,7 @@ def test_sensor1():
     B1 = pm.getB(possis)
     B2 = sens.getB(pm)
 
-    assert B1.shape == B2.shape, "FAIL sensor shape"
-    assert np.allclose(B1, B2), "FAIL sensor values"
+    np.testing.assert_allclose(B1, B2)
 
 
 def test_sensor2():
@@ -36,8 +35,7 @@ def test_sensor2():
     sens.move([(t, 0, 0) for t in poz], start=0)
     B2 = sens.getB(pm)
 
-    assert B1.shape == B2.shape, "FAIL sensor shape"
-    assert np.allclose(B1, B2), "FAIL sensor values"
+    np.testing.assert_allclose(B1, B2)
 
 
 def test_Sensor_getB_specs():
@@ -47,7 +45,7 @@ def test_Sensor_getB_specs():
 
     B1 = sens1.getB(pm1)
     B2 = magpy.getB(pm1, sens1)
-    assert np.allclose(B1, B2), "should be same"
+    np.testing.assert_allclose(B1, B2)
 
 
 def test_Sensor_squeeze():
diff --git a/tests/test_obj_Sphere.py b/tests/test_obj_Sphere.py
index 3066e24a..97913910 100644
--- a/tests/test_obj_Sphere.py
+++ b/tests/test_obj_Sphere.py
@@ -55,7 +55,7 @@ def test_Sphere_basics():
         btest += [pm.getB(poso)]
     btest = np.array(btest)
 
-    assert np.allclose(B, btest), "test_Sphere failed big time"
+    np.testing.assert_allclose(B, btest)
 
 
 def test_Sphere_add():
diff --git a/tests/test_path.py b/tests/test_path.py
index 6827076c..de8aac39 100644
--- a/tests/test_path.py
+++ b/tests/test_path.py
@@ -23,7 +23,7 @@ def test_path_old_new_move():
     possis = np.array([(t, 0, 0) for t in ts])
     B2 = pm2.getB(possis[::-1])
 
-    assert np.allclose(B1, B2), "path move problem"
+    np.testing.assert_allclose(B1, B2, err_msg="path move problem")
 
 
 def test_path_old_new_rotate():
@@ -55,4 +55,10 @@ def test_path_old_new_rotate():
         pm2.rotate_from_angax(60 / (n - 1), ax, anch)
     B2 = np.array(B2)
 
-    assert np.allclose(B1, B2), "path rotate problem"
+    np.testing.assert_allclose(
+        B1,
+        B2,
+        rtol=1e-05,
+        atol=1e-08,
+        err_msg="path rotate problem",
+    )
diff --git a/tests/test_physics_consistency.py b/tests/test_physics_consistency.py
index e68cf465..c8306543 100644
--- a/tests/test_physics_consistency.py
+++ b/tests/test_physics_consistency.py
@@ -16,18 +16,18 @@ def test_dipole_approximation():
     dia = np.sqrt(4 / np.pi)
     src2 = magpy.magnet.Cylinder(polarization=pol, dimension=(dia, 1))
     B2 = src2.getB(pos)
-    assert np.allclose(B1, B2)
+    np.testing.assert_allclose(B1, B2, rtol=1e-05, atol=1e-08)
 
     # Sphere with volume = 1 m^3
     dia = (6 / np.pi) ** (1 / 3)
     src3 = magpy.magnet.Sphere(polarization=pol, diameter=dia)
     B3 = src3.getB(pos)
-    assert np.allclose(B1, B3)
+    np.testing.assert_allclose(B1, B3, rtol=1e-05, atol=1e-08)
 
     #  Dipole with mom=pol
     src4 = magpy.misc.Dipole(moment=pol)
     B4 = src4.getB(pos)
-    assert np.allclose(B1, B4)
+    np.testing.assert_allclose(B1, B4, rtol=1e-05, atol=1e-08)
 
     # Circle loop vs Dipole
     dia = 2
@@ -37,7 +37,7 @@ def test_dipole_approximation():
     src2 = magpy.misc.Dipole(moment=(0, 0, m0))
     H1 = src1.getH(pos)
     H2 = src2.getH(pos)
-    assert np.allclose(H1, H2)
+    np.testing.assert_allclose(H1, H2, rtol=1e-05, atol=1e-08)
 
 
 def test_Circle_vs_Cylinder_field():
@@ -176,7 +176,7 @@ def test_Circle_vs_Cylinder_field():
     H1 = src1.getH(pos_obs)
     H2 = src2.getH(pos_obs)
 
-    assert np.allclose(H1, H2)
+    np.testing.assert_allclose(H1, H2)
 
 
 def test_Polyline_vs_Circle():
@@ -203,7 +203,7 @@ def test_Polyline_vs_Circle():
     src = magpy.current.Circle(current=1, diameter=2)
     Bcs = src.getB(po)
 
-    assert np.allclose(Bls, Bcs)
+    np.testing.assert_allclose(Bls, Bcs, rtol=1e-05, atol=1e-08)
 
 
 def test_Polyline_vs_Infinite():
@@ -229,4 +229,4 @@ def Binf(i0, pos):
     Bls = np.array(Bls)
     Binfs = np.array(Binfs) * 1e-6
 
-    assert np.allclose(Bls, Binfs)
+    np.testing.assert_allclose(Bls, Binfs)
diff --git a/tests/test_scaling.py b/tests/test_scaling.py
index afcc1e78..51029354 100644
--- a/tests/test_scaling.py
+++ b/tests/test_scaling.py
@@ -17,6 +17,6 @@ def test_scaling_loop():
     c4 = magpy.current.Circle(current=123000, diameter=10000)
     B4 = c4.getB([1000, 2000, 3000])
 
-    assert np.allclose(B1, B2)
-    assert np.allclose(B1, B3)
-    assert np.allclose(B1, B4)
+    np.testing.assert_allclose(B1, B2)
+    np.testing.assert_allclose(B1, B3)
+    np.testing.assert_allclose(B1, B4)
diff --git a/tests/test_utility.py b/tests/test_utility.py
index 7f155534..e122ae25 100644
--- a/tests/test_utility.py
+++ b/tests/test_utility.py
@@ -36,22 +36,42 @@ def test_format_getBH_class_inputs():
 
     B1 = pm1.getB(possis)
     B2 = pm1.getB(sens)
-    assert np.allclose(B1, B2), "pos_obs should give same as sens"
+    np.testing.assert_allclose(B1, B2, err_msg="pos_obs should give same as sens")
 
     B3 = pm1.getB(sens, sens)
     B4 = pm1.getB([sens, sens])
     B44 = pm1.getB((sens, sens))
-    assert np.allclose(B3, B4), "sens,sens should give same as [sens,sens]"
-    assert np.allclose(B3, B44), "sens,sens should give same as (sens,sens)"
+    np.testing.assert_allclose(
+        B3,
+        B4,
+        err_msg="sens,sens should give same as [sens,sens]",
+    )
+    np.testing.assert_allclose(
+        B3,
+        B44,
+        err_msg="sens,sens should give same as (sens,sens)",
+    )
 
     B1 = sens.getH(pm1) * 4
     B2 = sens.getH(pm1, pm2, col, sumup=True)
     B3 = sens.getH([col]) * 2
     B4 = sens.getH([col, pm1, pm2], sumup=True)
 
-    assert np.allclose(B1, B2), "src,src should give same as [src,src]"
-    assert np.allclose(B1, B3), "src should give same as [src]"
-    assert np.allclose(B1, B4), "src,src should give same as [src,src]"
+    np.testing.assert_allclose(
+        B1,
+        B2,
+        err_msg="src,src should give same as [src,src]",
+    )
+    np.testing.assert_allclose(
+        B1,
+        B3,
+        err_msg="src should give same as [src]",
+    )
+    np.testing.assert_allclose(
+        B1,
+        B4,
+        err_msg="src,src should give same as [src,src]",
+    )
 
 
 @pytest.mark.parametrize(
diff --git a/tests/test_vs_mag2.py b/tests/test_vs_mag2.py
index c5068eda..bbb0562c 100644
--- a/tests/test_vs_mag2.py
+++ b/tests/test_vs_mag2.py
@@ -40,7 +40,7 @@ def test_vs_mag2_linear():
     pm = magpy.magnet.Cuboid(polarization=(111, 222, 333), dimension=(1, 2, 3))
 
     B = magpy.getB(pm, poso)
-    assert np.allclose(B, data), "vs mag2 - linear"
+    np.testing.assert_allclose(B, data, err_msg="vs mag2 - linear")
 
 
 def test_vs_mag2_rotation():
@@ -53,7 +53,7 @@ def test_vs_mag2_rotation():
         for t in np.linspace(0, 444, 100)
     ]
     B = pm.getB(possis)
-    assert np.allclose(B, data), "vs mag2 - rot"
+    np.testing.assert_allclose(B, data, err_msg="vs mag2 - rot")
 
 
 def test_vs_mag2_spiral():
@@ -69,7 +69,7 @@ def test_vs_mag2_spiral():
     possis = np.linspace((0, 0, 0.1), (0, 0, 9.9), 99)
     pm.move(possis, start=1)
     B = pm.getB((0, 0, 0))
-    assert np.allclose(B, data), "vs mag2 - rot"
+    np.testing.assert_allclose(B, data, err_msg="vs mag2 - rot")
 
 
 def test_vs_mag2_line():
@@ -82,4 +82,4 @@ def test_vs_mag2_line():
     )
     B = src.getB([1, 2, 3])
 
-    assert np.allclose(Btest, B)
+    np.testing.assert_allclose(Btest, B)