Repository: magpylib/magpylib (language: python)

Issue:
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/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 485742231..8dc50c1d7 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -12,11 +12,11 @@ body:
       label: Magpylib version
       description: What version of Magpylib are you running?
       options:
+        - 5.x (Unreleased)
         - 4.x (Latest)
         - 3.x
         - 2.x
         - 1.x
-        - Unreleased
     validations:
       required: true
   - type: textarea
@@ -37,7 +37,7 @@ body:
         import numpy as np
         import magpylib as magpy
 
-        cuboid = magpy.magnet.Cuboid((0,0,1000), (1,1,1))
+        cuboid = magpy.magnet.Cuboid(polarization=(0.,0.,1.), dimension=(1.,1.,1.))
         cuboid.move(np.linspace((0,0,0), (0,0,10), 11), start=0)
         cuboid.show()
       render: Python
diff --git a/.gitignore b/.gitignore
index fb92fc1ed..5affe0c87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,6 +92,7 @@ target/
 # Jupyter Notebook
 .ipynb_checkpoints
 *.ipynb
+.virtual_documents/
 
 # IPython
 profile_default/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7332f6b46..9c43c6237 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,12 +3,12 @@ All notable changes to magpylib are documented here.
 
 # Changelog
 
-## [UNRELEASED]
+## [5.0.0dev]
 
-## [4.5.1]
+## [4.5.1] - 2023-12-28
 - Fixed a field computatio issue where H-field resulting from axial magnetization is computed incorrectly inside of Cylinders ([#703](https://github.com/magpylib/magpylib/issues/703))
 
-## [4.5.0]
+## [4.5.0] - 2023-12-13
 - Add optional handedness parameter for Sensors ([#687](https://github.com/magpylib/magpylib/pull/687))
 - Renaming classes: `Line`→`Polyline`, `Loop`→`Circle`. Old names are still valid but will issue a `DeprecationWarning` and will eventually be removed in the next major version ([#690](https://github.com/magpylib/magpylib/pull/690))
 - Rework CI/CD workflows ([#686](https://github.com/magpylib/magpylib/pull/686))
@@ -441,7 +441,7 @@ The first official release of the magpylib library.
 
 ---
 
-[UNRELEASED]:https://github.com/magpylib/magpylib/compare/4.5.1...HEAD
+[5.0.0dev]:https://github.com/magpylib/magpylib/compare/4.5.1...HEAD
 [4.5.1]:https://github.com/magpylib/magpylib/compare/4.5.0...4.5.1
 [4.5.0]:https://github.com/magpylib/magpylib/compare/4.4.0...4.5.0
 [4.4.1]:https://github.com/magpylib/magpylib/compare/4.4.0...4.4.1
diff --git a/README.md b/README.md
index 1f5ca373d..70e2e19ff 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,7 @@
 
+> [!WARNING]
+> Version 5 introduces critical breaking changes with, among others, the _move to SI units_. We recommended to pin your dependencies to `magpylib>=4.5<5` until you are ready to migrate to the latest version! ([see details](https://github.com/magpylib/magpylib/discussions/647))
+
 <p align="left"><img align="center" src=docs/_static/images/magpylib_flag.png width=35%>
 </p>
 
@@ -17,7 +20,7 @@
 </a>
 <a href="https://anaconda.org/conda-forge/magpylib"> <img src="https://anaconda.org/conda-forge/magpylib/badges/version.svg" alt="Conda Cloud" height="18">
 </a>
-<a href="https://mybinder.org/v2/gh/magpylib/magpylib/4.5.1?filepath=docs%2Fexamples"> <img src="https://mybinder.org/badge_logo.svg" alt="MyBinder link" height="18">
+<a href="https://mybinder.org/v2/gh/magpylib/magpylib/5.0.0dev?filepath=docs%2Fexamples"> <img src="https://mybinder.org/badge_logo.svg" alt="MyBinder link" height="18">
 </a>
 <a href="https://github.com/psf/black"> <img src="https://img.shields.io/badge/code%20style-black-000000.svg" alt="black" height="18">
 </a>
@@ -47,59 +50,59 @@ Magpylib supports _Python3.8+_ and relies on common scientific computation libra
 
 # Quickstart
 
-Here is an example how to use Magpylib.
+Here is an example on how to use Magpylib.
 
-```python3
+```python
 import magpylib as magpy
 
-# Create a Cuboid magnet with sides 1,2 and 3 mm respectively, and magnetization
-# (polarization) of 1000 mT pointing in x-direction.
+# Create a Cuboid magnet with sides 1,2 and 3 cm respectively, and a polarization
+# of 1000 mT pointing in x-direction.
 cube = magpy.magnet.Cuboid(
-  magnetization=(1000,0,0),
-  dimension=(1,2,3),
+    polarization=(1, 0, 0),  # in SI Units (T)
+    dimension=(0.01, 0.02, 0.03),  # in SI Units (m)
 )
 
 # By default, the magnet position is (0,0,0) and its orientation is the unit
 # rotation (given by a scipy rotation object), which corresponds to magnet sided
 # parallel to global coordinate axes.
-print(cube.position)                   # --> [0. 0. 0.]
-print(cube.orientation.as_rotvec())    # --> [0. 0. 0.]
+print(cube.position)  # --> [0. 0. 0.]
+print(cube.orientation.as_rotvec())  # --> [0. 0. 0.]
 
 # Manipulate object position and orientation through the respective attributes,
 # or by using the powerful `move` and `rotate` methods.
-cube.move((0,0,-2))
-cube.rotate_from_angax(angle=45, axis='z')
-print(cube.position)                            # --> [0. 0. -2.]
-print(cube.orientation.as_rotvec(degrees=True)) # --> [0. 0. 45.]
+cube.move((0, 0, -0.02))# in SI Units (m)
+cube.rotate_from_angax(angle=45, axis="z")
+print(cube.position)  # --> [0. 0. -0.02]
+print(cube.orientation.as_rotvec(degrees=True))  # --> [0. 0. 45.]
 
-# Compute the magnetic field in units of mT at a set of observer positions. Magpylib
+# Compute the magnetic B-field in units of T at a set of observer positions. Magpylib
 # makes use of vectorized computation. Hand over all field computation instances,
 # e.g. different observer positions, at one funtion call. Avoid Python loops !!!
-observers = [(0,0,0), (1,0,0), (2,0,0)]
+observers = [(0, 0, 0), (0.01, 0, 0), (0.02, 0, 0)]  # in SI Units (m)
 B = magpy.getB(cube, observers)
-print(B.round()) # --> [[-91. -91.   0.]
-                 #      [  1. -38.  84.]
-                 #      [ 18. -14.  26.]]
+print(B.round(2))  # --> [[-0.09 -0.09  0.  ]
+#                         [ 0.   -0.04  0.08]
+#                         [ 0.02 -0.01  0.03]]  # in SI Units (T)
 
 # Sensors are observer objects that can have their own position and orientation.
-# Compute the H-field in units of kA/m.
-sensor = magpy.Sensor(position=(0,0,0))
-sensor.rotate_from_angax(angle=45, axis=(1,1,1))
+# Compute the H-field in units of A/m.
+sensor = magpy.Sensor(position=(0, 0, 0))
+sensor.rotate_from_angax(angle=45, axis=(1, 1, 1))
 H = magpy.getH(cube, sensor)
-print(H.round()) # --> [-95. -36. -14.]
+print(H.round())  # --> [-94537. -35642. -14085.]  # in SI Units (A/m)
 
 # Position and orientation attributes of Magpylib objects can be vectors of
 # multiple positions/orientations refered to as "paths". When computing the
 # magnetic field of an object with a path, it is computed at every path index.
-cube.position = [(0,0,-2), (1,0,-2), (2,0,-2)]
+cube.position = [(0, 0, -.02), (1, 0, -.02), (2, 0, -.02)]  # in SI Units (m)
 B = cube.getB(sensor)
-print(B.round()) # --> [[-119.  -45.  -18.]
-                 #      [   8.  -73.  -55.]
-                 #      [  15.  -30.   -8.]]
+print(B.round(2))  # --> [[-0.12 -0.04 -0.02]
+#                         [ 0.   -0.    0.  ]
+#                         [ 0.   -0.    0.  ]] # in SI Units (T)
 
 # When several objects are involved and things are getting complex, make use of
 # the `show` function to view your system through Matplotlib, Plotly or Pyvista backends.
-magpy.show(cube, sensor, backend='pyvista')
+magpy.show(cube, sensor, backend="pyvista")
 ```
 
 More details and other important features are described in detail in the **[Documentation](https://magpylib.readthedocs.io/en/latest)**. Key features are:
@@ -133,7 +136,7 @@ A valid software citation could be
     author = {{Michael-Ortner et al.}},
     title = {magpylib},
     url = {https://magpylib.readthedocs.io/en/latest/},
-    version = {4.5.1},
+    version = {5.0.0dev},
     date = {2023-06-25},
 }
 ```
diff --git a/docs/_pages/docu/docu_graphics.md b/docs/_pages/docu/docu_graphics.md
index e791137a0..b6e7120dd 100644
--- a/docs/_pages/docu/docu_graphics.md
+++ b/docs/_pages/docu/docu_graphics.md
@@ -4,9 +4,9 @@ jupytext:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.15.0
+    jupytext_version: 1.16.0
 kernelspec:
-  display_name: Python 3 (ipykernel)
+  display_name: Python 3
   language: python
   name: python3
 orphan: true
@@ -24,67 +24,74 @@ The desired graphic backend is selected with the `backend` keyword argument. To
 The following example shows the graphical representation of various Magpylib objects and their paths using the default Matplotlib graphic backend.
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 import pyvista as pv
 
+import magpylib as magpy
+
 objects = {
     "Cuboid": magpy.magnet.Cuboid(
-        magnetization=(0, -100, 0),
-        dimension=(1, 1, 1),
-        position=(-6, 0, 0),
+        polarization=(0, -0.1, 0),
+        dimension=(0.01, 0.01, 0.01),
+        position=(-0.06, 0, 0),
     ),
     "Cylinder": magpy.magnet.Cylinder(
-        magnetization=(0, 0, 100),
-        dimension=(1, 1),
-        position=(-5, 0, 0),
+        polarization=(0, 0, 0.01),
+        dimension=(0.01, 0.01),
+        position=(-0.05, 0, 0),
     ),
     "CylinderSegment": magpy.magnet.CylinderSegment(
-        magnetization=(0, 0, 100),
-        dimension=(0.3, 1, 1, 0, 140),
-        position=(-3, 0, 0),
+        polarization=(0, 0, 0.01),
+        dimension=(0.003, 0.01, 0.01, 0, 140),
+        position=(-0.03, 0, 0),
     ),
     "Sphere": magpy.magnet.Sphere(
-        magnetization=(0, 0, 100),
-        diameter=1,
-        position=(-1, 0, 0),
+        polarization=(0, 0, 0.01),
+        diameter=0.01,
+        position=(-0.01, 0, 0),
     ),
     "Tetrahedron": magpy.magnet.Tetrahedron(
-        magnetization=(0, 0, 100),
-        vertices=((-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, -1, -1)),
-        position=(-4, 0, 4),
+        polarization=(0, 0, 0.01),
+        vertices=((-0.01, 0, 0), (0.01, 0, 0), (0, -0.01, 0), (0, -0.01, -0.01)),
+        position=(-0.04, 0, 0.04),
     ),
     "TriangularMesh": magpy.magnet.TriangularMesh.from_pyvista(
-        magnetization=(0, 0, 100),
-        polydata=pv.Dodecahedron(),
-        position=(-1, 0, 4),
+        polarization=(0, 0, 0.01),
+        polydata=pv.Dodecahedron(radius=0.01),
+        position=(-0.01, 0, 0.04),
     ),
     "Circle": magpy.current.Circle(
         current=1,
-        diameter=1,
-        position=(4, 0, 0),
+        diameter=0.01,
+        position=(0.04, 0, 0),
     ),
     "Polyline": magpy.current.Polyline(
         current=1,
-        vertices=[(1, 0, 0), (0, 1, 0), (-1, 0, 0), (0, -1, 0), (1, 0, 0)],
-        position=(1, 0, 0),
+        vertices=[
+            (0.01, 0, 0),
+            (0, 0.01, 0),
+            (-0.01, 0, 0),
+            (0, -0.01, 0),
+            (0.01, 0, 0),
+        ],
+        position=(0.01, 0, 0),
     ),
     "Dipole": magpy.misc.Dipole(
-        moment=(0, 0, 100),
-        position=(3, 0, 0),
+        moment=(0, 0, 1),
+        position=(0.03, 0, 0),
     ),
     "Triangle": magpy.misc.Triangle(
-        magnetization=(0, 0, 100),
-        vertices=((-1, 0, 0), (1, 0, 0), (0, 1, 0)),
-        position=(2, 0, 4),
+        polarization=(0, 0, 0.01),
+        vertices=((-0.01, 0, 0), (0.01, 0, 0), (0, 0.01, 0)),
+        position=(0.02, 0, 0.04),
     ),
     "Sensor": magpy.Sensor(
-        pixel=[(0, 0, z) for z in (-0.5, 0, 0.5)],
-        position=(0, -3, 0),
+        pixel=[(0, 0, z) for z in (-0.005, 0, 0.005)],
+        position=(0, -0.03, 0),
     ),
 }
 
-objects["Circle"].move(np.linspace((0, 0, 0), (0, 0, 5), 20))
+objects["Circle"].move(np.linspace((0, 0, 0), (0, 0, 0.05), 20))
 objects["Cuboid"].rotate_from_angax(np.linspace(0, 90, 20), "z", anchor=0)
 
 magpy.show(*objects.values())
@@ -142,50 +149,47 @@ There is a high level of **feature parity**, however, not all graphic features a
 | marker symbol                                                   | ✔️         | ✔️    | ❌      |
 | marker numbering                                                | ✔️         | ✔️    | ❌      |
 | zoom level                                                      | ✔️         | ✔️    | ❌[^2]  |
-| magnetization color                                             | ✔️[^8]     | ✔️    | ✔️[^3]  |
-| animation                                                       | ✔️         | ✔️    | ✔️[^6]  |
-| animation time                                                  | ✔️         | ✔️    | ✔️[^6]  |
-| animation fps                                                   | ✔️         | ✔️    | ✔️[^6]  |
+| magnetization color                                             | ✔️[^7]     | ✔️    | ✔️      |
+| animation                                                       | ✔️         | ✔️    | ✔️[^5]  |
+| animation time                                                  | ✔️         | ✔️    | ✔️[^5]  |
+| animation fps                                                   | ✔️         | ✔️    | ✔️[^5]  |
 | animation slider                                                | ✔️[^1]     | ✔️    | ❌      |
-| subplots 2D                                                     | ✔️         | ✔️    | ✔️[^7]  |
+| subplots 2D                                                     | ✔️         | ✔️    | ✔️[^6]  |
 | subplots 3D                                                     | ✔️         | ✔️    | ✔️      |
 | user canvas                                                     | ✔️         | ✔️    | ✔️      |
-| user extra 3d model [^4]                                        | ✔️         | ✔️    | ✔️ [^5] |
+| user extra 3d model [^3]                                        | ✔️         | ✔️    | ✔️ [^4] |
 
 
 [^1]: when returning animation object and exporting it as jshtml.
 
 [^2]: possible but not implemented at the moment.
 
-[^3]: does not work with `ipygany` jupyter backend. As of `pyvista>=0.38` these are deprecated and replaced by the [trame](https://docs.pyvista.org/api/plotting/trame.html) backend.
+[^3]: only `"scatter3d"`, and `"mesh3d"`. Gets "translated" to every other backend.
 
-[^4]: only `"scatter3d"`, and `"mesh3d"`. Gets "translated" to every other backend.
+[^4]: custom user defined trace constructors  allowed, which are specific to the backend.
 
-[^5]: custom user defined trace constructors  allowed, which are specific to the backend.
+[^5]: animation is only available through export as `gif` or `mp4`
 
-[^6]: animation is only available through export as `gif` or `mp4`
+[^6]: 2D plots are not supported for all jupyter_backends. As of pyvista>=0.38 these are deprecated and replaced by the [trame](https://docs.pyvista.org/api/plotting/trame.html) backend.
 
-[^7]: 2D plots are not supported for all jupyter_backends. As of pyvista>=0.38 these are deprecated and replaced by the [trame](https://docs.pyvista.org/api/plotting/trame.html) backend.
-
-[^8]: Matplotlib does not support color gradient. Instead magnetization is shown through object slicing and coloring.
+[^7]: Matplotlib does not support color gradient. Instead magnetization is shown through object slicing and coloring.
 
 The following example demonstrates the currently supported backends:
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 import pyvista as pv
 
-pv.set_jupyter_backend("panel")  # improve rendering in a jupyter notebook (pyvista only)
+import magpylib as magpy
 
 # define sources and paths
-loop = magpy.current.Circle(current=1, diameter=1)
-loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40)
+loop = magpy.current.Circle(current=1, diameter=0.01)
+loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40) / 100
 
 cylinder = magpy.magnet.Cylinder(
-    magnetization=(0, -100, 0), dimension=(1, 2), position=(0, -3, 0)
+    polarization=(0, -0.1, 0), dimension=(0.01, 0.02), position=(0, -0.03, 0)
 )
-cylinder.rotate_from_angax(np.linspace(0, 300, 40)[1:], "z", anchor=0)
+cylinder.rotate_from_angax(np.linspace(0, 300, 40), "z", anchor=0, start=0)
 
 # show the system using different backends
 for backend in magpy.SUPPORTED_PLOTTING_BACKENDS:
@@ -200,21 +204,22 @@ When calling `show`, a figure is automatically generated and displayed. It is al
 In the following example we show how to combine a 2D field plot with the 3D `show` output in **Matplotlib**:
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import matplotlib.pyplot as plt
 import numpy as np
 
+import magpylib as magpy
+
 # setup matplotlib figure and subplots
 fig = plt.figure(figsize=(10, 4))
 ax1 = fig.add_subplot(121)  # 2D-axis
 ax2 = fig.add_subplot(122, projection="3d")  # 3D-axis
 
 # define sources and paths
-loop = magpy.current.Circle(current=1, diameter=1)
-loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40)
+loop = magpy.current.Circle(current=1, diameter=0.01)
+loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40) / 100
 
 cylinder = magpy.magnet.Cylinder(
-    magnetization=(0, -100, 0), dimension=(1, 2), position=(0, -3, 0)
+    polarization=(0, -0.1, 0), dimension=(0.01, 0.02), position=(0, -0.03, 0)
 )
 cylinder.rotate_from_angax(np.linspace(0, 300, 40)[1:], "z", anchor=0)
 
@@ -233,21 +238,22 @@ plt.show()
 A similar example with **Plotly**:
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 import plotly.graph_objects as go
 
+import magpylib as magpy
+
 # setup plotly figure and subplots
 fig = go.Figure().set_subplots(
     rows=1, cols=2, specs=[[{"type": "xy"}, {"type": "scene"}]]
 )
 
 # define sources and paths
-loop = magpy.current.Circle(current=1, diameter=1)
-loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40)
+loop = magpy.current.Circle(current=1, diameter=0.01)
+loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40) / 100
 
 cylinder = magpy.magnet.Cylinder(
-    magnetization=(0, -100, 0), dimension=(1, 2), position=(0, -3, 0)
+    polarization=(0, -0.1, 0), dimension=(0.01, 0.02), position=(0, -0.03, 0)
 )
 cylinder.rotate_from_angax(np.linspace(0, 300, 40)[1:], "z", anchor=0)
 
@@ -269,18 +275,17 @@ fig.show()
 An example with **Pyvista**:
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 import pyvista as pv
 
-pv.set_jupyter_backend("panel")  # improve rending in a jupyter notebook
+import magpylib as magpy
 
 # define sources and paths
 loop = magpy.current.Circle(current=1, diameter=5)
-loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40)
+loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40) / 100
 
 cylinder = magpy.magnet.Cylinder(
-    magnetization=(0, -100, 0), dimension=(1, 2), position=(0, -3, 0)
+    polarization=(0, -0.1, 0), dimension=(0.01, 0.02), position=(0, -0.03, 0)
 )
 cylinder.rotate_from_angax(np.linspace(0, 300, 40)[1:], "z", anchor=0)
 
@@ -295,7 +300,7 @@ pl.add_lines(line, color="black")
 magpy.show(loop, cylinder, backend="pyvista", canvas=pl)
 
 # display scene
-pl.camera.position = (50, 10, 10)
+pl.camera.position = (.50, 10, 10)
 pl.set_background("black", top="white")
 pl.show()
 ```
@@ -305,18 +310,17 @@ pl.show()
 Instead of forwarding a figure to an existing canvas, it is also possible to return the figure object for further manipulation using the `return_fig` command. In the following example this is demonstrated for the pyvista backend.
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 import pyvista as pv
 
-pv.set_jupyter_backend("panel")  # improve rending in a jupyter notebook
+import magpylib as magpy
 
 # define sources and paths
-loop = magpy.current.Circle(current=1, diameter=5)
-loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40)
+loop = magpy.current.Circle(current=1, diameter=0.05)
+loop.position = np.linspace((0, 0, -3), (0, 0, 3), 40) / 100
 
 cylinder = magpy.magnet.Cylinder(
-    magnetization=(0, -100, 0), dimension=(1, 2), position=(0, -3, 0)
+    polarization=(0, -0.1, 0), dimension=(0.01, 0.02), position=(0, -0.03, 0)
 )
 cylinder.rotate_from_angax(np.linspace(0, 300, 40)[1:], "z", anchor=0)
 
@@ -325,13 +329,16 @@ pl = magpy.show(loop, cylinder, backend="pyvista", return_fig=True)
 
 # add line to the pyvista scene
 line = np.array(
-    [(t * np.cos(15 * t), t * np.sin(15 * t), t - 8) for t in np.linspace(3, 5, 200)]
+    [
+        (t * np.cos(15 * t), t * np.sin(15 * t), t - 8)
+        for t in np.linspace(0.03, 0.05, 200)
+    ]
 )
 pl.add_lines(line, color="black")
 
 # display scene
-pl.camera.position = (50, 10, 10)
-pl.set_background("purple", top="lightgreen")
+pl.camera.position = (.05, .01, .01)
+pl.set_background("yellow", top="lightgreen")
 pl.enable_anti_aliasing("ssaa")
 pl.show()
 ```
@@ -384,11 +391,13 @@ import magpylib as magpy
 
 magpy.defaults.reset()
 
-cube = magpy.magnet.Cuboid(magnetization=(1, 0, 0), dimension=(1, 1, 1))
+cube = magpy.magnet.Cuboid(polarization=(1, 0, 0), dimension=(0.01, 0.01, 0.01))
 cylinder = magpy.magnet.Cylinder(
-    magnetization=(0, -1, 0), dimension=(1, 1), position=(2, 0, 0)
+    polarization=(0, -1, 0), dimension=(0.01, 0.01), position=(0.02, 0, 0)
+)
+sphere = magpy.magnet.Sphere(
+    polarization=(0, 1, 1), diameter=0.01, position=(0.04, 0, 0)
 )
-sphere = magpy.magnet.Sphere(magnetization=(0, 1, 1), diameter=1, position=(4, 0, 0))
 
 print("Default magnetization style")
 magpy.show(cube, cylinder, sphere, backend="plotly")
@@ -463,19 +472,19 @@ import magpylib as magpy
 magpy.defaults.reset()  # reset defaults defined in previous example
 
 cube = magpy.magnet.Cuboid(
-    magnetization=(1, 0, 0),
-    dimension=(1, 1, 1),
+    polarization=(1, 0, 0),
+    dimension=(0.01, 0.01, 0.01),
     style_magnetization_color_mode="tricycle",
 )
 cylinder = magpy.magnet.Cylinder(
-    magnetization=(0, 1, 0),
-    dimension=(1, 1),
-    position=(2, 0, 0),
+    polarization=(0, 1, 0),
+    dimension=(0.01, 0.01),
+    position=(0.02, 0, 0),
 )
 sphere = magpy.magnet.Sphere(
-    magnetization=(0, 1, 1),
-    diameter=1,
-    position=(4, 0, 0),
+    polarization=(0, 1, 1),
+    diameter=0.01,
+    position=(0.04, 0, 0),
 )
 
 sphere.style.magnetization.color.mode = "bicolor"
@@ -494,9 +503,13 @@ import magpylib as magpy
 
 magpy.defaults.reset()  # reset defaults defined in previous example
 
-cube = magpy.magnet.Cuboid(magnetization=(1, 0, 0), dimension=(1, 1, 1))
-cylinder = magpy.magnet.Cylinder(magnetization=(0, 1, 0), dimension=(1, 1), position=(2, 0, 0))
-sphere = magpy.magnet.Sphere(magnetization=(0, 1, 1), diameter=1, position=(4, 0, 0))
+cube = magpy.magnet.Cuboid(polarization=(1, 0, 0), dimension=(0.01, 0.01, 0.01))
+cylinder = magpy.magnet.Cylinder(
+    polarization=(0, 1, 0), dimension=(0.01, 0.01), position=(0.02, 0, 0)
+)
+sphere = magpy.magnet.Sphere(
+    polarization=(0, 1, 1), diameter=0.01, position=(0.04, 0, 0)
+)
 
 coll = cube + cylinder
 
@@ -512,9 +525,13 @@ Finally it is possible to hand style input to the `show` function directly and l
 ```{code-cell} ipython3
 import magpylib as magpy
 
-cube = magpy.magnet.Cuboid(magnetization=(1, 0, 0), dimension=(1, 1, 1))
-cylinder = magpy.magnet.Cylinder(magnetization=(0, 1, 0), dimension=(1, 1), position=(2, 0, 0))
-sphere = magpy.magnet.Sphere(magnetization=(0, 1, 1), diameter=1, position=(4, 0, 0))
+cube = magpy.magnet.Cuboid(polarization=(1, 0, 0), dimension=(0.01, 0.01, 0.01))
+cylinder = magpy.magnet.Cylinder(
+    polarization=(0, 1, 0), dimension=(0.01, 0.01), position=(0.02, 0, 0)
+)
+sphere = magpy.magnet.Sphere(
+    polarization=(0, 1, 1), diameter=0.01, position=(0.04, 0, 0)
+)
 
 # use local style override
 magpy.show(cube, cylinder, sphere, backend="plotly", style_magnetization_show=False)
@@ -543,24 +560,25 @@ Ideally, the animation will show all path steps, but when e.g. `time` and `fps`
 The following example demonstrates the animation feature,
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 
+import magpylib as magpy
+
 # define objects with paths
 coll = magpy.Collection(
-    magpy.magnet.Cuboid(magnetization=(0, 1, 0), dimension=(2, 2, 2)),
-    magpy.magnet.Cylinder(magnetization=(0, 1, 0), dimension=(2, 2)),
-    magpy.magnet.Sphere(magnetization=(0, 1, 0), diameter=2),
+    magpy.magnet.Cuboid(polarization=(0, 1, 0), dimension=(0.02, 0.02, 0.02)),
+    magpy.magnet.Cylinder(polarization=(0, 1, 0), dimension=(0.02, 0.02)),
+    magpy.magnet.Sphere(polarization=(0, 1, 0), diameter=0.02),
 )
 
-start_positions = np.array([(1.414, 0, 1), (-1, -1, 1), (-1, 1, 1)])
+start_positions = np.array([(1.414, 0, 1), (-1, -1, 1), (-1, 1, 1)]) / 100
 for pos, src in zip(start_positions, coll):
     src.position = np.linspace(pos, pos * 5, 50)
     src.rotate_from_angax(np.linspace(0, 360, 50), "z", anchor=0, start=0)
 
-ts = np.linspace(-0.6, 0.6, 5)
+ts = np.linspace(-0.6, 0.6, 5) / 100
 sensor = magpy.Sensor(pixel=[(x, y, 0) for x in ts for y in ts])
-sensor.position = np.linspace((0, 0, -5), (0, 0, 5), 20)
+sensor.position = np.linspace((0, 0, -5), (0, 0, 5), 20) / 100
 
 # show with animation
 magpy.show(
@@ -599,21 +617,22 @@ Magpylib also offers the possibility to display objects into separate subplots.
 3D suplots can be directly defined in the `show` function by passing input objects as dictionaries with the arguments `objects`, `col` (column) and `row`, as in the example below. If now `row` or no `col` is specified, it defaults to 1.
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 
+import magpylib as magpy
+
 # define sensor and sources
-sensor = magpy.Sensor(pixel=[(-2,0,0), (2,0,0)])
+sensor = magpy.Sensor(pixel=[(-0.02, 0, 0), (0.02, 0, 0)])
 cyl1 = magpy.magnet.Cylinder(
-    magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+    polarization=(0.1, 0, 0), dimension=(0.01, 0.02), style_label="Cylinder1"
 )
 
 # define paths
-N=40
-sensor.position = np.linspace((0, 0, -3), (0, 0, 3), N)
-cyl1.position = (4, 0, 0)
+N = 40
+sensor.position = np.linspace((0, 0, -0.03), (0, 0, 0.03), N)
+cyl1.position = (0.04, 0, 0)
 cyl1.rotate_from_angax(angle=np.linspace(0, 300, N), start=0, axis="z", anchor=0)
-cyl2 = cyl1.copy().move((0, 0, 5))
+cyl2 = cyl1.copy().move((0, 0, 0.05))
 
 # display system in 3D with dict syntax
 magpy.show(
@@ -629,21 +648,22 @@ In order to make the subplot syntax more convenient we introduced the new `show_
 The above example becomes:
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 
+import magpylib as magpy
+
 # define sensor and sources
-sensor = magpy.Sensor(pixel=[(-2,0,0), (2,0,0)])
+sensor = magpy.Sensor(pixel=[(-0.02, 0, 0), (0.02, 0, 0)])
 cyl1 = magpy.magnet.Cylinder(
-    magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+    polarization=(0.1, 0, 0), dimension=(0.01, 0.02), style_label="Cylinder1"
 )
 
 # define paths
-N=40
-sensor.position = np.linspace((0, 0, -3), (0, 0, 3), N)
-cyl1.position = (4, 0, 0)
+N = 40
+sensor.position = np.linspace((0, 0, -0.03), (0, 0, 0.03), N)
+cyl1.position = (0.04, 0, 0)
 cyl1.rotate_from_angax(angle=np.linspace(0, 300, N), start=0, axis="z", anchor=0)
-cyl2 = cyl1.copy().move((0, 0, 5))
+cyl2 = cyl1.copy().move((0, 0, 0.05))
 
 # display system in 3D with context manager
 with magpy.show_context(backend="matplotlib") as sc:
@@ -686,25 +706,26 @@ with magpy.show_context():
 +++
 
 In addition the usual 3D models, it is also possible to draw 2D scatter plots of magnetic field data. This is achieved by assigning the `output` argument in the `show` function.
-By default `output='model3d'` displays the 3D representations of the objects. If output is a tuple of strings, it must be a combination of 'B' or 'H' and 'x', 'y' and/or 'z'. When having multiple coordinates, the field value is the combined vector length (e.g. `('Bx', 'Hxy', 'Byz')`). `'Bxy'` is equivalent to `sqrt(|Bx|^2 + |By|^2)`. A 2D line plot is then represented accordingly if the objects contain at least one source and one sensor.
+By default `output='model3d'` displays the 3D representations of the objects. If output is a tuple of strings, it must be a combination of 'B' or 'H' and 'x', 'y' and/or 'z'. When having multiple coordinates, the field value is the combined vector length (e.g. `('Bx', 'Hxy', 'Byz')`). `'Bxy'` is equivalent to `sqrt(|Bx|² + |By|²)`. A 2D line plot is then represented accordingly if the objects contain at least one source and one sensor.
 By default source outputs are summed up and sensor pixels, if any, are aggregated by mean (`pixel_agg="mean"`).
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 
+import magpylib as magpy
+
 # define sensor and sources
-sensor = magpy.Sensor(pixel=[(-2,0,0), (2,0,0)])
+sensor = magpy.Sensor(pixel=[(-0.02, 0, 0), (0.02, 0, 0)])
 cyl1 = magpy.magnet.Cylinder(
-    magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+    polarization=(0.1, 0, 0), dimension=(0.01, 0.02), style_label="Cylinder1"
 )
 
 # define paths
-N=40
-sensor.position = np.linspace((0, 0, -3), (0, 0, 3), N)
-cyl1.position = (4, 0, 0)
+N = 40
+sensor.position = np.linspace((0, 0, -3), (0, 0, 3), N) / 100
+cyl1.position = (0.04, 0, 0)
 cyl1.rotate_from_angax(angle=np.linspace(0, 300, N), start=0, axis="z", anchor=0)
-cyl2 = cyl1.copy().move((0, 0, 5))
+cyl2 = cyl1.copy().move((0, 0, 0.05))
 
 # display field data with context manager
 with magpy.show_context(cyl1, cyl2, sensor):
@@ -727,21 +748,22 @@ with magpy.show_context(cyl1, cyl2, sensor, sumup=False):
 Finally, Magpylib lets us show coupled 3D models with their field data while animating it.
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 
+import magpylib as magpy
+
 # define sensor and sources
-sensor = magpy.Sensor(pixel=[(-2,0,0), (2,0,0)])
+sensor = magpy.Sensor(pixel=[(-0.02, 0, 0), (0.02, 0, 0)])
 cyl1 = magpy.magnet.Cylinder(
-    magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+    polarization=(0.1, 0, 0), dimension=(0.01, 0.02), style_label="Cylinder1"
 )
 
 # define paths
-N=40
-sensor.position = np.linspace((0, 0, -3), (0, 0, 3), N)
-cyl1.position = (4, 0, 0)
+N = 40
+sensor.position = np.linspace((0, 0, -3), (0, 0, 3), N) / 100
+cyl1.position = (0.04, 0, 0)
 cyl1.rotate_from_angax(angle=np.linspace(0, 300, N), start=0, axis="z", anchor=0)
-cyl2 = cyl1.copy().move((0, 0, 5))
+cyl2 = cyl1.copy().move((0, 0, 0.05))
 
 # display field data with context manager, no sumup, no pixel_agg
 with magpy.show_context(cyl1, cyl2, sensor, animation=True, style_pixel_size=0.2):
@@ -772,11 +794,10 @@ The input `trace` is a dictionary which includes all necessary information for p
 The following example shows how a **generic** trace is constructed with  `Mesh3d` and `Scatter3d` and is displayed with three different backends:
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 import pyvista as pv
 
-pv.set_jupyter_backend("panel")  # improve rendering in a jupyter notebook
+import magpylib as magpy
 
 # Mesh3d trace #########################
 
@@ -784,16 +805,16 @@ trace_mesh3d = {
     "backend": "generic",
     "constructor": "Mesh3d",
     "kwargs": {
-        "x": (1, 0, -1, 0),
-        "y": (-0.5, 1.2, -0.5, 0),
-        "z": (-0.5, -0.5, -0.5, 1),
+        "x": (0.01, 0, -0.01, 0),
+        "y": (-0.005, 0.012, -0.005, 0),
+        "z": (-0.005, -0.005, -0.005, 0.01),
         "i": (0, 0, 0, 1),
         "j": (1, 1, 2, 2),
         "k": (2, 3, 3, 3),
         #'opacity': 0.5,
     },
 }
-coll = magpy.Collection(position=(0, -3, 0), style_label="'Mesh3d' trace")
+coll = magpy.Collection(position=(0, -0.03, 0), style_label="'Mesh3d' trace")
 coll.style.model3d.add_trace(trace_mesh3d)
 
 # Scatter3d trace ######################
@@ -803,9 +824,9 @@ trace_scatter3d = {
     "backend": "generic",
     "constructor": "Scatter3d",
     "kwargs": {
-        "x": np.cos(ts),
+        "x": np.cos(ts) / 100,
         "y": np.zeros(30),
-        "z": np.sin(ts),
+        "z": np.sin(ts) / 100,
         "mode": "lines",
     },
 }
@@ -824,19 +845,40 @@ It is possible to have multiple user-defined traces that will be displayed at th
 ```{code-cell} ipython3
 import copy
 
-dipole.style.size = 3
+import numpy as np
+
+import magpylib as magpy
+
+ts = np.linspace(0, 2 * np.pi, 30)
+trace_scatter3d = {
+    "backend": "generic",
+    "constructor": "Scatter3d",
+    "kwargs": {
+        "x": np.cos(ts) / 100,
+        "y": np.zeros(30),
+        "z": np.sin(ts) / 100,
+        "mode": "lines",
+    },
+}
+dipole = magpy.misc.Dipole(
+    moment=(0, 0, 1),
+    style_label="'Scatter3d' trace",
+    style_size=0.01,
+    style_sizemode="absolute",
+)
+
 
 # generate new trace from dictionary
 trace2 = copy.deepcopy(trace_scatter3d)
-trace2["kwargs"]["y"] = np.sin(ts)
+trace2["kwargs"]["y"] = np.sin(ts) / 100
 trace2["kwargs"]["z"] = np.zeros(30)
 
 dipole.style.model3d.add_trace(trace2)
 
 # generate new trace from Trace3d object
-trace3 = dipole.style.model3d.data[1].copy()
+trace3 = copy.deepcopy(dipole.style.model3d.data[0])
 trace3.kwargs["x"] = np.zeros(30)
-trace3.kwargs["z"] = np.cos(ts)
+trace3.kwargs["z"] = np.cos(ts) / 100
 
 dipole.style.model3d.add_trace(trace3)
 
@@ -846,17 +888,18 @@ dipole.show(dipole, backend="matplotlib")
 **Matplotlib** plotting functions often use positional arguments for $(x,y,z)$ input, that are handed over from `args=(x,y,z)` in `trace`. The following examples show how to construct traces with `plot`, `plot_surface` and `plot_trisurf`:
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import matplotlib.pyplot as plt
 import matplotlib.tri as mtri
 import numpy as np
 
+import magpylib as magpy
+
 # plot trace ###########################
 
 ts = np.linspace(-10, 10, 100)
-xs = np.cos(ts)
-ys = np.sin(ts)
-zs = ts / 20
+xs = np.cos(ts) / 100
+ys = np.sin(ts) / 100
+zs = ts / 20 / 100
 
 trace_plot = {
     "backend": "matplotlib",
@@ -864,15 +907,15 @@ trace_plot = {
     "args": (xs, ys, zs),
     "kwargs": {"ls": "--", "lw": 2},
 }
-magnet = magpy.magnet.Cylinder(magnetization=(0, 0, 1), dimension=(0.5, 1))
+magnet = magpy.magnet.Cylinder(polarization=(0, 0, 1), dimension=(0.005, 0.01))
 magnet.style.model3d.add_trace(trace_plot)
 
 # plot_surface trace ###################
 
 u, v = np.mgrid[0 : 2 * np.pi : 30j, 0 : np.pi : 20j]
-xs = np.cos(u) * np.sin(v)
-ys = np.sin(u) * np.sin(v)
-zs = np.cos(v)
+xs = np.cos(u) * np.sin(v) / 100
+ys = np.sin(u) * np.sin(v) / 100
+zs = np.cos(v) / 100
 
 trace_surf = {
     "backend": "matplotlib",
@@ -880,7 +923,7 @@ trace_surf = {
     "args": (xs, ys, zs),
     "kwargs": {"cmap": plt.cm.YlGnBu_r},
 }
-ball = magpy.Collection(position=(-3, 0, 0))
+ball = magpy.Collection(position=(-0.03, 0, 0))
 ball.style.model3d.add_trace(trace_surf)
 
 # plot_trisurf trace ###################
@@ -888,9 +931,9 @@ ball.style.model3d.add_trace(trace_surf)
 u, v = np.mgrid[0 : 2 * np.pi : 50j, -0.5:0.5:10j]
 u, v = u.flatten(), v.flatten()
 
-xs = (1 + 0.5 * v * np.cos(u / 2.0)) * np.cos(u)
-ys = (1 + 0.5 * v * np.cos(u / 2.0)) * np.sin(u)
-zs = 0.5 * v * np.sin(u / 2.0)
+xs = (1 + 0.5 * v * np.cos(u / 2.0)) * np.cos(u) / 100
+ys = (1 + 0.5 * v * np.cos(u / 2.0)) * np.sin(u) / 100
+zs = 0.5 * v * np.sin(u / 2.0) / 100
 
 tri = mtri.Triangulation(u, v)
 
@@ -903,10 +946,10 @@ trace_trisurf = {
         "cmap": plt.cm.coolwarm,
     },
 }
-mobius = magpy.misc.CustomSource(style_model3d_showdefault=False, position=(3, 0, 0))
+mobius = magpy.misc.CustomSource(style_model3d_showdefault=False, position=(0.03, 0, 0))
 mobius.style.model3d.add_trace(trace_trisurf)
 
-magpy.show(magnet, ball, mobius, zoom=5, backend="matplotlib")
+magpy.show(magnet, ball, mobius, backend="matplotlib")
 ```
 
 ### Pre-defined 3D models
@@ -920,9 +963,9 @@ from magpylib.graphics import model3d
 # prism trace ###################################
 trace_prism = model3d.make_Prism(
     base=6,
-    diameter=2,
-    height=1,
-    position=(-3, 0, 0),
+    diameter=0.02,
+    height=0.01,
+    position=(-0.03, 0, 0),
 )
 obj0 = magpy.Sensor(style_model3d_showdefault=False, style_label="Prism")
 obj0.style.model3d.add_trace(trace_prism)
@@ -930,33 +973,33 @@ obj0.style.model3d.add_trace(trace_prism)
 # pyramid trace #################################
 trace_pyramid = model3d.make_Pyramid(
     base=30,
-    diameter=2,
-    height=1,
-    position=(3, 0, 0),
+    diameter=0.02,
+    height=0.01,
+    position=(0.03, 0, 0),
 )
 obj1 = magpy.Sensor(style_model3d_showdefault=False, style_label="Pyramid")
 obj1.style.model3d.add_trace(trace_pyramid)
 
 # cuboid trace ##################################
 trace_cuboid = model3d.make_Cuboid(
-    dimension=(2, 2, 2),
-    position=(0, 3, 0),
+    dimension=(0.02, 0.02, 0.02),
+    position=(0, 0.03, 0),
 )
 obj2 = magpy.Sensor(style_model3d_showdefault=False, style_label="Cuboid")
 obj2.style.model3d.add_trace(trace_cuboid)
 
 # cylinder segment trace ########################
 trace_cylinder_segment = model3d.make_CylinderSegment(
-    dimension=(1, 2, 1, 140, 220),
-    position=(1, 0, -3),
+    dimension=(0.01, 0.02, 0.01, 140, 220),
+    position=(0.01, 0, -0.03),
 )
 obj3 = magpy.Sensor(style_model3d_showdefault=False, style_label="Cylinder Segment")
 obj3.style.model3d.add_trace(trace_cylinder_segment)
 
 # ellipsoid trace ###############################
 trace_ellipsoid = model3d.make_Ellipsoid(
-    dimension=(2, 2, 2),
-    position=(0, 0, 3),
+    dimension=(0.02, 0.02, 0.02),
+    position=(0, 0, 0.03),
 )
 obj4 = magpy.Sensor(style_model3d_showdefault=False, style_label="Ellipsoid")
 obj4.style.model3d.add_trace(trace_ellipsoid)
@@ -964,9 +1007,9 @@ obj4.style.model3d.add_trace(trace_ellipsoid)
 # arrow trace ###################################
 trace_arrow = model3d.make_Arrow(
     base=30,
-    diameter=0.6,
-    height=2,
-    position=(0, -3, 0),
+    diameter=0.006,
+    height=0.02,
+    position=(0, -0.03, 0),
 )
 obj5 = magpy.Sensor(style_model3d_showdefault=False, style_label="Arrow")
 obj5.style.model3d.add_trace(trace_arrow)
@@ -988,12 +1031,13 @@ The code below requires installation of the `numpy-stl` package.
 import os
 import tempfile
 
-import magpylib as magpy
 import numpy as np
 import requests
 from matplotlib.colors import to_hex
 from stl import mesh  # requires installation of numpy-stl
 
+import magpylib as magpy
+
 
 def bin_color_to_hex(x):
     """transform binary rgb into hex color"""
@@ -1025,6 +1069,7 @@ def trace_from_stl(stl_file):
     # generate and return a generic trace which can be translated into any backend
     colors = stl_mesh.attr.flatten()
     facecolor = np.array([bin_color_to_hex(c) for c in colors]).T
+    x, y, z = x / 1000, y / 1000, z / 1000  # mm->m
     trace = {
         "backend": "generic",
         "constructor": "mesh3d",
@@ -1050,8 +1095,8 @@ sensor = magpy.Sensor(style_label="PG-SSO-3 package")
 sensor.style.model3d.add_trace(trace)
 
 # create magnet and sensor path
-magnet = magpy.magnet.Cylinder(magnetization=(0, 0, 100), dimension=(15, 20))
-sensor.position = np.linspace((-15, 0, 8), (-15, 0, -4), 21)
+magnet = magpy.magnet.Cylinder(polarization=(0, 0, 1), dimension=(0.015, 0.02))
+sensor.position = np.linspace((-0.015, 0, 0.008), (-0.015, 0, -0.004), 21)
 sensor.rotate_from_angax(np.linspace(0, 180, 21), "z", anchor=0, start=0)
 
 # display with matplotlib and plotly backends
@@ -1060,3 +1105,7 @@ kwargs = dict(style_path_frames=5)
 magpy.show(args, **kwargs, backend="matplotlib")
 magpy.show(args, **kwargs, backend="plotly")
 ```
+
+```{code-cell} ipython3
+
+```
diff --git a/docs/_pages/docu/docu_magpylib_api.md b/docs/_pages/docu/docu_magpylib_api.md
index bd060c47a..a7dd66ba1 100644
--- a/docs/_pages/docu/docu_magpylib_api.md
+++ b/docs/_pages/docu/docu_magpylib_api.md
@@ -15,7 +15,7 @@ Magpylib requires no special input format. All scalar types (`int`, `float`, ...
 (docu-units)=
 ## Units
 
-For historical reasons Magpylib is by default set up for the following units
+For historical reasons Magpylib used non-SI units until Version 4. Starting with version 5 all inputs and outputs are SI-based.
 
 ::::{grid} 3
 :::{grid-item}
@@ -24,28 +24,33 @@ For historical reasons Magpylib is by default set up for the following units
 
 :::{grid-item}
 :columns: 10
-| PHYSICAL QUANTITY | MAGPYLIB PARAMETER | UNIT |
-|:---:|:---:|:---:|
-| magnetic polarization  | `magnetization`               | **mT**      |
-| electric current       | `current`                     | **A**       |
-| magnetic dipole moment | `moment`                      | **mT*mm^3** |
-| B-field                | `getB()`                      | **mT**      |
-| H-field                | `getH()`                      | **kA/m**    |
-| length-inputs          | `position`, `dimension`, ...  | **mm**      |
-| angle-inputs           | `angle`, `dimension`, ...     | **deg**     |
+| PHYSICAL QUANTITY | MAGPYLIB PARAMETER | UNITS from v5| UNITS until v4|
+|:---:|:---:|:---:|:---:|
+| Magnetic Polarization $\vec{J}$  | `polarization`                | **T**      | -        |
+| Magnetization $\vec{M}$          | `magnetization`               | **A/m**    | mT       |
+| Electric Current $i_0$           | `current`                     | **A**      | A        |
+| Magnetic Dipole Moment $\vec{m}$ | `moment`                      | **A·m²**   | mT·mm³   |
+| B-field $\vec{B}$                | `getB()`                      | **T**      | mT       |
+| H-field $\vec{H}$                | `getH()`                      | **A/m**    | kA/m     |
+| Length-inputs                    | `position`, `dimension`, ...  | **m**      | mm       |
+| Angle-inputs                     | `angle`, `dimension`, ...     | **°**      | °        |
 :::
 
 ::::
 
 ```{warning}
-Unfortunately Magpylib contributes to the naming confusion in magnetism that is explained well [here](https://www.e-magnetica.pl/doku.php/confusion_between_b_and_h). The input `magnetization` in Magpylib refers to the magnetic polarization (and not the magnetization), the difference being only in the physical unit.
+Up to version 4, Magpylib was unfortunately contributing to the naming confusion in magnetism that is explained well [here](https://www.e-magnetica.pl/doku.php/confusion_between_b_and_h). The input `magnetization` in Magpylib was refering to the magnetic polarization (and not the magnetization), the difference being only in the physical unit. From version 5 onwards this was fixed.
 ```
 
-The analytical solutions are scale invariant - _"a magnet with 1 mm sides creates the same field at 1 mm distance as a magnet with 1 m sides at 1 m distance"_. The choice of length input unit is therefore not relevant.
+```{note}
+All input and output units in Magpylib (version 5 and higher) are SI-based, see table above. However, for advanced use one should be aware that the analytical solutions are scale invariant - _"a magnet with 1 mm sides creates the same field at 1 mm distance as a magnet with 1 m sides at 1 m distance"_. The choice of length input unit is therefore not relevant, but it is critical to abide by the same length unit across one computation.
 
-In addition, `getB` returns the same unit as given by the `magnetization` input. When the magnetization is given in mT, then `getH` returns kA/m which is simply related by factor of $\frac{10}{4\pi}$.
+In addition, `getB` returns the same unit as given by the `polarization` input. 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=4\pi\cdot 10^{-7}$.
+```
 
-In {ref}`phys-remanence` the connection between the `magnetization` input and the remanence field of a magnet is explained.
+```{note}
+The connection between the magnetic polarization J, the magnetization M and the material parameters of a permanent magnet are shown in {ref}`gallery-tutorial-magnetmodel`.
+```
 
 <!-- ################################################################## -->
 <!-- ################################################################## -->
@@ -66,7 +71,7 @@ In Magpylib's object oriented interface magnetic field **sources** (generate the
 
 The following basic properties are shared by all Magpylib classes:
 
-* The <span style="color: orange">**position**</span> and <span style="color: orange">**orientation**</span> attributes describe the object placement in the global coordinate system. By default `position=(0,0,0)` and `orientation=None` (=unit rotation).
+* The <span style="color: orange">**position**</span> and <span style="color: orange">**orientation**</span> attributes describe the object placement in the global coordinate system.
 
 * The <span style="color: orange">**move()**</span> and <span style="color: orange">**rotate()**</span> methods enable relative object positioning.
 
@@ -90,16 +95,20 @@ See {ref}`docu-field-computation` for more information.
 
 * The <span style="color: orange">**parent**</span> attribute references a [Collection](docu-collection) that the object is part of.
 
-* The <span style="color: orange">**copy()**</span> method can be used to create a clone of any object where selected properties, given by kwargs, are modified.
+* The <span style="color: orange">**copy()**</span> method creates a clone of any object where selected properties, given by kwargs, are modified.
 
 * The <span style="color: orange">**describe()**</span> method provides a brief description of the object and returns the unique object id.
 
+
+---------------------------------------------
+
+
 ## Local and global coordinates
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-Magpylib objects span a local reference frame, and all object properties are defined within this frame, for example the vertices of a `Tetrahedron` magnet (see below). The position and orientation attributes describe how the local frame lies within the global coordinates. The two frames coincide by default, when `position=(0,0,0)` and `orientation=None` (=unit rotation).
+Magpylib objects span a local reference frame, and all object properties are defined within this frame, for example the vertices of a `Tetrahedron` magnet. The position and orientation attributes describe how the local frame lies within the global coordinates. The two frames coincide by default, when `position=(0,0,0)` and `orientation=None` (=unit rotation). The `position` and `orientation` attributes are described in detail in {ref}`docu-position`.
 :::
 :::{grid-item}
 :columns: 3
@@ -111,20 +120,21 @@ Magpylib objects span a local reference frame, and all object properties are def
 ---------------------------------------------
 
 
+(docu-magnet-classes)=
 ## Magnet classes
 
-All magnets are sources. They have the <span style="color: orange">**magnetization**</span> attribute which is of the format $(m_x, m_y, m_z)$ and denotes a homogeneous magnetization/polarization vector in the local object coordinates in arbitrary units. Information how this is related to material properties from data sheets is found in the [Physics and Computation](phys-remanence) section.
+All magnets are sources. They have the <span style="color: orange">**polarization**</span> attribute which is of the format $\vec{J}=(J_x, J_y, J_z)$ and denotes a homogeneous magnetic polarization vector in the local object coordinates in units of T. Alternatively, the magnetization vector can be set via the  <span style="color: orange">**magnetization**</span> attribute of the format $\vec{M}=(M_x, M_y, M_z)$. These two parameters are codependent and Magpylib ensures that they stay in sync via the relatoin $\vec{J}=\mu_0\cdot\vec{M}$. Information on how this is related to material properties from data sheets is found in {ref}`gallery-tutorial-magnetmodel`.
 
 
 ### Cuboid
 ```python
-magpy.magnet.Cuboid(magnetization, dimension, position, orientation, style)
+magpylib.magnet.Cuboid(position, orientation, dimension, polarization, magnetization, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Cuboid` objects represent magnets with cuboid shape. The <span style="color: orange">**dimension**</span> attribute has the format $(a,b,c)$ and denotes the sides of the cuboid in arbitrary length units. The center of the cuboid lies in the origin of the local coordinates, and the sides are parallel to the coordinate axes.
+`Cuboid` objects represent magnets with cuboid shape. The <span style="color: orange">**dimension**</span> attribute has the format $(a,b,c)$ and denotes the sides of the cuboid units of meter. The center of the cuboid lies in the origin of the local coordinates, and the sides are parallel to the coordinate axes.
 :::
 :::{grid-item}
 :columns: 3
@@ -135,13 +145,13 @@ magpy.magnet.Cuboid(magnetization, dimension, position, orientation, style)
 
 ### Cylinder
 ```python
-magpy.magnet.Cylinder(magnetization, dimension, position, orientation, style)
+magpylib.magnet.Cylinder(position, orientation, dimension, polarization, magnetization, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Cylinder` objects represent magnets with cylindrical shape. The <span style="color: orange">**dimension**</span> attribute has the format $(d,h)$ and denotes diameter and height of the cylinder in arbitrary length units. The center of the cylinder lies in the origin of the local coordinates, and the cylinder axis coincides with the z-axis.
+`Cylinder` objects represent magnets with cylindrical shape. The <span style="color: orange">**dimension**</span> attribute has the format $(d,h)$ and denotes diameter and height of the cylinder in units of meter. The center of the cylinder lies in the origin of the local coordinates, and the cylinder axis coincides with the z-axis.
 :::
 :::{grid-item}
 :columns: 3
@@ -152,13 +162,13 @@ magpy.magnet.Cylinder(magnetization, dimension, position, orientation, style)
 
 ### CylinderSegment
 ```python
-magpy.magnet.CylinderSegment(magnetization, dimension, position, orientation, style)
+magpylib.magnet.CylinderSegment(position, orientation, dimension, polarization, magnetization, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`CylinderSegment`represents a magnet with the shape of a cylindrical ring section. The <span style="color: orange">**dimension**</span> attribute has the format $(r_1,r_2,h,\varphi_1,\varphi_2)$ and denotes inner radius, outer radius and height in arbitrary length units, and the two section angles $\varphi_1<\varphi_2$ in deg. The center of the full cylinder lies in the origin of the local coordinates, and the cylinder axis coincides with the z-axis.
+`CylinderSegment` objects represent magnets with the shape of a cylindrical ring section. The <span style="color: orange">**dimension**</span> attribute has the format $(r_1,r_2,h,\varphi_1,\varphi_2)$ and denotes inner radius, outer radius and height in units of meter, and the two section angles $\varphi_1<\varphi_2$ in °. The center of the full cylinder lies in the origin of the local coordinates, and the cylinder axis coincides with the z-axis.
 :::
 :::{grid-item}
 :columns: 3
@@ -173,13 +183,13 @@ magpy.magnet.CylinderSegment(magnetization, dimension, position, orientation, st
 
 ### Sphere
 ```python
-magpy.magnet.Sphere(magnetization, diameter, position, orientation, style)
+magpylib.magnet.Sphere(position, orientation, diameter, polarization, magnetization, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Sphere` represents a magnet of spherical shape. The <span style="color: orange">**diameter**</span> attribute is the sphere diameter $d$ in arbitrary length units. The center of the sphere lies in the origin of the local coordinates.
+`Sphere` objects represent magnets of spherical shape. The <span style="color: orange">**diameter**</span> attribute is the sphere diameter $d$ in units of meter. The center of the sphere lies in the origin of the local coordinates.
 :::
 :::{grid-item}
 :columns: 3
@@ -190,13 +200,13 @@ magpy.magnet.Sphere(magnetization, diameter, position, orientation, style)
 
 ### Tetrahedron
 ```python
-magpy.magnet.Tetrahedron(magnetization, vertices, position, orientation, style)
+magpylib.magnet.Tetrahedron(position, orientation, vertices, polarization, magnetization, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Tetrahedron` represents a magnet of tetrahedral shape. The <span style="color: orange">**vertices**</span> attribute stores the four corner points $(P_1, P_2, P_3, P_4)$ in the local object coordinates in arbitrary length units.
+`Tetrahedron` objects represent magnets of tetrahedral shape. The <span style="color: orange">**vertices**</span> attribute stores the four corner points $(\vec{P}_1, \vec{P}_2, \vec{P}_3, \vec{P}_4)$ in the local object coordinates in units of m.
 :::
 :::{grid-item}
 :columns: 3
@@ -212,14 +222,20 @@ magpy.magnet.Tetrahedron(magnetization, vertices, position, orientation, style)
 
 ### TriangularMesh
 ```python
-magpy.magnet.TriangularMesh(magnetization, vertices, faces, position, orientation, check_open, check_disconnected, check_selfintersecting, reorient_faces, style)
+magpylib.magnet.TriangularMesh(position, orientation, vertices, faces, polarization, magnetization, check_open, check_disconnected, check_selfintersecting, reorient_faces, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`TriangularMesh` represents a magnet with surface given by a triangular mesh. The mesh is defined by the <span style="color: orange">**vertices**</span> attribute, an array of all unique corner points $(P_1, P_2, ...)$ in arbitrary length units, and the <span style="color: orange">**faces**</span> attribute, which is an array of index-triplets that define individual faces $(F_1, F_2, ...)$. The property <span style="color: orange">**mesh**</span> returns an array of all faces as point-triples $[(P_1^1, P_2^1, P_3^1), (P_1^2, P_2^2, P_3^2), ...]$.
-
+`TriangularMesh` objects represent magnets with surface given by a triangular mesh. The mesh is defined by the <span style="color: orange">**vertices**</span> attribute, an array of all unique corner points $(\vec{P}_1, \vec{P}_2, ...)$ in units of meter, and the <span style="color: orange">**faces**</span> attribute, which is an array of index-triplets that define individual faces $(\vec{F}_1, \vec{F}_2, ...)$. The property <span style="color: orange">**mesh**</span> returns an array of all faces as point-triples $[(\vec{P}_1^1, \vec{P}_2^1, \vec{P}_3^1), (\vec{P}_1^2, \vec{P}_2^2, \vec{P}_3^2), ...]$.
+:::
+:::{grid-item}
+:columns: 3
+![](../../_static/images/docu_classes_init_trimesh.png)
+:::
+:::{grid-item}
+:columns: 12
 At initialization the mesh integrity is automatically checked, and all faces are reoriented to point outwards. These actions are controlled via the kwargs
 * <span style="color: orange">**check_open**</span>
 * <span style="color: orange">**check_disconnected**</span>
@@ -243,21 +259,15 @@ The checks can also be performed after initialization using the methods
 * <span style="color: orange">**check_selfintersecting()**</span>
 * <span style="color: orange">**reorient_faces()**</span>
 
-The following class methods enable easy mesh loading and creating. They all take the mandatory <span style="color: orange">**magnetization**</span> argument, which overwrites possible magnetization from other inputs, as well as the optional mesh check parameters (see above).
+The following class methods enable easy mesh creating and mesh loading.
 
-* <span style="color: orange">**TriangularMesh.from_mesh()**</span> requires the input <span style="color: orange">**mesh**</span>, which is an array in the mesh format $[(P_1^1, P_2^1, P_3^1), (P_1^2, P_2^2, P_3^2), ...]$.
-* <span style="color: orange">**TriangularMesh.from_ConvexHull()**</span> requires the input <span style="color: orange">**points**</span>, which is an array of positions $(P_1, P_2, P_3, ...)$ from which the convex Hull is computed via the [Scipy ConvexHull](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.ConvexHull.html) implementation.
-* <span style="color: orange">**TriangularMesh.from_triangles()**</span> requires the input <span style="color: orange">**triangles**</span>, which is a list or a `Collection` of `Triangle` objects.
-* <span style="color: orange">**TriangularMesh.from_pyvista()**</span> requires the input <span style="color: orange">**polydata**</span>, which is a [Pyvista PolyData](https://docs.pyvista.org/version/stable/api/core/_autosummary/pyvista.PolyData.html) object.
+* <span style="color: orange">**TriangularMesh.from_mesh()**</span> generates a `TriangularMesh` objects from the input <span style="color: orange">**mesh**</span>, which is an array in the mesh format $[(\vec{P}_1^1, \vec{P}_2^1, \vec{P}_3^1), (\vec{P}_1^2, \vec{P}_2^2, \vec{P}_3^2), ...]$.
+* <span style="color: orange">**TriangularMesh.from_ConvexHull()**</span> generates a `TriangularMesh` object from the input <span style="color: orange">**points**</span>, which is an array of positions $(\vec{P}_1, \vec{P}_2, \vec{P}_3, ...)$ from which the convex Hull is computed via the [Scipy ConvexHull](https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.ConvexHull.html) implementation.
+* <span style="color: orange">**TriangularMesh.from_triangles()**</span> generates a `TriangularMesh` object from the input <span style="color: orange">**triangles**</span>, which is a list or a `Collection` of `Triangle` objects.
+* <span style="color: orange">**TriangularMesh.from_pyvista()**</span> generates a `TriangularMesh` object from the input <span style="color: orange">**polydata**</span>, which is a [Pyvista PolyData](https://docs.pyvista.org/version/stable/api/core/_autosummary/pyvista.PolyData.html) object.
 
 The method <span style="color: orange">**to_TriangleCollection()**</span> transforms a `TriangularMesh` object into a `Collection` of `Triangle` objects.
-:::
-:::{grid-item}
-:columns: 3
-![](../../_static/images/docu_classes_init_trimesh.png)
-:::
-:::{grid-item}
-:columns: 12
+
 **Info:** While the checks may be disabled, the field computation guarantees correct results only if the mesh is closed, connected, not self-intersecting and all faces are oriented outwards. Examples of working with the `TriangularMesh` class are found in {ref}`gallery-shapes-triangle` and in {ref}`gallery-shapes-pyvista`.
 :::
 ::::
@@ -268,17 +278,17 @@ The method <span style="color: orange">**to_TriangleCollection()**</span> transf
 
 ## Current classes
 
-All currents are sources. Current objects have the <span style="color: orange">**current**</span> attribute which is a scalar that denotes the electrical current in arbitrary units.
+All currents are sources. Current objects have the <span style="color: orange">**current**</span> attribute which is a scalar that denotes the electrical current in units of ampere.
 
 ### Circle
 ```python
-magpy.current.Circle(current, diameter, position, orientation, style)
+magpylib.current.Circle(position, orientation, diameter, current, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Circle` represents a circular line current loop. The <span style="color: orange">**diameter**</span> attribute is the loop diameter $d$ in arbitrary length units. The loop lies in the xy-plane with it's center in the origin of the local coordinates.
+`Circle` objects represent circular line current loops. The <span style="color: orange">**diameter**</span> attribute is the loop diameter $d$ in units of meter. The loop lies in the xy-plane with it's center in the origin of the local coordinates.
 :::
 :::{grid-item}
 :columns: 3
@@ -288,13 +298,13 @@ magpy.current.Circle(current, diameter, position, orientation, style)
 
 ### Polyline
 ```python
-magpy.current.Polyline(current, vertices, position, orientation, style)
+magpylib.current.Polyline(position, orientation, vertices, current, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Polyline` represents a set of line current segments that flow from vertex to vertex. The <span style="color: orange">**vertices**</span> attribute is a vector of all vertices $(P_1, P_2, ...)$ given in the local coordinates in arbitrary length units.
+`Polyline` objects represent line current segements where the electric current flows in straight lines from vertex to vertex. The <span style="color: orange">**vertices**</span> attribute is a vector of all vertices $(\vec{P}_1, \vec{P}_2, ...)$ given in the local coordinates in units of meter.
 :::
 :::{grid-item}
 :columns: 3
@@ -311,13 +321,13 @@ There are classes listed hereon that function as sources, but they do not repres
 
 ### Dipole
 ```python
-magpy.misc.Dipole(moment, position, orientation, style)
+magpylib.misc.Dipole(position, orientation, moment, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Dipole` represents a magnetic dipole moment with the <span style="color: orange">**moment**</span> attribute that describes the magnetic dipole moment $m=(m_x,m_y,m_z)$ in arbitrary units which lies in the origin of the local coordinates.
+`Dipole` objects represent magnetic dipole moments with the <span style="color: orange">**moment**</span> attribute that describes the magnetic dipole moment $\vec{m}=(m_x,m_y,m_z)$ in SI-units of Am², which lies in the origin of the local coordinates.
 :::
 :::{grid-item}
 :columns: 3
@@ -325,20 +335,20 @@ magpy.misc.Dipole(moment, position, orientation, style)
 :::
 :::{grid-item}
 :columns: 12
-**Info:** For homogeneous magnets the relation moment=magnetization$\times$volume holds.
+**Info:** The total dipole moment of a homogeneous magnet with body volume $V$ is given by $\vec{m}=\vec{J}\cdot V$.
 :::
 ::::
 
 
 ### Triangle
 ```python
-magpy.misc.Triangle(magnetization, vertices, position, orientation, style)
+magpylib.misc.Triangle(position, orientation, vertices, polarization, magnetization, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Triangle` represents a triangular surface with a homogeneous charge density given by the projection of the magnetization vector onto the surface normal. The <span style="color: orange">**magnetization**</span> attribute stores the magnetization vector $(m_x,m_y,m_z)$  in arbitrary units. The <span style="color: orange">**vertices**</span> attribute is a set of the three triangle corners $(P_1, P_2, P_3)$ in arbitrary length units in the local coordinates.
+`Triangle` objects represent triangular surfaces with homogeneous charge density given by the projection of the polarization or magnetization vector onto the surface normal. The attributes <span style="color: orange">**polarization**</span> and <span style="color: orange">**magnetization**</span> are treated similar as by the {ref}`docu-magnet-classes`. The <span style="color: orange">**vertices**</span> attribute is a set of the three triangle corners $(\vec{P}_1, \vec{P}_2, \vec{P}_3)$ in units of meter in the local coordinates.
 :::
 :::{grid-item}
 :columns: 3
@@ -346,7 +356,7 @@ magpy.misc.Triangle(magnetization, vertices, position, orientation, style)
 :::
 :::{grid-item}
 :columns: 12
-**Info:** When multiple Triangles with similar magnetization vectors form a closed surface, and all their orientations (right-hand-rule) point outwards, their total H-field is equivalent to the field of a homogeneous magnet of the same shape. The B-field is only correct on the outside of the body. On the inside the magnetization must be added to the field. This is demonstrated in the tutorial {ref}`gallery-shapes-triangle`.
+**Info:** When multiple Triangles with similar magnetization/polarization vectors form a closed surface, and all their orientations (right-hand-rule) point outwards, their total H-field is equivalent to the field of a homogeneous magnet of the same shape. In this case, the B-field is only correct on the outside of the body. On the inside the polarization must be added to the field. This is demonstrated in the tutorial {ref}`gallery-shapes-triangle`.
 :::
 ::::
 
@@ -354,13 +364,13 @@ magpy.misc.Triangle(magnetization, vertices, position, orientation, style)
 
 ### CustomSource
 ```python
-magpy.misc.CustomSource(field_func, position, orientation, style)
+magpylib.misc.CustomSource(field_func, position, orientation, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`CustomSource` is used to create user defined sources with their own field functions. The argument <span style="color: orange">**field_func**</span> takes a function that is then automatically called for the field computation. This custom field function is treated like a [core function](docu-field-comp-core). It must have the positional arguments `field` with values `"B"` or `"H"`, and `observers` (must accept array with shape (n,3)) and return the B-field and the H-field with a similar shape.
+The `CustomSource` class is used to create user defined sources provided with with custom field computation functions. The argument <span style="color: orange">**field_func**</span> takes a function that is then automatically called for the field computation. This custom field function is treated like a [core function](docu-field-comp-core). It must have the positional arguments `field` with values `"B"` or `"H"`, and `observers` (must accept array with shape (n,3)) and return the B-field and the H-field with a similar shape.
 :::
 :::{grid-item}
 :columns: 3
@@ -378,13 +388,13 @@ magpy.misc.CustomSource(field_func, position, orientation, style)
 
 ## Sensor
 ```python
-magpy.Sensor(position, pixel, orientation, style)
+magpylib.Sensor(position, orientation, pixel, handedness, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-`Sensor` represents a 3D magnetic field sensor and can be used as Magpylib `observers` input. The <span style="color: orange">**pixel**</span> attribute is an array of positions $(P_1, P_2, ...)$ in arbitrary length units in the local sensor coordinates where the field is computed. By default `pixel=(0,0,0)` and the sensor simply returns the field at it's position.
+`Sensor` objects represent observers of the magnetic field and can be used as Magpylib `observers` input for magnetic field computation. The <span style="color: orange">**pixel**</span> attribute is an array of positions $(\vec{P}_1, \vec{P}_2, ...)$ provided in units of meter in the local sensor coordinates. A sensor returns the magnetic field at these pixel positions. By default `pixel=(0,0,0)` and the sensor simply returns the field at it's position. The <span style="color: orange">**handedness**</span> attribute can be `"left"` or `"right"` (default) to set a left- or right-handed sensor coordinate system for the field computation.
 :::
 :::{grid-item}
 :columns: 3
@@ -392,7 +402,7 @@ magpy.Sensor(position, pixel, orientation, style)
 :::
 :::{grid-item}
 :columns: 12
-**Info:** With sensors it is possible to give observers their own position and orientation. The field is always computed in the reference frame of the sensor, which might itself be moving in the global coordinate system. This is demonstrated in {ref}`gallery-tutorial-field-computation-sensors`.
+**Info:** Sensors can have their own position and orientation and enable easy relative positioning between sources and observers. The field is always computed in the reference frame of the sensor, which might itself be moving in the global coordinate system. Magpylib sensors can be understood as perfect magnetic field sensors with infinitesimally sensitive elements. An example how to use sensors is given in {ref}`gallery-tutorial-field-computation-sensors`.
 :::
 ::::
 
@@ -404,13 +414,13 @@ magpy.Sensor(position, pixel, orientation, style)
 
 ## Collection
 ```python
-magpy.Collection(*children, position, orientation, style)
+magpylib.Collection(*children, position, orientation, override_parent, style)
 ```
 
 ::::{grid} 2
 :::{grid-item}
 :columns: 9
-A `Collection` is a group of Magpylib objects that is used for common manipulation. All these objects are stored by reference in the <span style="color: orange">**children**</span> attribute. There are several options for accessing only specific children via the following properties
+A `Collection` is a group of Magpylib objects that is used for common manipulation. All these objects are stored by reference in the <span style="color: orange">**children**</span> attribute. The collection becomes the <span style="color: orange">**parent**</span> of the object. An object can only have one parent. There are several options for accessing only specific children via the following properties
 
 * <span style="color: orange">**sources**</span>: return only sources
 * <span style="color: orange">**observers**</span>: return only observers
@@ -457,9 +467,9 @@ A tutorial {ref}`gallery-tutorial-collection` is provided in the example gallery
 
 :::{grid-item}
 :columns: 7
-The explicit magnetic field expressions, implemented in Magpylib, are generally described in convenient coordinates of the sources. It is a common problem to transform the field into an application relevant lab coordinate system. While not technically difficult, such transformations are prone to error.
+The explicit magnetic field expressions found in the literature, implemented in the [Magpylib core](docu-field-comp-core), are given in convenient source-coordinates. It is a common problem to transform the field into an application relevant observer coordinate system. While not technically difficult, such transformations are prone to error.
 
-Here Magpylib helps out. All Magpylib objects lie in a global Cartesian coordinate system. Object position and orientation are defined by the attributes `position` and `orientation`, 😏. Objects can easily be moved around using the `move()` and `rotate()` methods. Eventually, the field is computed in the reference frame of the observers.
+Here Magpylib helps out. All Magpylib sources and observers lie in a global Cartesian coordinate system. Object position and orientation are defined by the attributes `position` and `orientation`, 😏. Objects can easily be moved around using the `move()` and `rotate()` methods. Eventually, the field is computed in the reference frame of the observers (e.g. Sensor objects). Positions are given in units of meter, and the default unit for orientation is °.
 :::
 :::{grid-item}
 :columns: 5
@@ -473,7 +483,7 @@ Position and orientation of all Magpylib objects are defined by the two attribut
 :::{grid-item-card}
 :shadow: none
 :columns: 5
-<span style="color: orange">**position**</span> - a point $(x,y,z)$ in the global coordinates, or a set of such points $(P_1, P_2, ...)$. By default objects are created with `position=(0,0,0)`.
+<span style="color: orange">**position**</span> - a point $(x,y,z)$ in the global coordinates, or a set of such points $(\vec{P}_1, \vec{P}_2, ...)$. By default objects are created with `position=(0,0,0)`.
 :::
 :::{grid-item-card}
 :shadow: none
@@ -485,7 +495,7 @@ Position and orientation of all Magpylib objects are defined by the two attribut
 The position and orientation attributes can be either **scalar**, i.e. a single position or a single rotation, or **vector**, when they are arrays of such scalars. The two attributes together define the **path** of an object - Magpylib makes sure that they are always of the same length. When the field is computed, it is automatically computed for the whole path.
 
 ```{tip}
-To enable vectorized field computation, paths should always be used when modeling multiple object positions. Avoid using Python loops at all costs for that purpose! If your path is difficult to realize, consider using the [direct interface](docu-direct-interface) instead.
+To enable vectorized field computation, paths should always be used when modeling multiple object positions. Avoid using Python loops at all costs for that purpose! If your path is difficult to realize, consider using the [functional interface](docu-functional-interface) instead.
 ```
 
 Magpylib offers two powerful methods for object manipulation:
@@ -503,13 +513,14 @@ Magpylib offers two powerful methods for object manipulation:
 :::
 ::::
 
-- Scalar input is applied to the whole object path, starting with path index `start`. With the default `start="auto"` the index is set to `start=0` and the functionality is **moving objects around**.
-- Vector input of length $n$ applies the $n$ individual operations to $n$ object path entries, starting with path index `start`. Padding applies when the input exceeds the existing path. With the default `start="auto"` the index is set to `start=len(object path)` and the functionality is **appending paths**.
+- **Scalar input** is applied to the whole object path, starting with path index `start`. With the default `start="auto"` the index is set to `start=0` and the functionality is **moving objects around** (incl. their whole paths).
+- **Vector input** of length $n$ applies the $n$ individual operations to $n$ object path entries, starting with path index `start`. Padding applies when the input exceeds the existing path length. With the default `start="auto"` the index is set to `start=len(object path)` and the functionality is **appending the input**.
 
 The practical application of this formalism is best demonstrated by the following program
 
 ```python
 import magpylib as magpy
+# Note that all units are in SI
 
 sensor = magpy.Sensor()
 print(sensor.position)                                    # default value
@@ -592,40 +603,16 @@ The tutorial {ref}`gallery-tutorial-paths` shows intuitive good practice example
 
 <hr style="border:3px solid gray">
 
-Magnetic field computation in Magpylib is done via two top-level functions
+Magnetic field computation in Magpylib is done via two top-level functions <span style="color: orange">**getB**</span> and <span style="color: orange">**getH**</span>.
 
-::::{grid}
-:gutter: 2
 
-:::{grid-item}
-:columns: 1
-:::
-
-:::{grid-item-card}
-:shadow: none
-:columns: 10
-<span style="color: orange">**getB(**</span>`sources`, `observers`, `squeeze=True`, `pixel_agg=None`, `output="ndarray"`<span style="color: orange">**)**</span>
-:::
-
-:::{grid-item}
-:columns: 1
-:::
-
-:::{grid-item}
-:columns: 1
-:::
-
-:::{grid-item-card}
-:shadow: none
-:columns: 10
-<span style="color: orange">**getH(**</span>`sources`, `observers`, `squeeze=True`, `pixel_agg=None`, `output="ndarray"`<span style="color: orange">**)**</span>
-:::
-
-:::{grid-item}
-:columns: 1
-:::
+```python
+magpylib.getB(sources, observers, squeeze=True, pixel_agg=None, output="ndarray")
+```
 
-::::
+```python
+magpylib.getH(sources, observers, squeeze=True, pixel_agg=None, output="ndarray")
+```
 
 that compute the magnetic field generated by `sources` as seen by the `observers` in their local coordinates. `sources` can be any Magpylib source object (e.g. magnets) or a flat list thereof. `observers` can be an array of position vectors with shape `(n1,n2,n3,...,3)`, any Magpylib observer object (e.g. sensors), or a flat list thereof. The following code shows a minimal example for Magplyib field computation.
 
@@ -640,21 +627,26 @@ that compute the magnetic field generated by `sources` as seen by the `observers
 :columns: 8
 ```python
 import magpylib as magpy
+# All inputs and outputs in SI units
 
 # define source and observer objects
-loop = magpy.current.Circle(current=1, diameter=1)
+loop = magpy.current.Circle(current=1, diameter=.001)
 sens = magpy.Sensor()
 
 # compute field
 B = magpy.getB(loop, sens)
 
 print(B)
-#  --> [0.     0.     1.2566]
+#  --> [0.         0.         0.00125664]
 ```
 :::
 ::::
 
-The physical unit returned by `getB` and `getH` corresponds to the source excitation input units. For example, when magnet `magnetization` is given in mT, `getB` returns the B-field in units of mT and `getH` the H-field in units of kA/m. This is described in detail in {ref}`docu-units`.
+By default, `getB` returns the B-field in units of T, `getH` the H-field in units of A/m.
+
+```{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=4\pi\cdot 10^{-7}$.
+```
 
 The output of a field computation `magpy.getB(sources, observers)` is by default a Numpy array of shape `(l, m, k, n1, n2, n3, ..., 3)` where `l` is the number of input sources, `m` the (maximal) object path length, `k` the number of observers, `n1,n2,n3,...` the sensor pixel shape or the shape of the observer position array input and `3` the three magnetic field components $(B_x, B_y, B_z)$.
 
@@ -674,7 +666,7 @@ Try to make all field computations with as few calls to `getB` and `getH` as pos
 The tutorial {ref}`gallery-tutorial-field-computation` shows good practices with Magpylib field computation.
 
 
-(docu-direct-interface)=
+(docu-functional-interface)=
 ## Direct interface
 
 Users can bypass the object oriented functionality of Magpylib and instead compute the field for n given parameter sets. This is done by providing the following inputs to the top level functions `getB` and `getH`,
@@ -683,7 +675,7 @@ Users can bypass the object oriented functionality of Magpylib and instead compu
 2. `observers`: array-like of shape (3,) or (n,3) giving the observer positions.
 3. `kwargs`: a dictionary with inputs of shape (x,) or (n,x). Must include all mandatory class-specific inputs. By default, `position=(0,0,0)` and `orientation=None`(=unit rotation).
 
-All "scalar" inputs of shape (x,) are automatically tiled up to shape (n,x) to create a set of n computation instances. The field is returned in the shape (n,3). The following code demonstrates the direct interface.
+All "scalar" inputs of shape (x,) are automatically tiled up to shape (n,x) to create a set of n computation instances. The field is returned in the shape (n,3). The following code demonstrates the functional interface.
 
 ::::{grid}
 :gutter: 5
@@ -695,33 +687,37 @@ All "scalar" inputs of shape (x,) are automatically tiled up to shape (n,x) to c
 :::{grid-item}
 :columns: 8
 ```python
+import numpy as np
 import magpylib as magpy
+# All inputs and outputs in SI units
+# This example shows the scale invariance
 
 # compute the cuboid field for 3 input instances
+N = 3 # number of instances
 B = magpy.getB(
     sources='Cuboid',
-    observers=[(0,0,x) for x in range(3)],
-    dimension=[(d,d,d) for d in range(1,4)],
-    magnetization=(0,0,1000),
+    observers=np.linspace((0,0,1), (0,0,3), N),
+    dimension=np.linspace((1,1,1), (3,3,3),3, N),
+    polarization=(0,0,1),
 )
 
-print(B.round())
-#  --> [[  0.   0. 667.]
-#       [  0.   0. 436.]
-#       [  0.   0. 307.]]
+print(B)
+#  --> [[0.         0.         0.13478239]
+#       [0.         0.         0.13478239]
+#       [0.         0.         0.13478239]]
 ```
 :::
 ::::
 
 ```{note}
-The direct interface is potentially faster than the object oriented one if users know how to generate the input arrays efficiently with numpy (e.g. `np.arange`, `np.linspace`, `np.tile`, `np.repeat`, ...).
+The functional interface is potentially faster than the object oriented one if users know how to generate the input arrays efficiently with numpy (e.g. `np.arange`, `np.linspace`, `np.tile`, `np.repeat`, ...).
 ```
 
 
 (docu-field-comp-core)=
 ## Core interface
 
-At the heart of Magpylib lies a set of core functions that are our implementations of the explicit field expressions, see {ref}`docu-physics`, described in convenient local source coordinates. Direct access to these functions is given through the `magpylib.core` subpackage which includes,
+At the heart of Magpylib lies a set of core functions that are our implementations of explicit field expressions found in the literature, see {ref}`docu-physics`. Direct access to these functions is given through the `magpylib.core` subpackage which includes,
 
 ::::{grid} 1
 :gutter: 1
@@ -733,29 +729,29 @@ At the heart of Magpylib lies a set of core functions that are our implementatio
 <span style="color: orange">**current_circle_field(**</span> `field`, `observers`, `current`, `diameter`<span style="color: orange">**)**</span>
 :::
 :::{grid-item}
-<span style="color: orange">**magnet_cuboid_field(**</span> `field`, `observers`, `magnetization`, `dimension`<span style="color: orange">**)**</span>
+<span style="color: orange">**magnet_cuboid_field(**</span> `field`, `observers`, `polarization`, `dimension`<span style="color: orange">**)**</span>
 :::
 :::{grid-item}
-<span style="color: orange">**magnet_cylinder_field(**</span> `field`, `observers`, `magnetization`, `dimension`<span style="color: orange">**)**</span>
+<span style="color: orange">**magnet_cylinder_field(**</span> `field`, `observers`, `polarization`, `dimension`<span style="color: orange">**)**</span>
 :::
 :::{grid-item}
-<span style="color: orange">**magnet_cylinder_segment_field(**</span> `field`, `observers`, `magnetization`, `dimension`<span style="color: orange">**)**</span>
+<span style="color: orange">**magnet_cylinder_segment_field(**</span> `field`, `observers`, `polarization`, `dimension`<span style="color: orange">**)**</span>
 :::
 :::{grid-item}
-<span style="color: orange">**magnet_sphere_field(**</span> `field`, `observers`, `magnetization`, `diameter`<span style="color: orange">**)**</span>
+<span style="color: orange">**magnet_sphere_field(**</span> `field`, `observers`, `polarization`, `diameter`<span style="color: orange">**)**</span>
 :::
 :::{grid-item}
-<span style="color: orange">**magnet_tetrahedron_field(**</span> `field`, `observers`, `magnetization`, `vertices`<span style="color: orange">**)**</span>
+<span style="color: orange">**magnet_tetrahedron_field(**</span> `field`, `observers`, `polarization`, `vertices`<span style="color: orange">**)**</span>
 :::
 :::{grid-item}
 <span style="color: orange">**dipole_field(**</span> `field`, `observers`, `moment`<span style="color: orange">**)**</span>
 :::
 :::{grid-item}
-<span style="color: orange">**triangle_field(**</span> `field`, `observers`, `magnetization`, `vertices`<span style="color: orange">**)**</span>
+<span style="color: orange">**triangle_field(**</span> `field`, `observers`, `polarization`, `vertices`<span style="color: orange">**)**</span>
 :::
 ::::
 
-The input `field` is either `"B"` or `"H`. All other inputs must be Numpy ndarrays of shape (n,x). Their meaning is similar as above. Details can be found in the respective function docstrings. The following example demonstrates the core interface.
+The input `field` is either `"B"` or `"H`. All other inputs must be Numpy ndarrays of shape (n,x). Details can be found in the respective function docstrings. The following example demonstrates the core interface.
 
 ::::{grid}
 :gutter: 5
@@ -769,19 +765,20 @@ The input `field` is either `"B"` or `"H`. All other inputs must be Numpy ndarra
 ```python
 import numpy as np
 import magpylib as magpy
+# All inputs and outputs in SI units
 
 # prepare input
-mag = np.array([(1000,0,0)]*3)
+pol = np.array([(1,0,0)]*3)
 dim = np.array([(1,2)]*3)
 obs = np.array([(0,0,0)]*3)
 
 # compute field with core functions
-B = magpy.core.magnet_cylinder_field('B', obs, mag, dim)
+B = magpy.core.magnet_cylinder_field(field='B', observers=obs, polarization=pol, dimension=dim)
 
-print(B.round())
-#  --> [[553.   0.   0.]
-#       [553.   0.   0.]
-#       [553.   0.   0.]]
+print(B)
+#  --> [[0.5527864 0.        0.       ]
+#       [0.5527864 0.        0.       ]
+#       [0.5527864 0.        0.       ]]
 ```
 :::
 ::::
diff --git a/docs/_pages/docu/docu_physics.md b/docs/_pages/docu/docu_physics.md
index 19fd12f1a..a7908fede 100644
--- a/docs/_pages/docu/docu_physics.md
+++ b/docs/_pages/docu/docu_physics.md
@@ -90,7 +90,7 @@ Magpylib code is fully [vectorized](https://en.wikipedia.org/wiki/Array_programm
 Maximal performance is achieved when `.getB(sources, observers)` is called only a single time in your program. Try not to use loops.
 ```
 
-The object oriented interface comes with an overhead. If you want to achieve maximal performance this overhead can be avoided with {ref}`docu-direct-interface`.
+The object oriented interface comes with an overhead. If you want to achieve maximal performance this overhead can be avoided with {ref}`docu-functional-interface`.
 
 The analytical solutions provide extreme performance. Single field evaluations take of the order of `100 µs`. For large input arrays (e.g. many observer positions or many similar magnets) the computation time drops below `1 µs` per evaluation point on single state-of-the-art x86 mobile cores (tested on `Intel Core i5-8365U @ 1.60GHz`), depending on the source type.
 
diff --git a/docs/_pages/gallery/gallery_app_end_of_shaft.md b/docs/_pages/gallery/gallery_app_end_of_shaft.md
index 68d119831..3b486dcb8 100644
--- a/docs/_pages/gallery/gallery_app_end_of_shaft.md
+++ b/docs/_pages/gallery/gallery_app_end_of_shaft.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
-  display_name: Python 3 (ipykernel)
+  display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-app-end-of-shaft)=
@@ -28,40 +28,40 @@ import plotly.graph_objects as go
 
 # create magnet
 magnet = magpy.magnet.Cylinder(
-    magnetization=(1000, 0, 0),
-    dimension=(6, 2),
-    position=(0, 0, 1.5),
+    polarization=(1, 0, 0),
+    dimension=(.06, .02),
+    position=(0, 0, .015),
     style_label="Magnet",
     style_color=".7",
 )
 
 # create shaft dummy with 3D model
 shaft = magpy.misc.CustomSource(
-    position=(0, 0, 7),
+    position=(0, 0, .07),
     style_color=".7",
     style_model3d_showdefault=False,
     style_label="Shaft",
 )
 shaft_trace = magpy.graphics.model3d.make_Prism(
     base=20,
-    diameter=10,
-    height=10,
+    diameter=.1,
+    height=.1,
     opacity=0.3,
 )
 shaft.style.model3d.add_trace(shaft_trace)
 
 # shaft rotation / magnet wobble motion
-displacement = 1
+displacement = .01
 angles = np.linspace(0, 360, 72)
 coll = magnet + shaft
 magnet.move((displacement, 0, 0))
 coll.rotate_from_angax(angles, "z", anchor=0, start=0)
 
 # create sensor
-gap = 3
+gap = .03
 sens = magpy.Sensor(
     position=(0, 0, -gap),
-    pixel=[(1, 0, 0), (-1, 0, 0)],
+    pixel=[(.01, 0, 0), (-.01, 0, 0)],
     style_pixel_size=0.5,
     style_size=1.5,
 )
@@ -82,7 +82,11 @@ fig2 = px.line(
     x="angle (deg)",
     y=["Bx", "By"],
     line_dash="pixel",
-    labels={"value": "Field (mT)"},
+    labels={"value": "Field (T)"},
 )
 fig2.show()
 ```
+
+```{code-cell} ipython3
+
+```
diff --git a/docs/_pages/gallery/gallery_magnet_model.md b/docs/_pages/gallery/gallery_magnet_model.md
new file mode 100644
index 000000000..df2399adb
--- /dev/null
+++ b/docs/_pages/gallery/gallery_magnet_model.md
@@ -0,0 +1,17 @@
+---
+jupytext:
+  text_representation:
+    extension: .md
+    format_name: myst
+    format_version: 0.13
+    jupytext_version: 1.16.0
+kernelspec:
+  display_name: Python 3
+  language: python
+  name: python3
+orphan: true
+---
+
+(gallery-tutorial-magnetmodel)=
+
+# Modelling a permanent Magnet
\ No newline at end of file
diff --git a/docs/_pages/gallery/gallery_misc_compound.md b/docs/_pages/gallery/gallery_misc_compound.md
index 5880c0393..29753c789 100644
--- a/docs/_pages/gallery/gallery_misc_compound.md
+++ b/docs/_pages/gallery/gallery_misc_compound.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-misc-compound)=
@@ -51,7 +51,7 @@ class MagnetRing(magpy.Collection):
     def _update(self, cubes):
         """Update MagnetRing instance"""
         self._cubes = cubes
-        ring_radius = cubes/3
+        ring_radius = cubes/300
 
         # Store existing path
         pos_temp = self.position
@@ -65,8 +65,8 @@ class MagnetRing(magpy.Collection):
         # Add children
         for i in range(cubes):
             child = magpy.magnet.Cuboid(
-                magnetization=(0,0,1000),
-                dimension=(1,1,1),
+                polarization=(0,0,1),
+                dimension=(.01,.01,.01),
                 position=(ring_radius,0,0)
             )
             child.rotate_from_angax(360/cubes*i, 'z', anchor=0)
@@ -78,7 +78,7 @@ class MagnetRing(magpy.Collection):
 
         # Add parameter-dependent 3d trace
         trace = magpy.graphics.model3d.make_CylinderSegment(
-            dimension=(cubes/3-.6, cubes/3+0.6, 1.1, 0, 360),
+            dimension=(ring_radius-.006, ring_radius+.006, 0.011, 0, 360),
             vert=150,
             opacity=0.2,
         )
@@ -109,12 +109,11 @@ magpy.show(ring, sensor, backend='plotly')
 The `MagnetRing` parameter `cubes` can be modified dynamically:
 
 ```{code-cell} ipython3
-
-print(f"B-field at sensor for modified ring → {ring.getB(sensor).round(2)}")
+print(f"B-field at sensor for modified ring → {ring.getB(sensor).round(3)}")
 
 ring.cubes = 10
 
-print(f"B-field at sensor for modified ring → {ring.getB(sensor).round(2)}")
+print(f"B-field at sensor for modified ring → {ring.getB(sensor).round(3)}")
 
 magpy.show(ring, sensor, backend='plotly')
 ```
@@ -155,7 +154,7 @@ class MagnetRingAdv(magpy.Collection):
     def _update(self, cubes):
         """Update MagnetRing instance"""
         self._cubes = cubes
-        ring_radius = cubes/3
+        ring_radius = cubes/300
 
         # Store existing path and reset
         pos_temp = self.position
@@ -165,8 +164,8 @@ class MagnetRingAdv(magpy.Collection):
         # Add children
         for i in range(cubes):
             child = magpy.magnet.Cuboid(
-                magnetization=(0,0,1000),
-                dimension=(1,1,1),
+                polarization=(0,0,1),
+                dimension=(.01,.01,.01),
                 position=(ring_radius,0,0)
             )
             child.rotate_from_angax(360/cubes*i, 'z', anchor=0)
@@ -181,7 +180,7 @@ class MagnetRingAdv(magpy.Collection):
     def _custom_trace3d(self):
         """ creates a parameter-dependent 3d model"""
         trace = magpy.graphics.model3d.make_CylinderSegment(
-            dimension=(self.cubes/3-.6, self.cubes/3+0.6, 1.1, 0, 360),
+            dimension=(self.cubes/300-.006, self.cubes/300+0.006, 0.011, 0, 360),
             vert=150,
             opacity=0.2,
         )
@@ -192,10 +191,10 @@ We have removed the trace construction from the `_update` method, and instead pr
 
 ```{code-cell} ipython3
 ring0 = MagnetRing()
-%time for _ in range(100): ring0.cubes=10
+%time for _ in range(10): ring0.cubes=10
 
 ring1 = MagnetRingAdv()
-%time for _ in range(100): ring1.cubes=10
+%time for _ in range(10): ring1.cubes=10
 ```
 
 This example is not very impressive because the provided trace is not very heavy.
diff --git a/docs/_pages/gallery/gallery_misc_field_interpolation.md b/docs/_pages/gallery/gallery_misc_field_interpolation.md
index 532fc52d9..bc486bfb5 100644
--- a/docs/_pages/gallery/gallery_misc_field_interpolation.md
+++ b/docs/_pages/gallery/gallery_misc_field_interpolation.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.6
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-misc-field-interpolation)=
@@ -88,8 +88,8 @@ In the second step we create a custom source with an interpolated field `field_f
 
 ```{code-cell} ipython3
 # Create data for interpolation
-cube = magpy.magnet.Cuboid(magnetization=(0,0,1000), dimension=(2,2,2))
-ts = np.linspace(-7, 7, 21)
+cube = magpy.magnet.Cuboid(polarization=(0,0,1), dimension=(.02,.02,.02))
+ts = np.linspace(-.07, .07, 21)
 grid = np.array([(x,y,z) for x in ts for y in ts for z in ts])
 data = cube.getB(grid)
 
@@ -100,9 +100,9 @@ custom = magpy.misc.CustomSource(
 )
 
 # Add nice 3D model (dashed outline) to custom source
-xs = 1.1*np.array([-1, -1,  1,  1, -1, -1, -1, -1, -1,  1,  1,  1,  1, 1,  1, -1])
-ys = 1.1*np.array([-1,  1,  1, -1, -1, -1,  1,  1,  1,  1,  1,  1, -1, -1, -1, -1])
-zs = 1.1*np.array([-1, -1, -1, -1, -1,  1,  1, -1,  1,  1, -1,  1,  1, -1,  1,  1])
+xs = 0.011*np.array([-1, -1,  1,  1, -1, -1, -1, -1, -1,  1,  1,  1,  1, 1,  1, -1])
+ys = 0.011*np.array([-1,  1,  1, -1, -1, -1,  1,  1,  1,  1,  1,  1, -1, -1, -1, -1])
+zs = 0.011*np.array([-1, -1, -1, -1, -1,  1,  1, -1,  1,  1, -1,  1,  1, -1,  1,  1])
 trace = dict(
     backend='matplotlib',
     constructor='plot',
@@ -128,7 +128,7 @@ for src in [cube, custom]:
     src.rotate_from_angax(angle=45, axis=(1,1,1))
 
 # Add a sensor for testing
-sensor = magpy.Sensor(position=(-5,0,0))
+sensor = magpy.Sensor(position=(-.05,0,0))
 angs = np.linspace(3,150,49)
 sensor.rotate_from_angax(angle=angs, axis="y", anchor=0)
 
@@ -151,8 +151,12 @@ ax.grid(color=".9")
 ax.set(
     title="Field at sensor - real (solid), interpolated (dashed)",
     xlabel="sensor rotation angle (deg)",
-    ylabel="(mT)",
+    ylabel="(T)",
 )
 
 plt.show()
-```
\ No newline at end of file
+```
+
+```{code-cell} ipython3
+
+```
diff --git a/docs/_pages/gallery/gallery_shapes_convex_hull.md b/docs/_pages/gallery/gallery_shapes_convex_hull.md
index 850e7d8f5..e125fc3b5 100644
--- a/docs/_pages/gallery/gallery_shapes_convex_hull.md
+++ b/docs/_pages/gallery/gallery_shapes_convex_hull.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-shapes-convex-hull)=
@@ -25,16 +25,22 @@ Magpylib offers construction of convex hull magnets by combining the `magpylib.m
 This is the fastest way to construct a pyramid magnet.
 
 ```{code-cell} ipython3
+import numpy as np
+
 import magpylib as magpy
 
 # Create pyramid magnet
-points = [(-2,-2,0), (-2,2,0), (2,-2,0), (2,2,0), (0,0,3)]
+points = np.array([(-2, -2, 0), (-2, 2, 0), (2, -2, 0), (2, 2, 0), (0, 0, 3)]) / 100
 tmesh_pyramid = magpy.magnet.TriangularMesh.from_ConvexHull(
-    magnetization=(0, 0, 1000),
+    polarization=(0, 0, 1),
     points=points,
     style_label="Pyramid Magnet",
 )
 
 # Display graphically
 tmesh_pyramid.show(backend="plotly")
-```
\ No newline at end of file
+```
+
+```{code-cell} ipython3
+
+```
diff --git a/docs/_pages/gallery/gallery_shapes_pyvista.md b/docs/_pages/gallery/gallery_shapes_pyvista.md
index 31429409a..5c6657095 100644
--- a/docs/_pages/gallery/gallery_shapes_pyvista.md
+++ b/docs/_pages/gallery/gallery_shapes_pyvista.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-shapes-pyvista)=
@@ -32,21 +32,20 @@ import pyvista as pv
 import magpylib as magpy
 
 # Create a simple pyvista PolyData object
-dodec_mesh = pv.Dodecahedron()
+dodec_mesh = pv.Dodecahedron(radius=.01)
 
 dodec = magpy.magnet.TriangularMesh.from_pyvista(
-    magnetization=(0, 0, 100),
+    polarization=(0, 0, .1),
     polydata=dodec_mesh,
 )
 
 # Add a sensor with path
-sens = magpy.Sensor(position=np.linspace((-2,0,1), (2,0,1), 100))
+sens = magpy.Sensor(position=np.linspace((-2,0,1), (2,0,1), 100)/100)
 
 # Show system and field
 with magpy.show_context(dodec, sens, backend='plotly') as s:
     s.show(col=1)
     s.show(col=2, output=['Bx', 'Bz'])
-
 ```
 
 ## Boolean operations with Pyvista
@@ -58,13 +57,13 @@ import pyvista as pv
 import magpylib as magpy
 
 # Create a complex pyvista PolyData object using a boolean operation
-sphere = pv.Sphere(radius=0.6)
-cube = pv.Cube().triangulate()
+sphere = pv.Sphere(radius=0.006)
+cube = pv.Cube(x_length=.01, y_length=.01, z_length=.01).triangulate()
 obj = cube.boolean_difference(sphere)
 
 # Construct magnet from PolyData object and ignore check results
 magnet = magpy.magnet.TriangularMesh.from_pyvista(
-    magnetization=(0, 0, 100),
+    polarization=(0, 0, .1),
     polydata=obj,
     check_disconnected="ignore",
     check_open="ignore",
@@ -101,10 +100,11 @@ sphere = pv.Sphere(radius=0.6)
 cube = pv.Cube().triangulate().subdivide(2)
 obj = cube.boolean_difference(sphere)
 obj = obj.clean()
+obj = obj.scale([1e-2]*3)
 
 # Construct magnet from PolyData object
 magnet = magpy.magnet.TriangularMesh.from_pyvista(
-    magnetization=(0, 0, 100),
+    polarization=(0, 0, .1),
     polydata=obj,
     style_label="magnet",
 )
@@ -116,3 +116,11 @@ print(f'mesh status reoriented: {magnet.status_reoriented}')
 
 magnet.show(backend="plotly")
 ```
+
+```{code-cell} ipython3
+
+```
+
+```{code-cell} ipython3
+
+```
diff --git a/docs/_pages/gallery/gallery_shapes_superpos.md b/docs/_pages/gallery/gallery_shapes_superpos.md
index c6e3e3a5b..1878b777f 100644
--- a/docs/_pages/gallery/gallery_shapes_superpos.md
+++ b/docs/_pages/gallery/gallery_shapes_superpos.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-shapes-superpos)=
@@ -42,21 +42,23 @@ Geometric union by superposition is demonstrated in the following example where
 
 ```{code-cell} ipython3
 import numpy as np
+
 import magpylib as magpy
 
-# Create three magnet parts with similar magnetization
+# Create three magnet parts with similar polarization
 pt1 = magpy.magnet.CylinderSegment(
-    magnetization=(500,0,0),
-    dimension=(0,4,2,90,270),
+    polarization=(0.5, 0, 0),
+    dimension=(0, 0.04, 0.02, 90, 270),
 )
 pt2 = magpy.magnet.Cuboid(
-    magnetization=(500,0,0),
-    dimension=(2,8,2),
-    position=(1,0,0)
+    polarization=(0.5, 0, 0), dimension=(0.02, 0.08, 0.02), position=(0.01, 0, 0)
 )
 pt3 = magpy.magnet.TriangularMesh.from_ConvexHull(
-    magnetization=(500,0,0),
-    points=[(2,4,-1),(2,4,1),(2,-4,-1),(2,-4,1),(6,0,1),(6,0,-1)]
+    polarization=(0.5, 0, 0),
+    points=np.array(
+        [(2, 4, -1), (2, 4, 1), (2, -4, -1), (2, -4, 1), (6, 0, 1), (6, 0, -1)]
+    )
+    / 100,
 )
 
 # Combine parts in a Collection
@@ -64,15 +66,14 @@ magnet = magpy.Collection(pt1, pt2, pt3)
 
 # Add a sensor with path
 sensor = magpy.Sensor()
-sensor.position = np.linspace((7,-10,0), (7,10,0), 100)
+sensor.position = np.linspace((7, -10, 0), (7, 10, 0), 100) / 100
 
 # Plot
-with magpy.show_context(magnet, sensor, backend='plotly', style_legend_show=False) as s:
+with magpy.show_context(magnet, sensor, backend="plotly", style_legend_show=False) as s:
     s.show(col=1)
-    s.show(output='B', col=2)
+    s.show(output="B", col=2)
 ```
 
-
 ## Cut-out operation
 
 When two objects with opposing magnetization vectors of similar amplitude overlap, they will just cancel in the overlap region. This enables geometric cut-out operations. In the following example we construct an exact hollow cylinder solution from two concentric cylinder shapes with opposite magnetizations, and compare the result to the `CylinderSegment` class solution.
@@ -81,16 +82,16 @@ When two objects with opposing magnetization vectors of similar amplitude overla
 from magpylib.magnet import Cylinder, CylinderSegment
 
 # Create ring with CylinderSegment
-ring0 = CylinderSegment(magnetization=(0,0,100), dimension=(2,3,1,0,360))
+ring0 = CylinderSegment(polarization=(0, 0, .1), dimension=(.02, .03, .01, 0, 360))
 
 # Create ring with cut-out
-inner = Cylinder(magnetization=(0,0,-100), dimension=(4,1))
-outer = Cylinder(magnetization=(0,0, 100), dimension=(6,1))
+inner = Cylinder(polarization=(0, 0, -.1), dimension=(.04, .01))
+outer = Cylinder(polarization=(0, 0, .1), dimension=(.06, .01))
 ring1 = inner + outer
 
 # Print results
-print('CylinderSegment result:', ring0.getB((1,2,3)))
-print('Cut-out result:        ', ring1.getB((1,2,3)))
+print("CylinderSegment result:", ring0.getB((.01, .02, .03)))
+print("        Cut-out result:", ring1.getB((.01, .02, .03)))
 ```
 
 Note that, it is faster to compute the `Cylinder` field two times than computing the `CylinderSegment` field one time. This is why Magpylib automatically falls back to the `Cylinder` solution whenever `CylinderSegment` is called with 360 deg section angles. Unfortunately, cut-out operations cannot be displayed graphically at the moment, but {ref}`examples-own-3d-models` offer a solution here.
diff --git a/docs/_pages/gallery/gallery_shapes_triangle.md b/docs/_pages/gallery/gallery_shapes_triangle.md
index 5c1ba4bd2..3641e1d53 100644
--- a/docs/_pages/gallery/gallery_shapes_triangle.md
+++ b/docs/_pages/gallery/gallery_shapes_triangle.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.15.2
 kernelspec:
-  display_name: Python 3
+  display_name: Python 3 (ipykernel)
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-shapes-triangle)=
@@ -31,35 +31,37 @@ In this example `Triangle` is used to create a magnet with cuboctahedral shape.
 
 ```{code-cell} ipython3
 import magpylib as magpy
+import numpy as np
 
 # Create collection of triangles
-triangles = [
-    ([ 0, 1,-1], [-1, 1, 0], [ 1, 1, 0]),
-    ([ 0, 1, 1], [ 1, 1, 0], [-1, 1, 0]),
-    ([ 0, 1, 1], [-1, 0, 1], [ 0,-1, 1]),
-    ([ 0, 1, 1], [ 0,-1, 1], [ 1, 0, 1]),
-    ([ 0, 1,-1], [ 1, 0,-1], [ 0,-1,-1]),
-    ([ 0, 1,-1], [ 0,-1,-1], [-1, 0,-1]),
-    ([ 0,-1, 1], [-1,-1, 0], [ 1,-1, 0]),
-    ([ 0,-1,-1], [ 1,-1, 0], [-1,-1, 0]),
-    ([-1, 1, 0], [-1, 0,-1], [-1, 0, 1]),
-    ([-1,-1, 0], [-1, 0, 1], [-1, 0,-1]),
-    ([ 1, 1, 0], [ 1, 0, 1], [ 1, 0,-1]),
-    ([ 1,-1, 0], [ 1, 0,-1], [ 1, 0, 1]),
-    ([ 0, 1, 1], [-1, 1, 0], [-1, 0, 1]),
-    ([ 0, 1, 1], [ 1, 0, 1], [ 1, 1, 0]),
-    ([ 0, 1,-1], [-1, 0,-1], [-1, 1, 0]),
-    ([ 0, 1,-1], [ 1, 1, 0], [ 1, 0,-1]),
-    ([ 0,-1,-1], [-1,-1, 0], [-1, 0,-1]),
-    ([ 0,-1,-1], [ 1, 0,-1], [ 1,-1, 0]),
-    ([ 0,-1, 1], [-1, 0, 1], [-1,-1, 0]),
-    ([ 0,-1, 1], [ 1,-1, 0], [ 1, 0, 1]),
+triangles_cm = [
+    ([0, 1, -1], [-1, 1, 0], [1, 1, 0]),
+    ([0, 1, 1], [1, 1, 0], [-1, 1, 0]),
+    ([0, 1, 1], [-1, 0, 1], [0, -1, 1]),
+    ([0, 1, 1], [0, -1, 1], [1, 0, 1]),
+    ([0, 1, -1], [1, 0, -1], [0, -1, -1]),
+    ([0, 1, -1], [0, -1, -1], [-1, 0, -1]),
+    ([0, -1, 1], [-1, -1, 0], [1, -1, 0]),
+    ([0, -1, -1], [1, -1, 0], [-1, -1, 0]),
+    ([-1, 1, 0], [-1, 0, -1], [-1, 0, 1]),
+    ([-1, -1, 0], [-1, 0, 1], [-1, 0, -1]),
+    ([1, 1, 0], [1, 0, 1], [1, 0, -1]),
+    ([1, -1, 0], [1, 0, -1], [1, 0, 1]),
+    ([0, 1, 1], [-1, 1, 0], [-1, 0, 1]),
+    ([0, 1, 1], [1, 0, 1], [1, 1, 0]),
+    ([0, 1, -1], [-1, 0, -1], [-1, 1, 0]),
+    ([0, 1, -1], [1, 1, 0], [1, 0, -1]),
+    ([0, -1, -1], [-1, -1, 0], [-1, 0, -1]),
+    ([0, -1, -1], [1, 0, -1], [1, -1, 0]),
+    ([0, -1, 1], [-1, 0, 1], [-1, -1, 0]),
+    ([0, -1, 1], [1, -1, 0], [1, 0, 1]),
 ]
+triangles = np.array(triangles_cm) / 100  # cm -> m
 cuboc = magpy.Collection()
 for t in triangles:
     cuboc.add(
         magpy.misc.Triangle(
-            magnetization=(100, 200, 300),
+            polarization=(0.1, 0.2, 0.3),
             vertices=t,
         )
     )
@@ -67,10 +69,9 @@ for t in triangles:
 # Display collection of triangles
 magpy.show(
     cuboc,
-    backend='pyvista',
-    style_magnetization_mode='arrow',
-    style_orientation_color='yellow',
-    jupyter_backend="panel", # better pyvista rendering in a jupyter notebook
+    backend="pyvista",
+    style_magnetization_mode="arrow",
+    style_orientation_color="yellow",
 )
 ```
 
@@ -85,24 +86,19 @@ import magpylib as magpy
 
 # Create prism magnet as triangle collection
 top = magpy.misc.Triangle(
-    magnetization=(0,0,1000),
-    vertices=((-1,-1,1), (1,-1,1), (0,2,1)),
-    style_label="top"
+    polarization=(0, 0, 1),
+    vertices=((-0.01, -0.01, 0.01), (0.01, -0.01, 0.01), (0, 0.02, 0.01)),
+    style_label="top",
 )
 bott = magpy.misc.Triangle(
-    magnetization=(0,0,1000),
-    vertices=((-1,-1,-1), (0,2,-1), (1,-1,-1)),
-    style_label="bottom"
+    polarization=(0, 0, 1),
+    vertices=((-0.01, -0.01, -0.01), (0, 0.02, -0.01), (0.01, -0.01, -0.01)),
+    style_label="bottom",
 )
 prism = magpy.Collection(top, bott)
 
 # Display graphically
-magpy.show(
-    *prism,
-    backend='plotly',
-    style_opacity=0.5,
-    style_magnetization_show=False
-)
+magpy.show(*prism, backend="plotly", style_opacity=0.5, style_magnetization_show=False)
 ```
 
 ## TriangularMesh class
@@ -117,33 +113,28 @@ In this example we revisit the cubeoctahedron, but generate it through the `Tria
 
 ```{code-cell} ipython3
 import magpylib as magpy
+import numpy as np
 
-# Create cubeoctahedron magnet 
-vertices = [
-    ( 0, 1,-1), (-1, 1, 0), ( 1, 1, 0),
-    ( 0, 1, 1), (-1, 0, 1), ( 0,-1, 1),
-    ( 1, 0, 1), ( 1, 0,-1), ( 0,-1,-1),
-    (-1, 0,-1), (-1,-1, 0), ( 1,-1, 0),
+# Create cubeoctahedron magnet (vertices and faces are transposed here for more compact display)
+vertices_cm = [
+    [0, -1, 1, 0, -1, 0, 1, 1, 0, -1, -1, 1],
+    [1, 1, 1, 1, 0, -1, 0, 0, -1, 0, -1, -1],
+    [-1, 0, 0, 1, 1, 1, 1, -1, -1, -1, 0, 0],
 ]
+vertices = np.array(vertices_cm).T / 100  # cm -> m
 faces = [
-    (0,1,2),   (3,2,1),   (3,4,5),   (3,5,6),
-    (0,7,8),   (0,8,9), (5,10,11), (8,11,10),
-    (1,9,4),  (10,4,9),   (2,6,7),  (11,7,6),
-    (3,1,4),   (3,6,2),   (0,9,1),   (0,2,7),
-    (8,10,9), (8,7,11),  (5,4,10),  (5,11,6),
+    [0, 3, 3, 3, 0, 0, 5, 8, 1, 10, 2, 11, 3, 3, 0, 0, 8, 8, 5, 5],
+    [1, 2, 4, 5, 7, 8, 10, 11, 9, 4, 6, 7, 1, 6, 9, 2, 10, 7, 4, 11],
+    [2, 1, 5, 6, 8, 9, 11, 10, 4, 9, 7, 6, 4, 2, 1, 7, 9, 11, 10, 6],
 ]
+faces = np.array(faces).T
 cuboc = magpy.magnet.TriangularMesh(
-    magnetization=(100, 200, 300),
-    vertices=vertices,
-    faces=faces
+    polarization=(0.1, 0.2, 0.3), vertices=vertices, faces=faces
 )
 
 # Display TriangularMesh body
 magpy.show(
-    cuboc,
-    backend='plotly',
-    style_mesh_grid_show=True,
-    style_mesh_grid_line_width=4
+    cuboc, backend="plotly", style_mesh_grid_show=True, style_mesh_grid_line_width=4
 )
 ```
 
@@ -169,23 +160,23 @@ import numpy as np
 
 # Create top and bottom faces of a prism magnet
 top = magpy.misc.Triangle(
-    magnetization=(1000,0,0),
-    vertices= ((-1,-1,1), (1,-1,1), (0,2,1)),
+    polarization=(1, 0, 0),
+    vertices=((-0.01, -0.01, 0.01), (0.01, -0.01, 0.01), (0, 0.02, 0.01)),
 )
 bottom = magpy.misc.Triangle(
-    magnetization=(1000,0,0),
-    vertices= ((-1,-1,-1), (0,2,-1), (1,-1,-1)),
+    polarization=(1, 0, 0),
+    vertices=((-0.01, -0.01, -0.01), (0, 0.02, -0.01), (0.01, -0.01, -0.01)),
 )
 
 # Create prism with open edges
 prism = magpy.magnet.TriangularMesh.from_triangles(
-    magnetization=(0, 0, 1000),   # overrides triangles magnetization
+    polarization=(0, 0, 1),  # overrides triangles magnetization
     triangles=[top, bottom],
-    check_open="ignore",          # check but ignore open mesh
+    check_open="ignore",  # check but ignore open mesh
     check_disconnected="ignore",  # check but ignore disconnected mesh
-    reorient_faces="ignore",      # check but ignore non-orientable mesh
+    reorient_faces="ignore",  # check but ignore non-orientable mesh
 )
-prism.style.label = "Open Prism",
+prism.style.label = "Open Prism"
 prism.style.magnetization.mode = "arrow"
 
 print("mesh status open:", prism.status_open)
@@ -202,4 +193,4 @@ prism.show(
 
 ```{caution}
 Keep in mind that the inside-outside check will fail, so that `getB` may yield wrong results on the inside of the prism where the polarization vector should be added.
-```
\ No newline at end of file
+```
diff --git a/docs/_pages/gallery/gallery_tutorial_collection.md b/docs/_pages/gallery/gallery_tutorial_collection.md
index 23a39147a..15621a241 100644
--- a/docs/_pages/gallery/gallery_tutorial_collection.md
+++ b/docs/_pages/gallery/gallery_tutorial_collection.md
@@ -1,18 +1,17 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
-
 (gallery-tutorial-collection)=
 
 # Working with Collections
@@ -46,7 +45,6 @@ print(f"collections: {coll.collections}")
 New additions are always added at the end. Use the **`add`** method or the parameters.
 
 ```{code-cell} ipython3
-
 # Copy adjusts object label automatically
 x2 = x1.copy()
 s2 = s1.copy()
@@ -170,30 +168,31 @@ The following example demonstrates how collections enable user-friendly manipula
 
 ```{code-cell} ipython3
 import numpy as np
+
 import magpylib as magpy
 
 # Construct two coils from windings
 coil1 = magpy.Collection(style_label="coil1")
-for z in np.linspace(-.5, .5, 5):
-    coil1.add(magpy.current.Circle(current=1, diameter=20, position=(0,0,z)))
-coil1.position = (0,0,-5)
-coil2 = coil1.copy(position=(0,0,5))
+for z in np.linspace(-0.0005, 0.0005, 5):
+    coil1.add(magpy.current.Circle(current=1, diameter=0.02, position=(0, 0, z)))
+coil1.position = (0, 0, -0.005)
+coil2 = coil1.copy(position=(0, 0, 0.005))
 
 # Helmholtz consists of two coils
 helmholtz = coil1 + coil2
 
 # Move the helmholtz
-helmholtz.position = np.linspace((0,0,0), (10,0,0), 15)
-helmholtz.rotate_from_angax(np.linspace(0,180,15), "x", start=0)
+helmholtz.position = np.linspace((0, 0, 0), (0.01, 0, 0), 15)
+helmholtz.rotate_from_angax(np.linspace(0, 180, 15), "x", start=0)
 
 # Move the coils
-coil1.move(np.linspace((0,0,0), ( 5,0,0), 15))
-coil2.move(np.linspace((0,0,0), (-5,0,0), 15))
+coil1.move(np.linspace((0, 0, 0), (0.005, 0, 0), 15))
+coil2.move(np.linspace((0, 0, 0), (-0.005, 0, 0), 15))
 
 # Move the windings
 for coil in [coil1, coil2]:
-    for i,wind in enumerate(coil):
-        wind.move(np.linspace((0,0,0), (0,0,2-i), 15))
+    for i, wind in enumerate(coil):
+        wind.move(np.linspace((0, 0, 0), (0, 0, (2 - i) * 0.001), 15))
 
 # Display as animation
 magpy.show(*helmholtz, animation=True, style_path_show=False)
@@ -204,12 +203,14 @@ For magnetic field computation, a collection with source children behaves like a
 ```{code-cell} ipython3
 import matplotlib.pyplot as plt
 
-B = magpy.getB(helmholtz, (10,0,0))
-plt.plot(B, label=["Bx", "By", "Bz"])
+B = magpy.getB(helmholtz, (0.01, 0, 0))
+plt.plot(
+    B * 1000,  # T -> mT
+    label=["Bx", "By", "Bz"],
+)
 
 plt.gca().set(
-    title="B-field (mT) at position (10,0,0)",
-    xlabel="helmholtz path position index"
+    title="B-field (mT) at position x=10mm", xlabel="helmholtz path position index"
 )
 plt.gca().grid(color=".9")
 plt.gca().legend()
@@ -227,21 +228,21 @@ import magpylib as magpy
 coll = magpy.Collection()
 for index in range(10):
     cuboid = magpy.magnet.Cuboid(
-        magnetization=(0, 0, 1000 * (index%2-.5)),
-        dimension=(10,10,10),
-        position=(index*10,0,0),
+        polarization=(0, 0, (index % 2 - 0.5)),
+        dimension=(0.01, 0.01, 0.01),
+        position=(index * 0.01, 0, 0),
     )
     coll.add(cuboid)
 
 # Add an encompassing 3D-trace
 trace = magpy.graphics.model3d.make_Cuboid(
-    dimension=(104, 12, 12),
-    position=(45, 0, 0),
+    dimension=(0.104, 0.012, 0.012),
+    position=(0.045, 0, 0),
     opacity=0.5,
 )
 coll.style.model3d.add_trace(trace)
 
-coll.style.label="Collection with visible children"
+coll.style.label = "Collection with visible children"
 coll.show()
 
 # Hide the children default 3D representation
@@ -253,6 +254,3 @@ coll.show()
 ## Compound Objects
 
 Collections can be subclassed to form dynamic groups that seamlessly integrate into Magpylib. Such classes are referred to as **compounds**. An example how this is done is shown in {ref}`gallery-misc-compound`.
-
-
-
diff --git a/docs/_pages/gallery/gallery_tutorial_custom.md b/docs/_pages/gallery/gallery_tutorial_custom.md
index be1f2d325..66511aa70 100644
--- a/docs/_pages/gallery/gallery_tutorial_custom.md
+++ b/docs/_pages/gallery/gallery_tutorial_custom.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.14.5
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-tutorial-custom)=
@@ -32,42 +32,47 @@ $$
 
 Here the monopole lies in the origin of the local coordinates, $Q_m$ is the monopole charge and ${\bf r}$ is the observer position.
 
-We create this field as a Python function and hand it over to a CustomSource `field_func` argument. The `field_func` input must be a callable with two positional arguments `field` (can be `'B'` or `'H'`) and `observers` (must accept ndarrays of shape (n,3)), and return the respective fields in units of mT and kA/m in the same shape.
+We create this field as a Python function and hand it over to a CustomSource `field_func` argument. The `field_func` input must be a callable with two positional arguments `field` (can be `'B'` or `'H'`) and `observers` (must accept ndarrays of shape (n,3)), and return the respective fields in units of T and A/m in the same shape.
 
 ```{code-cell} ipython3
 import numpy as np
+
 import magpylib as magpy
 
+
 # Create monopole field
 def mono_field(field, observers):
     """
-    Monopole field 
+    Monopole field
 
     field: string, "B" or "H
         return B or H-field
 
     observers: array_like of shape (n,3)
         Observer positions
-    
+
     Returns: np.ndarray, shape (n,3)
         Magnetic monopole field
     """
-    if field=="B":
-        Qm = 1          # unit mT
+    Qm = 1e-6  # unit T·m²
+    obs = np.array(observers).T  # unit m
+    B = Qm * (obs / np.linalg.norm(obs, axis=0) ** 3).T  # unit T
+    if field == "B":
+        return B  # unit T
+    elif field == "H":
+        mu0 = 4 * np.pi * 1e-7
+        H = B / mu0  # unit A/m
+        return H
     else:
-        Qm = 10/4/np.pi # unit kA/m
-    obs = np.array(observers).T
-    field = Qm * obs / np.linalg.norm(obs, axis=0)**3
-    return field.T
+        raise ValueError("Field Value must be either B or H")
+
 
 # Create CustomSource with monopole field
-mono = magpy.misc.CustomSource(
-    field_func=mono_field
-)
+mono = magpy.misc.CustomSource(field_func=mono_field)
 
 # Compute field
-print(mono.getB((1,0,0)))
-print(mono.getH((1,0,0)))
+print(mono.getB((0.001, 0, 0)))
+print(mono.getH((0.001, 0, 0)))
 ```
 
 Multiple of these sources can now be combined, making use of the Magpylib position/orientation interface.
@@ -76,24 +81,18 @@ Multiple of these sources can now be combined, making use of the Magpylib positi
 import matplotlib.pyplot as plt
 
 # Create two monopole charges
-mono1 = magpy.misc.CustomSource(
-    field_func=mono_field,
-    position=(2,2,0)
-)
-mono2 = magpy.misc.CustomSource(
-    field_func=mono_field,
-    position=(-2,-2,0)
-)
+mono1 = magpy.misc.CustomSource(field_func=mono_field, position=(0.002, 0.002, 0))
+mono2 = magpy.misc.CustomSource(field_func=mono_field, position=(-0.002, -0.002, 0))
 
 # Compute field on observer-grid
-X, Y = np.mgrid[-5:5:40j, -5:5:40j].transpose((0, 2, 1))
+X, Y = np.mgrid[-0.005:0.005:40j, -0.005:0.005:40j].transpose((0, 2, 1))
 grid = np.stack([X, Y, np.zeros((40, 40))], axis=2)
 B = magpy.getB([mono1, mono2], grid, sumup=True)
 normB = np.linalg.norm(B, axis=2)
 
 # Plot field in x-y symmetry plane
-cp = plt.contourf(X, Y, np.log10(normB), cmap='gray_r', levels=10)
-plt.streamplot(X, Y, B[:, :, 0], B[:, :, 1], color='k', density=1)
+cp = plt.contourf(X, Y, np.log10(normB), cmap="gray_r", levels=10)
+plt.streamplot(X, Y, B[:, :, 0], B[:, :, 1], color="k", density=1)
 
 plt.tight_layout()
 plt.show()
@@ -106,12 +105,12 @@ While the CustomSource is graphically represented by a simple marker by default,
 ```{code-cell} ipython3
 # Load Sphere model
 trace_pole = magpy.graphics.model3d.make_Ellipsoid(
-    dimension=(.3,.3,.3),
-    )
+    dimension=np.array([3, 3, 3]) * 1e-4,
+)
 
 for mono in [mono1, mono2]:
     # Turn off default model
-    mono.style.model3d.showdefault=False
+    mono.style.model3d.showdefault = False
 
     # Add sphere model
     mono.style.model3d.add_trace(trace_pole)
@@ -122,48 +121,55 @@ magpy.show(mono1, mono2)
 
 ## Subclassing CustomSource
 
-In the above example it would be nice to make the CustomSource dynamic, so that it would have a property `charge` that can be changed at will, rather than having to redefine the `field_func` and initialize a new object every time. In the following example we show how to sub-class `CustomSource` to achieve this. The problem is reminiscent of {ref}`gallery-misc-compound`. 
+In the above example it would be nice to make the CustomSource dynamic, so that it would have a property `charge` that can be changed at will, rather than having to redefine the `field_func` and initialize a new object every time. In the following example we show how to sub-class `CustomSource` to achieve this. The problem is reminiscent of {ref}`gallery-misc-compound`.
 
 ```{code-cell} ipython3
 class Monopole(magpy.misc.CustomSource):
-    """ Magnetic Monopole class
+    """Magnetic Monopole class
 
     Parameters
     ----------
     charge: float
-        Monopole charge in units of mT
+        Monopole charge in units of T·m²
     """
+
     def __init__(self, charge, **kwargs):
         super().__init__(**kwargs)  # hand over style kwargs
         self._charge = charge
 
         # Add spherical 3d model
         trace_pole = magpy.graphics.model3d.make_Ellipsoid(
-            dimension=(.3,.3,.3),
+            dimension=np.array([3, 3, 3]) * 1e-4,
         )
-        self.style.model3d.showdefault=False
+        self.style.model3d.showdefault = False
         self.style.model3d.add_trace(trace_pole)
 
         # Add monopole field_func
         self._update()
 
     def _update(self):
-        """ Apply monopole field function """
-        
-        def mono_field(field, observers):
-            """ monopole field"""
-            chg = self._charge
-            if field=="H":
-                chg *= 10/4/np.pi  # unit kA/m
-            obs = np.array(observers).T
-            BH = chg * obs / np.linalg.norm(obs, axis=0)**3
-            return BH.T
+        """Apply monopole field function"""
 
+        def mono_field(field, observers):
+            """monopole field"""
+            Qm = self._charge  # unit T·m²
+            obs = np.array(observers).T  # unit m
+            B = Qm * (obs / np.linalg.norm(obs, axis=0) ** 3).T  # unit T
+            if field == "B":
+                return B  # unit T
+            elif field == "H":
+                mu0 = 4 * np.pi * 1e-7
+                H = B / mu0  # unit A/m
+                return H
+            else:
+                raise ValueError("Field Value must be either B or H")
+
+        self.style.label = f"Monopole (charge={self._charge} T·m²)"
         self.field_func = mono_field
 
     @property
     def charge(self):
-        """Number of cubes"""
+        """Return charge"""
         return self._charge
 
     @charge.setter
@@ -172,13 +178,14 @@ class Monopole(magpy.misc.CustomSource):
         self._charge = input
         self._update()
 
+
 # Use new class
-mono = Monopole(charge=1)
-print(mono.getB((1,0,0)))
+mono = Monopole(charge=1e-6)
+print(mono.getB((0.001, 0, 0)))
 
 # Make use of new property
-mono.charge = -1
-print(mono.getB((1,0,0)))
+mono.charge = -1e-6
+print(mono.getB((0.001, 0, 0)))
 ```
 
 The new class seamlessly integrates into the Magpylib interface as we show in the following example where we have a look at the Quadrupole field
@@ -187,49 +194,77 @@ The new class seamlessly integrates into the Magpylib interface as we show in th
 import matplotlib.pyplot as plt
 
 # Create a quadrupole from four monopoles
-mono1 = Monopole(charge= 1, style_color='r', position=( 1, 0, 0))
-mono2 = Monopole(charge= 1, style_color='r', position=(-1, 0, 0))
-mono3 = Monopole(charge=-1, style_color='b', position=( 0, 0, 1))
-mono4 = Monopole(charge=-1, style_color='b', position=( 0, 0,-1))
+mono1 = Monopole(charge=1e-6, style_color="r", position=(0.001, 0, 0))
+mono2 = Monopole(charge=1e-6, style_color="r", position=(-0.001, 0, 0))
+mono3 = Monopole(charge=-1e-6, style_color="b", position=(0, 0, 0.001))
+mono4 = Monopole(charge=-1e-6, style_color="b", position=(0, 0, -0.001))
 qpole = magpy.Collection(mono1, mono2, mono3, mono4)
 
 # Matplotlib figure with 3d and 2d axis
 fig = plt.figure(figsize=(12, 5))
-ax1 = fig.add_subplot(121, projection="3d", azim=-80, elev=15,)
-ax2 = fig.add_subplot(122,)
+ax1 = fig.add_subplot(
+    121,
+    projection="3d",
+    azim=-80,
+    elev=15,
+)
+ax2 = fig.add_subplot(
+    122,
+)
 
 # Show 3D model in ax1
 magpy.show(*qpole, canvas=ax1)
 
 # Compute B-field on xz-grid and display in ax2
 ts = np.linspace(-3, 3, 30)
-grid = np.array([[(x,0,z) for x in ts] for z in ts])
+grid = np.array([[(x / 1000, 0, z / 1000) for x in ts] for z in ts])
 B = qpole.getB(grid)
 
 scale = np.linalg.norm(B, axis=2)
-cp = ax2.contourf(grid[:,:,0], grid[:,:,2], np.log(scale), levels=100, cmap='rainbow')
-ax2.streamplot(grid[:,:,0], grid[:,:,2], B[:,:,0], B[:,:,2], density=2,
-    color='k', linewidth=scale**0.3)
+cp = ax2.contourf(
+    grid[:, :, 0],
+    grid[:, :, 2],
+    np.log(scale),
+    levels=100,
+    cmap="rainbow",
+)
+ax2.streamplot(
+    grid[:, :, 0],
+    grid[:, :, 2],
+    B[:, :, 0],
+    B[:, :, 2],
+    density=2,
+    color="k",
+    linewidth=scale**0.3,
+)
 
 # Display pole position in ax2
 pole_pos = np.array([mono.position for mono in qpole])
-ax2.plot(pole_pos[:,0], pole_pos[:,2], marker='o', ms=10, mfc='k', mec='w', ls='')
+ax2.plot(
+    pole_pos[:, 0],
+    pole_pos[:, 2],
+    marker="o",
+    ms=10,
+    mfc="k",
+    mec="w",
+    ls="",
+)
 
 # Figure styling
 ax1.set(
-    title='3D model',
-    xlabel='x-position (mm)',
-    ylabel='y-position (mm)',
-    zlabel='z-position (mm)',
+    title="3D model",
+    xlabel="x-position (m)",
+    ylabel="y-position (m)",
+    zlabel="z-position (m)",
 )
 ax2.set(
-    title='Quadrupole field',
-    xlabel='x-position (mm)',
-    ylabel='z-position (mm)',
+    title="Quadrupole field",
+    xlabel="x-position (m)",
+    ylabel="z-position (m)",
     aspect=1,
 )
-fig.colorbar(cp, label='[$charge/mm^2$]', ax=ax2)
+fig.colorbar(cp, label="[$charge/m^2$]", ax=ax2)
 
 plt.tight_layout()
 plt.show()
-```
\ No newline at end of file
+```
diff --git a/docs/_pages/gallery/gallery_tutorial_field_computation.md b/docs/_pages/gallery/gallery_tutorial_field_computation.md
index cc7659505..85a143b77 100644
--- a/docs/_pages/gallery/gallery_tutorial_field_computation.md
+++ b/docs/_pages/gallery/gallery_tutorial_field_computation.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.14.5
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-tutorial-field-computation)=
@@ -21,11 +21,14 @@ kernelspec:
 The v2 slogan was *"The magnetic field is only three lines of code away"*, which is demonstrated by the most fundamental use of Magpylib.
 
 ```{code-cell} ipython3
-import magpylib as magpy                          # Import Magpylib
-loop = magpy.current.Circle(current=1, diameter=1)  # Create magnetic source
-B = magpy.getB(loop, observers=(0,0,0))           # Compute field
+import magpylib as magpy  # Import Magpylib
 
-print(B.round(decimals=3))
+loop = magpy.current.Circle(
+    current=1, diameter=0.01
+)  # Create magnetic source, units: A, m
+B = magpy.getB(loop, observers=(0, 0, 0))  # Compute field in units of T
+
+print(B)
 ```
 
 ## Field on a Grid
@@ -33,32 +36,60 @@ print(B.round(decimals=3))
 When handed multiple observer positions, `getB` and `getH` will return the field in the shape of the input. In the following example, B- and H-field of a diametrically magnetized cylinder magnet are computed on a position grid in the symmetry plane, and are then displayed using Matplotlib.
 
 ```{code-cell} ipython3
-import numpy as np
 import matplotlib.pyplot as plt
+import numpy as np
+
 import magpylib as magpy
 
-fig, [ax1,ax2] = plt.subplots(1, 2, figsize=(10,5))
+fig, [ax1, ax2] = plt.subplots(1, 2, figsize=(10, 5))
 
 # Create an observer grid in the xz-symmetry plane
-X, Y = np.mgrid[-5:5:100j, -5:5:100j].transpose((0, 2, 1))
+X, Y = np.mgrid[-0.05:0.05:100j, -0.05:0.05:100j].transpose((0, 2, 1))
 grid = np.stack([X, Y, np.zeros((100, 100))], axis=2)
 
 # Compute B- and H-fields of a cylinder magnet on the grid
-cyl = magpy.magnet.Cylinder(magnetization=(500,500,0), dimension=(4,2))
+cyl = magpy.magnet.Cylinder(polarization=(0.5, 0.5, 0), dimension=(0.04, 0.02))
 B = cyl.getB(grid)
 H = cyl.getH(grid)
 
 # Display field with Pyplot
-ax1.streamplot(grid[:,:,0], grid[:,:,1], B[:,:,0], B[:,:,1], density=1.5,
-    color=np.log(np.linalg.norm(B, axis=2)), linewidth=1, cmap='spring_r')
+ax1.streamplot(
+    grid[:, :, 0] * 1000,  # m -> mm
+    grid[:, :, 1] * 1000,  # m -> mm
+    B[:, :, 0],
+    B[:, :, 1],
+    density=1.5,
+    color=np.log(np.linalg.norm(B, axis=2)),
+    linewidth=1,
+    cmap="spring_r",
+)
 
-ax2.streamplot(grid[:,:,0], grid[:,:,1], H[:,:,0], H[:,:,1], density=1.5,
-    color=np.log(np.linalg.norm(B, axis=2)), linewidth=1, cmap='winter_r')
+ax2.streamplot(
+    grid[:, :, 0] * 1000,  # m -> mm
+    grid[:, :, 1] * 1000,  # m -> mm
+    H[:, :, 0],
+    H[:, :, 1],
+    density=1.5,
+    color=np.log(np.linalg.norm(B, axis=2)),
+    linewidth=1,
+    cmap="winter_r",
+)
 
+ax1.set(
+    title="B-Field",
+    xlabel="x-position (mm)",
+    ylabel="y-position (mm)",
+)
+ax2.set(
+    title="H-Field",
+    xlabel="x-position (mm)",
+    ylabel="y-position (mm)",
+    aspect=1,
+)
 # Outline magnet boundary
-for ax in [ax1,ax2]:
-    ts = np.linspace(0, 2*np.pi, 50)
-    ax.plot(2*np.sin(ts), 2*np.cos(ts), 'k--')
+for ax in [ax1, ax2]:
+    ts = np.linspace(0, 2 * np.pi, 50)
+    ax.plot(20 * np.sin(ts), 20 * np.cos(ts), "k--")
 
 plt.tight_layout()
 plt.show()
@@ -74,6 +105,7 @@ The following example shows a moving and rotating sensor with two pixels. At the
 
 ```{code-cell} ipython3
 import numpy as np
+
 import magpylib as magpy
 
 # Reset defaults set in previous example
@@ -81,22 +113,24 @@ magpy.defaults.reset()
 
 
 # Define sensor with path
-sensor = magpy.Sensor(pixel=[(0,0,-.5), (0,0,.5)], style_size=1.5)
-sensor.position = np.linspace((0,0,-3), (0,0,3), 37)
+sensor = magpy.Sensor(pixel=[(0, 0, -0.0005), (0, 0, 0.0005)], style_size=1.5)
+sensor.position = np.linspace((0, 0, -0.003), (0, 0, 0.003), 37)
 
 angles = np.linspace(0, 360, 37)
-sensor.rotate_from_angax(angles, 'z', start=0)
+sensor.rotate_from_angax(angles, "z", start=0)
 
 # Define source with path
-cyl1 = magpy.magnet.Cylinder(magnetization=(100,0,0), dimension=(1,2), position=(3,0,0))
-cyl2 = cyl1.copy(position=(-3,0,0))
+cyl1 = magpy.magnet.Cylinder(
+    polarization=(0.1, 0, 0), dimension=(0.001, 0.002), position=(0.003, 0, 0)
+)
+cyl2 = cyl1.copy(position=(-0.003, 0, 0))
 coll = magpy.Collection(cyl1, cyl2)
-coll.rotate_from_angax(-angles, 'z', start=0)
+coll.rotate_from_angax(-angles, "z", start=0)
 
 # Display system and field at sensor
-with magpy.show_context(sensor, coll, animation=True, backend='plotly'):
+with magpy.show_context(sensor, coll, animation=True, backend="plotly"):
     magpy.show(col=1)
-    magpy.show(output='Bx', col=2, pixel_agg=None)
+    magpy.show(output="Bx", col=2, pixel_agg=None)
 ```
 
 ## Multiple Inputs
@@ -107,12 +141,12 @@ When `getB` and `getH` receive multiple inputs for sources and observers they wi
 import magpylib as magpy
 
 # Three sources
-cube1 = magpy.magnet.Cuboid(magnetization=(0,0,1000), dimension=(1,1,1))
+cube1 = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(0.1, 0.1, 0.1))
 cube2 = cube1.copy()
 cube3 = cube1.copy()
 
 # Two sensors with 4x5 pixel each
-pixel = [[[(i,j,0)] for i in range(4)] for j in range(5)]
+pixel = [[[(i / 1000, j / 1000, 0)] for i in range(4)] for j in range(5)]
 sens1 = magpy.Sensor(pixel=pixel)
 sens2 = sens1.copy()
 
@@ -137,29 +171,28 @@ Instead of a Numpy `ndarray`, the field computation can also return a [pandas](h
 
 ```{code-cell} ipython3
 import numpy as np
+
 import magpylib as magpy
 
 cube = magpy.magnet.Cuboid(
-    magnetization=(0, 0, 1000),
-    dimension=(1, 1, 1),
-    style_label='cube'
+    polarization=(0, 0, 1), dimension=(0.01, 0.01, 0.01), style_label="cube"
 )
 loop = magpy.current.Circle(
     current=200,
-    diameter=2,
-    style_label='loop',
+    diameter=0.02,
+    style_label="loop",
 )
 sens1 = magpy.Sensor(
-    pixel=[(0,0,0), (.5,0,0)],
-    position=np.linspace((-4, 0, 2), (4, 0, 2), 30),
-    style_label='sens1'
+    pixel=[(0, 0, 0), (0.005, 0, 0)],
+    position=np.linspace((-0.04, 0, 0.02), (0.04, 0, 0.02), 30),
+    style_label="sens1",
 )
-sens2 = sens1.copy(style_label='sens2').move((0,0,1))
+sens2 = sens1.copy(style_label="sens2").move((0, 0, 0.01))
 
 B = magpy.getB(
     [cube, loop],
     [sens1, sens2],
-    output='dataframe',
+    output="dataframe",
 )
 
 B
@@ -169,6 +202,7 @@ Plotting libraries such as [plotly](https://plotly.com/python/plotly-express/) o
 
 ```{code-cell} ipython3
 import plotly.express as px
+
 fig = px.line(
     B,
     x="path",
@@ -181,16 +215,16 @@ fig = px.line(
 fig.show()
 ```
 
-(gallery-tutorial-field-computation-direct-interface)=
+(gallery-tutorial-field-computation-functional-interface)=
 
-## Direct Interface
+## Functional Interface
 
-All above computations demonstrate the convenient object oriented interface of Magpylib. However, there are instances when it is better to work with the direct interface instead.
+All above computations demonstrate the convenient object oriented interface of Magpylib. However, there are instances when it is better to work with the functional interface instead.
 
 1. Reduce overhead of Python objects
 2. Complex computation instances
 
-In the following example we show how complex instances are computed using the direct interface.
+In the following example we show how complex instances are computed using the functional interface.
 
 ```{important}
 Use numpy operations for input array creation as shown in the example !
@@ -198,33 +232,38 @@ Use numpy operations for input array creation as shown in the example !
 
 ```{code-cell} ipython3
 import numpy as np
+
 import magpylib as magpy
 
 # Two different magnet dimensions
-dim1 = (2,4,4)
-dim2 = (4,2,2)
-DIM = np.vstack((
-    np.tile(dim1, (6,1)),
-    np.tile(dim2, (6,1)),
-    ))
+dim1 = (0.02, 0.04, 0.04)
+dim2 = (0.04, 0.02, 0.02)
+DIM = np.vstack(
+    (
+        np.tile(dim1, (6, 1)),
+        np.tile(dim2, (6, 1)),
+    )
+)
 
-# Sweep through different magnetization for each magnet type
-mags = np.linspace((0,0,500), (0,0,1000), 6)
-MAG = np.tile(mags, (2,1))
+# Sweep through different polarizations for each magnet type
+pol = np.linspace((0, 0, 0.5), (0, 0, 1), 6)
+POL = np.tile(pol, (2, 1))
 
 # Airgap must stay the same
-pos1 = (0,0,3)
-pos2 = (0,0,2)
-POS = np.vstack((
-    np.tile(pos1, (6,1)),
-    np.tile(pos2, (6,1)),
-    ))
-
-# Compute all instances with the direct interface
+pos1 = (0, 0, 0.03)
+pos2 = (0, 0, 0.02)
+POS = np.vstack(
+    (
+        np.tile(pos1, (6, 1)),
+        np.tile(pos2, (6, 1)),
+    )
+)
+
+# Compute all instances with the functional interface
 B = magpy.getB(
-    sources='Cuboid',
+    sources="Cuboid",
     observers=POS,
-    magnetization=MAG,
+    polarization=POL,
     dimension=DIM,
 )
 
diff --git a/docs/_pages/gallery/gallery_tutorial_paths.md b/docs/_pages/gallery/gallery_tutorial_paths.md
index 3e25110e1..eaae4b1e9 100644
--- a/docs/_pages/gallery/gallery_tutorial_paths.md
+++ b/docs/_pages/gallery/gallery_tutorial_paths.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.14.0
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-tutorial-paths)=
@@ -31,24 +31,24 @@ Absolute object paths are assigned at initialization or through the object prope
 ```{code-cell} ipython3
 import numpy as np
 from scipy.spatial.transform import Rotation as R
+
 import magpylib as magpy
 
 # Create paths
 ts = np.linspace(0, 10, 31)
-pos = np.array([(t, 0, np.sin(t)) for t in ts])
-ori = R.from_rotvec(np.array([(0, -np.cos(t)*0.785, 0) for t in ts]))
+pos = np.array([(0.1 * t, 0, 0.1 * np.sin(t)) for t in ts])
+ori = R.from_rotvec(np.array([(0, -0.1 * np.cos(t) * 0.785, 0) for t in ts]))
 
 # Set path at initialization
 sensor = magpy.Sensor(position=pos, orientation=ori)
 
 # Set path through properties
-cube = magpy.magnet.Cuboid(magnetization=(0,0,1), dimension=(1,1,1))
-cube.position = pos + np.array((0,0,3))
+cube = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(0.01, 0.01, 0.01))
+cube.position = pos + np.array((0, 0, 0.3))
 cube.orientation = ori
 
 # Display as animation
-magpy.show(sensor, cube, animation=True, backend='plotly')
-
+magpy.show(sensor, cube, animation=True, backend="plotly")
 ```
 
 ## Relative Paths
@@ -58,23 +58,24 @@ magpy.show(sensor, cube, animation=True, backend='plotly')
 ```{code-cell} ipython3
 import numpy as np
 from scipy.spatial.transform import Rotation as R
+
 import magpylib as magpy
 
 # Create paths
 ts = np.linspace(0, 10, 21)
-pos = np.array([(t, 0, np.sin(t)) for t in ts])
-ori = R.from_rotvec(np.array([(0, -np.cos(t)*0.785, 0) for t in ts]))
+pos = np.array([(0.1 * t, 0, 0.1 * np.sin(t)) for t in ts])
+ori = R.from_rotvec(np.array([(0, -0.1 * np.cos(t) * 0.785, 0) for t in ts]))
 
 # Set path at initialization
-sens1 = magpy.Sensor(position=pos, orientation=ori, style_label='sens1')
+sens1 = magpy.Sensor(position=pos, orientation=ori, style_label="sens1")
 
 # Apply move operation to whole path with scalar input
-sens2 = sens1.copy(style_label='sens2')
-sens2.move((0,0,2))
+sens2 = sens1.copy(style_label="sens2")
+sens2.move((0, 0, 0.05))
 
 # Apply rotate operation to whole path with scalar input
-sens3 = sens1.copy(style_label='sens3')
-sens3.rotate_from_angax(angle=90, axis='y', anchor=0)
+sens3 = sens1.copy(style_label="sens3")
+sens3.rotate_from_angax(angle=90, axis="y", anchor=0)
 
 # Display paths
 magpy.show(sens1, sens2, sens3)
@@ -84,14 +85,15 @@ When the input is a vector, the path is by default appended.
 
 ```{code-cell} ipython3
 import numpy as np
+
 from magpylib.magnet import Sphere
 
 # Create paths
-x_path = np.linspace((0,0,0), (10,0,0), 10)[1:]
-z_path = np.linspace((0,0,0), (0,0,10), 10)[1:]
+x_path = np.linspace((0, 0, 0), (0.1, 0, 0), 10)[1:]
+z_path = np.linspace((0, 0, 0), (0, 0, 0.1), 10)[1:]
 
 # Create sphere object
-sphere = Sphere(magnetization=(0,0,1), diameter=3)
+sphere = Sphere(polarization=(0, 0, 1), diameter=0.03)
 
 # Apply paths subsequently
 for _ in range(3):
@@ -107,20 +109,21 @@ Complex paths can be created by merging multiple path operations. This is done w
 
 ```{code-cell} ipython3
 import numpy as np
+
 from magpylib.magnet import Cuboid
 
 # Create cube and set linear path
-cube =  Cuboid(magnetization=(0,0,100), dimension=(2,2,2))
-cube.position = np.linspace((0,0,0), (10,0,0), 60)
+cube = Cuboid(polarization=(0, 0, 0.1), dimension=(0.02, 0.02, 0.02))
+cube.position = np.linspace((0, 0, 0), (0.1, 0, 0), 60)
 
 # Apply rotation about self - starting at index 0
-cube.rotate_from_rotvec(np.linspace((0,0,0), (0,0,360), 30), start=0)
+cube.rotate_from_rotvec(np.linspace((0, 0, 0), (0, 0, 360), 30), start=0)
 
 # Apply rotation about origin - starting at index 30
-cube.rotate_from_rotvec(np.linspace((0,0,0), (0,0,360), 30), anchor=0, start=30)
+cube.rotate_from_rotvec(np.linspace((0, 0, 0), (0, 0, 360), 30), anchor=0, start=30)
 
 # Display paths as animation
-cube.show(backend='plotly', animation=True)
+cube.show(backend="plotly", animation=True)
 ```
 
 ## Reset path
@@ -131,7 +134,9 @@ The `reset_path()` method allows users to reset an object path to `position=(0,0
 import magpylib as magpy
 
 # Create sensor object with complex path
-sensor=magpy.Sensor().rotate_from_angax([1,2,3,4], (1,2,3), anchor=(0,3,5))
+sensor = magpy.Sensor().rotate_from_angax(
+    [1, 2, 3, 4], (1, 2, 3), anchor=(0, 0.03, 0.05)
+)
 
 # Reset path
 sensor.reset_path()
@@ -152,13 +157,14 @@ In the following example the orientation attribute is padded by its edge value `
 
 ```{code-cell} ipython3
 from scipy.spatial.transform import Rotation as R
+
 import magpylib as magpy
 
 sensor = magpy.Sensor(
-    position=[(0,0,0), (1,1,1)],
-    orientation=R.from_rotvec([(0,0,.1), (0,0,.2)]),
+    position=[(0, 0, 0), (0.01, 0.01, 0.01)],
+    orientation=R.from_rotvec([(0, 0, 0.1), (0, 0, 0.2)]),
 )
-sensor.position=[(i,i,i) for i in range(4)]
+sensor.position = [(i / 100, i / 100, i / 100) for i in range(4)]
 print(sensor.position)
 print(sensor.orientation.as_rotvec())
 ```
@@ -168,10 +174,10 @@ When the field is computed of `loop1` with path length 4 and `loop2` with path l
 ```{code-cell} ipython3
 from magpylib.current import Circle
 
-loop1 = Circle(current=1, diameter=1, position=[(0,0,i) for i in range(4)])
-loop2 = Circle(current=1, diameter=1, position=[(0,0,i) for i in range(2)])
+loop1 = Circle(current=1, diameter=1, position=[(0, 0, i) for i in range(4)])
+loop2 = Circle(current=1, diameter=1, position=[(0, 0, i) for i in range(2)])
 
-B = magpy.getB([loop1,loop2], (0,0,0))
+B = magpy.getB([loop1, loop2], (0, 0, 0))
 print(B)
 ```
 
@@ -179,13 +185,18 @@ The idea behind **end-slicing** is that, whenever a path is automatically reduce
 
 ```{code-cell} ipython3
 from scipy.spatial.transform import Rotation as R
+
 from magpylib import Sensor
 
 sensor = Sensor(
-    position=[(0,0,0), (1,1,1), (2,2,2), (3,3,3)],
-    orientation=R.from_rotvec([(0,0,.1), (0,0,.2), (0,0,.3), (0,0,.4)]),
+    position=[(0, 0, 0), (0.01, 0.01, 0.01), (0.02, 0.02, 2), (0.03, 0.03, 0.03)],
+    orientation=R.from_rotvec([(0, 0, 0.1), (0, 0, 0.2), (0, 0, 0.3), (0, 0, 0.4)]),
 )
-sensor.position=[(1,2,3), (2,3,4)]
+sensor.position = [(0.01, 0.02, 0.03), (0.02, 0.03, 0.04)]
 print(sensor.position)
 print(sensor.orientation.as_rotvec())
 ```
+
+```{code-cell} ipython3
+
+```
diff --git a/docs/_pages/gallery/gallery_tutorial_trimesh.md b/docs/_pages/gallery/gallery_tutorial_trimesh.md
index 154075770..be9a07a13 100644
--- a/docs/_pages/gallery/gallery_tutorial_trimesh.md
+++ b/docs/_pages/gallery/gallery_tutorial_trimesh.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-tutorial-trimesh)=
@@ -47,12 +47,14 @@ The mesh status is set by the checks, and can be viewed via the properties `stat
 ## Example - Tetrahedron magnet
 
 ```{code-cell} ipython3
+import numpy as np
+
 import magpylib as magpy
 
 # create faceted tetrahedron from vertices and faces
 tmesh_tetra = magpy.magnet.TriangularMesh(
-    magnetization=(0, 0, 1000),
-    vertices=((0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)),
+    polarization=(0, 0, 1),
+    vertices=np.array(((0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1))) / 100,
     faces=((2, 1, 0), (3, 0, 1), (3, 2, 0), (3, 1, 2)),
 )
 
@@ -70,25 +72,26 @@ tmesh_tetra.show()
 In some cases it may be desirable to generate a `TriangularMesh` object from an open mesh, as described in {ref}`gallery-shapes-triangle`. In this case one has to be extremely careful because one cannot rely on the checks. Not to generate warnings or error messages, these checks can be disabled with `"skip"` or their outcome can be ignored with `"ignore"`. The `show` function can be used to view open edges and disconnected parts. In the following example we generate such an open mesh directly from `Triangle` objects.
 
 ```{code-cell} ipython3
-import magpylib as magpy
 import numpy as np
 
+import magpylib as magpy
+
 top = magpy.misc.Triangle(
-    magnetization=(1000,0,0),
-    vertices= ((-1,-1,1), (1,-1,1), (0,2,1)),
+    polarization=(1, 0, 0),
+    vertices=np.array(((-1, -1, 1), (1, -1, 1), (0, 2, 1))) / 100,
 )
 bottom = magpy.misc.Triangle(
-    magnetization=(1000,0,0),
-    vertices= ((-1,-1,-1), (0,2,-1), (1,-1,-1)),
+    polarization=(1, 0, 0),
+    vertices=np.array(((-1, -1, -1), (0, 2, -1), (1, -1, -1))) / 100,
 )
 
 # create faceted prism with open edges
 prism = magpy.magnet.TriangularMesh.from_triangles(
-    magnetization=(0, 0, 1000),   # overrides triangles magnetization
+    polarization=(0, 0, 1),  # overrides triangles polarization
     triangles=[top, bottom],
-    check_open="ignore",        # check but ignore open mesh
-    check_disconnected="ignore",     # check but ignore disconnected mesh
-    reorient_faces="ignore",      # check but ignore non-orientable mesh
+    check_open="ignore",  # check but ignore open mesh
+    check_disconnected="ignore",  # check but ignore disconnected mesh
+    reorient_faces="ignore",  # check but ignore non-orientable mesh
     style_label="Open prism",
 )
 prism.style.magnetization.mode = "arrow"
@@ -104,4 +107,3 @@ prism.show(
     style_mesh_disconnected_show=True,
 )
 ```
-
diff --git a/docs/_pages/gallery/gallery_vis_mpl_streamplot.md b/docs/_pages/gallery/gallery_vis_mpl_streamplot.md
index 29413522b..345233df6 100644
--- a/docs/_pages/gallery/gallery_vis_mpl_streamplot.md
+++ b/docs/_pages/gallery/gallery_vis_mpl_streamplot.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.14.5
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-vis-mpl-streamplot)=
@@ -23,41 +23,47 @@ In this example we show the B-field of a cuboid magnet using Matplotlib streamli
 ```{code-cell} ipython3
 import matplotlib.pyplot as plt
 import numpy as np
+
 import magpylib as magpy
 
 # Create a Matplotlib figure
 fig, ax = plt.subplots()
 
 # Create an observer grid in the xz-symmetry plane
-ts = np.linspace(-5,5,40)
-grid = np.array([[(x,0,z) for x in ts] for z in ts]) # slow Python loop
+ts = np.linspace(-0.05, 0.05, 40)
+grid = np.array([[(x, 0, z) for x in ts] for z in ts])
 
 # Compute the B-field of a cube magnet on the grid
-cube = magpy.magnet.Cuboid(magnetization=(500, 0, 500), dimension=(2, 2, 2))
+cube = magpy.magnet.Cuboid(polarization=(0.5, 0, 0.5), dimension=(0.02, 0.02, 0.02))
 B = cube.getB(grid)
 log10_norm_B = np.log10(np.linalg.norm(B, axis=2))
 
 # Display the B-field with streamplot using log10-scaled
 # color function and linewidth
 splt = ax.streamplot(
-    grid[:,:,0],
-    grid[:,:,2],
-    B[:, :, 0],
-    B[:, :, 2],
+    grid[:, :, 0]*1000, # m -> mm
+    grid[:, :, 2]*1000, # m -> mm
+    B[:, :, 0]*1000, # T -> mT
+    B[:, :, 2]*1000, # T -> mT
     color=log10_norm_B,
     density=1,
-    linewidth=log10_norm_B*2,
+    linewidth=log10_norm_B * 2,
     cmap="autumn",
 )
 
 # Add colorbar with logarithmic labels
 cb = fig.colorbar(splt.lines, ax=ax, label="|B| (mT)")
-ticks = np.array([3,10,30,100,300])
+ticks = np.array([3, 10, 30, 100, 300])
 cb.set_ticks(np.log10(ticks))
 cb.set_ticklabels(ticks)
 
 # Outline magnet boundary
-ax.plot([1, 1, -1, -1, 1], [1, -1, -1, 1, 1], "k--", lw=2)
+ax.plot(
+    np.array([1, 1, -1, -1, 1]) * 10, # mm
+    np.array([1, -1, -1, 1, 1]) * 10, # mm
+    "k--",
+    lw=2,
+)
 
 # Figure styling
 ax.set(
@@ -70,46 +76,63 @@ plt.show()
 ```
 
 ```{note}
-Be aware that the above code is not very performant, but quite readable. The following example creates the grid with numpy commands only instead of Python loops, and uses the {ref}`gallery-tutorial-field-computation-direct-interface` for field computation.
+Be aware that the above code is not very performant, but quite readable. The following example creates the grid with numpy commands only instead of Python loops, and uses the {ref}`gallery-tutorial-field-computation-functional-interface` for field computation.
 ```
 
 ## Example 2 - Hollow Cylinder Magnet
 
-A nice visualizaion is achieved by combining `streamplot` with `contourf`. In this example we show the B-field of a hollow Cylinder magnet with diametral magnetization in the xy-symmetry plane.
+A nice visualizaion is achieved by combining `streamplot` with `contourf`. In this example we show the B-field of a hollow Cylinder magnet with diametral polarization in the xy-symmetry plane.
 
 ```{code-cell} ipython3
-import numpy as np
 import matplotlib.pyplot as plt
+import numpy as np
+
 import magpylib as magpy
 
 # Create a Matplotlib figure
 fig, ax = plt.subplots()
 
 # Create an observer grid in the xy-symmetry plane - using pure numpy
-X, Y = np.mgrid[-5:5:100j, -5:5:100j].transpose((0, 2, 1))
+X, Y = np.mgrid[-0.05:0.05:100j, -0.05:0.05:100j].transpose((0, 2, 1))
 grid = np.stack([X, Y, np.zeros((100, 100))], axis=2)
 
-# Compute magnetic field on grid - using the direct interface
+# Compute magnetic field on grid - using the functional interface
 B = magpy.getB(
     "CylinderSegment",
-    observers=grid.reshape(-1,3),
-    dimension=(2,3,5,0,360),
-    magnetization=(100,0,0),
+    observers=grid.reshape(-1, 3),
+    dimension=(0.02, 0.03, 0.05, 0, 360),
+    polarization=(0.1, 0, 0),
 )
 B = B.reshape(grid.shape)
 normB = np.linalg.norm(B, axis=2)
 
 # combine streamplot with contourf
-cp = ax.contourf(X, Y, normB, cmap='rainbow', levels=100, zorder=1)
-splt = ax.streamplot(X, Y, B[:, :, 0], B[:, :, 1], color='k', density=1.5, linewidth=1, zorder=3)
+cp = ax.contourf(
+    X * 1000,  # m -> mm
+    Y * 1000,  # m -> mm
+    normB,
+    cmap="rainbow",
+    levels=100,
+    zorder=1,
+)
+splt = ax.streamplot(
+    X* 1000,  # m -> mm,
+    Y* 1000,  # m -> mm,
+    B[:, :, 0], # T -> mT
+    B[:, :, 1], # T -> mT
+    color="k",
+    density=1.5,
+    linewidth=1,
+    zorder=3,
+)
 
 # Add colorbar
 fig.colorbar(cp, ax=ax, label="|B| (mT)")
 
 # Outline magnet boundary
-ts = np.linspace(0, 2*np.pi, 50)
-ax.plot(3*np.cos(ts), 3*np.sin(ts), "w-", lw=2, zorder=2)
-ax.plot(2*np.cos(ts), 2*np.sin(ts), "w-", lw=2, zorder=2)
+ts = np.linspace(0, 2 * np.pi, 50)
+ax.plot(30 * np.cos(ts), 30 * np.sin(ts), "w-", lw=2, zorder=2)
+ax.plot(20 * np.cos(ts), 20 * np.sin(ts), "w-", lw=2, zorder=2)
 
 # Figure styling
 ax.set(
@@ -120,4 +143,4 @@ ax.set(
 
 plt.tight_layout()
 plt.show()
-```
\ No newline at end of file
+```
diff --git a/docs/_pages/gallery/gallery_vis_pv_streamlines.md b/docs/_pages/gallery/gallery_vis_pv_streamlines.md
index 21636ca43..1b772b2ea 100644
--- a/docs/_pages/gallery/gallery_vis_pv_streamlines.md
+++ b/docs/_pages/gallery/gallery_vis_pv_streamlines.md
@@ -1,15 +1,15 @@
 ---
-orphan: true
 jupytext:
   text_representation:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.14.5
+    jupytext_version: 1.16.0
 kernelspec:
   display_name: Python 3
   language: python
   name: python3
+orphan: true
 ---
 
 (gallery-vis-pv-streamlines)=
@@ -19,32 +19,29 @@ kernelspec:
 Pyvista offers field-line computation and visualization in 3D. In addition to the field computation, Magpylib offers magnet visualization that seamlessly integrates into a Pyvista plotting scene.
 
 ```{code-cell} ipython3
-import pyvista as pv
 import magpylib as magpy
-
-# This line is only needed for pyvista rendering in a jupyter notebook
-pv.set_jupyter_backend("panel")
+import pyvista as pv
 
 # Create a magnet with Magpylib
-magnet = magpy.magnet.Cylinder((0, 0, 1000), (10, 4))
+magnet = magpy.magnet.Cylinder(polarization=(0, 0, 1), dimension=(0.010, 0.004))
 
 # Create a 3D grid with Pyvista
-grid = pv.UniformGrid(
+grid = pv.ImageData(
     dimensions=(41, 41, 41),
-    spacing=(1, 1, 1),
-    origin=(-20, -20, -20),
+    spacing=(0.001, 0.001, 0.001),
+    origin=(-0.02, -0.02, -0.02),
 )
 
 # Compute B-field and add as data to grid
-grid["B"] = magnet.getB(grid.points)
+grid["B"] = magnet.getB(grid.points) * 1000  # T -> mT
 
 # Compute the field lines
-seed = pv.Disc(inner=1, outer=3, r_res=1, c_res=6)
+seed = pv.Disc(inner=0.001, outer=0.003, r_res=1, c_res=9)
 strl = grid.streamlines_from_source(
     seed,
     vectors="B",
-    max_time=180,
-    initial_step_length=0.01,
+    max_step_length=0.1,
+    max_time=.02,
     integration_direction="both",
 )
 
@@ -65,12 +62,12 @@ legend_args = {
 
 # Add streamlines and legend to scene
 pl.add_mesh(
-    strl.tube(radius=0.2),
+    strl.tube(radius=0.0002),
     cmap="bwr",
     scalar_bar_args=legend_args,
 )
 
 # Prepare and show scene
-pl.camera.position = (30, 30, 20)
+pl.camera.position = (0.03, 0.03, 0.03)
 pl.show()
 ```
\ No newline at end of file
diff --git a/docs/_pages/reso_get_started.md b/docs/_pages/reso_get_started.md
index 89b71d12e..5faf3aa42 100644
--- a/docs/_pages/reso_get_started.md
+++ b/docs/_pages/reso_get_started.md
@@ -4,9 +4,9 @@ jupytext:
     extension: .md
     format_name: myst
     format_version: 0.13
-    jupytext_version: 1.13.7
+    jupytext_version: 1.16.0
 kernelspec:
-  display_name: Python 3 (ipykernel)
+  display_name: Python 3
   language: python
   name: python3
 ---
@@ -47,9 +47,9 @@ import magpylib as magpy
 
 # Create a Cuboid magnet with magnetic polarization
 # of 1000 mT pointing in x-direction and sides of
-# 1,2 and 3 mm respectively.
+# 1,2 and 3 cm respectively (notice the use of SI units).
 
-cube = magpy.magnet.Cuboid(magnetization=(1000,0,0), dimension=(1,2,3))
+cube = magpy.magnet.Cuboid(polarization=(1,0,0), dimension=(0.01,0.02,0.03))
 
 # Create a Sensor for measuring the field
 
@@ -67,21 +67,21 @@ print(cube.position)                   # -> [0. 0. 0.]
 print(cube.orientation.as_rotvec())    # -> [0. 0. 0.]
 
 # Manipulate object position and orientation through
-# the respective attributes:
+# the respective attributes (move 10mm and rotate 45 deg):
 
 from scipy.spatial.transform import Rotation as R
-cube.position = (1,0,0)
+cube.position = (0.01,0,0) # in SI Units (m)
 cube.orientation = R.from_rotvec((0,0,45), degrees=True)
 
-print(cube.position)                            # -> [1. 0.  0.]
+print(cube.position)                            # -> [0.01 0.   0.  ]
 print(cube.orientation.as_rotvec(degrees=True)) # -> [0. 0. 45.]
 
 # Apply relative motion with the powerful `move`
 # and `rotate` methods.
-sensor.move((-1,0,0))
+sensor.move((-0.01,0,0))
 sensor.rotate_from_angax(angle=-45, axis='z')
 
-print(sensor.position)                            # -> [-1.  0.  0.]
+print(sensor.position)                            # -> [-0.01  0.    0.  ]
 print(sensor.orientation.as_rotvec(degrees=True)) # -> [ 0.  0. -45.]
 ```
 
@@ -99,20 +99,20 @@ magpy.show(cube, sensor, backend='plotly')
 ### Step 4: Compute the magnetic field
 
 ```python
-# Compute the B-field in units of mT for some points.
+# Compute the B-field in units of T for some points.
 
-points = [(0,0,-1), (0,0,0), (0,0,1)]
+points = [(0,0,-.01), (0,0,0), (0,0,.01)] # in SI Units (m)
 B = magpy.getB(cube, points)
 
-print(B.round()) # -> [[263.  68.  81.]
-                 #     [276.  52.   0.]
-                 #     [263.  68. -81.]]
+print(B.round(2)) # -> [[ 0.26  0.07  0.08]
+                     # [ 0.28  0.05  0.  ]
+                     # [ 0.26  0.07 -0.08]] # in SI Units (T)
 
-# Compute the H-field in units of kA/m at the sensor.
+# Compute the H-field in units of A/m at the sensor.
 
 H = magpy.getH(cube, sensor)
 
-print(H.round()) # -> [220.  41.   0.]
+print(H.round()) # -> [51017. 24210.     0.] # in SI Units (A/m)
 ```
 
 ```{warning}
@@ -129,20 +129,23 @@ import numpy as np
 import magpylib as magpy
 
 # Create magnet
-sphere = magpy.magnet.Sphere(diameter=1, magnetization=(0,0,1000))
+sphere = magpy.magnet.Sphere(
+    diameter=.01, # in SI Units (m)
+    polarization=(0,0,1) #  in SI Units (T)
+)
 
 # Assign a path
-sphere.position = np.linspace((-2,0,0), (2,0,0), 7)
+sphere.position = np.linspace((-.02,0,0), (.02,0,0), 7)
 
 # The field is automatically computed for every path position
-B = sphere.getB((0,0,1))
-print(B.round())  # ->[[  4.   0.  -1.]
-                  #    [ 13.   0.   1.]
-                  #    [ 33.   0.  26.]
-                  #    [  0.   0.  83.]
-                  #    [-33.   0.  26.]
-                  #    [-13.   0.   1.]
-                  #    [ -4.   0.  -1.]]
+B = sphere.getB((0,0,.01)) # in SI Units (m)
+print(B.round(3))  # ->[[ 0.004  0.    -0.001]
+                      # [ 0.013  0.     0.001]
+                      # [ 0.033  0.     0.026]
+                      # [ 0.     0.     0.083]
+                      # [-0.033  0.     0.026]
+                      # [-0.013  0.     0.001]
+                      # [-0.004  0.    -0.001]] # in SI Units (T)
 ```
 :::
 
@@ -156,16 +159,18 @@ import magpylib as magpy
 
 # Create objects
 obj1 = magpy.Sensor()
-obj2 = magpy.magnet.Cuboid(magnetization=(0,0,1000), dimension=(1,2,3))
+obj2 = magpy.magnet.Cuboid(
+    polarization=(0,0,1), # in SI Units (T)
+    dimension=(.01,.02,.03)) # in SI Units (m)
 
 # Group objects
 coll = magpy.Collection(obj1, obj2)
 
 # Manipulate Collection
-coll.move((1,2,3))
+coll.move((.001,.002,.003)) # in SI Units (m)
 
-print(obj1.position.round()) # -> [1. 2. 3.]
-print(obj2.position.round()) # -> [1. 2. 3.]
+print(obj1.position) # -> [0.001 0.002 0.003] # in SI Units (m)
+print(obj2.position) # -> [0.001 0.002 0.003] # in SI Units (m)
 ```
 :::
 
@@ -175,19 +180,26 @@ print(obj2.position.round()) # -> [1. 2. 3.]
 There most convenient way to create a magnet with complex shape is by using the ConvexHull of a point cloud (= simplest form that includes all given points).
 
 ```python
+import numpy as np
+
 import magpylib as magpy
 
 # Create a Pyramid magnet
-points = [
-    (-1,-1, 0),
-    (-1, 1, 0),
-    ( 1,-1, 0),
-    ( 1, 1, 0),
-    ( 0, 0, 2),
-]
+points = (
+    np.array(
+        [
+            (-1, -1, 0),
+            (-1, 1, 0),
+            (1, -1, 0),
+            (1, 1, 0),
+            (0, 0, 2),
+        ]
+    )
+    / 1000
+)  # mm to m
 pyramid = magpy.magnet.TriangularMesh.from_ConvexHull(
-    magnetization=(0,0,1000),
-    points=points
+    polarization=(0, 0, 1), # in SI Units (T)
+    points=points, # in SI Units (m)
 )
 
 # Display the magnet graphically
@@ -206,17 +218,17 @@ import magpylib as magpy
 
 # create Cuboid magnet with custom style
 cube = magpy.magnet.Cuboid(
-    magnetization=(0,0,1000),
-    dimension=(1,1,1),
+    polarization=(0,0,1), # in SI Units (T)
+    dimension=(.01,.01,.01), # in SI Units (m)
     style_color='r',
     style_magnetization_mode='arrow'
 )
 
 # create Cylinder magnet with custom style
 cyl = magpy.magnet.Cylinder(
-    magnetization=(0,0,1000),
-    dimension=(1,1),
-    position=(2,0,0),
+    polarization=(0,0,1), # in SI Units (T)
+    dimension=(.01,.01), # in SI Units (m)
+    position=(.02,0,0), # in SI Units (m)
     style_magnetization_color_mode='bicolor',
     style_magnetization_color_north='m',
     style_magnetization_color_south='c',
@@ -237,8 +249,15 @@ import magpylib as magpy
 
 
 # Create magnet with path
-cube = magpy.magnet.Cuboid(magnetization=(0,0,1000), dimension=(1,1,1))
-cube.rotate_from_angax(angle=np.linspace(10,360,18), axis='x')
+cube = magpy.magnet.Cuboid(
+    magnetization=(0,0,1), # in SI Units (T)
+    dimension=(1,1,1), # in SI Units (m)
+)
+cube.rotate_from_angax(
+    angle=np.linspace(10,360,18),
+    axis='x'
+    degrees=True # default, can be omitted
+)
 
 # Generate an animation with `show`
 cube.show(animation=True, backend="plotly")
@@ -248,22 +267,26 @@ cube.show(animation=True, backend="plotly")
 
 
 
-:::{dropdown} Direct interface
-Magpylib's object oriented interface is convenient to work with but is also slowed down by object initialization and handling. The direct interface bypasses this load and enables field computation for a set of input parameters.
+:::{dropdown} Functional interface
+Magpylib's object oriented interface is convenient to work with but is also slowed down by object initialization and handling. The functional interface bypasses this load and enables field computation for a set of input parameters.
 
 ```python
 import magpylib as magpy
 
-# Compute the magnetic field via the direct interface.
+# Compute the magnetic field via the functional interface.
 B = magpy.getB(
     sources="Cuboid",
-    observers=[(-1,0,1), (0,0,1), (1,0,1)],
-    dimension=(1,1,1),
-    magnetization=(0,0,1000)
+    observers=[(-.01, 0, .01), (0, 0, .01), (.01, 0, .01)],  # in SI Units (m)
+    dimension=(.01, .01, .01), # in SI Units (m)
+    polarization=(0, 0, 1), # in SI Units (T)
 )
 
-print(B.round()) # -> [[-43.   0.  14.]
-                 #     [  0.   0. 135.]
-                 #     [ 43.   0.  14.]]
+print(B.round(3))  # -> [[-0.043  0.     0.014]
+                       # [ 0.     0.     0.135]
+                       # [ 0.043  0.     0.014]] # in SI Units (T)
 ```
 :::
+
+```{code-cell} ipython3
+
+```
diff --git a/docs/_pages/reso_news.md b/docs/_pages/reso_news.md
deleted file mode 100644
index f614de947..000000000
--- a/docs/_pages/reso_news.md
+++ /dev/null
@@ -1,19 +0,0 @@
-(news)=
-
-# News
-
-## Release of version 4.4.0
-**03.09.2023**
-
-- Version 4.4 is now released. Most notable changes:
-    - dynamic multi-plots with `show_context`
-    - the `style_legend_show` option to disable the automatic legend without having to refer to own canvas
-    - the styling option for current lines and magnetization arrows.
-- Bunch of bugfixes, other graphic improvements
-
-## New Documentation
-**18.08.2023**
-
-- Happy to announce our new, more attractive, more user-friendly and more complete documentation ! Give us Feedback what you think :). There are still a lot of things to do (specifically in the Examples section). Documentation updates coming regularly now.
-
-- It is set up for Magpylib version 4.4 - so some documented features might not be working in 4.3 - release is imminent ! If you cannot wait install from  [main branch](https://github.com/magpylib/magpylib).
diff --git a/docs/_static/images/docu_field_comp_flow.png b/docs/_static/images/docu_field_comp_flow.png
index 6ecc10d5b..11ff11666 100644
Binary files a/docs/_static/images/docu_field_comp_flow.png and b/docs/_static/images/docu_field_comp_flow.png differ
diff --git a/docs/conf.py b/docs/conf.py
index a0bc4a937..fee61e91e 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -73,7 +73,7 @@ def setup(app):
 
 # If your documentation needs a minimal Sphinx version, state it here.
 #
-needs_sphinx = "5.3.0"
+needs_sphinx = "7.2"
 
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
diff --git a/docs/index.md b/docs/index.md
index 49772f326..186cdc57a 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -101,9 +101,7 @@ In Magpylib, **sources** (magnets, currents, ...) and **observers** (sensors, po
 
 ```{toctree}
 :maxdepth: 2
-:hidden:
 
-_pages/reso_news.md
 _pages/reso_get_started.md
 _pages/docu/docu_index.md
 _pages/gallery/gallery_index.md
diff --git a/magpylib/__init__.py b/magpylib/__init__.py
index 9c598af7b..fa518fc42 100644
--- a/magpylib/__init__.py
+++ b/magpylib/__init__.py
@@ -28,7 +28,7 @@
 
 """
 # module level dunders
-__version__ = "4.5.1"
+__version__ = "5.0.0dev"
 __author__ = "Michael Ortner & Alexandre Boisselet"
 __credits__ = "The Magpylib community"
 __all__ = [
diff --git a/magpylib/_src/defaults/defaults_values.py b/magpylib/_src/defaults/defaults_values.py
index 9b8e6de34..8b7ddb2fb 100644
--- a/magpylib/_src/defaults/defaults_values.py
+++ b/magpylib/_src/defaults/defaults_values.py
@@ -48,7 +48,7 @@
                     "numbering": False,
                 },
                 "description": {"show": True, "text": None},
-                "legend": {"show": True},
+                "legend": {"show": True, "text": None},
                 "opacity": 1,
                 "model3d": {"showdefault": True, "data": []},
                 "color": None,
diff --git a/magpylib/_src/display/backend_matplotlib.py b/magpylib/_src/display/backend_matplotlib.py
index 6428717ca..9fe593649 100644
--- a/magpylib/_src/display/backend_matplotlib.py
+++ b/magpylib/_src/display/backend_matplotlib.py
@@ -352,7 +352,7 @@ def draw_frame(frame_ind):
             count = count_with_labels.get(row_col_num, 0)
             if ax.name == "3d":
                 ax.set(
-                    **{f"{k}label": f"{k} (mm)" for k in "xyz"},
+                    **{f"{k}label": f"{k} (m)" for k in "xyz"},
                     **{f"{k}lim": r for k, r in zip("xyz", ranges)},
                 )
                 ax.set_box_aspect(aspect=(1, 1, 1))
diff --git a/magpylib/_src/display/backend_plotly.py b/magpylib/_src/display/backend_plotly.py
index 6243dc9c3..adbe6c28e 100644
--- a/magpylib/_src/display/backend_plotly.py
+++ b/magpylib/_src/display/backend_plotly.py
@@ -94,7 +94,7 @@ def apply_fig_ranges(fig, ranges, apply2d=True):
     """
     fig.update_scenes(
         **{
-            f"{k}axis": {"range": ranges[i], "autorange": False, "title": f"{k} (mm)"}
+            f"{k}axis": {"range": ranges[i], "autorange": False, "title": f"{k} (m)"}
             for i, k in enumerate("xyz")
         },
         aspectratio={k: 1 for k in "xyz"},
diff --git a/magpylib/_src/display/backend_pyvista.py b/magpylib/_src/display/backend_pyvista.py
index 652fa9bca..9aa4e0c64 100644
--- a/magpylib/_src/display/backend_pyvista.py
+++ b/magpylib/_src/display/backend_pyvista.py
@@ -3,7 +3,6 @@
 # pylint: disable=too-many-statements
 import os
 import tempfile
-import warnings
 from functools import lru_cache
 
 import numpy as np
@@ -55,8 +54,6 @@
     "longdashdot": "-..",
 }
 
-INCOMPATIBLE_JUPYTER_BACKENDS_2D = {"panel", "ipygany", "pythreejs"}
-
 
 @lru_cache(maxsize=32)
 def colormap_from_colorscale(colorscale, name="plotly_to_mpl", N=256, gamma=1.0):
@@ -76,7 +73,7 @@ def colormap_from_colorscale(colorscale, name="plotly_to_mpl", N=256, gamma=1.0)
     return LinearSegmentedColormap(name, cdict, N, gamma)
 
 
-def generic_trace_to_pyvista(trace, jupyter_backend=None):
+def generic_trace_to_pyvista(trace):
     """Transform a generic trace into a pyvista trace"""
     traces_pv = []
     leg_title = trace.get("legendgrouptitle_text", None)
@@ -108,11 +105,7 @@ def generic_trace_to_pyvista(trace, jupyter_backend=None):
             )
         traces_pv.append(trace_pv)
         if colorscale is not None:
-            # ipygany does not support custom colorsequences
-            if jupyter_backend == "ipygany":
-                trace_pv["cmap"] = "PiYG"
-            else:
-                trace_pv["cmap"] = colormap_from_colorscale(colorscale)
+            trace_pv["cmap"] = colormap_from_colorscale(colorscale)
     elif "scatter" in trace["type"]:
         line = trace.get("line", {})
         line_color = line.get("color", trace.get("line_color", None))
@@ -252,9 +245,6 @@ def display_pyvista(
     jupyter_backend = show_kwargs.pop("jupyter_backend", jupyter_backend)
     if jupyter_backend is None:
         jupyter_backend = pv.global_theme.jupyter_backend
-    jupyter_backend_2D_compatible = (
-        jupyter_backend not in INCOMPATIBLE_JUPYTER_BACKENDS_2D
-    )
     count_with_labels = {}
     charts_max_ind = 0
 
@@ -262,7 +252,7 @@ def draw_frame(frame_ind):
         nonlocal count_with_labels, charts_max_ind
         frame = frames[frame_ind]
         for tr0 in frame["data"]:
-            for tr1 in generic_trace_to_pyvista(tr0, jupyter_backend=jupyter_backend):
+            for tr1 in generic_trace_to_pyvista(tr0):
                 row = tr1.pop("row", 1)
                 col = tr1.pop("col", 1)
                 typ = tr1.pop("type")
@@ -276,17 +266,11 @@ def draw_frame(frame_ind):
                     getattr(canvas, f"add_{typ}")(**tr1)
                     canvas.show_axes()
                 else:
-                    if jupyter_backend_2D_compatible:
-                        if charts.get((row, col), None) is None:
-                            charts_max_ind += 1
-                            charts[(row, col)] = pv.Chart2D()
-                            canvas.add_chart(charts[(row, col)])
-                        getattr(charts[(row, col)], typ)(**tr1)
-                    else:
-                        warnings.warn(
-                            f"The set `jupyter_backend={jupyter_backend}` is incompatible with "
-                            "2D plots. Empty plots will be shown instead"
-                        )
+                    if charts.get((row, col), None) is None:
+                        charts_max_ind += 1
+                        charts[(row, col)] = pv.Chart2D()
+                        canvas.add_chart(charts[(row, col)])
+                    getattr(charts[(row, col)], typ)(**tr1)
         for rowcol, count in count_with_labels.items():
             if 0 < count <= legend_maxitems:
                 row, col = rowcol
@@ -334,8 +318,16 @@ def run_animation(filename, embed=True):
         animation_output = data["input_kwargs"].get("animation_output", None)
         animation_output = "gif" if animation_output is None else animation_output
         if animation_output in ("gif", "mp4"):
-            with tempfile.NamedTemporaryFile(suffix=f".{animation_output}") as temp:
-                run_animation(temp.name, embed=True)
+            try:
+                temp = os.path.join(tempfile.gettempdir(), os.urandom(24).hex())
+                temp += f".{animation_output}"
+                run_animation(temp, embed=True)
+            finally:
+                try:
+                    os.unlink(temp)
+                except FileNotFoundError:  # pragma: no cover
+                    # avoid exception if file is not found
+                    pass
         else:
             run_animation(animation_output, embed=True)
 
diff --git a/magpylib/_src/display/display.py b/magpylib/_src/display/display.py
index 58b72318f..1a6b37f72 100644
--- a/magpylib/_src/display/display.py
+++ b/magpylib/_src/display/display.py
@@ -15,7 +15,7 @@
 from magpylib._src.input_checks import check_format_input_vector
 from magpylib._src.input_checks import check_input_animation
 from magpylib._src.input_checks import check_input_zoom
-from magpylib._src.utility import test_path_format
+from magpylib._src.utility import check_path_format
 
 disp_args = get_defaults_dict("display").keys()
 
@@ -198,7 +198,7 @@ def _show(
     kwargs["subplot_specs"] = subplot_specs
 
     # test if every individual obj_path is good
-    test_path_format(obj_list_flat)
+    check_path_format(obj_list_flat)
 
     # input checks
     backend = check_format_input_backend(backend)
@@ -333,7 +333,7 @@ def show(
     Display multiple objects, object paths, markers in 3D using Matplotlib or Plotly:
 
     >>> import magpylib as magpy
-    >>> src = magpy.magnet.Sphere(magnetization=(0,0,1), diameter=1)
+    >>> src = magpy.magnet.Sphere(polarization=(0,0,1), diameter=1)
     >>> src.move([(0.1*x,0,0) for x in range(50)])
     Sphere...
     >>> src.rotate_from_angax(angle=[*range(0,400,10)], axis='z', anchor=0, start=11)
@@ -349,7 +349,7 @@ def show(
     >>> import matplotlib.pyplot as plt
     >>> import magpylib as magpy
     >>> my_axis = plt.axes(projection='3d')
-    >>> magnet = magpy.magnet.Cuboid(magnetization=(1,1,1), dimension=(1,2,3))
+    >>> magnet = magpy.magnet.Cuboid(polarization=(1,1,1), dimension=(1,2,3))
     >>> sens = magpy.Sensor(position=(0,0,3))
     >>> magpy.show(magnet, sens, canvas=my_axis, zoom=1)
     >>> plt.show() # doctest: +SKIP
@@ -359,8 +359,13 @@ def show(
     or as global style arguments in display.
 
     >>> import magpylib as magpy
-    >>> src1 = magpy.magnet.Sphere((1,1,1), 1, [(0,0,0), (0,0,3)])
-    >>> src2 = magpy.magnet.Sphere((1,1,1), 1, [(1,0,0), (1,0,3)], style_path_show=False)
+    >>> src1 = magpy.magnet.Sphere(position=[(0,0,0), (0,0,3)], diameter=1, polarization=(1,1,1))
+    >>> src2 = magpy.magnet.Sphere(
+    ...     position=[(1,0,0), (1,0,3)],
+    ...     diameter=1,
+    ...     polarization=(1,1,1),
+    ...     style_path_show=False
+    ... )
     >>> magpy.defaults.display.style.magnet.magnetization.size = 2
     >>> src1.style.magnetization.size = 1
     >>> magpy.show(src1, src2, style_color='r') # doctest: +SKIP
@@ -374,7 +379,7 @@ def show(
     >>> path_len = 40
     >>> sensor = magpy.Sensor()
     >>> cyl1 = magpy.magnet.Cylinder(
-    ...    magnetization=(100, 0, 0),
+    ...    polarization=(.1, 0, 0),
     ...    dimension=(1, 2),
     ...    position=(4, 0, 0),
     ...    style_label="Cylinder1",
diff --git a/magpylib/_src/display/traces_base.py b/magpylib/_src/display/traces_base.py
index 61444bd27..0890cacdf 100644
--- a/magpylib/_src/display/traces_base.py
+++ b/magpylib/_src/display/traces_base.py
@@ -307,9 +307,9 @@ def make_CylinderSegment(
 
     dimension: array_like, shape (5,), default=`None`
         Dimension/Size of the cylinder segment of the form (r1, r2, h, phi1, phi2)
-        where r1<r2 denote inner and outer radii in units of mm, phi1<phi2 denote
+        where r1<r2 denote inner and outer radii in units of m, phi1<phi2 denote
         the cylinder section angles in units of deg and h is the cylinder height
-        in units of mm.
+        in units of m.
 
     vert : int, default=50
         Number of vertices along a the complete 360 degrees arc. The number along the phi1-phi2-arc
diff --git a/magpylib/_src/display/traces_core.py b/magpylib/_src/display/traces_core.py
index b65eae4ad..fe470b2d5 100644
--- a/magpylib/_src/display/traces_core.py
+++ b/magpylib/_src/display/traces_core.py
@@ -545,7 +545,10 @@ def make_Sensor(obj, autosize=None, **kwargs) -> Dict[str, Any]:
     style = obj.style
     dimension = getattr(obj, "dimension", style.size)
     pixel = obj.pixel
-    pixel = np.unique(np.array(pixel).reshape((-1, 3)), axis=0)
+    no_pix = pixel is None
+    if not no_pix:
+        pixel = np.unique(np.array(pixel).reshape((-1, 3)), axis=0)
+    one_pix = not no_pix and pixel.shape[0] == 1
     style_arrows = style.arrows.as_dict(flatten=True, separator="_")
     sensor = get_sensor_mesh(
         **style_arrows, center_color=style.color, handedness=obj.handedness
@@ -557,8 +560,6 @@ def make_Sensor(obj, autosize=None, **kwargs) -> Dict[str, Any]:
         [dimension] * 3 if isinstance(dimension, (float, int)) else dimension[:3],
         dtype=float,
     )
-    no_pix = pixel.shape[0] == 1 and (pixel == 0).all()
-    one_pix = pixel.shape[0] == 1 and not (pixel == 0).all()
     if autosize is not None and style.sizemode == "scaled":
         dim *= autosize
     if no_pix:
diff --git a/magpylib/_src/display/traces_generic.py b/magpylib/_src/display/traces_generic.py
index 9d21ca88a..b267f4ff6 100644
--- a/magpylib/_src/display/traces_generic.py
+++ b/magpylib/_src/display/traces_generic.py
@@ -346,7 +346,9 @@ def get_label_and_color(obj):
                 label, color = label_sens, color_sens
             num_of_pix = (
                 len(sens.pixel.reshape(-1, 3))
-                if (not isinstance(sens, magpy.Collection)) and sens.pixel.ndim != 1
+                if (not isinstance(sens, magpy.Collection))
+                and sens.pixel is not None
+                and sens.pixel.ndim != 1
                 else 1
             )
             pix_suff = ""
diff --git a/magpylib/_src/display/traces_utility.py b/magpylib/_src/display/traces_utility.py
index c60cac959..a77139ed8 100644
--- a/magpylib/_src/display/traces_utility.py
+++ b/magpylib/_src/display/traces_utility.py
@@ -18,8 +18,15 @@ def get_legend_label(obj, style=None, suffix=True):
     """provides legend entry based on name and suffix"""
     style = obj.style if style is None else style
     name = style.label if style.label else obj.__class__.__name__
-    desc = getattr(obj, "_default_style_description", "")
-    suff = f" ({desc})" if style.description.show and desc and suffix else ""
+    legend_txt = style.legend.text
+    if legend_txt:
+        return legend_txt
+    suff = ""
+    if suffix and style.description.show:
+        desc = style.description.text
+        if not desc:
+            desc = getattr(obj, "_default_style_description", "")
+        suff = f" ({desc})"
     return f"{name}{suff}"
 
 
diff --git a/magpylib/_src/fields/field_BH_circle.py b/magpylib/_src/fields/field_BH_circle.py
index 69608bc9a..e53b6b2d1 100644
--- a/magpylib/_src/fields/field_BH_circle.py
+++ b/magpylib/_src/fields/field_BH_circle.py
@@ -11,56 +11,67 @@
 from magpylib._src.input_checks import check_field_input
 from magpylib._src.utility import cart_to_cyl_coordinates
 from magpylib._src.utility import cyl_field_to_cart
+from magpylib._src.utility import MU0
 
 
 # CORE
 def current_circle_field(
+    *,
     field: str,
     observers: np.ndarray,
-    current: np.ndarray,
     diameter: np.ndarray,
+    current: np.ndarray,
 ) -> np.ndarray:
-    """Magnetic field of a circular (line) current loop.
+    """Magnetic field of a circular (line) current loops.
 
     The loop lies in the z=0 plane with the coordinate origin at its center.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
+
+    diameter: ndarray, shape (n,)
+        Diameter of loop in units of m.
 
     current: ndarray, shape (n,)
         Electrical current in units of A.
 
-    diameter: ndarray, shape (n,)
-        Diameter of loop in units of mm.
-
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of current in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
-    Compute the field of three different loops at three different positions.
+    Compute the field of three different circular loops at three different positions.
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>> cur = np.array([1,1,2])
-    >>> dia = np.array([2,4,6])
-    >>> obs = np.array([(1,1,1), (2,2,2), (3,3,3)])
-    >>> B = magpy.core.current_circle_field('B', obs, cur, dia)
-    >>> print(B)
-    [[0.06235974 0.06235974 0.02669778]
-     [0.03117987 0.03117987 0.01334889]
-     [0.04157316 0.04157316 0.01779852]]
+    >>> H = magpy.core.current_circle_field(
+    ...     field='H',
+    ...     observers=np.array([(0,0,0), (1,1,1), (2,2,2)]),
+    ...     diameter=np.array([1,2,3]),
+    ...     current=np.array([1,1,2])
+    ... )
+    >>> print(H)
+    [[0.         0.         1.        ]
+     [0.0496243  0.0496243  0.02124542]
+     [0.02833835 0.02833835 0.00654999]]
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
     Implementation based on "Numerically stable and computationally efficient expression for
     the magnetic field of a current loop.", M.Ortner et al, Submitted to MDPI Magnetism, 2022
     """
@@ -125,14 +136,14 @@ def current_circle_field(
     # transform field to cartesian CS
     Bx_tot, By_tot = cyl_field_to_cart(phi, Br_tot)
     B_cart = (
-        np.concatenate(((Bx_tot,), (By_tot,), (Bz_tot,)), axis=0) * current
+        np.concatenate(((Bx_tot,), (By_tot,), (Bz_tot,)), axis=0) * current * 1e-6
     ).T  # ugly but fast
 
     # B or H field
     if bh:
         return B_cart
 
-    return B_cart / np.pi * 2.5
+    return B_cart / MU0
 
 
 def current_loop_field(*args, **kwargs):
diff --git a/magpylib/_src/fields/field_BH_cuboid.py b/magpylib/_src/fields/field_BH_cuboid.py
index 38ee8a18d..deec0e068 100644
--- a/magpylib/_src/fields/field_BH_cuboid.py
+++ b/magpylib/_src/fields/field_BH_cuboid.py
@@ -5,35 +5,43 @@
 import numpy as np
 
 from magpylib._src.input_checks import check_field_input
+from magpylib._src.utility import MU0
 
 
+# CORE
 def magnet_cuboid_field(
-    field: str, observers: np.ndarray, magnetization: np.ndarray, dimension: np.ndarray
+    *,
+    field: str,
+    observers: np.ndarray,
+    dimension: np.ndarray,
+    polarization: np.ndarray,
 ) -> np.ndarray:
-    """Magnetic field of a homogeneously magnetized cuboid.
+    """Magnetic field of homogeneously magnetized cuboids.
 
     The cuboid sides are parallel to the coordinate axes. The geometric center of the
     cuboid lies in the origin.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
-
-    magnetization: ndarray, shape (n,3)
-        Homogeneous magnetization vector in units of mT.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
     dimension: ndarray, shape (n,3)
-        Cuboid side lengths in units of mm.
+        Length of Cuboid sides in units of m.
+
+    polarization: ndarray, shape (n,3)
+        Magnetic polarization vectors in units of T.
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of magnet in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
@@ -41,17 +49,24 @@ def magnet_cuboid_field(
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>> mag = np.array([(222,333,555), (33,44,55), (0,0,100)])
-    >>> dim = np.array([(1,1,1), (2,3,4), (1,2,3)])
-    >>> obs = np.array([(1,2,3), (2,3,4), (0,0,0)])
-    >>> B = magpy.core.magnet_cuboid_field('B', obs, mag, dim)
+    >>> B = magpy.core.magnet_cuboid_field(
+    ...     field='B',
+    ...     observers=np.array([(1,2,0), (2,3,4), (0,0,0)]),
+    ...     dimension=np.array([(2,2,2), (3,3,3), (4,4,4)]),
+    ...     polarization=np.array([(0,0,1), (1,0,0), (0,0,1)]),
+    ... )
     >>> print(B)
-    [[ 0.49343022  1.15608356  1.65109312]
-     [ 0.82221622  1.18511282  1.46945423]
-     [ 0.          0.         88.77487579]]
+    [[ 0.          0.         -0.05227894]
+     [-0.00820941  0.00849123  0.011429  ]
+     [ 0.          0.          0.66666667]]
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
     Field computations via magnetic surface charge density. Published
     several times with similar expressions:
 
@@ -59,7 +74,7 @@ def magnet_cuboid_field(
 
     Engel-Herbert: Journal of Applied Physics 97(7):074504 - 074504-4 (2005)
 
-    Camacho: Revista Mexicana de Fisica E 59 (2013) 8–17
+    Camacho: Revista Mexicana de Fisica E 59 (2013) 8-17
 
     Avoiding indeterminate forms:
 
@@ -78,7 +93,7 @@ def magnet_cuboid_field(
 
     bh = check_field_input(field, "magnet_cuboid_field()")
 
-    magx, magy, magz = magnetization.T
+    magx, magy, magz = polarization.T
     a, b, c = np.abs(dimension.T) / 2
     x, y, z = observers.T
 
@@ -120,7 +135,7 @@ def magnet_cuboid_field(
     mask_gen = ~mask1 & mask2 & ~mask3
 
     if np.any(mask_gen):
-        magx, magy, magz = magnetization[mask_gen].T
+        magx, magy, magz = polarization[mask_gen].T
         a, b, c = dimension[mask_gen].T / 2
         x, y, z = np.copy(observers[mask_gen]).T
 
@@ -215,17 +230,17 @@ def magnet_cuboid_field(
             - np.arctan2((xpa * ypb), (zpc * ppp))
         )
 
-        # contributions from x-magnetization
+        # contributions from x-polarization
         bx_magx = (
             magx * ff1x * qsigns[:, 0, 0]
         )  # the 'missing' third sign is hidden in ff1x
         by_magx = magx * ff2z * qsigns[:, 0, 1]
         bz_magx = magx * ff2y * qsigns[:, 0, 2]
-        # contributions from y-magnetization
+        # contributions from y-polarization
         bx_magy = magy * ff2z * qsigns[:, 1, 0]
         by_magy = magy * ff1y * qsigns[:, 1, 1]
         bz_magy = -magy * ff2x * qsigns[:, 1, 2]
-        # contributions from z-magnetization
+        # contributions from z-polarization
         bx_magz = magz * ff2y * qsigns[:, 2, 0]
         by_magz = -magz * ff2x * qsigns[:, 2, 1]
         bz_magz = magz * ff1z * qsigns[:, 2, 2]
@@ -247,8 +262,8 @@ def magnet_cuboid_field(
     if bh:
         return B
 
-    # if inside magnet subtract magnetization vector
+    # if inside magnet subtract polarization vector
     mask_inside = mx2 & my2 & mz2
-    B[mask_inside] -= magnetization[mask_inside]
-    H = B * 10 / 4 / np.pi  # mT -> kA/m
+    B[mask_inside] -= polarization[mask_inside]
+    H = B / MU0  # T -> A/m
     return H
diff --git a/magpylib/_src/fields/field_BH_cylinder.py b/magpylib/_src/fields/field_BH_cylinder.py
index 60245a8f6..0ab22a438 100644
--- a/magpylib/_src/fields/field_BH_cylinder.py
+++ b/magpylib/_src/fields/field_BH_cylinder.py
@@ -11,6 +11,7 @@
 from magpylib._src.input_checks import check_field_input
 from magpylib._src.utility import cart_to_cyl_coordinates
 from magpylib._src.utility import cyl_field_to_cart
+from magpylib._src.utility import MU0
 
 
 def fieldB_cylinder_axial(z0: np.ndarray, r: np.ndarray, z: np.ndarray) -> list:
@@ -24,14 +25,14 @@ def fieldB_cylinder_axial(z0: np.ndarray, r: np.ndarray, z: np.ndarray) -> list:
     Parameters
     ----------
     dim: ndarray, shape (n,2)
-        dimension of cylinder (d, h), diameter and height, in units of mm
+        dimension of cylinder (d, h), diameter and height, in units of m
     pos_obs: ndarray, shape (n,2)
-        position of observer (r,z) in cylindrical coordinates in units of mm
+        position of observer (r,z) in cylindrical coordinates in units of m
 
     Returns
     -------
     B-field: ndarray
-        B-field array of shape (n,2) in cylindrical coordinates (Br,Bz) in units of mT.
+        B-field array of shape (n,2) in cylindrical coordinates (Br,Bz) in units of T.
     """
     n = len(z0)
 
@@ -85,16 +86,16 @@ def fieldH_cylinder_diametral(
     Parameters
     ----------
     dim: ndarray, shape (n,2)
-        dimension of cylinder (d, h), diameter and height, in units of mm
+        dimension of cylinder (d, h), diameter and height, in units of m
     tetta: ndarray, shape (n,)
         angle between magnetization vector and x-axis in [rad]. M = (cos(tetta), sin(tetta), 0)
     obs_pos: ndarray, shape (n,3)
-        position of observer (r,phi,z) in cylindrical coordinates in units of mm and rad
+        position of observer (r,phi,z) in cylindrical coordinates in units of m and rad
 
     Returns
     -------
     H-field: ndarray
-        H-field array of shape (n,3) in cylindrical coordinates (Hr, Hphi, Hz) in units of kA/m.
+        H-field array of shape (n,3) in cylindrical coordinates (Hr, Hphi, Hz) in units of A/m.
     """
     # pylint: disable=too-many-statements
 
@@ -249,59 +250,61 @@ def fieldH_cylinder_diametral(
 
 # CORE
 def magnet_cylinder_field(
+    *,
     field: str,
     observers: np.ndarray,
-    magnetization: np.ndarray,
     dimension: np.ndarray,
+    polarization: np.ndarray,
 ) -> np.ndarray:
-    """Magnetic field of a homogeneously magnetized cylinder.
+    """Magnetic field of homogeneously magnetized cylinders.
 
     The cylinder axis coincides with the z-axis and the geometric center of the
     cylinder lies in the origin.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
-
-    magnetization: ndarray, shape (n,3)
-        Homogeneous magnetization vector in units of mT.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
     dimension: ndarray, shape (n,2)
-        Cylinder dimension (d,h) with diameter d and height h in units of mm.
+        Cylinder dimension (d,h) with diameter d and height h in units of m.
 
-    observer: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
-
-    field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+    polarization: ndarray, shape (n,3)
+        Magnetic polarization vectors in units of T.
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of magnet in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
-    Compute the B-field of two different cylinder magnets at position (1,2,3).
+    Compute the B-field of two different cylinder magnets at position (1,0,0).
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>> mag = np.array([(0,0,1000), (100,0,100)])
-    >>> dim = np.array([(1,1), (2,3)])
-    >>> obs = np.array([(1,2,3), (1,2,3)])
-    >>> B = magpy.core.magnet_cylinder_field('B', obs, mag, dim)
+    >>> B = magpy.core.magnet_cylinder_field(
+    ...     field='B',
+    ...     observers=np.array([(1,0,0), (1,0,0)]),
+    ...     dimension=np.array([(1,1), (1,3)]),
+    ...     polarization=np.array([(0,0,1), (.5,0,.5)]),
+    ... )
     >>> print(B)
-    [[ 0.77141782  1.54283565  1.10384481]
-     [-0.15185713  2.90352915  2.23601722]]
+    [[ 0.          0.         -0.05185272]
+     [ 0.06821654  0.         -0.01576545]]
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
 
     Axial implementation based on
 
@@ -335,7 +338,7 @@ def magnet_cylinder_field(
     m3 = r <= 1  # inside Cylinder hull plane
 
     # special case: mag = 0
-    mask0 = np.linalg.norm(magnetization, axis=1) == 0
+    mask0 = np.linalg.norm(polarization, axis=1) == 0
 
     # special case: on Cylinder edge
     mask_edge = m0 & m1
@@ -343,8 +346,8 @@ def magnet_cylinder_field(
     # general case
     mask_gen = ~mask0 & ~mask_edge
 
-    # axial/transv magnetization cases
-    magx, magy, magz = magnetization.T
+    # axial/transv polarization cases
+    magx, magy, magz = polarization.T
     mask_tv = (magx != 0) | (magy != 0)
     mask_ax = magz != 0
 
@@ -356,7 +359,7 @@ def magnet_cylinder_field(
     mask_ax = mask_ax & mask_gen
     mask_inside = mask_inside & mask_gen
 
-    # transversal magnetization contributions -----------------------
+    # transversal polarization contributions -----------------------
     if any(mask_tv):
         magxy = np.sqrt(magx**2 + magy**2)[mask_tv]
         tetta = np.arctan2(magy[mask_tv], magx[mask_tv])
@@ -369,7 +372,7 @@ def magnet_cylinder_field(
         Bphi[mask_tv] += magxy * bphi_tv
         Bz[mask_tv] += magxy * bz_tv
 
-    # axial magnetization contributions -----------------------------
+    # axial polarization contributions -----------------------------
     if any(mask_ax):
         br_ax, bz_ax = fieldB_cylinder_axial(z0[mask_ax], r[mask_ax], z[mask_ax])
         Br[mask_ax] += magz[mask_ax] * br_ax
@@ -387,108 +390,4 @@ def magnet_cylinder_field(
 
     if any(mask_ax):  # ax computes B-field
         Bz[mask_ax * mask_inside] -= magz[mask_ax * mask_inside]
-    return np.concatenate(((Bx,), (By,), (Bz,)), axis=0).T * 10 / 4 / np.pi
-
-
-# old iterative solution by Furlani
-
-# def magnet_cyl_dia_H_Furlani1994(
-#         tetta: np.ndarray,
-#         dim: np.ndarray,
-#         pos_obs: np.ndarray,
-#         niter: int,
-#         ) -> np.ndarray:
-#     """
-#     H-field in Cylindrical CS of Cylinder magnet with homogenous
-#     diametral unit magnetization. The Cylinder axis coincides with the z-axis of the
-#     CS. The geometric center of the Cylinder is in the origin.
-
-#     Implementation from [Furlani1994].
-
-#     Parameters
-#     ----------
-#     dim: ndarray, shape (n,2)
-#         dimension of cylinder (d, h), diameter and height, in units of mm
-#     tetta: ndarray, shape (n,)
-#         angle between magnetization vector and x-axis in [rad]. M = (cos(tetta), sin(tetta), 0)
-#     obs_pos: ndarray, shape (n,3)
-#         position of observer (r,phi,z) in cylindrical coordinates in units of mm and rad
-#     niter: int
-#         Iterations for Simpsons approximation of the final integral
-
-#     Returns
-#     -------
-#     H-field: ndarray
-#         H-field array of shape (n,3) in cylindrical coordinates (Hr, Hphi Hz) in units of kA/m.
-
-#     Examples
-#     --------
-#     Compute field at three instances.
-
-#     >>> import numpy as np
-#     >>> import magpylib as magpy
-#     >>> tetta = np.zeros(3)
-#     >>> dim = np.array([(2,2), (2,3), (3,4)])
-#     >>> obs = np.array([(.1,0,2), (2,0.12,3), (4,0.2,1)])
-#     >>> B = magpy.core.magnet_cyl_dia_H_Furlani1994(tetta, dim, obs, 1000)
-#     >>> print(B)
-#     [[-5.99240321e-02  1.41132875e-19  8.02440419e-03]
-#      [ 1.93282782e-03  2.19048077e-03  2.60408201e-02]
-#      [ 5.27008607e-02  6.06112282e-03  1.54692676e-02]]
-
-#     Notes
-#     -----
-#     H-Field computed from the charge picture, Simpsons approximation used
-#     to approximate the integral.
-#     """
-
-#     r0, z0 = dim.T/2
-#     r, phi, z = pos_obs.T
-#     n = len(r0)
-
-#     # phi is now relative between mag and pos_obs
-#     phi = phi-tetta
-
-#     #implementation of Furlani1993
-#     # generating the iterative summand basics for simpsons approximation
-#     phi0 = 2*np.pi/niter       # discretization
-#     sphi = np.arange(niter+1)
-#     sphi[sphi%2==0] = 2.
-#     sphi[sphi%2==1] = 4.
-#     sphi[0] = 1.
-#     sphi[-1] = 1.
-
-#     sphiex = np.outer(sphi, np.ones(n))
-#     phi0ex = np.outer(np.arange(niter+1), np.ones(n))*phi0
-#     zex    = np.outer(np.ones(niter+1), z)
-#     hex   = np.outer(np.ones(niter+1), z0)       # pylint: disable=redefined-builtin
-#     phiex  = np.outer(np.ones(niter+1), phi)
-#     dr2ex  = np.outer(np.ones(niter+1), 2*r0*r)
-#     r2d2ex = np.outer(np.ones(niter+1), r**2+r0**2)
-
-#     # repetitives
-#     cos_phi0ex = np.cos(phi0ex)
-#     cos_phi = np.cos(phiex-phi0ex)
-
-#     # compute r-phi components
-#     mask = (r2d2ex-dr2ex*cos_phi == 0) # special case r = d/2 and cos_phi=1
-#     unite  = np.ones([niter+1,n])
-#     unite[mask] = - (1/2)/(zex[mask]+hex[mask])**2 + (1/2)/(zex[mask]-hex[mask])**2
-
-#     rrc = r2d2ex[~mask] - dr2ex[~mask]*cos_phi[~mask]
-#     g_m = 1/np.sqrt(rrc + (zex[~mask] + hex[~mask])**2)
-#     g_p = 1/np.sqrt(rrc + (zex[~mask] - hex[~mask])**2)
-#     unite[~mask] = ((zex+hex)[~mask]*g_m - (zex-hex)[~mask]*g_p)/rrc
-
-#     summand = sphiex/3*cos_phi0ex*unite
-
-#     Br   = r0/2/niter*np.sum(summand*(r-r0*cos_phi), axis=0)
-#     Bphi = r0**2/2/niter*np.sum(summand*np.sin(phiex-phi0ex), axis=0)
-
-#     # compute z-component
-#     gz_m = 1/np.sqrt(r**2 + r0**2 - 2*r0*r*cos_phi + (zex+z0)**2)
-#     gz_p = 1/np.sqrt(r**2 + r0**2 - 2*r0*r*cos_phi + (zex-z0)**2)
-#     summandz = sphiex/3*cos_phi0ex*(gz_p - gz_m)
-#     Bz = r0/2/niter*np.sum(summandz, axis=0)
-
-#     return np.array([Br, Bphi, Bz]).T
+    return np.concatenate(((Bx,), (By,), (Bz,)), axis=0).T / MU0
diff --git a/magpylib/_src/fields/field_BH_cylinder_segment.py b/magpylib/_src/fields/field_BH_cylinder_segment.py
index eb22fdc98..f3f8cf9ce 100644
--- a/magpylib/_src/fields/field_BH_cylinder_segment.py
+++ b/magpylib/_src/fields/field_BH_cylinder_segment.py
@@ -10,6 +10,7 @@
 from magpylib._src.fields.field_BH_cylinder import magnet_cylinder_field
 from magpylib._src.fields.special_el3 import el3_angle
 from magpylib._src.input_checks import check_field_input
+from magpylib._src.utility import MU0
 
 
 def arctan_k_tan_2(k, phi):
@@ -2140,16 +2141,16 @@ def magnet_cylinder_segment_core(
     Parameters
     ----------
     mag: ndarray, shape (n,3)
-        magnetization vector (M, phi, th) in spherical CS, units: mT, rad
+        magnetization vector (M, phi, th) in spherical CS, units: T, rad
     obs_pos : ndarray, shape (n,3)
-        observer positions (r,phi,z) in cy CS, units: mm rad
+        observer positions (r,phi,z) in cy CS, units: m, rad
     dim: ndarray, shape (n,6)
-        segment dimensions (r1,r2,phi1,phi2,z1,z2) in cy CS , units: mm, rad
+        segment dimension (r1,r2,phi1,phi2,z1,z2) in cy CS , units: m, rad
 
     Returns
     -------
     H-field: ndarray
-        H-field in cylindrical coordinates (Hr, Hphi, Hz), shape (n,3) in units of kA/m.
+        H-field in cylindrical coordinates (Hr, Hphi, Hz), shape (n,3) in units of A/m.
 
     Notes
     -----
@@ -2299,7 +2300,7 @@ def magnet_cylinder_segment_core(
 def magnet_cylinder_segment_field_internal(
     field: str,
     observers: np.ndarray,
-    magnetization: np.ndarray,
+    polarization: np.ndarray,
     dimension: np.ndarray,
 ) -> np.ndarray:
     """
@@ -2308,7 +2309,7 @@ def magnet_cylinder_segment_field_internal(
     Falls back to magnet_cylinder_field whenever the section angles describe the full
     360° cylinder.
     """
-    n = len(magnetization)
+    n = len(polarization)
 
     BHfinal = np.zeros((n, 3))
 
@@ -2318,28 +2319,28 @@ def magnet_cylinder_segment_field_internal(
     mask1 = (phi2 - phi1) < 360
 
     BHfinal[mask1] = magnet_cylinder_segment_field(
-        field,
-        observers[mask1],
-        magnetization[mask1],
-        dimension[mask1],
+        field=field,
+        observers=observers[mask1],
+        polarization=polarization[mask1],
+        dimension=dimension[mask1],
     )
 
     # case2: full cylinder
     mask1x = ~mask1
     BHfinal[mask1x] = magnet_cylinder_field(
-        field,
-        observers[mask1x],
-        magnetization[mask1x],
-        np.c_[2 * r2[mask1x], h[mask1x]],
+        field=field,
+        observers=observers[mask1x],
+        polarization=polarization[mask1x],
+        dimension=np.c_[2 * r2[mask1x], h[mask1x]],
     )
 
     # case2a: hollow cylinder <- should be vectorized together with above
     mask2 = (r1 != 0) & mask1x
     BHfinal[mask2] -= magnet_cylinder_field(
-        field,
-        observers[mask2],
-        magnetization[mask2],
-        np.c_[2 * r1[mask2], h[mask2]],
+        field=field,
+        observers=observers[mask2],
+        polarization=polarization[mask2],
+        dimension=np.c_[2 * r1[mask2], h[mask2]],
     )
 
     return BHfinal
@@ -2347,36 +2348,40 @@ def magnet_cylinder_segment_field_internal(
 
 # CORE
 def magnet_cylinder_segment_field(
+    *,
     field: str,
     observers: np.ndarray,
-    magnetization: np.ndarray,
     dimension: np.ndarray,
+    polarization: np.ndarray,
 ) -> np.ndarray:
-    """Magnetic field of a homogeneously magnetized cylinder segment.
+    """Magnetic field of homogeneously magnetized cylinder segments.
 
-    The full cylinder axis coincides with the z-axis of the coordinate system. The geometric
-    center of the full cylinder lies in the origin.
+    The cylinder axis coincides with the z-axis of the global coordinate
+    system. The geometric center of the cylinder lies in the origin.
+
+    SI units are used for all inputs and outputs.
 
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
-
-    magnetization: ndarray, shape (n,3)
-        Homogeneous magnetization vector in units of mT.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
     dimension: ndarray, shape (n,5)
-        Cylinder segment dimensions (r1,r2,h,phi1,phi2) with inner radius r1, outer radius r2,
-        height h in units of mm and the two segment angles phi1 and phi2 in units of deg.
+        Dimensions of CylinderSegments (r1,r2,h,phi1,phi2) with inner radius
+        r1, outer radius r2, height h in units of m and the two segment
+        angles phi1 < phi2 in units of deg.
+
+    polarization: ndarray, shape (n,3)
+        Magnetic polarization vectors in units of T.
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of magnet in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
@@ -2384,23 +2389,29 @@ def magnet_cylinder_segment_field(
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>> mag = np.array([(0,0,100), (50,50,0)])
-    >>> dim = np.array([(0,1,2,0,90), (1,2,4,35,125)])
-    >>> obs = np.array([(1,1,1), (1,1,1)])
-    >>> B = magpy.core.magnet_cylinder_segment_field('B', obs, mag, dim)
+    >>> B = magpy.core.magnet_cylinder_segment_field(
+    ...     field='B',
+    ...     observers=np.array([(1,1,1), (1,1,1)]),
+    ...     dimension=np.array([(0,1,2,-90,90), (1,2,4,35,125)]),
+    ...     polarization=np.array([(0,0,1), (.5,.5,0)]),
+    ... )
     >>> print(B)
-    [[ 6.27410168  6.27410168 -1.20044166]
-     [29.84602335 20.75731598  0.34961733]]
+    [[ 0.07046526  0.08373724 -0.0198113 ]
+     [ 0.29846023  0.20757316  0.00349617]]
 
     Notes
     -----
-    Implementation based on
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
 
-    Slanovc: Journal of Magnetism and Magnetic Materials, 2022 (in review)
+    Implementation based on F.Slanovc, Journal of Magnetism and Magnetic
+    Materials, Volume 559, 1 October 2022, 169482
     """
     bh = check_field_input(field, "magnet_cylinder_segment_field()")
 
-    BHfinal = np.zeros((len(magnetization), 3))
+    BHfinal = np.zeros((len(polarization), 3))
 
     r1, r2, h, phi1, phi2 = dimension.T
     r1 = abs(r1)
@@ -2452,7 +2463,7 @@ def magnet_cylinder_segment_field(
         return BHfinal
 
     # redefine input if there are some surface-points -------------------------
-    magg = magnetization[mask_not_on_surf]
+    magg = polarization[mask_not_on_surf]
     dim = dim[mask_not_on_surf]
     pos_obs_cy = pos_obs_cy[mask_not_on_surf]
     phi = phi[mask_not_on_surf]
@@ -2468,15 +2479,15 @@ def magnet_cylinder_segment_field(
     Hr, Hphi, Hz = H_cy.T
     Hx = Hr * np.cos(phi) - Hphi * np.sin(phi)
     Hy = Hr * np.sin(phi) + Hphi * np.cos(phi)
-    H = np.concatenate(((Hx,), (Hy,), (Hz,)), axis=0).T * 10 / 4 / np.pi
+    H = np.concatenate(((Hx,), (Hy,), (Hz,)), axis=0).T
 
     # return B or H --------------------------------------------------------
     if not bh:
-        BHfinal[mask_not_on_surf] = H
+        BHfinal[mask_not_on_surf] = H / MU0
         return BHfinal
 
-    B = H / (10 / 4 / np.pi)  # kA/m -> mT
+    B = H
     BHfinal[mask_not_on_surf] = B
     maskX = mask_inside * mask_not_on_surf
-    BHfinal[maskX] += magnetization[maskX]
+    BHfinal[maskX] += polarization[maskX]
     return BHfinal
diff --git a/magpylib/_src/fields/field_BH_dipole.py b/magpylib/_src/fields/field_BH_dipole.py
index 49592d863..70cdd48d9 100644
--- a/magpylib/_src/fields/field_BH_dipole.py
+++ b/magpylib/_src/fields/field_BH_dipole.py
@@ -1,54 +1,65 @@
 """
-Dipole implementation
+Core implementation of dipole field
 """
 import numpy as np
 
 from magpylib._src.input_checks import check_field_input
+from magpylib._src.utility import MU0
 
 
 # CORE
 def dipole_field(
+    *,
     field: str,
     observers: np.ndarray,
     moment: np.ndarray,
 ) -> np.ndarray:
-    """Magnetic field of a dipole moment.
+    """Magnetic field of a dipole moments.
 
     The dipole moment lies in the origin of the coordinate system.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
     moment: ndarray, shape (n,3)
-        Dipole moment vector in units of mT*mm^3.
+        Dipole moment vector in units of A·m².
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of dipole in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
     Compute the B-field of two different dipole-observer instances.
 
-    >>> import numpy as np
     >>> import magpylib as magpy
-    >>> mom = np.array([(1,2,3), (0,0,1)])
-    >>> obs = np.array([(1,1,1), (0,0,2)])
-    >>> B = magpy.core.dipole_field('B', obs, mom)
+    >>> import numpy as np
+    >>> B = magpy.core.dipole_field(
+    ...     field="B",
+    ...     observers=np.array([(1,2,3), (-1,-2,-3)]),
+    ...     moment=np.array([(0,0,1e6), (1e5,0,1e7)])
+    ... )
     >>> print(B)
-    [[0.07657346 0.06125877 0.04594407]
-     [0.         0.         0.01989437]]
+    [[0.00122722 0.00245444 0.00177265]
+     [0.01212221 0.02462621 0.01784923]]
 
     Notes
     -----
-    The field is similar to the outside-field of a spherical magnet with Volume = 1 mm^3.
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
+    The moment of a magnet is given by its volume*magnetization.
     """
     bh = check_field_input(field, "dipole_field()")
 
@@ -58,13 +69,9 @@ def dipole_field(
         # 0/0 produces invalid warn and results in np.nan
         # x/0 produces divide warn and results in np.inf
         B = (
-            (
-                3 * np.sum(moment * observers, axis=1) * observers.T / r**5
-                - moment.T / r**3
-            ).T
-            / 4
-            / np.pi
-        )
+            3 * np.sum(moment * observers, axis=1) * observers.T / r**5
+            - moment.T / r**3
+        ).T * 1e-7
 
     # when r=0 return np.inf in all non-zero moment directions
     mask1 = r == 0
@@ -73,9 +80,8 @@ def dipole_field(
             B[mask1] = moment[mask1] / 0.0
             np.nan_to_num(B, copy=False, posinf=np.inf, neginf=np.NINF)
 
-    # return B or H
     if bh:
         return B
 
-    H = B * 10 / 4 / np.pi
+    H = B / MU0
     return H
diff --git a/magpylib/_src/fields/field_BH_polyline.py b/magpylib/_src/fields/field_BH_polyline.py
index 7f61c72f0..2ca9bb7ab 100644
--- a/magpylib/_src/fields/field_BH_polyline.py
+++ b/magpylib/_src/fields/field_BH_polyline.py
@@ -8,6 +8,7 @@
 
 from magpylib._src.exceptions import MagpylibDeprecationWarning
 from magpylib._src.input_checks import check_field_input
+from magpylib._src.utility import MU0
 
 
 def current_vertices_field(
@@ -27,14 +28,18 @@ def current_vertices_field(
     - bh (boolean): True=B, False=H
     - current (ndarray n): current on line in units of A
     - vertex_sets (list of len n): n vertex sets (each of shape (mi,3))
-    - pos_obs (ndarray nx3): n observer positions in units of mm
+    - pos_obs (ndarray nx3): n observer positions in units of m
 
     ### Returns:
-    - B-field (ndarray nx3): B-field vectors at pos_obs in units of mT
+    - B-field (ndarray nx3): B-field vectors at pos_obs in units of T
     """
     if vertices is None:
         return current_polyline_field(
-            field, observers, current, segment_start, segment_end
+            field=field,
+            observers=observers,
+            current=current,
+            segment_start=segment_start,
+            segment_end=segment_end,
         )
 
     nvs = np.array([f.shape[0] for f in vertices])  # lengths of vertices sets
@@ -65,39 +70,42 @@ def current_vertices_field(
 
 # CORE
 def current_polyline_field(
+    *,
     field: str,
     observers: np.ndarray,
-    current: np.ndarray,
     segment_start: np.ndarray,
     segment_end: np.ndarray,
+    current: np.ndarray,
 ) -> np.ndarray:
     """Magnetic field of line current segments.
 
     The current flows from start to end positions. The field is set to (0,0,0) on a
     line segment.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
-    current: ndarray, shape (n,)
-        Electrical current in units of A.
+    segment_start: ndarray, shape (n,3)
+        Polyline start positions (x,y,z) in Cartesian coordinates in units of m.
 
-    start: ndarray, shape (n,3)
-        Polyline start positions (x,y,z) in Cartesian coordinates in units of mm.
+    segment_end: ndarray, shape (n,3)
+        Polyline end positions (x,y,z) in Cartesian coordinates in units of m.
 
-    end: ndarray, shape (n,3)
-        Polyline end positions (x,y,z) in Cartesian coordinates in units of mm.
+    current: ndarray, shape (n,)
+        Electrical current in units of A.
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of current in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
@@ -106,17 +114,25 @@ def current_polyline_field(
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>> curr = np.array([1,2])
-    >>> start = np.array([(-1,0,0), (-1,0,0)])
-    >>> end   = np.array([( 1,0,0), ( 2,0,0)])
-    >>> obs   = np.array([( 0,0,1), ( 0,0,0)])
-    >>> B = magpy.core.current_polyline_field('B', obs, curr, start, end)
-    >>> print(B)
-    [[ 0.         -0.14142136  0.        ]
-     [ 0.          0.          0.        ]]
+    >>> H = magpy.core.current_polyline_field(
+    ...     field='H',
+    ...     observers=np.array([( 0,0,1)]*3),
+    ...     segment_start=np.array([(-.5,0,0), (.5,0,0), (1.5,0,0)]),
+    ...     segment_end=np.array([(-1.5,0,0), (-.5,0,0), (.5,0,0)]),
+    ...     current=np.array([1,1,1]),
+    ... )
+    >>> print(H)
+    [[ 0.          0.03062433 -0.        ]
+     [ 0.          0.07117625 -0.        ]
+     [ 0.          0.03062433 -0.        ]]
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
     Field computation via law of Biot Savart. See also countless online resources.
     eg. http://www.phys.uri.edu/gerhard/PHY204/tsl216.pdf
     """
@@ -204,18 +220,18 @@ def current_polyline_field(
     mask4 = ~mask2 * ~mask3
     deltaSin[mask4] = abs(sinTh1[mask4] + sinTh2[mask4])
 
-    field = (deltaSin / norm_o4 * eB.T / norm_12 * current / 10).T  # m->mm, T->mT
+    field = (deltaSin / norm_o4 * eB.T / norm_12 * current * 1e-7).T
 
     # broadcast general case results into allocated vector
     mask0[~mask0] = mask1
     field_all[~mask0] = field
 
-    # return B or H
+    # return B
     if bh:
         return field_all
 
-    # H: mT -> kA/m
-    return field_all * 10 / 4 / np.pi
+    # return H
+    return field_all / MU0
 
 
 def current_line_field(*args, **kwargs):
diff --git a/magpylib/_src/fields/field_BH_sphere.py b/magpylib/_src/fields/field_BH_sphere.py
index 900b5ec24..39d261cf0 100644
--- a/magpylib/_src/fields/field_BH_sphere.py
+++ b/magpylib/_src/fields/field_BH_sphere.py
@@ -5,38 +5,42 @@
 import numpy as np
 
 from magpylib._src.input_checks import check_field_input
+from magpylib._src.utility import MU0
 
 
 # CORE
 def magnet_sphere_field(
+    *,
     field: str,
     observers: np.ndarray,
-    magnetization: np.ndarray,
     diameter: np.ndarray,
+    polarization: np.ndarray,
 ) -> np.ndarray:
-    """Magnetic field of a homogeneously magnetized sphere.
+    """Magnetic field of homogeneously magnetized spheres.
 
     The center of the sphere lies in the origin of the coordinate system.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
-    magnetization: ndarray, shape (n,3)
-        Homogeneous magnetization vector in units of mT.
+    diameter: ndarray, shape (n,)
+        Sphere diameters in units of m.
 
-    diameter: ndarray, shape (n,3)
-        Sphere diameter in units of mm.
+    polarization: ndarray, shape (n,3)
+        Magnetic polarization vectors in units of T.
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of magnet in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
@@ -45,16 +49,23 @@ def magnet_sphere_field(
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>> dia = np.array([1,5])
-    >>> obs = np.array([(1,1,1), (1,1,1)])
-    >>> mag = np.array([(1,2,3), (0,0,3)])
-    >>> B = magpy.core.magnet_sphere_field('B', obs, mag, dia)
+    >>> B = magpy.core.magnet_sphere_field(
+    ...     field='B',
+    ...     observers=np.array([(1,1,1), (1,1,1)]),
+    ...     diameter=np.array([1,5]),
+    ...     polarization=np.array([(1,2,3), (0,0,3)]),
+    ... )
     >>> print(B)
     [[0.04009377 0.03207501 0.02405626]
      [0.         0.         2.        ]]
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
     The field corresponds to a dipole field on the outside and is 2/3*mag
     in the inside (see e.g. "Theoretical Physics, Bertelmann").
     """
@@ -68,12 +79,12 @@ def magnet_sphere_field(
     r0 = abs(diameter) / 2
 
     # inside field & allocate
-    B = magnetization * 2 / 3
+    B = polarization * 2 / 3
 
     # overwrite outside field entries
     mask_out = r >= r0
 
-    mag1 = magnetization[mask_out]
+    mag1 = polarization[mask_out]
     obs1 = observers[mask_out]
     r1 = r[mask_out]
     r01 = r0[mask_out]
@@ -89,6 +100,6 @@ def magnet_sphere_field(
         return B
 
     # adjust and return H
-    B[~mask_out] = -magnetization[~mask_out] / 3
-    H = B * 10 / 4 / np.pi
+    B[~mask_out] = -polarization[~mask_out] / 3
+    H = B / MU0
     return H
diff --git a/magpylib/_src/fields/field_BH_tetrahedron.py b/magpylib/_src/fields/field_BH_tetrahedron.py
index f2f70ba45..6a0f68458 100644
--- a/magpylib/_src/fields/field_BH_tetrahedron.py
+++ b/magpylib/_src/fields/field_BH_tetrahedron.py
@@ -57,35 +57,39 @@ def point_inside(points: np.ndarray, vertices: np.ndarray) -> np.ndarray:
     return inside
 
 
+# CORE
 def magnet_tetrahedron_field(
+    *,
     field: str,
     observers: np.ndarray,
-    magnetization: np.ndarray,
     vertices: np.ndarray,
+    polarization: np.ndarray,
 ) -> np.ndarray:
     """
-    Magnetic field generated by a homogeneously magnetized tetrahedron.
+    Magnetic field generated by a homogeneously magnetized tetrahedra.
+
+    SI units are used for all inputs and outputs.
 
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
-
-    magnetization: ndarray, shape (n,3)
-        Homogeneous magnetization vector in units of mT.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
     vertices: ndarray, shape (n,4,3)
         Vertices of the individual tetrahedrons [(pos1a, pos1b, pos1c, pos1d),
-        (pos2a, pos2b, pos2c, pos2d), ...].
+        (pos2a, pos2b, pos2c, pos2d), ...] given in units of m.
+
+    polarization: ndarray, shape (n,3)
+        Magnetic polarization vectors in units of T.
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of magnet in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
@@ -93,20 +97,26 @@ def magnet_tetrahedron_field(
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>>
-    >>> obs = np.array([(1,2,3), (2,3,4)])
-    >>> mag = np.array([(222,333,444), (111,112,113)])
-    >>> vert = np.array([((-1,0,0), (1,-1,0), (1,1,0), (0,0,1))]*2)
-    >>> B = magpy.core.magnet_tetrahedron_field('B', obs, mag, vert)
+    >>> B = magpy.core.magnet_tetrahedron_field(
+    ...     field='B',
+    ...     observers=np.array([(1,2,3), (2,3,4)]),
+    ...     vertices=np.array([((-1,0,0), (1,-1,0), (1,1,0), (0,0,1))]*2),
+    ...     polarization=np.array([(222,333,444), (111,112,113)]),
+    ... )
     >>> print(B)
     [[0.19075398 0.8240532  1.18170862]
      [0.03125701 0.08445416 0.1178967 ]]
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
     The tetrahedron is built up via 4 faces applying the Triangle class, making sure that
-    all normal vectors point outwards, and providing inside-outside evaluation to distinguish
-    between B- and H-field.
+    all normal vectors point outwards, and providing inside-outside evaluation to
+    distinguish between B- and H-field.
     """
 
     bh = check_field_input(field, "magnet_tetrahedron_field()")
@@ -124,10 +134,10 @@ def magnet_tetrahedron_field(
         axis=0,
     )
     tri_fields = triangle_field(
-        field,
-        np.tile(observers, (4, 1)),
-        np.tile(magnetization, (4, 1)),
-        tri_vertices,
+        field=field,
+        observers=np.tile(observers, (4, 1)),
+        vertices=tri_vertices,
+        polarization=np.tile(polarization, (4, 1)),
     )
     tetra_field = (  # slightly faster than reshape + sum
         tri_fields[:n]
@@ -139,7 +149,7 @@ def magnet_tetrahedron_field(
     if not bh:
         return tetra_field
 
-    # if B, and inside magnet add magnetization vector
+    # if B, and inside magnet add polarization vector
     mask_inside = point_inside(observers, vertices)
-    tetra_field[mask_inside] += magnetization[mask_inside]
+    tetra_field[mask_inside] += polarization[mask_inside]
     return tetra_field
diff --git a/magpylib/_src/fields/field_BH_triangle.py b/magpylib/_src/fields/field_BH_triangle.py
index e1bb45363..0691043b9 100644
--- a/magpylib/_src/fields/field_BH_triangle.py
+++ b/magpylib/_src/fields/field_BH_triangle.py
@@ -6,6 +6,7 @@
 import numpy as np
 
 from magpylib._src.input_checks import check_field_input
+from magpylib._src.utility import MU0
 
 
 def vcross3(a: np.ndarray, b: np.ndarray) -> np.ndarray:
@@ -71,13 +72,17 @@ def solid_angle(R: np.ndarray, r: np.ndarray) -> np.ndarray:
     return np.where(abs(result) > 6.2831853, 0, result)
 
 
+# CORE
 def triangle_field(
+    *,
     field: str,
     observers: np.ndarray,
-    magnetization: np.ndarray,
     vertices: np.ndarray,
+    polarization: np.ndarray,
 ) -> np.ndarray:
-    """Magnetic field generated by homogeneous (magnetic) charges on triangular surfaces.
+    """Magnetic field generated by homogeneously magnetically charged triangular surfaces.
+
+    SI units are used for all inputs and outputs.
 
     Can be used to compute the field of a homogeneously magnetized bodies
     with triangular surface mesh. In this case each Triangle must be defined so that the
@@ -86,26 +91,24 @@ def triangle_field(
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
-    magnetization: ndarray, shape (n,3)
-        Homogeneous magnetization vector in units of mT. The triangle surface charge is the
-        projection of the magnetization vector onto the surface normal vector. The order
-        of the vertices defines the sign of the normal vector (right-hand-rule).
+    dimensions: ndarray, shape (n,3)
+        Length of Cuboid sides in units of m.
 
-    vertices: ndarray, shape (n,3,3)
-        Vertices of triangular faces of the format
-        [(pos1a, pos1b, pos1c), (pos2a, pos2b, pos2c), ...].
-        The vertex order defines the normal vector orientation of the face (right-hand-rule).
+    polarization: ndarray, shape (n,3)
+        Magnetic polarization vectors in units of T. The triangle surface charge is the
+        projection of the polarization vector onto the surface normal vector. The order
+        of the vertices defines the sign of the normal vector (right-hand-rule).
 
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of magnet in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Examples
     --------
@@ -113,17 +116,23 @@ def triangle_field(
 
     >>> import numpy as np
     >>> import magpylib as magpy
-
-    >>> mag = np.array([(22,33,44), (33,44,55)])
-    >>> vert = np.array([((-1,0,0), (1,-1,0), (1,1,0))]*2)
-    >>> obs = np.array([(1,2,3), (2,3,4)])
-    >>> B = magpy.core.triangle_field('B', obs, mag, vert)
+    >>> B = magpy.core.triangle_field(
+    ...     field='B',
+    ...     observers=np.array([(-.1,.2,.1), (.1,.2,.1)]),
+    ...     vertices=np.array([((-1,0,0), (1,-1,0), (1,1,0))]*2),
+    ...     polarization=np.array([(.22,.33,.44), (.33,.44,.55)]),
+    ... )
     >>> print(B)
-    [[0.08836711 0.27062047 0.42198603]
-     [0.09721743 0.17609525 0.23937461]]
+    [[-0.0548087   0.05350955  0.17683832]
+     [-0.04252323  0.05292106  0.23092368]]
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
     Field computations implemented from Guptasarma, Geophysics, 1999, 64:1, 70-74.
     Corners give (nan, nan, nan). Edges and in-plane perp components are set to 0.
     Loss of precision when approaching a triangle as (x-edge)**2 :(
@@ -133,7 +142,7 @@ def triangle_field(
     bh = check_field_input(field, "triangle_field()")
 
     n = norm_vector(vertices)
-    sigma = np.einsum("ij, ij->i", n, magnetization)  # vectorized inner product
+    sigma = np.einsum("ij, ij->i", n, polarization)  # vectorized inner product
 
     # vertex <-> observer
     R = np.swapaxes(vertices, 0, 1) - observers
@@ -182,5 +191,5 @@ def triangle_field(
     if bh:
         return B.T / np.pi / 4.0
 
-    H = B.T / 1.6 / np.pi**2  # mT -> kA/m
+    H = B.T / 4 / np.pi / MU0
     return H
diff --git a/magpylib/_src/fields/field_BH_triangularmesh.py b/magpylib/_src/fields/field_BH_triangularmesh.py
index 070a81505..bd0de6caf 100644
--- a/magpylib/_src/fields/field_BH_triangularmesh.py
+++ b/magpylib/_src/fields/field_BH_triangularmesh.py
@@ -8,6 +8,7 @@
 import scipy.spatial
 
 from magpylib._src.fields.field_BH_triangle import triangle_field
+from magpylib._src.utility import MU0
 
 
 def calculate_centroid(vertices, faces):
@@ -493,33 +494,39 @@ def mask_inside_trimesh(points: np.ndarray, faces: np.ndarray) -> np.ndarray:
     return mask_inside
 
 
+# CORE LIKE - but is not a core function!
 def magnet_trimesh_field(
+    *,
     field: str,
     observers: np.ndarray,
-    magnetization: np.ndarray,
     mesh: np.ndarray,
+    polarization: np.ndarray,
     in_out="auto",
 ) -> np.ndarray:
     """
-    core-like function that computes the field of triangular meshes using the triangle_field
-    - closed nice meshes are assumed (input comes only from TriangularMesh class)
+    Core-like function that computes the field of triangular meshes using the triangle_field
+
+    !!!Closed meshes are assumed (input comes only from TriangularMesh class)!!!
+    This is the reasons that this is not a core function
+
+    SI units are used for all inputs and outputs.
 
     Parameters
     ----------
     field: str, default=`'B'`
-        If `field='B'` return B-field in units of mT, if `field='H'` return H-field
-        in units of kA/m.
+        If `field='B'` return B-field in units of T, if `field='H'` return H-field
+        in units of A/m.
 
     observers: ndarray, shape (n,3)
-        Observer positions (x,y,z) in Cartesian coordinates in units of mm.
-
-    magnetization: ndarray, shape (n,3)
-        Homogeneous magnetization vector in units of mT.
+        Observer positions (x,y,z) in Cartesian coordinates in units of m.
 
     mesh: ndarray, shape (n,n1,3,3) or ragged sequence
         Triangular mesh of shape [(x1,y1,z1), (x2,y2,z2), (x3,y3,z3)].
         `mesh` can be a ragged sequence of mesh-children with different lengths.
 
+    polarization: ndarray, shape (n,3)
+        Magnetic polarization vectors in units of T.
+
     in_out: {'auto', 'inside', 'outside'}
         Tells if the points are inside or outside the enclosing mesh for the correct B/H-field
         calculation. By default `in_out='auto'` and the inside/outside mask is automatically
@@ -531,10 +538,15 @@ def magnet_trimesh_field(
     Returns
     -------
     B-field or H-field: ndarray, shape (n,3)
-        B/H-field of magnet in Cartesian coordinates (Bx, By, Bz) in units of mT/(kA/m).
+        B- or H-field of source in Cartesian coordinates in units of T or A/m.
 
     Notes
     -----
+    Advanced unit use: The input unit of magnetization and polarization
+    gives the output unit of H and B. All results are independent of the
+    length input units. One must be careful, however, to use consistently
+    the same length unit throughout a script.
+
     Field computations via publication:
     Guptasarma: GEOPHYSICS 1999 64:1, 70-74
     """
@@ -542,12 +554,12 @@ def magnet_trimesh_field(
         n0, n1, *_ = mesh.shape
         vertices_tiled = mesh.reshape(-1, 3, 3)
         observers_tiled = np.repeat(observers, n1, axis=0)
-        magnetization_tiled = np.repeat(magnetization, n1, axis=0)
+        polarization_tiled = np.repeat(polarization, n1, axis=0)
         B = triangle_field(
             field="B",
             observers=observers_tiled,
-            magnetization=magnetization_tiled,
             vertices=vertices_tiled,
+            polarization=polarization_tiled,
         )
         B = B.reshape((n0, n1, 3))
         B = np.sum(B, axis=1)
@@ -556,12 +568,12 @@ def magnet_trimesh_field(
         split_indices = np.cumsum(nvs)[:-1]  # remove last to avoid empty split
         vertices_tiled = np.concatenate([f.reshape((-1, 3, 3)) for f in mesh])
         observers_tiled = np.repeat(observers, nvs, axis=0)
-        magnetization_tiled = np.repeat(magnetization, nvs, axis=0)
+        polarization_tiled = np.repeat(polarization, nvs, axis=0)
         B = triangle_field(
             field="B",
             observers=observers_tiled,
-            magnetization=magnetization_tiled,
             vertices=vertices_tiled,
+            polarization=polarization_tiled,
         )
         b_split = np.split(B, split_indices)
         B = np.array([np.sum(bh, axis=0) for bh in b_split])
@@ -569,7 +581,7 @@ def magnet_trimesh_field(
     if field == "B":
         if in_out == "auto":
             prev_ind = 0
-            # group similar meshs for inside-outside evaluation and adding B
+            # group similar meshes for inside-outside evaluation and adding B
             for new_ind, _ in enumerate(B):
                 if (
                     new_ind == len(B) - 1
@@ -581,14 +593,14 @@ def magnet_trimesh_field(
                     inside_mask = mask_inside_trimesh(
                         observers[prev_ind:new_ind], mesh[prev_ind]
                     )
-                    # if inside magnet add magnetization vector
-                    B[prev_ind:new_ind][inside_mask] += magnetization[prev_ind:new_ind][
+                    # if inside magnet add polarization vector
+                    B[prev_ind:new_ind][inside_mask] += polarization[prev_ind:new_ind][
                         inside_mask
                     ]
                     prev_ind = new_ind
         elif in_out == "inside":
-            B += magnetization
+            B += polarization
         return B
 
-    H = B * 10 / 4 / np.pi  # mT -> kA/m
+    H = B / MU0
     return H
diff --git a/magpylib/_src/fields/field_wrap_BH.py b/magpylib/_src/fields/field_wrap_BH.py
index 5cadd1efe..a266eefcd 100644
--- a/magpylib/_src/fields/field_wrap_BH.py
+++ b/magpylib/_src/fields/field_wrap_BH.py
@@ -166,7 +166,7 @@ def getBH_level2(
     squeeze : bool, default=True:
         If True output is squeezed (axes of length 1 are eliminated)
     pixel_agg : str
-        A compatible numpy aggregator string (e.g. `'min', 'max', 'mean'`)
+        A compatible numpy aggregator string (e.g. `'min'`, `'max'`, `'mean'`)
         which applies on pixel output values.
     field : {'B', 'H'}
         'B' computes B field, 'H' computes H-field
@@ -301,7 +301,12 @@ def getBH_level2(
     #   allows sensors with different pixel shapes <- relevant?
     poso = [
         [
-            r.apply(sens.pixel.reshape(-1, 3)) + p
+            (
+                np.array([[0, 0, 0]])
+                if sens.pixel is None
+                else r.apply(sens.pixel.reshape(-1, 3))
+            )
+            + p
             for r, p in zip(sens._orientation, sens._position)
         ]
         for sens in sensors
@@ -447,7 +452,7 @@ def getBH_dict_level2(
     squeeze=True,
     **kwargs: dict,
 ) -> np.ndarray:
-    """Direct interface access to vectorized computation
+    """Functional interface access to vectorized computation
 
     Parameters
     ----------
@@ -455,7 +460,7 @@ def getBH_dict_level2(
 
     Returns
     -------
-    field: ndarray, shape (N,3), field at obs_pos in mT or kA/m
+    field: ndarray, shape (N,3), field at obs_pos in tesla or A/m
 
     Info
     ----
@@ -488,7 +493,7 @@ def getBH_dict_level2(
     except KeyError as err:
         raise MagpylibBadUserInput(
             f"Input parameter `sources` must be one of {list(source_classes)}"
-            " when using the direct interface."
+            " when using the functional interface."
         ) from err
 
     kwargs["observers"] = observers
@@ -557,7 +562,7 @@ def getB(
     output="ndarray",
     **kwargs,
 ):
-    """Compute B-field in units of mT for given sources and observers.
+    """Compute B-field in units of T for given sources and observers.
 
     Field implementations can be directly accessed (avoiding the object oriented
     Magpylib interface) by providing a string input `sources=source_type`, array_like
@@ -568,19 +573,19 @@ def getB(
     ----------
     sources: source and collection objects or 1D list thereof
         Sources that generate the magnetic field. Can be a single source (or collection)
-        or a 1D list of l source and/or collection objects.
+        or a 1D list of l sources and/or collection objects.
 
-        Direct interface: input must be one of (`'Cuboid'`, `'Cylinder'`, `'CylinderSegment'`,
-        `'Sphere'`, `'Dipole'`, `'Circle'` or `'Polyline'`).
+        Functional interface: input must be one of (`Cuboid`, `Cylinder`, `CylinderSegment`,
+        `Sphere`, `Dipole`, `Circle` or `Polyline`).
 
     observers: array_like or (list of) `Sensor` objects
         Can be array_like positions of shape (n1, n2, ..., 3) where the field
         should be evaluated, a `Sensor` object with pixel shape (n1, n2, ..., 3) or a list
         of such sensor objects (must all have similar pixel shapes). All positions
-        are given in units of mm.
+        are given in units of m.
 
-        Direct interface: Input must be array_like with shape (3,) or (n,3) corresponding
-        positions to observer positions in units of mm.
+        Functional interface: Input must be array_like with shape (3,) or (n,3) corresponding
+        positions to observer positions in units of m.
 
     sumup: bool, default=`False`
         If `True`, the fields of all sources are summed up.
@@ -594,64 +599,71 @@ def getB(
         which is applied to observer output values, e.g. mean of all sensor pixel outputs.
         With this option, observers input with different (pixel) shapes is allowed.
 
-    output: str, default='ndarray'
-        Output type, which must be one of `('ndarray', 'dataframe')`. By default a
-        `numpy.ndarray` object is returned. If 'dataframe' is chosen, a `pandas.DataFrame`
+    output: str, default=`'ndarray'`
+        Output type, which must be one of (`'ndarray'`, `'dataframe'`). By default a
+        `numpy.ndarray` object is returned. If `'dataframe'` is chosen, a `pandas.DataFrame`
         object is returned (the Pandas library must be installed).
 
     See Also
     --------
-    *Direct-interface
+    *Functional interface
 
     position: array_like, shape (3,) or (n,3), default=`(0,0,0)`
-        Source position(s) in the global coordinates in units of mm.
+        Source position(s) in the global coordinates in units of m.
 
     orientation: scipy `Rotation` object with length 1 or n, default=`None`
         Object orientation(s) in the global coordinates. `None` corresponds to
         a unit-rotation.
 
-    magnetization: array_like, shape (3,) or (n,3)
-        Only source_type in (`'Cuboid'`, `'Cylinder'`, `'CylinderSegment'`, `'Sphere'`)!
-        Magnetization vector(s) (mu0*M, remanence field) in units of kA/m given in
-        the local object coordinates (rotates with object).
+    polarization: array_like, shape (3,) or (n,3)
+        Only source_type in (`Cuboid`, `Cylinder`, `CylinderSegment`, `Sphere`,
+        `Tetrahedron`, `Triangle`, `TriangularMesh`)!
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).
 
-    moment: array_like, shape (3) or (n,3), unit mT*mm^3
-        Only source_type == `'Dipole'`!
-        Magnetic dipole moment(s) in units of mT*mm^3 given in the local object coordinates
+    magnetization: array_like, shape (3,) or (n,3)
+        Only source_type in (`Cuboid`, `Cylinder`, `CylinderSegment`, `Sphere`,
+        `Tetrahedron`, `Triangle`, `TriangularMesh`)!
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).
+
+    moment: array_like, shape (3) or (n,3), unit A·m²
+        Only source_type == `Dipole`!
+        Magnetic dipole moment(s) in units of A·m² given in the local object coordinates
         (rotates with object). For homogeneous magnets the relation moment=magnetization*volume
         holds.
 
     current: array_like, shape (n,)
-        Only source_type == `'Circle'` or `'Polyline'`!
+        Only source_type == `Circle` or `Polyline`!
         Electrical current in units of A.
 
     dimension: array_like, shape (x,) or (n,x)
-        Only source_type in (`'Cuboid'`, `'Cylinder'`, `'CylinderSegment'`)!
-        Magnet dimension input in units of mm and deg. Dimension format x of sources is similar
+        Only source_type in (`Cuboid`, `Cylinder`, `CylinderSegment`)!
+        Magnet dimension input in units of m and deg. Dimension format x of sources is similar
         as in object oriented interface.
 
     diameter: array_like, shape (n,)
-        Only source_type == `'Sphere'` or `'Circle'`!
-        Diameter of source in units of mm.
+        Only source_type == `Sphere` or `Circle`!
+        Diameter of source in units of m.
 
     segment_start: array_like, shape (n,3)
-        Only source_type == `'Polyline'`!
-        Start positions of line current segments in units of mm.
+        Only source_type == `Polyline`!
+        Start positions of line current segments in units of m.
 
     segment_end: array_like, shape (n,3)
-        Only source_type == `'Polyline'`!
-        End positions of line current segments in units of mm.
+        Only source_type == `Polyline`!
+        End positions of line current segments in units of m.
 
     Returns
     -------
     B-field: ndarray, shape squeeze(m, k, n1, n2, ..., 3) or DataFrame
-        B-field at each path position (m) for each sensor (k) and each sensor pixel
-        position (n1, n2, ...) in units of mT. Sensor pixel positions are equivalent
-        to simple observer positions. Paths of objects that are shorter than m will be
+        B-field at each path position (index m) for each sensor (index k) and each sensor pixel
+        position (indices n1, n2, ...) in units of T. Sensor pixel positions are equivalent
+        to simple observer positions. Paths of objects that are shorter than index m are
         considered as static beyond their end.
 
-    Direct interface: ndarray, shape (n,3)
-        B-field for every parameter set in units of mT.
+    Functional interface: ndarray, shape (n,3)
+        B-field for every parameter set in units of T.
 
     Notes
     -----
@@ -661,51 +673,51 @@ def getB(
 
     Examples
     --------
-    In this example we compute the B-field in units of mT of a spherical magnet and a current loop
-    at the observer position (1,1,1) given in units of mm:
+    In this example we compute the B-field in T of a spherical magnet and a current
+    loop at the observer position (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> src1 = magpy.current.Circle(current=100, diameter=2)
-    >>> src2 = magpy.magnet.Sphere(magnetization=(0,0,100), diameter=1)
-    >>> B = magpy.getB([src1, src2], (1,1,1))
+    >>> src1 = magpy.current.Circle(current=100, diameter=.002)
+    >>> src2 = magpy.magnet.Sphere(polarization=(0,0,.1), diameter=.001)
+    >>> B = magpy.getB([src1, src2], (.01,.01,.01))
     >>> print(B)
-    [[6.23597388e+00 6.23597388e+00 2.66977810e+00]
-     [8.01875374e-01 8.01875374e-01 1.48029737e-16]]
+    [[6.05434592e-06 6.05434592e-06 2.35680448e-08]
+     [8.01875374e-07 8.01875374e-07 1.51582450e-22]]
 
     We can also use sensor objects as observers input:
 
-    >>> sens1 = magpy.Sensor(position=(1,1,1))
-    >>> sens2 = sens1.copy(position=(1,1,-1))
+    >>> sens1 = magpy.Sensor(position=(.01,.01,.01))
+    >>> sens2 = sens1.copy(position=(.01,.01,-.01))
     >>> B = magpy.getB([src1, src2], [sens1, sens2])
     >>> print(B)
-    [[[ 6.23597388e+00  6.23597388e+00  2.66977810e+00]
-      [-6.23597388e+00 -6.23597388e+00  2.66977810e+00]]
+    [[[ 6.05434592e-06  6.05434592e-06  2.35680448e-08]
+      [-6.05434592e-06 -6.05434592e-06  2.35680448e-08]]
     <BLANKLINE>
-     [[ 8.01875374e-01  8.01875374e-01  1.48029737e-16]
-      [-8.01875374e-01 -8.01875374e-01  1.48029737e-16]]]
+     [[ 8.01875374e-07  8.01875374e-07  1.51582450e-22]
+      [-8.01875374e-07 -8.01875374e-07  1.51582450e-22]]]
 
-    Through the direct interface we can compute the same fields for the loop as:
+    Through the functional interface we can compute the same fields for the loop as:
 
-    >>> obs = [(1,1,1), (1,1,-1)]
-    >>> B = magpy.getB('Circle', obs, current=100, diameter=2)
+    >>> obs = [(.01,.01,.01), (.01,.01,-.01)]
+    >>> B = magpy.getB('Circle', obs, current=100, diameter=.002)
     >>> print(B)
-    [[ 6.23597388  6.23597388  2.6697781 ]
-     [-6.23597388 -6.23597388  2.6697781 ]]
+    [[ 6.05434592e-06  6.05434592e-06  2.35680448e-08]
+     [-6.05434592e-06 -6.05434592e-06  2.35680448e-08]]
 
     But also for a set of four completely different instances:
 
     >>> B = magpy.getB(
     ...     'Circle',
-    ...     observers=((1,1,1), (1,1,-1), (1,2,3), (2,2,2)),
+    ...     observers=((.01,.01,.01), (.01,.01,-.01), (.01,.02,.03), (.02,.02,.02)),
     ...     current=(11, 22, 33, 44),
-    ...     diameter=(1, 2, 3, 4),
-    ...     position=((0,0,0), (0,0,1), (0,0,2), (0,0,3)),
+    ...     diameter=(.001, .002, .003, .004),
+    ...     position=((0,0,0), (0,0,.01), (0,0,.02), (0,0,.03)),
     ... )
     >>> print(B)
-    [[ 0.17111325  0.17111325  0.01705189]
-     [-0.38852048 -0.38852048  0.49400758]
-     [ 1.14713551  2.29427102 -0.22065346]
-     [-2.48213467 -2.48213467 -0.79683487]]
+    [[ 1.66322588e-07  1.66322588e-07  1.61742625e-10]
+     [-4.69451597e-07 -4.69451597e-07  4.70690813e-07]
+     [ 7.96993186e-07  1.59398637e-06 -7.91258466e-07]
+     [-1.37369334e-06 -1.37369334e-06 -1.36554287e-06]]
     """
     return getBH_level2(
         sources,
@@ -728,7 +740,7 @@ def getH(
     output="ndarray",
     **kwargs,
 ):
-    """Compute H-field in kA/m for given sources and observers.
+    """Compute H-field in units of A/m for given sources and observers.
 
     Field implementations can be directly accessed (avoiding the object oriented
     Magpylib interface) by providing a string input `sources=source_type`, array_like
@@ -739,19 +751,19 @@ def getH(
     ----------
     sources: source and collection objects or 1D list thereof
         Sources that generate the magnetic field. Can be a single source (or collection)
-        or a 1D list of l source and/or collection objects.
+        or a 1D list of l sources and/or collection objects.
 
-        Direct interface: input must be one of (`'Cuboid'`, `'Cylinder'`, `'CylinderSegment'`,
-        `'Sphere'`, `'Dipole'`, `'Circle'` or `'Polyline'`).
+        Functional interface: input must be one of (`Cuboid`, `Cylinder`, `CylinderSegment`,
+        `Sphere`, `Dipole`, `Circle` or `Polyline`).
 
     observers: array_like or (list of) `Sensor` objects
         Can be array_like positions of shape (n1, n2, ..., 3) where the field
         should be evaluated, a `Sensor` object with pixel shape (n1, n2, ..., 3) or a list
         of such sensor objects (must all have similar pixel shapes). All positions
-        are given in units of mm.
+        are given in units of m.
 
-        Direct interface: Input must be array_like with shape (3,) or (n,3) corresponding
-        positions to observer positions in units of mm.
+        Functional interface: Input must be array_like with shape (3,) or (n,3) corresponding
+        positions to observer positions in units of m.
 
     sumup: bool, default=`False`
         If `True`, the fields of all sources are summed up.
@@ -765,64 +777,64 @@ def getH(
         which is applied to observer output values, e.g. mean of all sensor pixel outputs.
         With this option, observers input with different (pixel) shapes is allowed.
 
-    output: str, default='ndarray'
-        Output type, which must be one of `('ndarray', 'dataframe')`. By default a
-        `numpy.ndarray` object is returned. If 'dataframe' is chosen, a `pandas.DataFrame`
+    output: str, default=`'ndarray'`
+        Output type, which must be one of (`'ndarray'`, `'dataframe'`). By default a
+        `numpy.ndarray` object is returned. If `'dataframe'` is chosen, a `pandas.DataFrame`
         object is returned (the Pandas library must be installed).
 
     See Also
     --------
-    *Direct-interface
+    *Functional interface
 
     position: array_like, shape (3,) or (n,3), default=`(0,0,0)`
-        Source position(s) in the global coordinates in units of mm.
+        Source position(s) in the global coordinates in units of m.
 
     orientation: scipy `Rotation` object with length 1 or n, default=`None`
         Object orientation(s) in the global coordinates. `None` corresponds to
         a unit-rotation.
 
     magnetization: array_like, shape (3,) or (n,3)
-        Only source_type in (`'Cuboid'`, `'Cylinder'`, `'CylinderSegment'`, `'Sphere'`)!
-        Magnetization vector(s) (mu0*M, remanence field) in units of kA/m given in
+        Only source_type in (`Cuboid`, `Cylinder`, `CylinderSegment`, `Sphere`)!
+        Magnetization vector(s) (mu0*M, remanence field) in units of A/m given in
         the local object coordinates (rotates with object).
 
-    moment: array_like, shape (3) or (n,3), unit mT*mm^3
-        Only source_type == `'Dipole'`!
-        Magnetic dipole moment(s) in units of mT*mm^3 given in the local object coordinates
+    moment: array_like, shape (3) or (n,3), unit A·m²
+        Only source_type == `Dipole`!
+        Magnetic dipole moment(s) in units of A·m² given in the local object coordinates
         (rotates with object). For homogeneous magnets the relation moment=magnetization*volume
         holds.
 
     current: array_like, shape (n,)
-        Only source_type == `'Circle'` or `'Polyline'`!
+        Only source_type == `Circle` or `Polyline`!
         Electrical current in units of A.
 
     dimension: array_like, shape (x,) or (n,x)
-        Only source_type in (`'Cuboid'`, `'Cylinder'`, `'CylinderSegment'`)!
-        Magnet dimension input in units of mm and deg. Dimension format x of sources is similar
+        Only source_type in (`Cuboid`, `Cylinder`, `CylinderSegment`)!
+        Magnet dimension input in units of m and deg. Dimension format x of sources is similar
         as in object oriented interface.
 
     diameter: array_like, shape (n,)
-        Only source_type == `'Sphere'` or `'Circle'`!
-        Diameter of source in units of mm.
+        Only source_type == `Sphere` or `Circle`!
+        Diameter of source in units of m.
 
     segment_start: array_like, shape (n,3)
-        Only source_type == `'Polyline'`!
-        Start positions of line current segments in units of mm.
+        Only source_type == `Polyline`!
+        Start positions of line current segments in units of m.
 
     segment_end: array_like, shape (n,3)
-        Only source_type == `'Polyline'`!
-        End positions of line current segments in units of mm.
+        Only source_type == `Polyline`!
+        End positions of line current segments in units of m.
 
     Returns
     -------
     H-field: ndarray, shape squeeze(m, k, n1, n2, ..., 3) or DataFrame
-        H-field at each path position (m) for each sensor (k) and each sensor pixel
-        position (n1, n2, ...) in units of kA/m. Sensor pixel positions are equivalent
-        to simple observer positions. Paths of objects that are shorter than m will be
+        H-field at each path position (index m) for each sensor (index k) and each sensor pixel
+        position (indices n1, n2, ...) in units of A/m. Sensor pixel positions are equivalent
+        to simple observer positions. Paths of objects that are shorter than index m are
         considered as static beyond their end.
 
-    Direct interface: ndarray, shape (n,3)
-        H-field for every parameter set in units of kA/m.
+    Functional interface: ndarray, shape (n,3)
+        H-field for every parameter set in units of A/m.
 
     Notes
     -----
@@ -832,51 +844,51 @@ def getH(
 
     Examples
     --------
-    In this example we compute the H-field kA/m of a spherical magnet and a current loop
-    at the observer position (1,1,1) given in units of mm:
+    In this example we compute the H-field in A/m of a spherical magnet and a current loop
+    at the observer position (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> src1 = magpy.current.Circle(current=100, diameter=2)
-    >>> src2 = magpy.magnet.Sphere(magnetization=(0,0,100), diameter=1)
-    >>> H = magpy.getH([src1, src2], (1,1,1))
+    >>> src1 = magpy.current.Circle(current=100, diameter=.002)
+    >>> src2 = magpy.magnet.Sphere(polarization=(0,0,.1), diameter=.001)
+    >>> H = magpy.getH([src1, src2], (.01,.01,.01))
     >>> print(H)
-    [[4.96243034e+00 4.96243034e+00 2.12454191e+00]
-     [6.38112147e-01 6.38112147e-01 1.17798322e-16]]
+    [[4.81789540e+00 4.81789540e+00 1.87548541e-02]
+     [6.38112147e-01 6.38112147e-01 1.20625481e-16]]
 
     We can also use sensor objects as observers input:
 
-    >>> sens1 = magpy.Sensor(position=(1,1,1))
-    >>> sens2 = sens1.copy(position=(1,1,-1))
+    >>> sens1 = magpy.Sensor(position=(.01,.01,.01))
+    >>> sens2 = sens1.copy(position=(.01,.01,-.01))
     >>> H = magpy.getH([src1, src2], [sens1, sens2])
     >>> print(H)
-    [[[ 4.96243034e+00  4.96243034e+00  2.12454191e+00]
-      [-4.96243034e+00 -4.96243034e+00  2.12454191e+00]]
+    [[[ 4.81789540e+00  4.81789540e+00  1.87548541e-02]
+      [-4.81789540e+00 -4.81789540e+00  1.87548541e-02]]
     <BLANKLINE>
-     [[ 6.38112147e-01  6.38112147e-01  1.17798322e-16]
-      [-6.38112147e-01 -6.38112147e-01  1.17798322e-16]]]
+     [[ 6.38112147e-01  6.38112147e-01  1.20625481e-16]
+      [-6.38112147e-01 -6.38112147e-01  1.20625481e-16]]]
 
-    Through the direct interface we can compute the same fields for the loop as:
+    Through the functional interface we can compute the same fields for the loop as:
 
-    >>> obs = [(1,1,1), (1,1,-1)]
-    >>> H = magpy.getH('Circle', obs, current=100, diameter=2)
+    >>> obs = [(.01,.01,.01), (.01,.01,-.01)]
+    >>> H = magpy.getH('Circle', obs, current=100, diameter=.002)
     >>> print(H)
-    [[ 4.96243034  4.96243034  2.12454191]
-     [-4.96243034 -4.96243034  2.12454191]]
+    [[ 4.8178954   4.8178954   0.01875485]
+     [-4.8178954  -4.8178954   0.01875485]]
 
     But also for a set of four completely different instances:
 
     >>> H = magpy.getH(
     ...     'Circle',
-    ...     observers=((1,1,1), (1,1,-1), (1,2,3), (2,2,2)),
+    ...     observers=((.01,.01,.01), (.01,.01,-.01), (.01,.02,.03), (.02,.02,.02)),
     ...     current=(11, 22, 33, 44),
-    ...     diameter=(1, 2, 3, 4),
-    ...     position=((0,0,0), (0,0,1), (0,0,2), (0,0,3)),
+    ...     diameter=(.001, .002, .003, .004),
+    ...     position=((0,0,0), (0,0,.01), (0,0,.02), (0,0,.03)),
     ... )
     >>> print(H)
-    [[ 0.1361676   0.1361676   0.01356947]
-     [-0.30917477 -0.30917477  0.39311875]
-     [ 0.91286143  1.82572286 -0.17559045]
-     [-1.97522001 -1.97522001 -0.63410104]]
+    [[ 1.32355310e-01  1.32355310e-01  1.28710691e-04]
+     [-3.73577711e-01 -3.73577711e-01  3.74563848e-01]
+     [ 6.34227026e-01  1.26845405e+00 -6.29663481e-01]
+     [-1.09315042e+00 -1.09315042e+00 -1.08666449e+00]]
     """
     return getBH_level2(
         sources,
diff --git a/magpylib/_src/input_checks.py b/magpylib/_src/input_checks.py
index f108ac559..06ab08183 100644
--- a/magpylib/_src/input_checks.py
+++ b/magpylib/_src/input_checks.py
@@ -505,7 +505,8 @@ def check_format_input_observers(inp, pixel_agg=None):
 
         # all pixel shapes must be the same
         pix_shapes = [
-            (1, 3) if s.pixel.shape == (3,) else s.pixel.shape for s in sensors
+            (1, 3) if (s.pixel is None or s.pixel.shape == (3,)) else s.pixel.shape
+            for s in sensors
         ]
         if pixel_agg is None and not all_same(pix_shapes):
             raise MagpylibBadUserInput(
@@ -595,7 +596,7 @@ def check_dimensions(sources):
 def check_excitations(sources):
     """check if all sources have excitation initialized"""
     for src in sources:
-        for arg in ("magnetization", "current", "moment"):
+        for arg in ("polarization", "current", "moment"):
             if hasattr(src, arg):
                 if getattr(src, arg) is None:
                     raise MagpylibMissingInput(
diff --git a/magpylib/_src/obj_classes/class_BaseDisplayRepr.py b/magpylib/_src/obj_classes/class_BaseDisplayRepr.py
index 726651828..b69b93e7b 100644
--- a/magpylib/_src/obj_classes/class_BaseDisplayRepr.py
+++ b/magpylib/_src/obj_classes/class_BaseDisplayRepr.py
@@ -8,12 +8,14 @@
 
 UNITS = {
     "parent": None,
-    "position": "mm",
-    "orientation": "degrees",
-    "dimension": "mm",
-    "diameter": "mm",
+    "position": "m",
+    "orientation": "deg",
+    "dimension": "m",
+    "diameter": "m",
     "current": "A",
-    "magnetization": "mT",
+    "magnetization": "A/m",
+    "polarization": "T",
+    "moment": "A·m²",
 }
 
 
@@ -61,11 +63,12 @@ def _get_description(self, exclude=None):
                     val = f"{val[-1]}"
                 elif k == "pixel":
                     val = getattr(self, "pixel")
-                    px_shape = val.shape[:-1]
-                    val_str = f"{int(np.prod(px_shape))}"
-                    if val.ndim > 2:
-                        val_str += f" ({'x'.join(str(p) for p in px_shape)})"
-                    val = val_str
+                    if val is not None:
+                        px_shape = val.shape[:-1]
+                        val_str = f"{int(np.prod(px_shape))}"
+                        if val.ndim > 2:
+                            val_str += f" ({'x'.join(str(p) for p in px_shape)})"
+                        val = val_str
                 elif k == "status_disconnected_data":
                     val = getattr(self, k)
                     if val is not None:
diff --git a/magpylib/_src/obj_classes/class_BaseExcitations.py b/magpylib/_src/obj_classes/class_BaseExcitations.py
index 8d94b74ba..20ce7f91e 100644
--- a/magpylib/_src/obj_classes/class_BaseExcitations.py
+++ b/magpylib/_src/obj_classes/class_BaseExcitations.py
@@ -1,5 +1,10 @@
 """BaseHomMag class code"""
 # pylint: disable=cyclic-import
+import warnings
+
+import numpy as np
+
+from magpylib._src.exceptions import MagpylibDeprecationWarning
 from magpylib._src.fields.field_wrap_BH import getBH_level2
 from magpylib._src.input_checks import check_format_input_scalar
 from magpylib._src.input_checks import check_format_input_vector
@@ -30,7 +35,7 @@ def field_func(self):
         """
         The function for B- and H-field computation must have the two positional arguments
         `field` and `observers`. With `field='B'` or `field='H'` the B- or H-field in units
-        of mT or kA/m must be returned respectively. The `observers` argument must
+        of T or A/m must be returned respectively. The `observers` argument must
         accept numpy ndarray inputs of shape (n,3), in which case the returned fields must
         be numpy ndarrays of shape (n,3) themselves.
         """
@@ -47,15 +52,17 @@ def field_func(self, val):
         self._field_func = val
 
     def getB(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
-        """Compute the B-field in units of mT generated by the source.
+        """Compute the B-field at observers in units of T generated by the source.
+
+        SI units are used for all inputs and outputs.
 
         Parameters
         ----------
         observers: array_like or (list of) `Sensor` objects
             Can be array_like positions of shape (n1, n2, ..., 3) where the field
             should be evaluated, a `Sensor` object with pixel shape (n1, n2, ..., 3) or a list
-            of such sensor objects (must all have similar pixel shapes). All positions
-            are given in units of mm.
+            of such sensor objects (must all have similar pixel shapes). All positions are given
+            in units of m.
 
         squeeze: bool, default=`True`
             If `True`, the output is squeezed, i.e. all axes of length 1 in the output (e.g.
@@ -75,9 +82,9 @@ def getB(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
         Returns
         -------
         B-field: ndarray, shape squeeze(m, k, n1, n2, ..., 3) or DataFrame
-            B-field at each path position (m) for each sensor (k) and each sensor pixel
-            position (n1,n2,...) in units of mT. Sensor pixel positions are equivalent
-            to simple observer positions. Paths of objects that are shorter than m will be
+            B-field at each path position (index m) for each sensor (index k) and each sensor
+            pixel position (indices n1,n2,...) in units of T. Sensor pixel positions are equivalent
+            to simple observer positions. Paths of objects that are shorter than index m will be
             considered as static beyond their end.
 
         Examples
@@ -85,12 +92,12 @@ def getB(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
         Compute the B-field of a spherical magnet at three positions:
 
         >>> import magpylib as magpy
-        >>> src = magpy.magnet.Sphere((0,0,1000), 1)
+        >>> src = magpy.magnet.Sphere(polarization=(0,0,1.), diameter=1)
         >>> B = src.getB(((0,0,0), (1,0,0), (2,0,0)))
         >>> print(B)
-        [[  0.           0.         666.66666667]
-         [  0.           0.         -41.66666667]
-         [  0.           0.          -5.20833333]]
+        [[ 0.          0.          0.66666667]
+         [ 0.          0.         -0.04166667]
+         [ 0.          0.         -0.00520833]]
 
         Compute the B-field at two sensors, each one with two pixels
 
@@ -98,11 +105,11 @@ def getB(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
         >>> sens2 = sens1.copy(position=(2,0,0))
         >>> B = src.getB(sens1, sens2)
         >>> print(B)
-        [[[ 12.19288783   0.         -39.83010025]
-          [-12.19288783   0.         -39.83010025]]
+        [[[ 0.01219289  0.         -0.0398301 ]
+          [-0.01219289  0.         -0.0398301 ]]
         <BLANKLINE>
-         [[  0.77638847   0.          -5.15004352]
-          [ -0.77638847   0.          -5.15004352]]]
+         [[ 0.00077639  0.         -0.00515004]
+          [-0.00077639  0.         -0.00515004]]]
         """
         observers = format_star_input(observers)
         return getBH_level2(
@@ -116,7 +123,7 @@ def getB(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
         )
 
     def getH(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
-        """Compute the H-field in units of kA/m generated by the source.
+        """Compute the H-field in units of A/m at observers generated by the source.
 
         Parameters
         ----------
@@ -124,7 +131,7 @@ def getH(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
             Can be array_like positions of shape (n1, n2, ..., 3) where the field
             should be evaluated, a `Sensor` object with pixel shape (n1, n2, ..., 3) or a list
             of such sensor objects (must all have similar pixel shapes). All positions
-            are given in units of mm.
+            are given in units of m.
 
         squeeze: bool, default=`True`
             If `True`, the output is squeezed, i.e. all axes of length 1 in the output (e.g.
@@ -144,10 +151,10 @@ def getH(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
         Returns
         -------
         H-field: ndarray, shape squeeze(m, k, n1, n2, ..., 3) or DataFrame
-            H-field at each path position (m) for each sensor (k) and each sensor pixel
-            position (n1,n2,...) in units of kA/m. Sensor pixel positions are equivalent
-            to simple observer positions. Paths of objects that are shorter than m will be
-            considered as static beyond their end.
+            H-field at each path position (index m) for each sensor (index k) and each sensor
+            pixel position (indices n1,n2,...) in units of A/m. Sensor pixel positions are
+            equivalent to simple observer positions. Paths of objects that are shorter than
+            index m will be considered as static beyond their end.
 
         Examples
         --------
@@ -155,12 +162,12 @@ def getH(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
 
         >>> import magpylib as magpy
 
-        >>> src = magpy.magnet.Sphere((0,0,1000), 1)
+        >>> src = magpy.magnet.Sphere(polarization=(0,0,1.), diameter=1)
         >>> H = src.getH(((0,0,0), (1,0,0), (2,0,0)))
         >>> print(H)
-        [[   0.            0.         -265.25823849]
-         [   0.            0.          -33.15727981]
-         [   0.            0.           -4.14465998]]
+        [[      0.               0.         -265258.23848649]
+         [      0.               0.          -33157.27981081]
+         [      0.               0.           -4144.65997635]]
 
         Compute the H-field at two sensors, each one with two pixels
 
@@ -168,11 +175,12 @@ def getH(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
         >>> sens2 = sens1.copy(position=(2,0,0))
         >>> H = src.getH(sens1, sens2)
         >>> print(H)
-        [[[  9.70279185   0.         -31.69578669]
-          [ -9.70279185   0.         -31.69578669]]
+        [[[  9702.7918453       0.         -31695.78669464]
+          [ -9702.7918453       0.         -31695.78669464]]
         <BLANKLINE>
-         [[  0.61783031   0.          -4.09827441]
-          [ -0.61783031   0.          -4.09827441]]]
+         [[   617.83031378      0.          -4098.27441472]
+          [  -617.83031378      0.          -4098.27441472]]]
+
         """
         observers = format_star_input(observers)
         return getBH_level2(
@@ -187,13 +195,26 @@ def getH(self, *observers, squeeze=True, pixel_agg=None, output="ndarray"):
 
 
 class BaseMagnet(BaseSource):
-    """provides the magnetization attribute  for homogeneously magnetized magnets"""
+    """provides the magnetization and polarization attributes for magnet classes"""
 
     _style_class = MagnetStyle
 
-    def __init__(self, position, orientation, magnetization, style, **kwargs):
+    def __init__(
+        self, position, orientation, magnetization, polarization, style, **kwargs
+    ):
         super().__init__(position, orientation, style=style, **kwargs)
-        self.magnetization = magnetization
+
+        self._polarization = None
+        self._magnetization = None
+        if magnetization is not None:
+            self.magnetization = magnetization
+            if polarization is not None:
+                raise ValueError(
+                    "The attributes magnetization and polarization are dependent. "
+                    "Only one can be provided at magnet initialization."
+                )
+        if polarization is not None:
+            self.polarization = polarization
 
     @property
     def magnetization(self):
@@ -202,7 +223,7 @@ def magnetization(self):
 
     @magnetization.setter
     def magnetization(self, mag):
-        """Set magnetization vector, array_like, shape (3,), unit mT."""
+        """Set magnetization vector, array_like, shape (3,), unit A/m."""
         self._magnetization = check_format_input_vector(
             mag,
             dims=(1,),
@@ -211,6 +232,38 @@ def magnetization(self, mag):
             sig_type="array_like (list, tuple, ndarray) with shape (3,)",
             allow_None=True,
         )
+        self._polarization = self._magnetization * (4 * np.pi * 1e-7)
+        if np.linalg.norm(self._magnetization) < 2000:
+            self._magnetization_low_warning()
+
+    @property
+    def polarization(self):
+        """Object polarization attribute getter and setter."""
+        return self._polarization
+
+    @polarization.setter
+    def polarization(self, mag):
+        """Set polarization vector, array_like, shape (3,), unit T."""
+        self._polarization = check_format_input_vector(
+            mag,
+            dims=(1,),
+            shape_m1=3,
+            sig_name="polarization",
+            sig_type="array_like (list, tuple, ndarray) with shape (3,)",
+            allow_None=True,
+        )
+        self._magnetization = self._polarization / (4 * np.pi * 1e-7)
+
+    def _magnetization_low_warning(self):
+        warnings.warn(
+            (
+                f"{self} received a very low magnetization. "
+                "In Magpylib v5 magnetization is given in units of A/m, "
+                "while polarization is given in units of T."
+            ),
+            MagpylibDeprecationWarning,
+            stacklevel=2,
+        )
 
 
 class BaseCurrent(BaseSource):
diff --git a/magpylib/_src/obj_classes/class_BaseGeo.py b/magpylib/_src/obj_classes/class_BaseGeo.py
index 1ee7ef6e1..59e7d1690 100644
--- a/magpylib/_src/obj_classes/class_BaseGeo.py
+++ b/magpylib/_src/obj_classes/class_BaseGeo.py
@@ -154,7 +154,7 @@ def parent(self, inp):
     @property
     def position(self):
         """
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
         """
         return np.squeeze(self._position)
diff --git a/magpylib/_src/obj_classes/class_BaseTransform.py b/magpylib/_src/obj_classes/class_BaseTransform.py
index f4aad125a..7e1ba5ce5 100644
--- a/magpylib/_src/obj_classes/class_BaseTransform.py
+++ b/magpylib/_src/obj_classes/class_BaseTransform.py
@@ -248,7 +248,7 @@ class BaseTransform:
     """Inherit this class to provide rotation() and move() methods."""
 
     def move(self, displacement, start="auto"):
-        """Move object by the displacement input.
+        """Move object by the displacement input. SI units are used for all inputs and outputs.
 
         Terminology for move/rotate methods:
 
@@ -271,7 +271,7 @@ def move(self, displacement, start="auto"):
         Parameters
         ----------
         displacement: array_like, shape (3,) or (n,3)
-            Displacement vector in units of mm.
+            Displacement vector in units of m.
 
         start: int or str, default=`'auto'`
             Starting index when applying operations. See 'General move/rotate behavior' above
@@ -381,7 +381,7 @@ def rotate(self, rotation: R, anchor=None, start="auto"):
             as unit rotation.
 
         anchor: `None`, `0` or array_like with shape (3,) or (n,3), default=`None`
-            The axis of rotation passes through the anchor point given in units of mm.
+            The axis of rotation passes through the anchor point given in units of m.
             By default (`anchor=None`) the object will rotate about its own center.
             `anchor=0` rotates the object about the origin `(0,0,0)`.
 
@@ -466,7 +466,7 @@ def rotate_from_angax(self, angle, axis, anchor=None, start="auto", degrees=True
             or a string 'x', 'y' or 'z' to denote respective directions.
 
         anchor: `None`, `0` or array_like with shape (3,) or (n,3), default=`None`
-            The axis of rotation passes through the anchor point given in units of mm.
+            The axis of rotation passes through the anchor point given in units of m.
             By default (`anchor=None`) the object will rotate about its own center.
             `anchor=0` rotates the object about the origin `(0,0,0)`.
 
@@ -567,7 +567,7 @@ def rotate_from_rotvec(self, rotvec, anchor=None, start="auto", degrees=True):
             the rotation angle in units of rad.
 
         anchor: `None`, `0` or array_like with shape (3,) or (n,3), default=`None`
-            The axis of rotation passes through the anchor point given in units of mm.
+            The axis of rotation passes through the anchor point given in units of m.
             By default (`anchor=None`) the object will rotate about its own center.
             `anchor=0` rotates the object about the origin `(0,0,0)`.
 
@@ -655,7 +655,7 @@ def rotate_from_euler(self, angle, seq, anchor=None, start="auto", degrees=True)
             rotations cannot be mixed in one function call.
 
         anchor: `None`, `0` or array_like with shape (3,) or (n,3), default=`None`
-            The axis of rotation passes through the anchor point given in units of mm.
+            The axis of rotation passes through the anchor point given in units of m.
             By default (`anchor=None`) the object will rotate about its own center.
             `anchor=0` rotates the object about the origin `(0,0,0)`.
 
@@ -738,7 +738,7 @@ def rotate_from_matrix(self, matrix, anchor=None, start="auto"):
             Rotation input. See scipy.spatial.transform.Rotation for details.
 
         anchor: `None`, `0` or array_like with shape (3,) or (n,3), default=`None`
-            The axis of rotation passes through the anchor point given in units of mm.
+            The axis of rotation passes through the anchor point given in units of m.
             By default (`anchor=None`) the object will rotate about its own center.
             `anchor=0` rotates the object about the origin `(0,0,0)`.
 
@@ -803,7 +803,7 @@ def rotate_from_mrp(self, mrp, anchor=None, start="auto"):
             Parameters (MRPs).
 
         anchor: `None`, `0` or array_like with shape (3,) or (n,3), default=`None`
-            The axis of rotation passes through the anchor point given in units of mm.
+            The axis of rotation passes through the anchor point given in units of m.
             By default (`anchor=None`) the object will rotate about its own center.
             `anchor=0` rotates the object about the origin `(0,0,0)`.
 
@@ -867,7 +867,7 @@ def rotate_from_quat(self, quat, anchor=None, start="auto"):
             Rotation input in quaternion form.
 
         anchor: `None`, `0` or array_like with shape (3,) or (n,3), default=`None`
-            The axis of rotation passes through the anchor point given in units of mm.
+            The axis of rotation passes through the anchor point given in units of m.
             By default (`anchor=None`) the object will rotate about its own center.
             `anchor=0` rotates the object about the origin `(0,0,0)`.
 
diff --git a/magpylib/_src/obj_classes/class_Collection.py b/magpylib/_src/obj_classes/class_Collection.py
index 8d9753ae5..f0a484f23 100644
--- a/magpylib/_src/obj_classes/class_Collection.py
+++ b/magpylib/_src/obj_classes/class_Collection.py
@@ -456,7 +456,10 @@ def set_children_styles(self, arg=None, recursive=True, _validate=True, **kwargs
         >>> import magpylib as magpy
         >>>
         >>> col = magpy.Collection(
-        ...     [magpy.magnet.Sphere((0, 0, 1), 1, position=(i, 0, 0)) for i in range(3)]
+        ...     [
+        ...         magpy.magnet.Sphere(position=(i, 0, 0), diameter=1, polarization=(0, 0, 0.1))
+        ...         for i in range(3)
+        ...     ]
         ... )
         >>> # We apply styles using underscore magic for magnetization vector size and a style
         >>> # dictionary for the color.
@@ -469,7 +472,7 @@ def set_children_styles(self, arg=None, recursive=True, _validate=True, **kwargs
         >>> # Finally we create a separate sphere magnet to demonstrate the default style
         >>> # the collection and the separate magnet with Matplotlib:
         >>>
-        >>> src = magpy.magnet.Sphere((0, 0, 1), 1, position=(3, 0, 0))
+        >>> src = magpy.magnet.Sphere(position=(3, 0, 0), diameter=1, polarization=(0, 0, .1))
         >>> magpy.show(col, src) # doctest: +SKIP
         >>> # graphic output
         """
@@ -516,7 +519,9 @@ def _validate_getBH_inputs(self, *inputs):
         return sources, sensors
 
     def getB(self, *inputs, squeeze=True, pixel_agg=None, output="ndarray"):
-        """Compute B-field in mT for given sources and observers.
+        """Compute B-field for given sources and observers.
+
+        SI units are used for all inputs and outputs.
 
         Parameters
         ----------
@@ -543,17 +548,17 @@ def getB(self, *inputs, squeeze=True, pixel_agg=None, output="ndarray"):
         Returns
         -------
         B-field: ndarray, shape squeeze(m, k, n1, n2, ..., 3) or DataFrame
-            B-field at each path position (m) for each sensor (k) and each sensor pixel
-            position (n1,n2,...) in units of mT. Sensor pixel positions are equivalent
-            to simple observer positions. Paths of objects that are shorter than m will be
-            considered as static beyond their end.
+            B-field at each path position ( index m) for each sensor (index k) and each
+            sensor pixel position (indices n1,n2,...) in units of T. Sensor pixel positions
+            are equivalent to simple observer positions. Paths of objects that are shorter
+            than index m are considered as static beyond their end.
 
         Examples
         --------
         In this example we create a collection from two sources and two sensors:
 
         >>> import magpylib as magpy
-        >>> src1 = magpy.magnet.Sphere((0,0,1000), 1)
+        >>> src1 = magpy.magnet.Sphere(polarization=(0,0,1.), diameter=1)
         >>> src2 = src1.copy()
         >>> sens1 = magpy.Sensor(position=(0,0,1))
         >>> sens2 = sens1.copy()
@@ -567,11 +572,11 @@ def getB(self, *inputs, squeeze=True, pixel_agg=None, output="ndarray"):
         >>> B = magpy.getB([src1, src2], col)
         >>> B = magpy.getB([src1, src2], [sens1, sens2])
         >>> print(B)
-        [[[ 0.          0.         83.33333333]
-          [ 0.          0.         83.33333333]]
+        [[[0.         0.         0.08333333]
+          [0.         0.         0.08333333]]
         <BLANKLINE>
-         [[ 0.          0.         83.33333333]
-          [ 0.          0.         83.33333333]]]
+         [[0.         0.         0.08333333]
+          [0.         0.         0.08333333]]]
         """
 
         sources, sensors = self._validate_getBH_inputs(*inputs)
@@ -587,7 +592,9 @@ def getB(self, *inputs, squeeze=True, pixel_agg=None, output="ndarray"):
         )
 
     def getH(self, *inputs, squeeze=True, pixel_agg=None, output="ndarray"):
-        """Compute H-field in kA/m for given sources and observers.
+        """Compute H-field for given sources and observers.
+
+        SI units are used for all inputs and outputs.
 
         Parameters
         ----------
@@ -614,17 +621,17 @@ def getH(self, *inputs, squeeze=True, pixel_agg=None, output="ndarray"):
         Returns
         -------
         H-field: ndarray, shape squeeze(m, k, n1, n2, ..., 3) or DataFrame
-            H-field at each path position (m) for each sensor (k) and each sensor pixel
-            position (n1,n2,...) in units of kA/m. Sensor pixel positions are equivalent
-            to simple observer positions. Paths of objects that are shorter than m will be
-            considered as static beyond their end.
+            H-field at each path position (index m) for each sensor (index k) and each sensor
+            pixel position (indeices n1,n2,...) in units of A/m. Sensor pixel positions are
+            equivalent to simple observer positions. Paths of objects that are shorter than
+            index m are considered as static beyond their end.
 
         Examples
         --------
         In this example we create a collection from two sources and two sensors:
 
         >>> import magpylib as magpy
-        >>> src1 = magpy.magnet.Sphere((0,0,1000), 1)
+        >>> src1 = magpy.magnet.Sphere(polarization=(0,0,1.), diameter=1)
         >>> src2 = src1.copy()
         >>> sens1 = magpy.Sensor(position=(0,0,1))
         >>> sens2 = sens1.copy()
@@ -638,11 +645,11 @@ def getH(self, *inputs, squeeze=True, pixel_agg=None, output="ndarray"):
         >>> H = magpy.getH([src1, src2], col)
         >>> H = magpy.getH([src1, src2], [sens1, sens2])
         >>> print(H)
-        [[[ 0.          0.         66.31455962]
-          [ 0.          0.         66.31455962]]
+        [[[    0.             0.         66314.55962162]
+          [    0.             0.         66314.55962162]]
         <BLANKLINE>
-         [[ 0.          0.         66.31455962]
-          [ 0.          0.         66.31455962]]]
+         [[    0.             0.         66314.55962162]
+          [    0.             0.         66314.55962162]]]
         """
 
         sources, sensors = self._validate_getBH_inputs(*inputs)
@@ -687,11 +694,28 @@ class Collection(BaseGeo, BaseCollection):
     functions like a single source. When the collection contains sensors
     it functions like a list of all its sensors.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
     children: sources, `Sensor` or `Collection` objects
         An ordered list of all children in the collection.
 
+    position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
+        Object position(s) in the global coordinates in units of m. For m>1, the
+        `position` and `orientation` attributes together represent an object path.
+
+    orientation: scipy `Rotation` object with length 1 or m, default=`None`
+        Object orientation(s) in the global coordinates. `None` corresponds to
+        a unit-rotation. For m>1, the `position` and `orientation` attributes
+        together represent an object path.
+
+    override_parent: bool, default=False
+        If False thrown an error when an attempt is made to add an object that
+        has already a parent to a Collection. If True, allow adding the object
+        and override the objects parent attribute thus removing it from its
+        previous collection.
+
     sensors: `Sensor` objects
         An ordered list of all sensor objects in the collection.
 
@@ -701,14 +725,6 @@ class Collection(BaseGeo, BaseCollection):
     collections: `Collection` objects
         An ordered list of all collection objects in the collection.
 
-    position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
-        `position` and `orientation` attributes together represent an object path.
-
-    orientation: scipy `Rotation` object with length 1 or m, default=`None`
-        Object orientation(s) in the global coordinates. `None` corresponds to
-        a unit-rotation. For m>1, the `position` and `orientation` attributes
-        together represent an object path.
 
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
@@ -727,8 +743,8 @@ class Collection(BaseGeo, BaseCollection):
     we create a collection with two sources and move the whole collection:
 
     >>> import magpylib as magpy
-    >>> src1 = magpy.magnet.Sphere((1,2,3), 1, position=(2,0,0))
-    >>> src2 = magpy.current.Circle(1, 1, position=(-2,0,0))
+    >>> src1 = magpy.magnet.Sphere(position=(2,0,0), diameter=1,polarization=(.1,.2,.3))
+    >>> src2 = magpy.current.Circle(position=(-2,0,0), diameter=1, current=1)
     >>> col = magpy.Collection(src1, src2)
     >>> col.move(((0,0,2)))
     Collection(id=...)
@@ -756,7 +772,7 @@ class Collection(BaseGeo, BaseCollection):
 
     >>> B = col.getB((0,0,0))
     >>> print(B)
-    [ 0.00126232 -0.00093169 -0.00034448]
+    [ 2.32922681e-04 -9.31694991e-05 -3.44484717e-10]
 
     We add a sensor at position (0,0,0) to the collection:
 
@@ -771,7 +787,7 @@ class Collection(BaseGeo, BaseCollection):
 
     >>> B = col.getB()
     >>> print(B)
-    [ 0.00126232 -0.00093169 -0.00034448]
+    [ 2.32922681e-04 -9.31694991e-05 -3.44484717e-10]
     """
 
     def __init__(
@@ -779,8 +795,8 @@ def __init__(
         *args,
         position=(0, 0, 0),
         orientation=None,
-        style=None,
         override_parent=False,
+        style=None,
         **kwargs,
     ):
         BaseGeo.__init__(
diff --git a/magpylib/_src/obj_classes/class_Sensor.py b/magpylib/_src/obj_classes/class_Sensor.py
index a0eec6bb0..2a4a70c3a 100644
--- a/magpylib/_src/obj_classes/class_Sensor.py
+++ b/magpylib/_src/obj_classes/class_Sensor.py
@@ -19,18 +19,21 @@ class Sensor(BaseGeo, BaseDisplayRepr):
     When `position=(0,0,0)` and `orientation=None` local object coordinates
     coincide with the global coordinate system.
 
-    A sensor is made up of pixel (sensing elements) where the magnetic field is evaluated.
+    A sensor is made up of pixel (sensing elements / positions) where the magnetic
+    field is evaluated.
+
+    SI units are used for all inputs and outputs.
 
     Parameters
     ----------
 
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
     pixel: array_like, shape (3,) or (n1,n2,...,3), default=`(0,0,0)`
         Sensor pixel (=sensing elements) positions in the local object coordinates
-        (rotate with object), in units of mm.
+        (rotate with object), in units of m.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
         Object orientation(s) in the global coordinates. `None` corresponds to
@@ -54,14 +57,14 @@ class Sensor(BaseGeo, BaseDisplayRepr):
     Examples
     --------
     `Sensor` objects are observers for magnetic field computation. In this example we compute the
-    B-field in units of mT as seen by the sensor in the center of a circular current loop:
+    B-field in units of T as seen by the sensor in the center of a circular current loop:
 
     >>> import magpylib as magpy
     >>> sens = magpy.Sensor()
-    >>> loop = magpy.current.Circle(current=1, diameter=1)
+    >>> loop = magpy.current.Circle(current=1, diameter=0.01)
     >>> B = sens.getB(loop)
     >>> print(B)
-    [0.         0.         1.25663706]
+    [0.         0.         0.00012566]
 
     We rotate the sensor by 45 degrees and compute the field again:
 
@@ -69,16 +72,16 @@ class Sensor(BaseGeo, BaseDisplayRepr):
     Sensor(id=...)
     >>> B = sens.getB(loop)
     >>> print(B)
-    [0.         0.88857659 0.88857659]
+    [0.00000000e+00 8.88576588e-05 8.88576588e-05]
 
     Finally we set some sensor pixels and compute the field again:
 
-    >>> sens.pixel=((0,0,0), (.1,0,0), (.2,0,0))
+    >>> sens.pixel=((0,0,0), (.001,0,0), (.002,0,0))
     >>> B = sens.getB(loop)
     >>> print(B)
-    [[0.         0.88857659 0.88857659]
-     [0.         0.916274   0.916274  ]
-     [0.         1.01415383 1.01415383]]
+    [[0.00000000e+00 8.88576588e-05 8.88576588e-05]
+     [0.00000000e+00 9.16274003e-05 9.16274003e-05]
+     [0.00000000e+00 1.01415383e-04 1.01415383e-04]]
     """
 
     _style_class = SensorStyle
@@ -88,10 +91,10 @@ class Sensor(BaseGeo, BaseDisplayRepr):
     def __init__(
         self,
         position=(0, 0, 0),
-        pixel=(0, 0, 0),
         orientation=None,
-        style=None,
+        pixel=None,
         handedness="right",
+        style=None,
         **kwargs,
     ):
         # instance attributes
@@ -106,7 +109,7 @@ def __init__(
     @property
     def pixel(self):
         """Sensor pixel (=sensing elements) positions in the local object coordinates
-        (rotate with object), in units of mm.
+        (rotate with object), in units of m.
         """
         return self._pixel
 
@@ -120,7 +123,8 @@ def pixel(self, pix):
             dims=range(1, 20),
             shape_m1=3,
             sig_name="pixel",
-            sig_type="array_like (list, tuple, ndarray) with shape (n1, n2, ..., 3)",
+            sig_type="array_like (list, tuple, ndarray) with shape (n1, n2, ..., 3) or None",
+            allow_None=True,
         )
 
     @property
@@ -140,7 +144,7 @@ def handedness(self, val):
     def getB(
         self, *sources, sumup=False, squeeze=True, pixel_agg=None, output="ndarray"
     ):
-        """Compute the B-field in units of mT as seen by the sensor.
+        """Compute the B-field in units of T as seen by the sensor.
 
         Parameters
         ----------
@@ -168,21 +172,21 @@ def getB(
         Returns
         -------
         B-field: ndarray, shape squeeze(l, m, n1, n2, ..., 3) or DataFrame
-            B-field of each source (l) at each path position (m) and each sensor pixel
-            position (n1,n2,...) in units of mT. Paths of objects that are shorter than
-            m will be considered as static beyond their end.
+            B-field of each source (index l) at each path position (index m) and each sensor pixel
+            position (indices n1,n2,...) in units of T. Paths of objects that are shorter than
+            index m are considered as static beyond their end.
 
         Examples
         --------
         Sensors are observers for magnetic field computation. In this example we compute the
-        B-field in units of mT as seen by the sensor in the center of a circular current loop:
+        B-field in T as seen by the sensor in the center of a circular current loop:
 
         >>> import magpylib as magpy
         >>> sens = magpy.Sensor()
-        >>> loop = magpy.current.Circle(current=1, diameter=1)
+        >>> loop = magpy.current.Circle(current=1, diameter=.01)
         >>> B = sens.getB(loop)
         >>> print(B)
-        [0.         0.         1.25663706]
+        [0.         0.         0.00012566]
 
         Then we rotate the sensor by 45 degrees and compute the field again:
 
@@ -190,16 +194,16 @@ def getB(
         Sensor(id=...)
         >>> B = sens.getB(loop)
         >>> print(B)
-        [0.         0.88857659 0.88857659]
+        [0.00000000e+00 8.88576588e-05 8.88576588e-05]
 
         Finally we set some sensor pixels and compute the field again:
 
-        >>> sens.pixel=((0,0,0), (.1,0,0), (.2,0,0))
+        >>> sens.pixel=((0,0,0), (.001,0,0), (.002,0,0))
         >>> B = sens.getB(loop)
         >>> print(B)
-        [[0.         0.88857659 0.88857659]
-         [0.         0.916274   0.916274  ]
-         [0.         1.01415383 1.01415383]]
+        [[0.00000000e+00 8.88576588e-05 8.88576588e-05]
+         [0.00000000e+00 9.16274003e-05 9.16274003e-05]
+         [0.00000000e+00 1.01415383e-04 1.01415383e-04]]
         """
         sources = format_star_input(sources)
         return getBH_level2(
@@ -215,7 +219,7 @@ def getB(
     def getH(
         self, *sources, sumup=False, squeeze=True, pixel_agg=None, output="ndarray"
     ):
-        """Compute the H-field in units of kA/m as seen by the sensor.
+        """Compute the H-field in units of A/m as seen by the sensor.
 
         Parameters
         ----------
@@ -243,21 +247,21 @@ def getH(
         Returns
         -------
         H-field: ndarray, shape squeeze(l, m, n1, n2, ..., 3) or DataFrame
-            H-field of each source (l) at each path position (m) and each sensor pixel
-            position (n1,n2,...) in units of kA/m. Paths of objects that are shorter than
-            m will be considered as static beyond their end.
+            H-field of each source (index l) at each path position (index m) and each sensor pixel
+            position (indices n1,n2,...) in units of A/m. Paths of objects that are shorter than
+            index m are considered as static beyond their end.
 
         Examples
         --------
         Sensors are observers for magnetic field computation. In this example we compute the
-        H-field in kA/m as seen by the sensor in the center of a circular current loop:
+        B-field in T as seen by the sensor in the center of a circular current loop:
 
         >>> import magpylib as magpy
         >>> sens = magpy.Sensor()
-        >>> loop = magpy.current.Circle(current=1, diameter=1)
+        >>> loop = magpy.current.Circle(current=1, diameter=.01)
         >>> H = sens.getH(loop)
         >>> print(H)
-        [0. 0. 1.]
+        [  0.   0. 100.]
 
         Then we rotate the sensor by 45 degrees and compute the field again:
 
@@ -265,16 +269,16 @@ def getH(
         Sensor(id=...)
         >>> H = sens.getH(loop)
         >>> print(H)
-        [0.         0.70710678 0.70710678]
+        [ 0.         70.71067812 70.71067812]
 
         Finally we set some sensor pixels and compute the field again:
 
-        >>> sens.pixel=((0,0,0), (.1,0,0), (.2,0,0))
+        >>> sens.pixel=((0,0,0), (.001,0,0), (.002,0,0))
         >>> H = sens.getH(loop)
         >>> print(H)
-        [[0.         0.70710678 0.70710678]
-         [0.         0.72914768 0.72914768]
-         [0.         0.80703798 0.80703798]]
+        [[ 0.         70.71067812 70.71067812]
+         [ 0.         72.9147684  72.9147684 ]
+         [ 0.         80.7037979  80.7037979 ]]
         """
         sources = format_star_input(sources)
         return getBH_level2(
@@ -290,13 +294,12 @@ def getH(
     @property
     def _default_style_description(self):
         """Default style description text"""
-        pixel = np.array(self.pixel).reshape((-1, 3))
-        pix_uniq = np.unique(pixel, axis=0)
-        one_pix = pix_uniq.shape[0] == 1 and not (pix_uniq == 0).all()
-        return (
-            f" ({'x'.join(str(p) for p in self.pixel.shape[:-1])} pixels)"
-            if self.pixel.ndim != 1
-            else f" ({pixel[1:].shape[0]} pixel)"
-            if one_pix
-            else ""
-        )
+        pix = self.pixel
+        desc = ""
+        if pix is not None:
+            px_shape = pix.shape[:-1]
+            nop = int(np.prod(px_shape))
+            if pix.ndim > 2:
+                desc += f"{'x'.join(str(p) for p in px_shape)}="
+            desc += f"{nop} pixel{'s'[:nop^1]}"
+        return desc
diff --git a/magpylib/_src/obj_classes/class_current_Circle.py b/magpylib/_src/obj_classes/class_current_Circle.py
index 206b3ef9b..a4830722f 100644
--- a/magpylib/_src/obj_classes/class_current_Circle.py
+++ b/magpylib/_src/obj_classes/class_current_Circle.py
@@ -16,18 +16,14 @@ class Circle(BaseCurrent):
 
     When `position=(0,0,0)` and `orientation=None` the current loop lies
     in the x-y plane of the global coordinate system, with its center in
-    the origin. The Circle class has a dipole moment of pi**2/10*diameter**2*current.
+    the origin.
+
+    SI units are used for all inputs and outputs.
 
     Parameters
     ----------
-    current: float, default=`None`
-        Electrical current in units of A.
-
-    diameter: float, default=`None`
-        Diameter of the loop in units of mm.
-
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -35,6 +31,12 @@ class Circle(BaseCurrent):
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    diameter: float, default=`None`
+        Diameter of the loop in units of m.
+
+    current: float, default=`None`
+        Electrical current in units of A.
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -48,37 +50,37 @@ class Circle(BaseCurrent):
 
     Examples
     --------
-    `Circle` objects are magnetic field sources. In this example we compute the H-field kA/m
-    of such a current loop with 100 A current and a diameter of 2 mm at the observer position
-    (1,1,1) given in units of mm:
+    `Circle` objects are magnetic field sources. In this example we compute the H-field in A/m
+    of such a current loop with 100 A current and a diameter of 2 meters at the observer position
+    (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
     >>> src = magpy.current.Circle(current=100, diameter=2)
-    >>> H = src.getH((1,1,1))
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [4.96243034 4.96243034 2.12454191]
+    [7.50093701e-03 7.50093701e-03 4.99999967e+01]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     Circle(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[-1.44441884e-15  6.72068135e+00 -6.72068135e+00]
-     [-9.88027010e-17  5.89248328e-01 -5.89248328e-01]
-     [-3.55802727e-17  1.65201495e-01 -1.65201495e-01]]
+    [[-1.63585841e-24 -4.44388287e-05  4.44388287e-05]
+     [-6.55449367e-24 -4.44688604e-05  4.44688604e-05]
+     [-9.85948764e-24 -4.45190261e-05  4.45190261e-05]]
 
     The same result is obtained when the rotated source moves along a path away from an
     observer at position (1,1,1). This time we use a `Sensor` object as observer.
 
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     Circle(id=...)
-    >>> sens = magpy.Sensor(position=(1,1,1))
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
     >>> B = src.getB(sens)
     >>> print(B)
-    [[-1.44441884e-15  6.72068135e+00 -6.72068135e+00]
-     [-9.88027010e-17  5.89248328e-01 -5.89248328e-01]
-     [-3.55802727e-17  1.65201495e-01 -1.65201495e-01]]
+    [[-1.63585841e-24 -4.44388287e-05  4.44388287e-05]
+     [-6.55449367e-24 -4.44688604e-05  4.44688604e-05]
+     [-9.85948764e-24 -4.45190261e-05  4.45190261e-05]]
     """
 
     _field_func = staticmethod(current_circle_field)
@@ -87,10 +89,11 @@ class Circle(BaseCurrent):
 
     def __init__(
         self,
-        current=None,
-        diameter=None,
         position=(0, 0, 0),
         orientation=None,
+        diameter=None,
+        current=None,
+        *,
         style=None,
         **kwargs,
     ):
@@ -103,12 +106,12 @@ def __init__(
     # property getters and setters
     @property
     def diameter(self):
-        """Diameter of the loop in units of mm."""
+        """Diameter of the loop in units of m."""
         return self._diameter
 
     @diameter.setter
     def diameter(self, dia):
-        """Set Circle loop diameter, float, mm."""
+        """Set Circle loop diameter, float, meter."""
         self._diameter = check_format_input_scalar(
             dia,
             sig_name="diameter",
diff --git a/magpylib/_src/obj_classes/class_current_Polyline.py b/magpylib/_src/obj_classes/class_current_Polyline.py
index 1670cae97..bb3b15c93 100644
--- a/magpylib/_src/obj_classes/class_current_Polyline.py
+++ b/magpylib/_src/obj_classes/class_current_Polyline.py
@@ -10,25 +10,19 @@
 
 
 class Polyline(BaseCurrent):
-    """Current flowing in straight lines from vertex to vertex.
+    """Line current flowing in straight paths from vertex to vertex.
 
     Can be used as `sources` input for magnetic field computation.
 
     The vertex positions are defined in the local object coordinates (rotate with object).
     When `position=(0,0,0)` and `orientation=None` global and local coordinates coincide.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    current: float, default=`None`
-        Electrical current in units of A.
-
-    vertices: array_like, shape (n,3), default=`None`
-        The current flows along the vertices which are given in units of mm in the
-        local object coordinates (move/rotate with object). At least two vertices
-        must be given.
-
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -36,6 +30,14 @@ class Polyline(BaseCurrent):
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    vertices: array_like, shape (n,3), default=`None`
+        The current flows along the vertices which are given in units of m in the
+        local object coordinates (move/rotate with object). At least two vertices
+        must be given.
+
+    current: float, default=`None`
+        Electrical current in units of A.
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -49,40 +51,40 @@ class Polyline(BaseCurrent):
 
     Examples
     --------
-    `Polyline` objects are magnetic field sources. In this example we compute the H-field kA/m
+    `Polyline` objects are magnetic field sources. In this example we compute the H-field in A/m
     of a square-shaped line-current with 1 A current at the observer position (1,1,1) given in
-    units of mm:
+    units of m:
 
     >>> import magpylib as magpy
     >>> src = magpy.current.Polyline(
     ...     current=1,
-    ...     vertices=((1,0,0), (0,1,0), (-1,0,0), (0,-1,0), (1,0,0)),
+    ...     vertices=((.01,0,0), (0,.01,0), (-.01,0,0), (0,-.01,0), (.01,0,0)),
     ... )
-    >>> H = src.getH((1,1,1))
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [0.03160639 0.03160639 0.00766876]
+    [3.16063859 3.16063859 0.76687556]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     Polyline(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[-6.68990257e-18  3.50341393e-02 -3.50341393e-02]
-     [-5.94009823e-19  3.62181325e-03 -3.62181325e-03]
-     [-2.21112416e-19  1.03643004e-03 -1.03643004e-03]]
+    [[-1.04529728e-21  3.50341393e-06 -3.50341393e-06]
+     [-9.28140348e-23  3.62181325e-07 -3.62181325e-07]
+     [-1.72744075e-23  1.03643004e-07 -1.03643004e-07]]
 
     The same result is obtained when the rotated source moves along a path away from an
     observer at position (1,1,1). This time we use a `Sensor` object as observer.
 
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     Polyline(id=...)
-    >>> sens = magpy.Sensor(position=(1,1,1))
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
     >>> B = src.getB(sens)
     >>> print(B)
-    [[-6.68990257e-18  3.50341393e-02 -3.50341393e-02]
-     [-5.94009823e-19  3.62181325e-03 -3.62181325e-03]
-     [-2.21112416e-19  1.03643004e-03 -1.03643004e-03]]
+    [[-1.04529728e-21  3.50341393e-06 -3.50341393e-06]
+     [-9.28140348e-23  3.62181325e-07 -3.62181325e-07]
+     [-1.72744075e-23  1.03643004e-07 -1.03643004e-07]]
     """
 
     # pylint: disable=dangerous-default-value
@@ -114,7 +116,7 @@ def __init__(
     @property
     def vertices(self):
         """
-        The current flows along the vertices which are given in units of mm in the
+        The current flows along the vertices which are given in units of m in the
         local object coordinates (move/rotate with object). At least two vertices
         must be given.
         """
@@ -122,7 +124,7 @@ def vertices(self):
 
     @vertices.setter
     def vertices(self, vert):
-        """Set Polyline vertices, array_like, mm."""
+        """Set Polyline vertices, array_like, meter."""
         self._vertices = check_format_input_vertices(vert)
 
     @property
diff --git a/magpylib/_src/obj_classes/class_magnet_Cuboid.py b/magpylib/_src/obj_classes/class_magnet_Cuboid.py
index 45c610c26..2e3e4646d 100644
--- a/magpylib/_src/obj_classes/class_magnet_Cuboid.py
+++ b/magpylib/_src/obj_classes/class_magnet_Cuboid.py
@@ -15,28 +15,31 @@ class Cuboid(BaseMagnet):
     to the global coordinate basis vectors and the geometric center of the Cuboid
     is located in the origin.
 
-    Units can be chosen freely. B-field output unit is the same as magnetization
-    input unit. Computation is independend of Length-unit. See online documentation
-    for fore information
+    SI units are used for all inputs and outputs.
 
     Parameters
     ----------
-    magnetization: array_like, shape (3,), default=`None`
-        Magnetization (polarization) vector (mu0*M, remanence field) in arbitrary
-        units given in the local object coordinates (rotates with object).
-
-    dimension: array_like, shape (3,), default=`None`
-        Length of the cuboid sides [a,b,c] in arbitrary units.
-
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in arbitrary units. For m>1, the
-        `position` and `orientation` attributes together represent an object path.
+        Object position(s) in the global coordinates in units of m.
+        For m>1, the `position` and `orientation` attributes together
+        represent an object path.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
         Object orientation(s) in the global coordinates. `None` corresponds to
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    dimension: array_like, shape (3,), default=`None`
+        Length of the cuboid sides [a,b,c] in meters.
+
+    polarization: array_like, shape (3,), default=`None`
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).
+
+    magnetization: array_like, shape (3,), default=`None`
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -50,49 +53,38 @@ class Cuboid(BaseMagnet):
 
     Examples
     --------
-    `Cuboid` magnets are magnetic field sources. Below we compute the H-field in kA/m of a
-    cubical magnet with magnetization (100,200,300) in units of mT and 1 mm sides
-    at the observer position (1,1,1) given in units of mm:
+    `Cuboid` magnets are magnetic field sources. Below we compute the H-field in A/m of a
+    cubical magnet with magnetic polarization of (0.5,0.6,0.7) in units of T and
+    0.01 meter sides at the observer position (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> src = magpy.magnet.Cuboid(magnetization=(100,200,300), dimension=(1,1,1))
-    >>> H = src.getH((1,1,1))
+    >>> src = magpy.magnet.Cuboid(polarization=(.5,.6,.7), dimension=(.01,.01,.01))
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [6.21116976 4.9689358  3.72670185]
+    [16149.04136518 14906.80741401 13664.57346284]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     Cuboid(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,0,0), (0,.01,0), (0,0,.01)])
     >>> print(B)
-    [[4.30496934 6.9363475  0.50728577]
-     [0.54127889 0.86827283 0.05653357]
-     [0.1604214  0.25726266 0.01664045]]
-
-    The same result is obtained when the rotated source moves along a path away from an
-    observer at position (1,1,1). Here we use a `Sensor` object as observer.
-
-    >>> sens = magpy.Sensor(position=(1,1,1))
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
-    Cuboid(id=...)
-    >>> B = src.getB(sens)
-    >>> print(B)
-    [[4.30496934 6.9363475  0.50728577]
-     [0.54127889 0.86827283 0.05653357]
-     [0.1604214  0.25726266 0.01664045]]
+    [[ 0.06739119  0.00476528 -0.0619486 ]
+     [-0.03557183 -0.01149497 -0.08403664]
+     [-0.03557183  0.00646436  0.14943466]]
     """
 
     _field_func = staticmethod(magnet_cuboid_field)
-    _field_func_kwargs_ndim = {"magnetization": 2, "dimension": 2}
+    _field_func_kwargs_ndim = {"polarization": 2, "dimension": 2}
     get_trace = make_Cuboid
 
     def __init__(
         self,
-        magnetization=None,
-        dimension=None,
         position=(0, 0, 0),
         orientation=None,
+        dimension=None,
+        polarization=None,
+        magnetization=None,
         style=None,
         **kwargs,
     ):
@@ -100,17 +92,19 @@ def __init__(
         self.dimension = dimension
 
         # init inheritance
-        super().__init__(position, orientation, magnetization, style, **kwargs)
+        super().__init__(
+            position, orientation, magnetization, polarization, style, **kwargs
+        )
 
     # property getters and setters
     @property
     def dimension(self):
-        """Length of the cuboid sides [a,b,c] in units of mm."""
+        """Length of the cuboid sides [a,b,c] in arbitrary length units, e.g. in meter."""
         return self._dimension
 
     @dimension.setter
     def dimension(self, dim):
-        """Set Cuboid dimension (a,b,c), shape (3,), mm."""
+        """Set Cuboid dimension (a,b,c), shape (3,)"""
         self._dimension = check_format_input_vector(
             dim,
             dims=(1,),
@@ -126,5 +120,5 @@ def _default_style_description(self):
         """Default style description text"""
         if self.dimension is None:
             return "no dimension"
-        d = [unit_prefix(d / 1000) for d in self.dimension]
+        d = [unit_prefix(d) for d in self.dimension]
         return f"{d[0]}m|{d[1]}m|{d[2]}m"
diff --git a/magpylib/_src/obj_classes/class_magnet_Cylinder.py b/magpylib/_src/obj_classes/class_magnet_Cylinder.py
index d123d9db2..61b289334 100644
--- a/magpylib/_src/obj_classes/class_magnet_Cylinder.py
+++ b/magpylib/_src/obj_classes/class_magnet_Cylinder.py
@@ -15,17 +15,12 @@ class Cylinder(BaseMagnet):
     cylinder lies in the origin of the global coordinate system and
     the cylinder axis coincides with the global z-axis.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    magnetization: array_like, shape (3,), default=`None`
-        Magnetization vector (mu0*M, remanence field) in units of mT given in
-        the local object coordinates (rotates with object).
-
-    dimension: array_like, shape (2,), default=`None`
-        Dimension (d,h) denote diameter and height of the cylinder in units of mm.
-
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -33,6 +28,17 @@ class Cylinder(BaseMagnet):
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    dimension: array_like, shape (2,), default=`None`
+        Dimension (d,h) denote diameter and height of the cylinder in units of m.
+
+    polarization: array_like, shape (3,), default=`None`
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).
+
+    magnetization: array_like, shape (3,), default=`None`
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -46,49 +52,50 @@ class Cylinder(BaseMagnet):
 
     Examples
     --------
-    `Cylinder` magnets are magnetic field sources. Below we compute the H-field in kA/m of a
-    cylinder magnet with magnetization (100,200,300) in units of mT and 1 mm diameter and height
-    at the observer position (1,1,1) given in units of mm:
+    `Cylinder` magnets are magnetic field sources. Below we compute the H-field in A/m of a
+    cylinder magnet with polarization (.1,.2,.3) in units of T and 0.01 meter diameter and
+    height at the observer position (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> src = magpy.magnet.Cylinder(magnetization=(100,200,300), dimension=(1,1))
-    >>> H = src.getH((1,1,1))
+    >>> src = magpy.magnet.Cylinder(polarization=(.1,.2,.3), dimension=(.01,.01))
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [4.84991343 3.88317816 2.73973202]
+    [4849.91343385 3883.17815728 2739.73202386]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     Cylinder(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[3.31419501 5.26683023 0.37767015]
-     [0.42298405 0.67710536 0.04464932]
-     [0.12571523 0.20144503 0.01312389]]
+    [[3.31419501e-03 5.26683023e-03 3.77670149e-04]
+     [4.22984050e-04 6.77105357e-04 4.46493154e-05]
+     [1.25715233e-04 2.01445027e-04 1.31238931e-05]]
 
     The same result is obtained when the rotated source moves along a path away from an
-    observer at position (1,1,1). Here we use a `Sensor` object as observer.
+    observer at position (0.01,0.01,0.01). Here we use a `Sensor` object as observer.
 
-    >>> sens = magpy.Sensor(position=(1,1,1))
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     Cylinder(id=...)
     >>> B = src.getB(sens)
     >>> print(B)
-    [[3.31419501 5.26683023 0.37767015]
-     [0.42298405 0.67710536 0.04464932]
-     [0.12571523 0.20144503 0.01312389]]
+    [[3.31419501e-03 5.26683023e-03 3.77670149e-04]
+     [4.22984050e-04 6.77105357e-04 4.46493154e-05]
+     [1.25715233e-04 2.01445027e-04 1.31238931e-05]]
     """
 
     _field_func = staticmethod(magnet_cylinder_field)
-    _field_func_kwargs_ndim = {"magnetization": 2, "dimension": 2}
+    _field_func_kwargs_ndim = {"polarization": 2, "dimension": 2}
     get_trace = make_Cylinder
 
     def __init__(
         self,
-        magnetization=None,
-        dimension=None,
         position=(0, 0, 0),
         orientation=None,
+        dimension=None,
+        polarization=None,
+        magnetization=None,
         style=None,
         **kwargs,
     ):
@@ -96,17 +103,19 @@ def __init__(
         self.dimension = dimension
 
         # init inheritance
-        super().__init__(position, orientation, magnetization, style, **kwargs)
+        super().__init__(
+            position, orientation, magnetization, polarization, style, **kwargs
+        )
 
     # property getters and setters
     @property
     def dimension(self):
-        """Dimension (d,h) denote diameter and height of the cylinder in units of mm."""
+        """Dimension (d,h) denote diameter and height of the cylinder in units of m."""
         return self._dimension
 
     @dimension.setter
     def dimension(self, dim):
-        """Set Cylinder dimension (d,h) in units of mm."""
+        """Set Cylinder dimension (d,h) in units of m."""
         self._dimension = check_format_input_vector(
             dim,
             dims=(1,),
@@ -122,5 +131,5 @@ def _default_style_description(self):
         """Default style description text"""
         if self.dimension is None:
             return "no dimension"
-        d = [unit_prefix(d / 1000) for d in self.dimension]
+        d = [unit_prefix(d) for d in self.dimension]
         return f"D={d[0]}m, H={d[1]}m"
diff --git a/magpylib/_src/obj_classes/class_magnet_CylinderSegment.py b/magpylib/_src/obj_classes/class_magnet_CylinderSegment.py
index fe31f2a21..e5445c6a4 100644
--- a/magpylib/_src/obj_classes/class_magnet_CylinderSegment.py
+++ b/magpylib/_src/obj_classes/class_magnet_CylinderSegment.py
@@ -20,31 +20,33 @@ class CylinderSegment(BaseMagnet):
     the cylinder axis coincides with the global z-axis. Section angle 0
     corresponds to an x-z plane section of the cylinder.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    magnetization: array_like, shape (3,), default=`None`
-        Magnetization vector (mu0*M, remanence field) in units of mT given in
-        the local object coordinates (rotates with object).
-
-    dimension: array_like, shape (5,), default=`None`
-        Dimension/Size of the cylinder segment of the form (r1, r2, h, phi1, phi2)
-        where r1<r2 denote inner and outer radii in units of mm, phi1<phi2 denote
-        the cylinder section angles in units of deg and h is the cylinder height
-        in units of mm.
-
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
-    barycenter: array_like, shape (3,)
-        Read only property that returns the geometric barycenter (=center of mass)
-        of the object.
-
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
         Object orientation(s) in the global coordinates. `None` corresponds to
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    dimension: array_like, shape (5,), default=`None`
+        Dimension/Size of the cylinder segment of the form (r1, r2, h, phi1, phi2)
+        where r1<r2 denote inner and outer radii in units of m, phi1<phi2 denote
+        the cylinder section angles in units of deg and h is the cylinder height
+        in units of m.
+
+    polarization: array_like, shape (3,), default=`None`
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).
+
+    magnetization: array_like, shape (3,), default=`None`
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -52,6 +54,12 @@ class CylinderSegment(BaseMagnet):
         Object style inputs must be in dictionary form, e.g. `{'color':'red'}` or
         using style underscore magic, e.g. `style_color='red'`.
 
+    Attributes
+    ----------
+    barycenter: array_like, shape (3,)
+        Read only property that returns the geometric barycenter (=center of mass)
+        of the object.
+
     Returns
     -------
     magnet source: `CylinderSegment` object
@@ -59,49 +67,50 @@ class CylinderSegment(BaseMagnet):
     Examples
     --------
     `CylinderSegment` magnets are magnetic field sources. In this example we compute the
-    H-field kA/m of such a cylinder segment magnet with magnetization (100,200,300)
-    in units of mT, inner radius 1 mm, outer radius 2 mm, height 1 mm, and
-    section angles 0 and 45 deg at the observer position (2,2,2) in units of mm:
+    H-field in A/m of such a cylinder segment magnet with polarization (.1,.2,.3)
+    in units of T, inner radius 0.01 meter, outer radius 0.02 meter, height 0.01 meter, and
+    section angles 0 and 45 deg at the observer position (0.02,0.02,0.02) in units of m:
 
     >>> import magpylib as magpy
-    >>> src = magpy.magnet.CylinderSegment(magnetization=(100,200,300), dimension=(1,2,1,0,45))
-    >>> H = src.getH((2,2,2))
+    >>> src = magpy.magnet.CylinderSegment(polarization=(.1,.2,.3), dimension=(.01,.02,.01,0,45))
+    >>> H = src.getH((.02,.02,.02))
     >>> print(H)
-    [0.80784692 1.93422813 2.74116805]
+    [ 807.84692335 1934.22812967 2741.16804712]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     CylinderSegment(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[-32.82849635  30.15882073 -16.32885658]
-     [  0.62876075   3.97579164   0.73297829]
-     [  0.25439493   0.74331628   0.11682542]]
+    [[-0.0328285   0.03015882 -0.01632886]
+     [ 0.00062876  0.00397579  0.00073298]
+     [ 0.00025439  0.00074332  0.00011683]]
 
     The same result is obtained when the rotated source moves along a path away from an
-    observer at position (1,1,1). Here we use a `Sensor` object as observer.
+    observer at position (.01,.01,.01). Here we use a `Sensor` object as observer.
 
-    >>> sens = magpy.Sensor(position=(1,1,1))
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     CylinderSegment(id=...)
     >>> B = src.getB(sens)
     >>> print(B)
-    [[-32.82849635  30.15882073 -16.32885658]
-     [  0.62876075   3.97579164   0.73297829]
-     [  0.25439493   0.74331628   0.11682542]]
+    [[-0.0328285   0.03015882 -0.01632886]
+     [ 0.00062876  0.00397579  0.00073298]
+     [ 0.00025439  0.00074332  0.00011683]]
     """
 
     _field_func = staticmethod(magnet_cylinder_segment_field_internal)
-    _field_func_kwargs_ndim = {"magnetization": 2, "dimension": 2}
+    _field_func_kwargs_ndim = {"polarization": 2, "dimension": 2}
     get_trace = make_CylinderSegment
 
     def __init__(
         self,
-        magnetization=None,
-        dimension=None,
         position=(0, 0, 0),
         orientation=None,
+        dimension=None,
+        polarization=None,
+        magnetization=None,
         style=None,
         **kwargs,
     ):
@@ -109,22 +118,24 @@ def __init__(
         self.dimension = dimension
 
         # init inheritance
-        super().__init__(position, orientation, magnetization, style, **kwargs)
+        super().__init__(
+            position, orientation, magnetization, polarization, style, **kwargs
+        )
 
     # property getters and setters
     @property
     def dimension(self):
         """
         Dimension/Size of the cylinder segment of the form (r1, r2, h, phi1, phi2)
-        where r1<r2 denote inner and outer radii in units of mm, phi1<phi2 denote
+        where r1<r2 denote inner and outer radii in units of m, phi1<phi2 denote
         the cylinder section angles in units of deg and h is the cylinder height
-        in units of mm.
+        in units of m.
         """
         return self._dimension
 
     @dimension.setter
     def dimension(self, dim):
-        """Set Cylinder dimension (r1,r2,h,phi1,phi2), shape (5,), (mm, deg)."""
+        """Set Cylinder dimension (r1,r2,h,phi1,phi2), shape (5,), (meter, deg)."""
         self._dimension = check_format_input_cylinder_segment(dim)
 
     @property
@@ -169,8 +180,5 @@ def _default_style_description(self):
         """Default style description text"""
         if self.dimension is None:
             return "no dimension"
-        d = [
-            unit_prefix(d / (1000 if i < 3 else 1))
-            for i, d in enumerate(self.dimension)
-        ]
+        d = [unit_prefix(d) for d in self.dimension]
         return f"r={d[0]}m|{d[1]}m, h={d[2]}m, φ={d[3]}°|{d[4]}°"
diff --git a/magpylib/_src/obj_classes/class_magnet_Sphere.py b/magpylib/_src/obj_classes/class_magnet_Sphere.py
index 024cd3624..b002f0c0f 100644
--- a/magpylib/_src/obj_classes/class_magnet_Sphere.py
+++ b/magpylib/_src/obj_classes/class_magnet_Sphere.py
@@ -14,17 +14,12 @@ class Sphere(BaseMagnet):
     When `position=(0,0,0)` and `orientation=None` the sphere center is located
     in the origin of the global coordinate system.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    magnetization: array_like, shape (3,), default=`None`
-        Magnetization vector (mu0*M, remanence field) in units of mT given in
-        the local object coordinates (rotates with object).
-
-    diameter: float, default=`None`
-        Diameter of the sphere in units of mm.
-
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -32,6 +27,17 @@ class Sphere(BaseMagnet):
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    diameter: float, default=`None`
+        Diameter of the sphere in units of m.
+
+    polarization: array_like, shape (3,), default=`None`
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).
+
+    magnetization: array_like, shape (3,), default=`None`
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -46,49 +52,50 @@ class Sphere(BaseMagnet):
 
     Examples
     --------
-    `Sphere` objects are magnetic field sources. In this example we compute the H-field kA/m
-    of a spherical magnet with magnetization (100,200,300) in units of mT and diameter
-    of 1 mm at the observer position (1,1,1) given in units of mm:
+    `Sphere` objects are magnetic field sources. In this example we compute the H-field in A/m
+    of a spherical magnet with polarization (0.1,0.2,0.3) in units of T and diameter
+    of 0.01 meter at the observer position (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> src = magpy.magnet.Sphere(magnetization=(100,200,300), diameter=1)
-    >>> H = src.getH((1,1,1))
+    >>> src = magpy.magnet.Sphere(polarization=(.1,.2,.3), diameter=.01)
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [3.19056074 2.55244859 1.91433644]
+    [3190.56073739 2552.44858992 1914.33644244]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     Sphere(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[2.26804606 3.63693295 0.23486386]
-     [0.28350576 0.45461662 0.02935798]
-     [0.08400171 0.13470122 0.00869866]]
+    [[2.26804606e-03 3.63693295e-03 2.34863859e-04]
+     [2.83505757e-04 4.54616618e-04 2.93579824e-05]
+     [8.40017059e-05 1.34701220e-04 8.69866146e-06]]
 
     The same result is obtained when the rotated source moves along a path away from an
-    observer at position (1,1,1). This time we use a `Sensor` object as observer.
+    observer at position (.01,.01,.01). This time we use a `Sensor` object as observer.
 
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     Sphere(id=...)
-    >>> sens = magpy.Sensor(position=(1,1,1))
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
     >>> B = src.getB(sens)
     >>> print(B)
-    [[2.26804606 3.63693295 0.23486386]
-     [0.28350576 0.45461662 0.02935798]
-     [0.08400171 0.13470122 0.00869866]]
+    [[2.26804606e-03 3.63693295e-03 2.34863859e-04]
+     [2.83505757e-04 4.54616618e-04 2.93579824e-05]
+     [8.40017059e-05 1.34701220e-04 8.69866146e-06]]
     """
 
     _field_func = staticmethod(magnet_sphere_field)
-    _field_func_kwargs_ndim = {"magnetization": 2, "diameter": 1}
+    _field_func_kwargs_ndim = {"polarization": 2, "diameter": 1}
     get_trace = make_Sphere
 
     def __init__(
         self,
-        magnetization=None,
-        diameter=None,
         position=(0, 0, 0),
         orientation=None,
+        diameter=None,
+        polarization=None,
+        magnetization=None,
         style=None,
         **kwargs,
     ):
@@ -96,17 +103,19 @@ def __init__(
         self.diameter = diameter
 
         # init inheritance
-        super().__init__(position, orientation, magnetization, style, **kwargs)
+        super().__init__(
+            position, orientation, magnetization, polarization, style, **kwargs
+        )
 
     # property getters and setters
     @property
     def diameter(self):
-        """Diameter of the sphere in units of mm."""
+        """Diameter of the sphere in units of m."""
         return self._diameter
 
     @diameter.setter
     def diameter(self, dia):
-        """Set Sphere diameter, float, mm."""
+        """Set Sphere diameter, float, meter."""
         self._diameter = check_format_input_scalar(
             dia,
             sig_name="diameter",
@@ -120,4 +129,4 @@ def _default_style_description(self):
         """Default style description text"""
         if self.diameter is None:
             return "no dimension"
-        return f"D={unit_prefix(self.diameter / 1000)}m"
+        return f"D={unit_prefix(self.diameter)}m"
diff --git a/magpylib/_src/obj_classes/class_magnet_Tetrahedron.py b/magpylib/_src/obj_classes/class_magnet_Tetrahedron.py
index bddea9115..66409c651 100644
--- a/magpylib/_src/obj_classes/class_magnet_Tetrahedron.py
+++ b/magpylib/_src/obj_classes/class_magnet_Tetrahedron.py
@@ -17,30 +17,32 @@ class Tetrahedron(BaseMagnet):
     is determined by its vertices and. It is not necessarily located in the origin an can
     be computed with the barycenter property.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    magnetization: array_like, shape (3,), default=`None`
-        Magnetization vector (mu0*M, remanence field) in units of mT given in
-        the local object coordinates (rotates with object).
-
-    vertices: ndarray, shape (4,3)
-        Vertices [(x1,y1,z1), (x2,y2,z2), (x3,y3,z3), (x4,y4,z4)], in the relative
-        coordinate system of the tetrahedron.
-
     position: array_like, shape (3,) or (m,3)
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
         When setting vertices, the initial position is set to the barycenter.
 
-    barycenter: array_like, shape (3,)
-        Read only property that returns the geometric barycenter (=center of mass)
-        of the object.
-
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
         Object orientation(s) in the global coordinates. `None` corresponds to
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    vertices: ndarray, shape (4,3)
+        Vertices [(x1,y1,z1), (x2,y2,z2), (x3,y3,z3), (x4,y4,z4)], in the relative
+        coordinate system of the tetrahedron.
+
+    polarization: array_like, shape (3,), default=`None`
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).
+
+    magnetization: array_like, shape (3,), default=`None`
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -48,76 +50,84 @@ class Tetrahedron(BaseMagnet):
         Object style inputs must be in dictionary form, e.g. `{'color':'red'}` or
         using style underscore magic, e.g. `style_color='red'`.
 
+    Attributes
+    ----------
+    barycenter: array_like, shape (3,)
+        Read only property that returns the geometric barycenter (=center of mass)
+        of the object.
+
     Returns
     -------
     magnet source: `Tetrahedron` object
 
     Examples
     --------
-    `Tetrahedron` magnets are magnetic field sources. Below we compute the H-field in kA/m of a
-    tetrahedron magnet with magnetization (100,200,300) in units of mT dimensions defined
-    through the vertices (0,0,0), (1,0,0), (0,1,0) and (0,0,1) in units of mm at the
-    observer position (1,1,1) given in units of mm:
+    `Tetrahedron` magnets are magnetic field sources. Below we compute the H-field in A/m of a
+    tetrahedron magnet with polarization (0.1,0.2,0.3) in units of T dimensions defined
+    through the vertices (0,0,0), (.01,0,0), (0,.01,0) and (0,0,.01) in units of m at the
+    observer position (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> verts = [(0,0,0), (1,0,0), (0,1,0), (0,0,1)]
-    >>> src = magpy.magnet.Tetrahedron(magnetization=(100,200,300), vertices=verts)
-    >>> H = src.getH((1,1,1))
+    >>> verts = [(0,0,0), (.01,0,0), (0,.01,0), (0,0,.01)]
+    >>> src = magpy.magnet.Tetrahedron(polarization=(.1,.2,.3), vertices=verts)
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [2.07089783 1.65671826 1.2425387 ]
+    [2070.89782733 1656.71826186 1242.5386964 ]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
-    src.rotate_from_angax(45, 'x')
+    >>> src.rotate_from_angax(45, 'x')
     Tetrahedron(id=...)
-    B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
-    print(B)
-    [[ 8.68006559e-01  2.00895792e+00 -5.03469140e-01]
-    [ 1.01357229e-01  1.93731796e-01 -1.59677364e-02]
-    [ 2.90426931e-02  5.22556994e-02 -1.70596096e-03]]
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
+    >>> print(B)
+    [[ 8.68006559e-04  2.00895792e-03 -5.03469140e-04]
+     [ 1.01357229e-04  1.93731796e-04 -1.59677364e-05]
+     [ 2.90426931e-05  5.22556994e-05 -1.70596096e-06]]
 
     The same result is obtained when the rotated source moves along a path away from an
     observer at position (1,1,1). Here we use a `Sensor` object as observer.
 
-    sens = magpy.Sensor(position=(1,1,1))
-    src.move([(-1,-1,-1), (-2,-2,-2)])
-    Sensor(id=...)
-    B = src.getB(sens)
-    print(B)
-    [[ 8.68006559e-01  2.00895792e+00 -5.03469140e-01]
-    [ 1.01357229e-01  1.93731796e-01 -1.59677364e-02]
-    [ 2.90426931e-02  5.22556994e-02 -1.70596096e-03]]
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
+    Tetrahedron(id=...)
+    >>> B = src.getB(sens)
+    >>> print(B)
+    [[ 8.68006559e-04  2.00895792e-03 -5.03469140e-04]
+     [ 1.01357229e-04  1.93731796e-04 -1.59677364e-05]
+     [ 2.90426931e-05  5.22556994e-05 -1.70596096e-06]]
     """
 
     _field_func = staticmethod(magnet_tetrahedron_field)
-    _field_func_kwargs_ndim = {"magnetization": 1, "vertices": 3}
+    _field_func_kwargs_ndim = {"polarization": 1, "vertices": 3}
     get_trace = make_Tetrahedron
 
     def __init__(
         self,
-        magnetization=None,
-        vertices=None,
         position=(0, 0, 0),
         orientation=None,
+        vertices=None,
+        polarization=None,
+        magnetization=None,
         style=None,
         **kwargs,
     ):
         # instance attributes
         self.vertices = vertices
-        self._object_type = "Tetrahedron"
 
         # init inheritance
-        super().__init__(position, orientation, magnetization, style, **kwargs)
+        super().__init__(
+            position, orientation, magnetization, polarization, style, **kwargs
+        )
 
     # property getters and setters
     @property
     def vertices(self):
-        """Length of the Tetrahedron sides [a,b,c] in units of mm."""
+        """Length of the Tetrahedron sides [a,b,c] in units of m."""
         return self._vertices
 
     @vertices.setter
     def vertices(self, dim):
-        """Set Tetrahedron vertices (a,b,c), shape (3,), (mm)."""
+        """Set Tetrahedron vertices (a,b,c), shape (3,), (meter)."""
         self._vertices = check_format_input_vector(
             dim,
             dims=(2,),
diff --git a/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py b/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py
index c6b9883ba..5e987b5f5 100644
--- a/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py
+++ b/magpylib/_src/obj_classes/class_magnet_TriangularMesh.py
@@ -28,30 +28,37 @@
 class TriangularMesh(BaseMagnet):
     """Magnet with homogeneous magnetization defined by triangular surface mesh.
     Can be used as `sources` input for magnetic field computation.
+
     When `position=(0,0,0)` and `orientation=None` the TriangularMesh vertices
     are the same as in the global coordinate system.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    magnetization: array_like, shape (3,), default=`None`
-        Magnetization vector (mu0*M, remanence field) in units of mT given in
-        the local object coordinates (rotates with object).
+    position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
+        Object position(s) in the global coordinates in units of m. For m>1, the
+        `position` and `orientation` attributes together represent an object path.
+
+    orientation: scipy `Rotation` object with length 1 or m, default=`None`
+        Object orientation(s) in the global coordinates. `None` corresponds to
+        a unit-rotation. For m>1, the `position` and `orientation` attributes
+        together represent an object path.
 
     vertices: ndarray, shape (n,3)
-        A set of points in units of mm in the local object coordinates from which the
+        A set of points in units of m in the local object coordinates from which the
         triangular faces of the mesh are constructed by the additional `faces`input.
 
     faces: ndarray, shape (n,3)
         Indices of vertices. Each triplet represents one triangle of the mesh.
 
-    position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
-        `position` and `orientation` attributes together represent an object path.
+    polarization: array_like, shape (3,), default=`None`
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).
 
-    orientation: scipy `Rotation` object with length 1 or m, default=`None`
-        Object orientation(s) in the global coordinates. `None` corresponds to
-        a unit-rotation. For m>1, the `position` and `orientation` attributes
-        together represent an object path.
+    magnetization: array_like, shape (3,), default=`None`
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).
 
     reorient_faces: bool or string, default=`True`
         In a properly oriented mesh, all faces must be oriented outwards.
@@ -95,30 +102,31 @@ class TriangularMesh(BaseMagnet):
 
     Examples
     --------
-    We compute the B-field in units of mT of a triangular mesh (4 vertices, 4 faces)
-    with magnetization (100,200,300) in units of mT at the observer position
-    (1,1,1) given in units of mm:
+    We compute the B-field in units of T of a triangular mesh (4 vertices, 4 faces)
+    with polarization (0.1,0.2,0.3) in units of T at the observer position
+    (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> vv = ((0,0,0), (1,0,0), (0,1,0), (0,0,1))
+    >>> vv = ((0,0,0), (.01,0,0), (0,.01,0), (0,0,.01))
     >>> tt = ((0,1,2), (0,1,3), (0,2,3), (1,2,3))
-    >>> trim = magpy.magnet.TriangularMesh(magnetization=(100,200,300), vertices=vv, faces=tt)
-    >>> print(trim.getB((1,1,1)))
-    [2.60236696 2.08189357 1.56142018]
+    >>> trim = magpy.magnet.TriangularMesh(polarization=(.1,.2,.3), vertices=vv, faces=tt)
+    >>> print(trim.getB((.01,.01,.01)))
+    [0.00260237 0.00208189 0.00156142]
     """
 
     _field_func = staticmethod(magnet_trimesh_field)
-    _field_func_kwargs_ndim = {"magnetization": 2, "mesh": 3}
+    _field_func_kwargs_ndim = {"polarization": 2, "mesh": 3}
     get_trace = make_TriangularMesh
     _style_class = TriangularMeshStyle
 
     def __init__(
         self,
-        magnetization=None,
-        vertices=None,
-        faces=None,
         position=(0, 0, 0),
         orientation=None,
+        vertices=None,
+        faces=None,
+        polarization=None,
+        magnetization=None,
         check_open="warn",
         check_disconnected="warn",
         check_selfintersecting="warn",
@@ -141,7 +149,9 @@ def __init__(
         self.check_selfintersecting(mode=check_selfintersecting)
 
         # inherit
-        super().__init__(position, orientation, magnetization, style, **kwargs)
+        super().__init__(
+            position, orientation, magnetization, polarization, style, **kwargs
+        )
 
     # property getters and setters
     @property
@@ -507,9 +517,7 @@ def _input_check(self, vertices, faces):
 
     def to_TriangleCollection(self):
         """Return a Collection of Triangle objects from the current TriangularMesh"""
-        tris = [
-            Triangle(magnetization=self.magnetization, vertices=v) for v in self.mesh
-        ]
+        tris = [Triangle(polarization=self.polarization, vertices=v) for v in self.mesh]
         coll = Collection(tris)
         coll.position = self.position
         coll.orientation = self.orientation
@@ -520,10 +528,11 @@ def to_TriangleCollection(self):
     @classmethod
     def from_ConvexHull(
         cls,
-        magnetization=None,
-        points=None,
         position=(0, 0, 0),
         orientation=None,
+        points=None,
+        polarization=None,
+        magnetization=None,
         check_open="warn",
         check_disconnected="warn",
         reorient_faces=True,
@@ -532,17 +541,12 @@ def from_ConvexHull(
     ):
         """Create a TriangularMesh magnet from a point cloud via its convex hull.
 
+        SI units are used for all inputs and outputs.
+
         Parameters
         ----------
-        magnetization: array_like, shape (3,), default=`None`
-            Magnetization vector (mu0*M, remanence field) in units of mT given in
-            the local object coordinates (rotates with object).
-
-        points: ndarray, shape (n,3)
-            Point cloud from which the convex hull is computed.
-
         position: array_like, shape (3,) or (m,3)
-            Object position(s) in the global coordinates in units of mm. For m>1, the
+            Object position(s) in the global coordinates in units of m. For m>1, the
             `position` and `orientation` attributes together represent an object path.
 
         orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -550,6 +554,17 @@ def from_ConvexHull(
             a unit-rotation. For m>1, the `position` and `orientation` attributes
             together represent an object path.
 
+        points: ndarray, shape (n,3)
+            Point cloud from which the convex hull is computed.
+
+        polarization: array_like, shape (3,), default=`None`
+            Magnetic polarization vector J = mu0*M in units of T,
+            given in the local object coordinates (rotates with object).
+
+        magnetization: array_like, shape (3,), default=`None`
+            Magnetization vector M = J/mu0 in units of A/m,
+            given in the local object coordinates (rotates with object).
+
         reorient_faces: bool, default=`True`
             In a properly oriented mesh, all faces must be oriented outwards.
             If `True`, check and fix the orientation of each triangle.
@@ -590,11 +605,12 @@ def from_ConvexHull(
         --------
         """
         return cls(
-            magnetization=magnetization,
-            vertices=points,
-            faces=ConvexHull(points).simplices,
             position=position,
             orientation=orientation,
+            vertices=points,
+            faces=ConvexHull(points).simplices,
+            polarization=polarization,
+            magnetization=magnetization,
             reorient_faces=reorient_faces,
             check_open=check_open,
             check_disconnected=check_disconnected,
@@ -605,10 +621,11 @@ def from_ConvexHull(
     @classmethod
     def from_pyvista(
         cls,
-        magnetization=None,
-        polydata=None,
         position=(0, 0, 0),
         orientation=None,
+        polydata=None,
+        polarization=None,
+        magnetization=None,
         check_open="warn",
         check_disconnected="warn",
         reorient_faces=True,
@@ -617,17 +634,12 @@ def from_pyvista(
     ):
         """Create a TriangularMesh magnet from a pyvista PolyData mesh object.
 
+        SI units are used for all inputs and outputs.
+
         Parameters
         ----------
-        magnetization: array_like, shape (3,), default=`None`
-            Magnetization vector (mu0*M, remanence field) in units of mT given in
-            the local object coordinates (rotates with object).
-
-        polydata: pyvista.core.pointset.PolyData object
-            A valid pyvista Polydata mesh object. (e.g. `pyvista.Sphere()`)
-
         position: array_like, shape (3,) or (m,3)
-            Object position(s) in the global coordinates in units of mm. For m>1, the
+            Object position(s) in the global coordinates in units of m. For m>1, the
             `position` and `orientation` attributes together represent an object path.
 
         orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -635,6 +647,17 @@ def from_pyvista(
             a unit-rotation. For m>1, the `position` and `orientation` attributes
             together represent an object path.
 
+        polydata: pyvista.core.pointset.PolyData object
+            A valid pyvista Polydata mesh object. (e.g. `pyvista.Sphere()`)
+
+        polarization: array_like, shape (3,), default=`None`
+            Magnetic polarization vector J = mu0*M in units of T,
+            given in the local object coordinates (rotates with object).
+
+        magnetization: array_like, shape (3,), default=`None`
+            Magnetization vector M = J/mu0 in units of A/m,
+            given in the local object coordinates (rotates with object).
+
         reorient_faces: bool, default=`True`
             In a properly oriented mesh, all faces must be oriented outwards.
             If `True`, check and fix the orientation of each triangle.
@@ -692,11 +715,12 @@ def from_pyvista(
         faces = polydata.faces.reshape(-1, 4)[:, 1:]
 
         return cls(
-            magnetization=magnetization,
-            vertices=vertices,
-            faces=faces,
             position=position,
             orientation=orientation,
+            vertices=vertices,
+            faces=faces,
+            polarization=polarization,
+            magnetization=magnetization,
             reorient_faces=reorient_faces,
             check_open=check_open,
             check_disconnected=check_disconnected,
@@ -707,10 +731,11 @@ def from_pyvista(
     @classmethod
     def from_triangles(
         cls,
-        magnetization=None,
-        triangles=None,
         position=(0, 0, 0),
         orientation=None,
+        triangles=None,
+        polarization=None,
+        magnetization=None,
         reorient_faces=True,
         check_open="warn",
         check_disconnected="warn",
@@ -719,17 +744,12 @@ def from_triangles(
     ):
         """Create a TriangularMesh magnet from a list or Collection of Triangle objects.
 
+        SI units are used for all inputs and outputs.
+
         Parameters
         ----------
-        magnetization: array_like, shape (3,), default=`None`
-            Magnetization vector (mu0*M, remanence field) in units of mT given in
-            the local object coordinates (rotates with object).
-
-        triangles: list or Collection of Triangle objects
-            Only vertices of Triangle objects are taken, magnetization is ignored.
-
         position: array_like, shape (3,) or (m,3)
-            Object position(s) in the global coordinates in units of mm. For m>1, the
+            Object position(s) in the global coordinates in units of m. For m>1, the
             `position` and `orientation` attributes together represent an object path.
 
         orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -737,6 +757,17 @@ def from_triangles(
             a unit-rotation. For m>1, the `position` and `orientation` attributes
             together represent an object path.
 
+        triangles: list or Collection of Triangle objects
+            Only vertices of Triangle objects are taken, magnetization is ignored.
+
+        polarization: array_like, shape (3,), default=`None`
+            Magnetic polarization vector J = mu0*M in units of T,
+            given in the local object coordinates (rotates with object).
+
+        magnetization: array_like, shape (3,), default=`None`
+            Magnetization vector M = J/mu0 in units of A/m,
+            given in the local object coordinates (rotates with object).
+
         reorient_faces: bool, default=`True`
             In a properly oriented mesh, all faces must be oriented outwards.
             If `True`, check and fix the orientation of each triangle.
@@ -792,11 +823,12 @@ def from_triangles(
         faces = tr.reshape((-1, 3))
 
         return cls(
-            magnetization=magnetization,
-            vertices=vertices,
-            faces=faces,
             position=position,
             orientation=orientation,
+            vertices=vertices,
+            faces=faces,
+            polarization=polarization,
+            magnetization=magnetization,
             reorient_faces=reorient_faces,
             check_open=check_open,
             check_disconnected=check_disconnected,
@@ -807,10 +839,11 @@ def from_triangles(
     @classmethod
     def from_mesh(
         cls,
-        magnetization=None,
-        mesh=None,
         position=(0, 0, 0),
         orientation=None,
+        mesh=None,
+        polarization=None,
+        magnetization=None,
         reorient_faces=True,
         check_open="warn",
         check_disconnected="warn",
@@ -819,17 +852,12 @@ def from_mesh(
     ):
         """Create a TriangularMesh magnet from a mesh input.
 
+        SI units are used for all inputs and outputs.
+
         Parameters
         ----------
-        magnetization: array_like, shape (3,), default=`None`
-            Magnetization vector (mu0*M, remanence field) in units of mT given in
-            the local object coordinates (rotates with object).
-
-        mesh: array_like, shape (n,3,3)
-            An array_like of triangular faces that make up a triangular mesh.
-
         position: array_like, shape (3,) or (m,3)
-            Object position(s) in the global coordinates in units of mm. For m>1, the
+            Object position(s) in the global coordinates in units of m. For m>1, the
             `position` and `orientation` attributes together represent an object path.
 
         orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -837,6 +865,17 @@ def from_mesh(
             a unit-rotation. For m>1, the `position` and `orientation` attributes
             together represent an object path.
 
+        mesh: array_like, shape (n,3,3)
+            An array_like of triangular faces that make up a triangular mesh.
+
+        polarization: array_like, shape (3,), default=`None`
+            Magnetic polarization vector J = mu0*M in units of T,
+            given in the local object coordinates (rotates with object).
+
+        magnetization: array_like, shape (3,), default=`None`
+            Magnetization vector M = J/mu0 in units of A/m,
+            given in the local object coordinates (rotates with object).
+
         reorient_faces: bool, default=`True`
             In a properly oriented mesh, all faces must be oriented outwards.
             If `True`, check and fix the orientation of each triangle.
@@ -885,11 +924,12 @@ def from_mesh(
         faces = tr.reshape((-1, 3))
 
         return cls(
-            magnetization=magnetization,
-            vertices=vertices,
-            faces=faces,
             position=position,
             orientation=orientation,
+            vertices=vertices,
+            faces=faces,
+            polarization=polarization,
+            magnetization=magnetization,
             reorient_faces=reorient_faces,
             check_open=check_open,
             check_disconnected=check_disconnected,
diff --git a/magpylib/_src/obj_classes/class_misc_CustomSource.py b/magpylib/_src/obj_classes/class_misc_CustomSource.py
index a8896a074..ce821d016 100644
--- a/magpylib/_src/obj_classes/class_misc_CustomSource.py
+++ b/magpylib/_src/obj_classes/class_misc_CustomSource.py
@@ -10,17 +10,13 @@ class CustomSource(BaseSource):
     When `position=(0,0,0)` and `orientation=None` local object coordinates
     coincide with the global coordinate system.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    field_func: callable, default=`None`
-        The function for B- and H-field computation must have the two positional arguments
-        `field` and `observers`. With `field='B'` or `field='H'` the B- or H-field in units
-        of mT or kA/m must be returned respectively. The `observers` argument must
-        accept numpy ndarray inputs of shape (n,3), in which case the returned fields must
-        be numpy ndarrays of shape (n,3) themselves.
 
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -28,6 +24,13 @@ class CustomSource(BaseSource):
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    field_func: callable, default=`None`
+        The function for B- and H-field computation must have the two positional arguments
+        `field` and `observers`. With `field='B'` or `field='H'` the B- or H-field in units
+        of T or A/m must be returned respectively. The `observers` argument must
+        accept numpy ndarray inputs of shape (n,3), in which case the returned fields must
+        be numpy ndarrays of shape (n,3) themselves.
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -44,47 +47,47 @@ class CustomSource(BaseSource):
     With version 4 `CustomSource` objects enable users to define their own source
     objects, and to embedded them in the Magpylib object oriented interface. In this example
     we create a source that generates a constant field and evaluate the field at observer
-    position (1,1,1) given in mm:
+    position (0.01,0.01,0.01) given in meters:
 
     >>> import numpy as np
     >>> import magpylib as magpy
-    >>>
-    >>> funcBH = lambda field, observers: np.array([(100 if field=='B' else 80,0,0)]*len(observers))
+    >>> def funcBH(field, observers):
+    ...     return np.array([(.01 if field=='B' else .08,0,0)]*len(observers))
     >>> src = magpy.misc.CustomSource(field_func=funcBH)
-    >>> H = src.getH((1,1,1))
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [80.  0.  0.]
+    [0.08 0.   0.  ]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'z')
     CustomSource(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[70.71067812 70.71067812  0.        ]
-     [70.71067812 70.71067812  0.        ]
-     [70.71067812 70.71067812  0.        ]]
+    [[0.00707107 0.00707107 0.        ]
+     [0.00707107 0.00707107 0.        ]
+     [0.00707107 0.00707107 0.        ]]
 
     The same result is obtained when the rotated source moves along a path away from an
-    observer at position (1,1,1). This time we use a `Sensor` object as observer.
+    observer at position (0.01,0.01,0.01). This time we use a `Sensor` object as observer.
 
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     CustomSource(id=...)
-    >>> sens = magpy.Sensor(position=(1,1,1))
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
     >>> B = src.getB(sens)
     >>> print(B)
-    [[70.71067812 70.71067812  0.        ]
-     [70.71067812 70.71067812  0.        ]
-     [70.71067812 70.71067812  0.        ]]
+    [[0.00707107 0.00707107 0.        ]
+     [0.00707107 0.00707107 0.        ]
+     [0.00707107 0.00707107 0.        ]]
     """
 
     _editable_field_func = True
 
     def __init__(
         self,
-        field_func=None,
         position=(0, 0, 0),
         orientation=None,
+        field_func=None,
         style=None,
         **kwargs,
     ):
diff --git a/magpylib/_src/obj_classes/class_misc_Dipole.py b/magpylib/_src/obj_classes/class_misc_Dipole.py
index 3513a37fe..ae18537df 100644
--- a/magpylib/_src/obj_classes/class_misc_Dipole.py
+++ b/magpylib/_src/obj_classes/class_misc_Dipole.py
@@ -17,15 +17,12 @@ class Dipole(BaseSource):
     When `position=(0,0,0)` and `orientation=None` the dipole is located in the origin of
     global coordinate system.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    moment: array_like, shape (3,), unit mT*mm^3, default=`None`
-        Magnetic dipole moment in units of mT*mm^3 given in the local object coordinates.
-        For homogeneous magnets the relation moment=magnetization*volume holds. The dipole
-        moment of a Circle object is pi**2/10*diameter**2*current.
-
     position: array_like, shape (3,) or (m,3), default=`(0,0,0)`
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
@@ -33,6 +30,11 @@ class Dipole(BaseSource):
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    moment: array_like, shape (3,), unit A·m², default=`None`
+        Magnetic dipole moment in units of A·m² given in the local object coordinates.
+        For homogeneous magnets the relation moment=magnetization*volume holds. For
+        current loops the relation moment = current*loop_surface holds.
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -46,37 +48,37 @@ class Dipole(BaseSource):
 
     Examples
     --------
-    `Dipole` objects are magnetic field sources. In this example we compute the H-field kA/m
-    of such a magnetic dipole with a moment of (100,100,100) in units of mT*mm^2 at an
-    observer position (1,1,1) given in units of mm:
+    `Dipole` objects are magnetic field sources. In this example we compute the H-field in A/m
+    of such a magnetic dipole with a moment of (100,100,100) in units of A·m² at an
+    observer position (.01,.01,.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> src = magpy.misc.Dipole(moment=(100,100,100))
-    >>> H = src.getH((1,1,1))
+    >>> src = magpy.misc.Dipole(moment=(10,10,10))
+    >>> H = src.getH((.01,.01,.01))
     >>> print(H)
-    [2.43740886 2.43740886 2.43740886]
+    [306293.83078988 306293.83078988 306293.83078988]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     Dipole(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[2.16582445 3.6972936  1.53146915]
-     [0.27072806 0.4621617  0.19143364]
-     [0.08021572 0.1369368  0.05672108]]
+    [[0.27216553 0.46461562 0.19245009]
+     [0.03402069 0.05807695 0.02405626]
+     [0.0100802  0.01720799 0.00712778]]
 
     The same result is obtained when the rotated source moves along a path away from an
     observer at position (1,1,1). This time we use a `Sensor` object as observer.
 
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     Dipole(id=...)
-    >>> sens = magpy.Sensor(position=(1,1,1))
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
     >>> B = src.getB(sens)
     >>> print(B)
-    [[2.16582445 3.6972936  1.53146915]
-     [0.27072806 0.4621617  0.19143364]
-     [0.08021572 0.1369368  0.05672108]]
+    [[0.27216553 0.46461562 0.19245009]
+     [0.03402069 0.05807695 0.02405626]
+     [0.0100802  0.01720799 0.00712778]]
     """
 
     _field_func = staticmethod(dipole_field)
@@ -87,9 +89,9 @@ class Dipole(BaseSource):
 
     def __init__(
         self,
-        moment=None,
         position=(0, 0, 0),
         orientation=None,
+        moment=None,
         style=None,
         **kwargs,
     ):
@@ -102,12 +104,12 @@ def __init__(
     # property getters and setters
     @property
     def moment(self):
-        """Magnetic dipole moment in units of mT*mm^3 given in the local object coordinates."""
+        """Magnetic dipole moment in units of A·m² given in the local object coordinates."""
         return self._moment
 
     @moment.setter
     def moment(self, mom):
-        """Set dipole moment vector, shape (3,), unit mT*mm^3."""
+        """Set dipole moment vector, shape (3,), unit A·m²."""
         self._moment = check_format_input_vector(
             mom,
             dims=(1,),
@@ -124,4 +126,4 @@ def _default_style_description(self):
         moment_mag = np.linalg.norm(moment)
         if moment_mag == 0:
             return "no moment"
-        return f"moment={unit_prefix(moment_mag)}mT mm³"
+        return f"moment={unit_prefix(moment_mag)}A·m²"
diff --git a/magpylib/_src/obj_classes/class_misc_Triangle.py b/magpylib/_src/obj_classes/class_misc_Triangle.py
index 1ac9e82c7..8f14f974c 100644
--- a/magpylib/_src/obj_classes/class_misc_Triangle.py
+++ b/magpylib/_src/obj_classes/class_misc_Triangle.py
@@ -18,30 +18,34 @@ class Triangle(BaseMagnet):
     Triangle vertices coincide with the global coordinate system. The geometric
     center of the Triangle is determined by its vertices.
 
+    SI units are used for all inputs and outputs.
+
     Parameters
     ----------
-    magnetization: array_like, shape (3,), default=`None`
-        Magnetization vector (mu0*M, remanence field) in units of mT given in
-        the local object coordinates (rotates with object). The homogeneous surface
-        charge of the Triangle is given by the projection of the magnetization on the
-        Triangle normal vector (right-hand-rule).
-
-    vertices: ndarray, shape (3,3)
-        Triple of vertices in the local object coordinates.
-
     position: array_like, shape (3,) or (m,3)
-        Object position(s) in the global coordinates in units of mm. For m>1, the
+        Object position(s) in the global coordinates in units of m. For m>1, the
         `position` and `orientation` attributes together represent an object path.
 
-    barycenter: array_like, shape (3,)
-        Read only property that returns the geometric barycenter (=center of mass)
-        of the object.
-
     orientation: scipy `Rotation` object with length 1 or m, default=`None`
         Object orientation(s) in the global coordinates. `None` corresponds to
         a unit-rotation. For m>1, the `position` and `orientation` attributes
         together represent an object path.
 
+    vertices: ndarray, shape (3,3)
+        Triple of vertices in the local object coordinates.
+
+    polarization: array_like, shape (3,), default=`None`
+        Magnetic polarization vector J = mu0*M in units of T,
+        given in the local object coordinates (rotates with object).The homogeneous surface
+        charge of the Triangle is given by the projection of the polarization on the
+        Triangle normal vector (right-hand-rule).
+
+    magnetization: array_like, shape (3,), default=`None`
+        Magnetization vector M = J/mu0 in units of A/m,
+        given in the local object coordinates (rotates with object).The homogeneous surface
+        charge of the Triangle is given by the projection of the magnetization on the
+        Triangle normal vector (right-hand-rule).
+
     parent: `Collection` object or `None`
         The object is a child of it's parent collection.
 
@@ -49,66 +53,74 @@ class Triangle(BaseMagnet):
         Object style inputs must be in dictionary form, e.g. `{'color':'red'}` or
         using style underscore magic, e.g. `style_color='red'`.
 
+    Attributes
+    ----------
+    barycenter: array_like, shape (3,)
+        Read only property that returns the geometric barycenter (=center of mass)
+        of the object.
+
     Returns
     -------
     magnet source: `Triangle` object
 
     Examples
     --------
-    `Triangle` objects are magnetic field sources. Below we compute the H-field in kA/m of a
-    Triangle object with magnetization (100,200,300) in units of mT, dimensions defined
-    through the vertices (0,0,0), (1,0,0) and (0,1,0) in units of mm at the
-    observer position (1,1,1) given in units of mm:
+    `Triangle` objects are magnetic field sources. Below we compute the H-field in A/m of a
+    Triangle object with polarization (0.01,0.02,0.03) in units of T, dimensions defined
+    through the vertices (0,0,0), (0.01,0,0) and (0,0.01,0) in units of m at the
+    observer position (0.01,0.01,0.01) given in units of m:
 
     >>> import magpylib as magpy
-    >>> verts = [(0,0,0), (1,0,0), (0,1,0)]
-    >>> src = magpy.misc.Triangle(magnetization=(100,200,300), vertices=verts)
-    >>> H = src.getH((1,1,1))
+    >>> verts = [(0,0,0), (.01,0,0), (0,.01,0)]
+    >>> src = magpy.misc.Triangle(polarization=(.1,.2,.3), vertices=verts)
+    >>> H = src.getH((.1,.1,.1))
     >>> print(H)
-    [2.24851814 2.24851814 3.49105683]
+    [18.88869831 18.88869831 19.54560637]
 
     We rotate the source object, and compute the B-field, this time at a set of observer positions:
 
     >>> src.rotate_from_angax(45, 'x')
     Triangle(id=...)
-    >>> B = src.getB([(1,1,1), (2,2,2), (3,3,3)])
+    >>> B = src.getB([(.01,.01,.01), (.02,.02,.02), (.03,.03,.03)])
     >>> print(B)
-    [[3.94659011 4.21772671 4.21772671]
-     [0.73745776 0.77325648 0.77325648]
-     [0.30049474 0.31043974 0.31043974]]
+    [[0.00394659 0.00421773 0.00421773]
+     [0.00073746 0.00077326 0.00077326]
+     [0.00030049 0.00031044 0.00031044]]
 
     The same result is obtained when the rotated source moves along a path away from an
-    observer at position (1,1,1). Here we use a `Sensor` object as observer.
+    observer at position (0.01,0.01,0.01). Here we use a `Sensor` object as observer.
 
-    >>> sens = magpy.Sensor(position=(1,1,1))
-    >>> src.move([(-1,-1,-1), (-2,-2,-2)])
+    >>> sens = magpy.Sensor(position=(.01,.01,.01))
+    >>> src.move([(-.01,-.01,-.01), (-.02,-.02,-.02)])
     Triangle(id=...)
     >>> B = src.getB(sens)
     >>> print(B)
-    [[3.94659011 4.21772671 4.21772671]
-     [0.73745776 0.77325648 0.77325648]
-     [0.30049474 0.31043974 0.31043974]]
-
+    [[0.00394659 0.00421773 0.00421773]
+     [0.00073746 0.00077326 0.00077326]
+     [0.00030049 0.00031044 0.00031044]]
     """
 
     _field_func = staticmethod(triangle_field)
-    _field_func_kwargs_ndim = {"magnetization": 2, "vertices": 2}
+    _field_func_kwargs_ndim = {"polarization": 2, "vertices": 2}
     get_trace = make_Triangle
     _style_class = TriangleStyle
 
     def __init__(
         self,
-        magnetization=None,
-        vertices=None,
         position=(0, 0, 0),
         orientation=None,
+        vertices=None,
+        polarization=None,
+        magnetization=None,
         style=None,
         **kwargs,
     ):
         self.vertices = vertices
 
         # init inheritance
-        super().__init__(position, orientation, magnetization, style, **kwargs)
+        super().__init__(
+            position, orientation, magnetization, polarization, style, **kwargs
+        )
 
     # property getters and setters
     @property
@@ -118,7 +130,7 @@ def vertices(self):
 
     @vertices.setter
     def vertices(self, val):
-        """Set face vertices (a,b,c), shape (3,3), mm."""
+        """Set face vertices (a,b,c), shape (3,3), meter."""
         self._vertices = check_format_input_vector(
             val,
             dims=(2,),
diff --git a/magpylib/_src/style.py b/magpylib/_src/style.py
index af59359d4..fa5aa56c2 100644
--- a/magpylib/_src/style.py
+++ b/magpylib/_src/style.py
@@ -324,6 +324,9 @@ class Legend(MagicProperties):
 
     Parameters
     ----------
+    text: str, default=None
+        Object description text.
+
     show: bool, default=None
         If True, adds legend entry based on value.
     """
@@ -331,6 +334,19 @@ class Legend(MagicProperties):
     def __init__(self, show=None, **kwargs):
         super().__init__(show=show, **kwargs)
 
+    @property
+    def text(self):
+        """Legend text."""
+        return self._text
+
+    @text.setter
+    def text(self, val):
+        assert val is None or isinstance(val, str), (
+            f"The `show` property of {type(self).__name__} must be a string,\n"
+            f"but received {repr(val)} instead."
+        )
+        self._text = val
+
     @property
     def show(self):
         """If True, adds legend entry based on value."""
@@ -1497,7 +1513,7 @@ class SensorProperties:
 
     sizemode: {'scaled', 'absolute'}, default='scaled'
         Defines the scale reference for the sensor size. If 'absolute', the `size` parameters
-        becomes the sensor size in millimeters.
+        becomes the sensor size in meters.
 
     pixel: dict, Pixel, default=None
         `Pixel` object or dict with equivalent key/value pairs (e.g. `color`, `size`).
@@ -1561,7 +1577,7 @@ class DefaultSensor(MagicProperties, SensorProperties):
 
     sizemode: {'scaled', 'absolute'}, default='scaled'
         Defines the scale reference for the sensor size. If 'absolute', the `size` parameters
-        becomes the sensor size in millimeters.
+        becomes the sensor size in meters.
 
     pixel: dict, Pixel, default=None
         `Pixel` object or dict with equivalent key/value pairs (e.g. `color`, `size`).
@@ -1640,7 +1656,7 @@ class Pixel(MagicProperties):
 
     sizemode: {'scaled', 'absolute'}, default='scaled'
         Defines the scale reference for the pixel size. If 'absolute', the `size` parameters
-        becomes the pixel size in millimeters.
+        becomes the pixel size in meters.
 
     color: str, default=None
         Defines the pixel color@property.
@@ -1804,7 +1820,7 @@ class Arrow(Line):
 
     sizemode: {'scaled', 'absolute'}, default='scaled'
         Defines the scale reference for the arrow size. If 'absolute', the `size` parameters
-        becomes the arrow length in millimeters.
+        becomes the arrow length in meters.
 
     offset: float, default=0.5
         Defines the arrow offset. `offset=0` results in the arrow head to be coincident to start
@@ -2000,7 +2016,7 @@ class DipoleProperties:
 
     sizemode: {'scaled', 'absolute'}, default='scaled'
         Defines the scale reference for the dipole size. If 'absolute', the `size` parameters
-        becomes the dipole size in millimeters.
+        becomes the dipole size in meters.
 
     pivot: str
         The part of the arrow that is anchored to the X, Y grid.
@@ -2063,7 +2079,7 @@ class DefaultDipole(MagicProperties, DipoleProperties):
 
     sizemode: {'scaled', 'absolute'}, default='scaled'
         Defines the scale reference for the dipole size. If 'absolute', the `size` parameters
-        becomes the dipole size in millimeters.
+        becomes the dipole size in meters.
 
     pivot: str, default=None
         The part of the arrow that is anchored to the X, Y grid.
diff --git a/magpylib/_src/utility.py b/magpylib/_src/utility.py
index 7870a89a7..f4eef2514 100644
--- a/magpylib/_src/utility.py
+++ b/magpylib/_src/utility.py
@@ -21,6 +21,8 @@ def get_allowed_sources_msg():
 - string {srcs}"""
 
 
+MU0 = 4 * np.pi * 1e-7
+
 ALLOWED_OBSERVER_MSG = """Observers must be either
 - array_like positions of shape (N1, N2, ..., 3)
 - Sensor object
@@ -167,7 +169,7 @@ def check_duplicates(obj_list: Sequence) -> list:
     return obj_list_new
 
 
-def test_path_format(inp):
+def check_path_format(inp):
     """check if each object path has same length
     of obj.pos and obj.rot
     Parameters
diff --git a/pyproject.toml b/pyproject.toml
index f6a318d16..717c8fa71 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -40,7 +40,7 @@ code_style = [
     "pre-commit",
 ]
 docs = [
-    "sphinx==5.3",
+    "sphinx==7.2",
     "sphinx-design",
     "sphinx-thebe",
     "sphinx-favicon",
@@ -50,8 +50,7 @@ docs = [
     "myst-nb",
     "pandas",
     "numpy-stl",
-    "pyvista==0.37",
-    "panel",
+    "pyvista",
 ]
 test = [
     "tox>=4.11",
@@ -60,9 +59,8 @@ test = [
     "coverage",
     "pandas",
     "pyvista",
-    "ipygany",
-    "imageio[tifffile]",
-    "kaleido",
+    "ipywidgets", # for plotly FigureWidget
+    "imageio[tifffile, ffmpeg]",
     "jupyterlab",
 ]
 binder = [
@@ -79,5 +77,7 @@ Changelog = "https://github.com/magpylib/magpylib/blob/master/CHANGELOG.md"
 
 
 [tool.pytest.ini_options]
-addopts = "--doctest-modules"
+# backend_pyvista.py file imports pyvista on top level which messes with the namespace when running
+# doctests with the missing_pyvista test
+addopts = ["--doctest-modules", "--ignore-glob=*backend_pyvista.py"]
 testpaths = ["magpylib", "tests"]


Test patch:
diff --git a/tests/test_Coumpound_setters.py b/tests/test_Coumpound_setters.py
index c057cd4a5..8cb3083e8 100644
--- a/tests/test_Coumpound_setters.py
+++ b/tests/test_Coumpound_setters.py
@@ -58,7 +58,7 @@ def make_wheel(Ncubes=6, height=10, diameter=36, path_len=5, label=None):
 
     def cs_lambda():
         return magpy.magnet.Cuboid(
-            (1, 0, 0),
+            polarization=(1, 0, 0),
             dimension=[height] * 3,
             position=(diameter / 2, 0, 0),
         )
diff --git a/tests/test__missing_optional_modules.py b/tests/test__missing_optional_modules.py
index 7ee84dedf..3f96f1ae8 100644
--- a/tests/test__missing_optional_modules.py
+++ b/tests/test__missing_optional_modules.py
@@ -8,15 +8,15 @@
 
 def test_show_with_missing_pyvista():
     """Should raise if pyvista is not installed"""
-    src = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
+    src = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
     with patch.dict(sys.modules, {"pyvista": None}):
-        # with pytest.raises(ModuleNotFoundError):
-        src.show(return_fig=True, backend="pyvista")
+        with pytest.raises(ModuleNotFoundError):
+            src.show(return_fig=True, backend="pyvista")
 
 
 def test_dataframe_output_missing_pandas():
     """test if pandas is installed when using dataframe output in `getBH`"""
-    src = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
+    src = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
     with patch.dict(sys.modules, {"pandas": None}):
         with pytest.raises(ModuleNotFoundError):
             src.getB((0, 0, 0), output="dataframe")
diff --git a/tests/test_core_field_functions.py b/tests/test_core_field_functions.py
deleted file mode 100644
index 5aced4511..000000000
--- a/tests/test_core_field_functions.py
+++ /dev/null
@@ -1,630 +0,0 @@
-import numpy as np
-import pytest
-from numpy.testing import assert_allclose
-
-import magpylib as magpy
-from magpylib._src.exceptions import MagpylibDeprecationWarning
-from magpylib._src.exceptions import MagpylibMissingInput
-from magpylib._src.fields.field_BH_polyline import current_vertices_field
-from magpylib.core import current_circle_field
-from magpylib.core import current_line_field
-from magpylib.core import current_loop_field
-from magpylib.core import current_polyline_field
-from magpylib.core import dipole_field
-from magpylib.core import magnet_cuboid_field
-from magpylib.core import magnet_cylinder_segment_field
-from magpylib.core import magnet_sphere_field
-
-
-def test_magnet_cuboid_Bfield():
-    """test cuboid field"""
-    mag = np.array(
-        [
-            (0, 0, 0),
-            (1, 2, 3),
-            (1, 2, 3),
-            (1, 2, 3),
-            (1, 2, 3),
-            (2, 2, 2),
-            (2, 2, 2),
-            (1, 1, 1),
-            (1, 1, 1),
-        ]
-    )
-    dim = np.array(
-        [
-            (1, 2, 3),
-            (-1, -2, 2),
-            (1, 2, 2),
-            (0, 2, 2),
-            (1, 2, 3),
-            (2, 2, 2),
-            (2, 2, 2),
-            (2, 2, 2),
-            (2, 2, 2),
-        ]
-    )
-    pos = np.array(
-        [
-            (1, 2, 3),
-            (1, -1, 0),
-            (1, -1, 0),
-            (1, -1, 0),
-            (1, 2, 3),
-            (1, 1 + 1e-14, 0),
-            (1, 1, 1),
-            (1, -1, 2),
-            (1 + 1e-14, -1, 2),
-        ]
-    )
-    B = magnet_cuboid_field("B", pos, mag, dim)
-
-    Btest = [
-        [0.0, 0.0, 0.0],
-        [-0.14174376, -0.16976459, -0.20427478],
-        [-0.14174376, -0.16976459, -0.20427478],
-        [0.0, 0.0, 0.0],
-        [0.02596336, 0.04530334, 0.05840059],
-        [np.inf, np.inf, -0.29516724],
-        [0.0, 0.0, 0.0],
-        [-0.0009913, -0.08747071, 0.04890262],
-        [-0.0009913, -0.08747071, 0.04890262],
-    ]
-
-    np.testing.assert_allclose(B, Btest, rtol=1e-5)
-
-
-def test_magnet_cuboid_field_mag0():
-    """test cuboid field magnetization=0"""
-    n = 10
-    mag = np.zeros((n, 3))
-    dim = np.random.rand(n, 3)
-    pos = np.random.rand(n, 3)
-    B = magnet_cuboid_field("B", pos, mag, dim)
-    assert_allclose(mag, B)
-
-
-def test_field_BH_cylinder_tile_mag0():
-    """test cylinder_tile field magnetization=0"""
-    n = 10
-    mag = np.zeros((n, 3))
-    r1, r2, h, phi1, phi2 = np.random.rand(5, n)
-    r2 = r1 + r2
-    phi2 = phi1 + phi2
-    dim = np.array([r1, r2, h, phi1, phi2]).T
-    pos = np.random.rand(n, 3)
-    B = magnet_cylinder_segment_field("B", pos, mag, dim)
-    assert_allclose(mag, B)
-
-
-def test_field_sphere_vs_v2():
-    """testing against old version"""
-    result_v2 = np.array(
-        [
-            [22.0, 44.0, 66.0],
-            [22.0, 44.0, 66.0],
-            [38.47035383, 30.77628307, 23.0822123],
-            [0.60933932, 0.43524237, 1.04458169],
-            [22.0, 44.0, 66.0],
-            [-0.09071337, -0.18142674, -0.02093385],
-            [-0.17444878, -0.0139559, -0.10466927],
-        ]
-    )
-
-    dim = np.array([1.23] * 7)
-    mag = np.array([(33, 66, 99)] * 7)
-    poso = np.array(
-        [
-            (0, 0, 0),
-            (0.2, 0.2, 0.2),
-            (0.4, 0.4, 0.4),
-            (-1, -1, -2),
-            (0.1, 0.1, 0.1),
-            (1, 2, -3),
-            (-3, 2, 1),
-        ]
-    )
-    B = magnet_sphere_field("B", poso, mag, dim)
-
-    np.testing.assert_allclose(result_v2, B, rtol=1e-6)
-
-
-def test_magnet_sphere_field_mag0():
-    """test cuboid field magnetization=0"""
-    n = 10
-    mag = np.zeros((n, 3))
-    dim = np.random.rand(n)
-    pos = np.random.rand(n, 3)
-    B = magnet_sphere_field("B", pos, mag, dim)
-    assert_allclose(mag, B)
-
-
-def test_field_dipole1():
-    """Test standard dipole field output computed with mathematica"""
-    poso = np.array([(1, 2, 3), (-1, 2, 3)])
-    mom = np.array([(2, 3, 4), (0, -3, -2)])
-    B = dipole_field("B", poso, mom) * np.pi
-    Btest = np.array(
-        [
-            (0.01090862, 0.02658977, 0.04227091),
-            (0.0122722, -0.01022683, -0.02727156),
-        ]
-    )
-
-    assert_allclose(B, Btest, rtol=1e-6)
-
-
-def test_field_dipole2():
-    """test nan return when pos_obs=0"""
-    moment = np.array([(100, 200, 300)] * 2 + [(0, 0, 0)] * 2)
-    observer = np.array([(0, 0, 0), (1, 2, 3)] * 2)
-    B = dipole_field("B", observer, moment)
-
-    assert all(np.isinf(B[0]))
-    assert_allclose(
-        B[1:], [[0.3038282, 0.6076564, 0.91148459], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
-    )
-
-
-def test_field_circle():
-    """test if field function gives correct outputs"""
-    # from hyperphysics
-    # current = 1A
-    # loop radius = 1mm
-    # B at center = 0.6283185307179586 mT
-    # B at 1mm on zaxis = 0.22214414690791835 mT
-    pos_test_hyper = [[0, 0, 0], [0, 0, 1]]
-    Btest_hyper = [[0, 0, 0.6283185307179586], [0, 0, 0.22214414690791835]]
-
-    # from magpylib 2
-    pos_test_mag2 = [
-        [1, 2, 3],
-        [-3, 2, 1],
-        [1, -0.2, 0.3],
-        [1, 0.2, -1],
-        [-0.1, -0.2, 3],
-        [-1, 0.2, -0.3],
-        [3, -3, -3],
-        [-2, -0.2, -0.3],
-    ]
-    Btest_mag2 = [
-        [0.44179833, 0.88359665, 0.71546231],
-        [-0.53137126, 0.35424751, -0.59895825],
-        [72.87320789, -14.57464158, 22.07633404],
-        [-13.75612867, -2.75122573, 11.36467552],
-        [-0.10884885, -0.21769769, 2.41206364],
-        [72.87320789, -14.57464158, 22.07633404],
-        [-0.27939151, 0.27939151, 0.01220605],
-        [3.25697271, 0.32569727, -5.49353046],
-    ]
-
-    pos_test = np.array(pos_test_hyper + pos_test_mag2)
-    Btest = np.array(Btest_hyper + Btest_mag2)
-
-    current = np.array([1, 1] + [123] * 8)
-    dim = np.array([2, 2] + [2] * 8)
-
-    B = current_circle_field("B", pos_test, current, dim)
-
-    assert_allclose(B, Btest, rtol=1e-6)
-
-    Htest = Btest * 10 / 4 / np.pi
-    H = current_circle_field("H", pos_test, current, dim)
-    assert_allclose(H, Htest, rtol=1e-6)
-
-    with pytest.warns(MagpylibDeprecationWarning):
-        B = current_loop_field("B", pos_test, current, dim)
-    assert_allclose(B, Btest, rtol=1e-6)
-
-
-def test_field_loop2():
-    """test if field function accepts correct inputs"""
-    curr = np.array([1])
-    dim = np.array([2])
-    poso = np.array([[0, 0, 0]])
-    B = current_circle_field("B", poso, curr, dim)
-
-    curr = np.array([1] * 2)
-    dim = np.array([2] * 2)
-    poso = np.array([[0, 0, 0]] * 2)
-    B2 = current_circle_field("B", poso, curr, dim)
-
-    assert_allclose(B, (B2[0],))
-    assert_allclose(B, (B2[1],))
-
-
-def test_field_loop_specials():
-    """test loop special cases"""
-    cur = np.array([1, 1, 1, 1, 0, 2])
-    dia = np.array([2, 2, 0, 0, 2, 2])
-    obs = np.array([(0, 0, 0), (1, 0, 0), (0, 0, 0), (1, 0, 0), (1, 0, 0), (0, 0, 0)])
-
-    B = current_circle_field("B", obs, cur, dia)
-    Btest = [
-        [0, 0, 0.62831853],
-        [0, 0, 0],
-        [0, 0, 0],
-        [0, 0, 0],
-        [0, 0, 0],
-        [0, 0, 1.25663706],
-    ]
-    assert_allclose(B, Btest)
-
-
-def test_field_line():
-    """test line current for all cases"""
-
-    c1 = np.array([1])
-    po1 = np.array([(1, 2, 3)])
-    ps1 = np.array([(0, 0, 0)])
-    pe1 = np.array([(2, 2, 2)])
-
-    # only normal
-    B1 = current_polyline_field("B", po1, c1, ps1, pe1)
-    x1 = np.array([[0.02672612, -0.05345225, 0.02672612]])
-    assert_allclose(x1, B1, rtol=1e-6)
-
-    # only on_line
-    po1b = np.array([(1, 1, 1)])
-    B2 = current_polyline_field("B", po1b, c1, ps1, pe1)
-    x2 = np.zeros((1, 3))
-    assert_allclose(x2, B2, rtol=1e-6)
-
-    # only zero-segment
-    B3 = current_polyline_field("B", po1, c1, ps1, ps1)
-    x3 = np.zeros((1, 3))
-    assert_allclose(x3, B3, rtol=1e-6)
-
-    # only on_line and zero_segment
-    c2 = np.array([1] * 2)
-    ps2 = np.array([(0, 0, 0)] * 2)
-    pe2 = np.array([(0, 0, 0), (2, 2, 2)])
-    po2 = np.array([(1, 2, 3), (1, 1, 1)])
-    B4 = current_polyline_field("B", po2, c2, ps2, pe2)
-    x4 = np.zeros((2, 3))
-    assert_allclose(x4, B4, rtol=1e-6)
-
-    # normal + zero_segment
-    po2b = np.array([(1, 2, 3), (1, 2, 3)])
-    B5 = current_polyline_field("B", po2b, c2, ps2, pe2)
-    x5 = np.array([[0, 0, 0], [0.02672612, -0.05345225, 0.02672612]])
-    assert_allclose(x5, B5, rtol=1e-6)
-
-    # normal + on_line
-    pe2b = np.array([(2, 2, 2)] * 2)
-    B6 = current_polyline_field("B", po2, c2, ps2, pe2b)
-    x6 = np.array([[0.02672612, -0.05345225, 0.02672612], [0, 0, 0]])
-    assert_allclose(x6, B6, rtol=1e-6)
-
-    # normal + zero_segment + on_line
-    c4 = np.array([1] * 3)
-    ps4 = np.array([(0, 0, 0)] * 3)
-    pe4 = np.array([(0, 0, 0), (2, 2, 2), (2, 2, 2)])
-    po4 = np.array([(1, 2, 3), (1, 2, 3), (1, 1, 1)])
-    B7 = current_polyline_field("B", po4, c4, ps4, pe4)
-    x7 = np.array([[0, 0, 0], [0.02672612, -0.05345225, 0.02672612], [0, 0, 0]])
-    assert_allclose(x7, B7, rtol=1e-6)
-
-    with pytest.warns(MagpylibDeprecationWarning):
-        x7 = current_line_field("B", po4, c4, ps4, pe4)
-    assert_allclose(x7, B7, rtol=1e-6)
-
-
-def test_field_line_from_vert():
-    """test the Polyline field from vertex input"""
-    observers = np.array([(1, 2, 2), (1, 2, 3), (-1, 0, -3)])
-    current = np.array([1, 5, -3])
-
-    vertices = np.array(
-        [
-            np.array(
-                [(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (1, 2, 3), (-3, 4, -5)]
-            ),
-            np.array([(0, 0, 0), (3, 3, 3), (-3, 4, -5)]),
-            np.array([(1, 2, 3), (-2, -3, 3), (3, 2, 1), (3, 3, 3)]),
-        ],
-        dtype="object",
-    )
-
-    B_vert = current_vertices_field("B", observers, current, vertices)
-
-    B = []
-    for obs, vert, curr in zip(observers, vertices, current):
-        p1 = vert[:-1]
-        p2 = vert[1:]
-        po = np.array([obs] * (len(vert) - 1))
-        cu = np.array([curr] * (len(vert) - 1))
-        B += [np.sum(current_polyline_field("B", po, cu, p1, p2), axis=0)]
-    B = np.array(B)
-
-    assert_allclose(B_vert, B)
-
-
-def test_field_line_v4():
-    """test current_line_Bfield() for all cases"""
-    cur = np.array([1] * 7)
-    start = np.array([(-1, 0, 0)] * 7)
-    end = np.array([(1, 0, 0), (-1, 0, 0), (1, 0, 0), (-1, 0, 0)] + [(1, 0, 0)] * 3)
-    obs = np.array(
-        [
-            (0, 0, 1),
-            (0, 0, 0),
-            (0, 0, 0),
-            (0, 0, 0),
-            (0, 0, 1e-16),
-            (2, 0, 1),
-            (-2, 0, 1),
-        ]
-    )
-    B = current_polyline_field("B", obs, cur, start, end)
-    Btest = np.array(
-        [
-            [0, -0.14142136, 0],
-            [0, 0.0, 0],
-            [0, 0.0, 0],
-            [0, 0.0, 0],
-            [0, 0.0, 0],
-            [0, -0.02415765, 0],
-            [0, -0.02415765, 0],
-        ]
-    )
-    np.testing.assert_allclose(B, Btest)
-
-
-def test_triangle1():
-    """test core triangle VS cube"""
-    obs = np.array([(3, 4, 5)] * 4)
-    mag = np.array([(0, 0, 333)] * 4)
-    fac = np.array(
-        [
-            [(-1, -1, 1), (1, -1, 1), (-1, 1, 1)],  # top1
-            [(1, -1, -1), (-1, -1, -1), (-1, 1, -1)],  # bott1
-            [(1, -1, 1), (1, 1, 1), (-1, 1, 1)],  # top2
-            [(1, 1, -1), (1, -1, -1), (-1, 1, -1)],  # bott2
-        ]
-    )
-    b = magpy.core.triangle_field("B", obs, mag, fac)
-    b = np.sum(b, axis=0)
-
-    obs = np.array([(3, 4, 5)])
-    mag = np.array([(0, 0, 333)])
-    dim = np.array([(2, 2, 2)])
-    bb = magpy.core.magnet_cuboid_field("B", obs, mag, dim)[0]
-
-    np.testing.assert_allclose(b, bb)
-
-
-def test_triangle2():
-    """test core single triangle vs same surface split up into 4 triangular faces"""
-    obs = np.array([(3, 4, 5)])
-    mag = np.array([(111, 222, 333)])
-    fac = np.array(
-        [
-            [(0, 0, 0), (10, 0, 0), (0, 10, 0)],
-        ]
-    )
-    b = magpy.core.triangle_field("B", obs, mag, fac)
-    b = np.sum(b, axis=0)
-
-    obs = np.array([(3, 4, 5)] * 4)
-    mag = np.array([(111, 222, 333)] * 4)
-    fac = np.array(
-        [
-            [(0, 0, 0), (3, 0, 0), (0, 10, 0)],
-            [(3, 0, 0), (5, 0, 0), (0, 10, 0)],
-            [(5, 0, 0), (6, 0, 0), (0, 10, 0)],
-            [(6, 0, 0), (10, 0, 0), (0, 10, 0)],
-        ]
-    )
-    bb = magpy.core.triangle_field("B", obs, mag, fac)
-    bb = np.sum(bb, axis=0)
-
-    np.testing.assert_allclose(b, bb)
-
-
-def test_triangle3():
-    """test core tetrahedron vs cube"""
-    ver = np.array(
-        [
-            [(1, 1, -1), (1, 1, 1), (-1, 1, 1), (1, -1, 1)],
-            [(-1, -1, 1), (-1, 1, 1), (1, -1, 1), (1, -1, -1)],
-            [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (1, -1, -1)],
-            [(-1, 1, -1), (1, -1, -1), (-1, -1, 1), (-1, 1, 1)],
-            [(1, -1, -1), (1, 1, -1), (1, -1, 1), (-1, 1, 1)],
-            [(-1, 1, -1), (-1, 1, 1), (1, 1, -1), (1, -1, -1)],
-        ]
-    )
-
-    mags = [
-        [1.03595366, 0.42840487, 0.10797529],
-        [0.33513152, 1.61629547, 0.15959791],
-        [0.29904441, 1.32185041, 1.81218046],
-        [0.82665456, 1.86827489, 1.67338911],
-        [0.97619806, 1.52323106, 1.63628455],
-        [1.70290645, 1.49610608, 0.13878711],
-        [1.49886747, 1.55633919, 1.41351862],
-        [0.9959534, 0.62059942, 1.28616663],
-        [0.60114354, 0.96120344, 0.32009221],
-        [0.83133901, 0.7925518, 0.64574592],
-    ]
-
-    obss = [
-        [0.82811352, 1.77818627, 0.19819379],
-        [0.84147235, 1.10200857, 1.51687527],
-        [0.30751474, 0.89773196, 0.56468564],
-        [1.87437889, 1.55908581, 1.10579983],
-        [0.64810548, 1.38123846, 1.90576802],
-        [0.48981034, 0.09376294, 0.53717129],
-        [1.42826412, 0.30246674, 0.57649909],
-        [1.58376758, 1.70420478, 0.22894022],
-        [0.26791832, 0.36839769, 0.67934335],
-        [1.15140149, 0.10549875, 0.98304184],
-    ]
-
-    for mag in mags:
-        for obs in obss:
-            obs6 = np.tile(obs, (6, 1))
-            mag6 = np.tile(mag, (6, 1))
-            b = magpy.core.magnet_tetrahedron_field("B", obs6, mag6, ver)
-            h = magpy.core.magnet_tetrahedron_field("H", obs6, mag6, ver)
-            b = np.sum(b, axis=0)
-            h = np.sum(h, axis=0)
-
-            obs1 = np.reshape(obs, (1, 3))
-            mag1 = np.reshape(mag, (1, 3))
-            dim = np.array([(2, 2, 2)])
-            bb = magpy.core.magnet_cuboid_field("B", obs1, mag1, dim)[0]
-            hh = magpy.core.magnet_cuboid_field("H", obs1, mag1, dim)[0]
-            np.testing.assert_allclose(b, bb)
-            np.testing.assert_allclose(h, hh)
-
-
-def test_triangle4():
-    """test core tetrahedron vs cube"""
-    obs = np.array([(3, 4, 5)] * 6)
-    mag = np.array([(111, 222, 333)] * 6)
-    ver = np.array(
-        [
-            [(1, 1, -1), (1, 1, 1), (-1, 1, 1), (1, -1, 1)],
-            [(-1, -1, 1), (-1, 1, 1), (1, -1, 1), (1, -1, -1)],
-            [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (1, -1, -1)],
-            [(-1, 1, -1), (1, -1, -1), (-1, -1, 1), (-1, 1, 1)],
-            [(1, -1, -1), (1, 1, -1), (1, -1, 1), (-1, 1, 1)],
-            [(-1, 1, -1), (-1, 1, 1), (1, 1, -1), (1, -1, -1)],
-        ]
-    )
-    b = magpy.core.magnet_tetrahedron_field("B", obs, mag, ver)
-    b = np.sum(b, axis=0)
-
-    obs = np.array([(3, 4, 5)])
-    mag = np.array([(111, 222, 333)])
-    dim = np.array([(2, 2, 2)])
-    bb = magpy.core.magnet_cuboid_field("B", obs, mag, dim)[0]
-
-    np.testing.assert_allclose(b, bb)
-
-
-def test_triangle5():
-    """special case tests on edges - result is continuous and 0 for vertical component"""
-    btest1 = [
-        [26.29963526814195, 15.319834473660082, 0.0],
-        [54.91549594789228, 41.20535983076747, 0.0],
-        [32.25241487782939, 15.087161660417559, 0.0],
-        [10.110611199952707, -11.41176203622237, 0.0],
-        [-3.8084378251737285, -30.875600143560657, -0.0],
-        [-15.636505140623612, -50.00854548249858, -0.0],
-        [-27.928308992688645, -72.80800891847107, -0.0],
-        [-45.34417750711242, -109.5871836961927, -0.0],
-        [-36.33970306054345, 12.288824457077656, 0.0],
-        [-16.984738462958845, 4.804383318447626, 0.0],
-    ]
-
-    btest2 = [
-        [15.31983447366009, 26.299635268142033, 0.0],
-        [41.20535983076747, 54.91549594789104, 0.0],
-        [-72.61316618947018, 32.25241487782958, 0.0],
-        [-54.07597251255013, 10.110611199952693, 0.0],
-        [-44.104089712909634, -3.808437825173785, -0.0],
-        [-36.78005591314963, -15.636505140623605, -0.0],
-        [-30.143798442143236, -27.92830899268858, -0.0],
-        [-21.886855846306176, -45.34417750711366, -0.0],
-        [12.288824457077965, -36.33970306054315, 0.0],
-        [4.80438331844773, -16.98473846295874, 0.0],
-    ]
-
-    n = 10
-    ts = np.linspace(-1, 6, n)
-    obs1 = np.array([(t, 0, 0) for t in ts])
-    obs2 = np.array([(0, t, 0) for t in ts])
-    mag = np.array([(111, 222, 333)] * n)
-    ver = np.array([[(0, 0, 0), (0, 5, 0), (5, 0, 0)]] * n)
-
-    b1 = magpy.core.triangle_field("H", obs1, mag, ver)
-    np.testing.assert_allclose(btest1, b1)
-    b2 = magpy.core.triangle_field("H", obs2, mag, ver)
-    np.testing.assert_allclose(btest2, b2)
-
-
-def test_triangle6():
-    """special case tests on corners - result is nan"""
-    obs1 = np.array([(0, 0, 0)])
-    obs2 = np.array([(0, 5, 0)])
-    obs3 = np.array([(5, 0, 0)])
-    mag = np.array([(111, 222, 333)])
-    ver = np.array([[(0, 0, 0), (0, 5, 0), (5, 0, 0)]])
-    b1 = magpy.core.triangle_field("B", obs1, mag, ver)
-    b2 = magpy.core.triangle_field("B", obs2, mag, ver)
-    b3 = magpy.core.triangle_field("B", obs3, mag, ver)
-
-    for b in [b1, b2, b3]:
-        np.testing.assert_equal(b, np.array([[np.nan] * 3]))
-
-
-@pytest.mark.parametrize(
-    ("module", "class_", "missing_arg"),
-    [
-        ("magnet", "Cuboid", "dimension"),
-        ("magnet", "Cylinder", "dimension"),
-        ("magnet", "CylinderSegment", "dimension"),
-        ("magnet", "Sphere", "diameter"),
-        ("magnet", "Tetrahedron", "vertices"),
-        ("magnet", "TriangularMesh", "vertices"),
-        ("current", "Circle", "diameter"),
-        ("current", "Polyline", "vertices"),
-        ("misc", "Triangle", "vertices"),
-    ],
-)
-def test_getB_on_missing_dimensions(module, class_, missing_arg):
-    """test_getB_on_missing_dimensions"""
-    with pytest.raises(
-        MagpylibMissingInput,
-        match=rf"Parameter `{missing_arg}` of .* must be set.",
-    ):
-        getattr(getattr(magpy, module), class_)().getB([0, 0, 0])
-
-
-@pytest.mark.parametrize(
-    ("module", "class_", "missing_arg", "kwargs"),
-    [
-        ("magnet", "Cuboid", "magnetization", {"dimension": (1, 1, 1)}),
-        ("magnet", "Cylinder", "magnetization", {"dimension": (1, 1)}),
-        (
-            "magnet",
-            "CylinderSegment",
-            "magnetization",
-            {"dimension": (0, 1, 1, 45, 120)},
-        ),
-        ("magnet", "Sphere", "magnetization", {"diameter": 1}),
-        (
-            "magnet",
-            "Tetrahedron",
-            "magnetization",
-            {"vertices": [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]},
-        ),
-        (
-            "magnet",
-            "TriangularMesh",
-            "magnetization",
-            {
-                "vertices": ((0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)),
-                "faces": ((0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)),
-            },
-        ),
-        ("current", "Circle", "current", {"diameter": 1}),
-        ("current", "Polyline", "current", {"vertices": [[0, -1, 0], [0, 1, 0]]}),
-        (
-            "misc",
-            "Triangle",
-            "magnetization",
-            {"vertices": [(0, 0, 0), (1, 0, 0), (0, 1, 0)]},
-        ),
-        ("misc", "Dipole", "moment", {}),
-    ],
-)
-def test_getB_on_missing_excitations(module, class_, missing_arg, kwargs):
-    """test_getB_on_missing_excitations"""
-    with pytest.raises(
-        MagpylibMissingInput,
-        match=rf"Parameter `{missing_arg}` of .* must be set.",
-    ):
-        getattr(getattr(magpy, module), class_)(**kwargs).getB([0, 0, 0])
diff --git a/tests/test_core_misc.py b/tests/test_core_misc.py
new file mode 100644
index 000000000..3a9c7526a
--- /dev/null
+++ b/tests/test_core_misc.py
@@ -0,0 +1,952 @@
+import numpy as np
+import pytest
+from numpy.testing import assert_allclose
+
+import magpylib as magpy
+from magpylib._src.exceptions import MagpylibDeprecationWarning
+from magpylib._src.fields.field_BH_polyline import current_vertices_field
+from magpylib._src.fields.field_BH_triangularmesh import magnet_trimesh_field
+from magpylib._src.utility import MU0
+from magpylib.core import current_circle_field
+from magpylib.core import current_line_field
+from magpylib.core import current_loop_field
+from magpylib.core import current_polyline_field
+from magpylib.core import magnet_cuboid_field
+from magpylib.core import magnet_cylinder_segment_field
+from magpylib.core import magnet_sphere_field
+from magpylib.core import magnet_tetrahedron_field
+from magpylib.core import triangle_field
+
+
+#######################################################################################
+#######################################################################################
+#######################################################################################
+
+# NEW V5 BASIC FIELD COMPUTATION TESTS
+
+
+def test_magnet_cuboid_field_BH():
+    """test cuboid field"""
+    pol = np.array(
+        [
+            (0, 0, 0),
+            (1, 2, 3),
+            (1, 2, 3),
+            (1, 2, 3),
+            (1, 2, 3),
+            (1, 2, 3),
+        ]
+    )
+    dim = np.array(
+        [
+            (1, 2, 3),
+            (-1, -2, 2),
+            (1, 2, 2),
+            (0, 2, 2),
+            (1, 2, 3),
+            (3, 3, 3),
+        ]
+    )
+    obs = np.array(
+        [
+            (1, 2, 3),
+            (1, -1, 0),
+            (1, -1, 0),
+            (1, -1, 0),
+            (1, 2, 3),
+            (0, 0, 0),
+        ]
+    )
+
+    B = magnet_cuboid_field(
+        field="B",
+        observers=obs,
+        polarization=pol,
+        dimension=dim,
+    )
+    H = magnet_cuboid_field(
+        field="H",
+        observers=obs,
+        polarization=pol,
+        dimension=dim,
+    )
+    J = np.array([(0, 0, 0)] * 5 + [(1, 2, 3)])
+    np.testing.assert_allclose(B, MU0 * H + J)
+
+    Btest = [
+        [0.0, 0.0, 0.0],
+        [-0.14174376, -0.16976459, -0.20427478],
+        [-0.14174376, -0.16976459, -0.20427478],
+        [0.0, 0.0, 0.0],
+        [0.02596336, 0.04530334, 0.05840059],
+        [0.66666667, 1.33333333, 2.0],
+    ]
+    np.testing.assert_allclose(B, Btest, rtol=1e-5)
+
+    Htest = [
+        [0.0, 0.0, 0.0],
+        [-112796.09804171, -135094.37189185, -162556.70519527],
+        [-112796.09804171, -135094.37189185, -162556.70519527],
+        [0.0, 0.0, 0.0],
+        [20660.98851314, 36051.25202256, 46473.71425434],
+        [-265258.23848649, -530516.47697298, -795774.71545948],
+    ]
+    np.testing.assert_allclose(H, Htest, rtol=1e-5)
+
+
+def test_magnet_cylinder_field_BH():
+    """test cylinder field computation"""
+    pol = np.array(
+        [
+            (0, 0, 0),
+            (1, 2, 3),
+            (3, 2, -1),
+            (1, 1, 1),
+        ]
+    )
+    dim = np.array(
+        [
+            (1, 2),
+            (2, 2),
+            (1, 2),
+            (3, 3),
+        ]
+    )
+    obs = np.array(
+        [
+            (1, 2, 3),
+            (1, -1, 0),
+            (1, 1, 1),
+            (0, 0, 0),
+        ]
+    )
+    B = magpy.core.magnet_cylinder_field(
+        field="B",
+        observers=obs,
+        polarization=pol,
+        dimension=dim,
+    )
+    H = magpy.core.magnet_cylinder_field(
+        field="H",
+        observers=obs,
+        polarization=pol,
+        dimension=dim,
+    )
+    J = np.array([(0, 0, 0), (0, 0, 0), (0, 0, 0), (1, 1, 1)])
+    np.testing.assert_allclose(B, MU0 * H + J)
+
+    Btest = [
+        [0.0, 0.0, 0.0],
+        [-0.36846057, -0.10171405, -0.33006492],
+        [0.05331225, 0.07895873, 0.10406998],
+        [0.64644661, 0.64644661, 0.70710678],
+    ]
+    np.testing.assert_allclose(B, Btest)
+
+    Htest = [
+        [0.0, 0.0, 0.0],
+        [-293211.60229288, -80941.4714998, -262657.31858654],
+        [42424.54100401, 62833.36365626, 82816.25721518],
+        [-281348.8487991, -281348.8487991, -233077.01786129],
+    ]
+    np.testing.assert_allclose(H, Htest)
+
+
+def test_magnet_sphere_field_BH():
+    """test magnet_sphere_field"""
+    pol = np.array(
+        [
+            (0, 0, 0),
+            (1, 2, 3),
+            (2, 3, -1),
+            (2, 3, -1),
+        ]
+    )
+    dia = np.array([1, 2, 3, 4])
+    obs = np.array(
+        [
+            (1, 2, 3),
+            (1, -1, 0),
+            (0, -1, 0),
+            (1, -1, 0.5),
+        ]
+    )
+    B = magnet_sphere_field(
+        field="B",
+        observers=obs,
+        diameter=dia,
+        polarization=pol,
+    )
+    H = magnet_sphere_field(
+        field="H",
+        observers=obs,
+        diameter=dia,
+        polarization=pol,
+    )
+    J = np.array([(0, 0, 0), (0, 0, 0), pol[2], pol[3]])
+    np.testing.assert_allclose(B, MU0 * H + J)
+
+    Btest = [
+        [0.0, 0.0, 0.0],
+        [-0.29462783, -0.05892557, -0.35355339],
+        [1.33333333, 2.0, -0.66666667],
+        [1.33333333, 2.0, -0.66666667],
+    ]
+    np.testing.assert_allclose(B, Btest)
+
+    Htest = [
+        [0.0, 0.0, 0.0],
+        [-234457.37399925, -46891.47479985, -281348.8487991],
+        [-530516.47697298, -795774.71545948, 265258.23848649],
+        [-530516.47697298, -795774.71545948, 265258.23848649],
+    ]
+    np.testing.assert_allclose(H, Htest)
+
+
+def test_field_cylinder_segment_BH():
+    """CylinderSegmetn field test"""
+    pol = np.array(
+        [
+            (0, 0, 0),
+            (1, 2, 3),
+            (2, 3, -1),
+            (2, 3, -1),
+        ]
+    )
+    dim = np.array(
+        [
+            (1, 2, 3, 10, 20),
+            (1, 2, 3, 10, 20),
+            (1, 3, 2, -50, 50),
+            (0.1, 5, 2, 20, 370),
+        ]
+    )
+    obs = np.array(
+        [
+            (1, 2, 3),
+            (1, -1, 0),
+            (0, -1, 0),
+            (1, -1, 0.5),
+        ]
+    )
+    B = magnet_cylinder_segment_field(
+        field="B",
+        observers=obs,
+        dimension=dim,
+        polarization=pol,
+    )
+    H = magnet_cylinder_segment_field(
+        field="H",
+        observers=obs,
+        dimension=dim,
+        polarization=pol,
+    )
+    J = np.array([(0, 0, 0)] * 3 + [pol[3]])
+    np.testing.assert_allclose(B, MU0 * H + J)
+
+    Btest = [
+        [0.0, 0.0, 0.0],
+        [0.00762186, 0.04194934, -0.01974813],
+        [0.52440702, -0.04650694, 0.09432828],
+        [1.75574175, 2.58945648, -0.19025747],
+    ]
+    np.testing.assert_allclose(B, Btest, rtol=1e-6)
+
+    Htest = [
+        [0.0, 0.0, 0.0],
+        [6065.28627343, 33382.22618218, -15715.05894253],
+        [417309.84428576, -37009.05020239, 75064.06294505],
+        [-194374.5385654, -326700.15326755, 644372.62925584],
+    ]
+    np.testing.assert_allclose(H, Htest, rtol=1e-6)
+
+
+def test_triangle_field_BH():
+    """Test of triangle field core function"""
+    pol = np.array(
+        [
+            (0, 0, 0),
+            (1, 2, 3),
+            (2, -1, 1),
+            (1, -1, 2),
+        ]
+    )
+    vert = np.array(
+        [
+            [(0, 0, 0), (0, 1, 0), (1, 0, 0)],
+            [(0, 0, 0), (0, 1, 0), (1, 0, 0)],
+            [(1, 2, 3), (0, 1, -5), (1, 1, 5)],
+            [(1, 2, 2), (0, 1, -1), (3, -1, 1)],
+        ]
+    )
+    obs = np.array(
+        [
+            (1, 1, 1),
+            (1, 1, 1),
+            (1, 1, 1),
+            (2, 3, 1),
+        ]
+    )
+    B = triangle_field(
+        field="B",
+        observers=obs,
+        vertices=vert,
+        polarization=pol,
+    )
+    H = triangle_field(
+        field="H",
+        observers=obs,
+        vertices=vert,
+        polarization=pol,
+    )
+    np.testing.assert_allclose(B, MU0 * H)
+
+    Btest = [
+        [0.0, 0.0, 0.0],
+        [-0.02825571, -0.02825571, -0.04386991],
+        [-0.34647603, 0.29421715, 0.06980312],
+        [0.02041789, 0.05109073, 0.00218011],
+    ]
+    np.testing.assert_allclose(B, Btest, rtol=1e-06)
+
+    Htest = [
+        [0.0, 0.0, 0.0],
+        [-22485.1813849, -22485.1813849, -34910.56834885],
+        [-275716.86458395, 234130.57085866, 55547.55765999],
+        [16248.03897974, 40656.7134656, 1734.8781397],
+    ]
+    np.testing.assert_allclose(H, Htest, rtol=1e-06)
+
+
+def test_magnet_tetrahedron_field_BH():
+    """Test of tetrahedron field core function"""
+    pol = np.array(
+        [
+            (0, 0, 0),
+            (1, 2, 3),
+            (-1, 0.5, 0.1),
+            (2, 2, -1),
+        ]
+    )
+    vert = np.array(
+        [
+            [(0, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, 1)],
+            [(0, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, 1)],
+            [(-1, 0, -1), (1, 1, -1), (1, -1, -1), (0, 0, 1)],
+            [(-1, 0, -1), (1, 1, -1), (1, -1, -1), (0, 0, 1)],
+        ]
+    )
+    obs = np.array(
+        [
+            (1, 1, 1),
+            (1, 1, 1),
+            (0, 0, 0),
+            (2, 0, 0),
+        ]
+    )
+    B = magnet_tetrahedron_field(
+        field="B",
+        observers=obs,
+        vertices=vert,
+        polarization=pol,
+    )
+    H = magnet_tetrahedron_field(
+        field="H",
+        observers=obs,
+        vertices=vert,
+        polarization=pol,
+    )
+    J = np.array([(0, 0, 0)] * 2 + [pol[2]] + [(0, 0, 0)])
+    np.testing.assert_allclose(B, MU0 * H + J)
+
+    Btest = [
+        [0.0, 0.0, 0.0],
+        [0.02602367, 0.02081894, 0.0156142],
+        [-0.69704332, 0.20326329, 0.11578416],
+        [0.04004769, -0.03186713, 0.03854207],
+    ]
+    np.testing.assert_allclose(B, Btest, rtol=1e-06)
+
+    Htest = [
+        [0.0, 0.0, 0.0],
+        [20708.97827326, 16567.1826186, 12425.38696395],
+        [241085.26350642, -236135.56979233, 12560.63814427],
+        [31868.94160192, -25359.05664996, 30670.80436549],
+    ]
+    np.testing.assert_allclose(H, Htest, rtol=1e-06)
+
+
+def test_magnet_trimesh_field_BH():
+    """Test of magnet_trimesh_field core-like function"""
+
+    mesh1 = [
+        [
+            [0.7439252734184265, 0.5922041535377502, 0.30962786078453064],
+            [0.3820107579231262, -0.8248414397239685, -0.416778564453125],
+            [-0.5555410385131836, 0.4872661232948303, -0.6737549901008606],
+        ],
+        [
+            [-0.5555410385131836, 0.4872661232948303, -0.6737549901008606],
+            [0.3820107579231262, -0.8248414397239685, -0.416778564453125],
+            [-0.5703949332237244, -0.25462886691093445, 0.7809056639671326],
+        ],
+        [
+            [0.7439252734184265, 0.5922041535377502, 0.30962786078453064],
+            [-0.5703949332237244, -0.25462886691093445, 0.7809056639671326],
+            [0.3820107579231262, -0.8248414397239685, -0.416778564453125],
+        ],
+        [
+            [0.7439252734184265, 0.5922041535377502, 0.30962786078453064],
+            [-0.5555410385131836, 0.4872661232948303, -0.6737549901008606],
+            [-0.5703949332237244, -0.25462886691093445, 0.7809056639671326],
+        ],
+    ]
+    mesh2 = [
+        [
+            [0.9744000434875488, 0.15463787317276, 0.16319207847118378],
+            [-0.12062954157590866, -0.8440634608268738, -0.522499144077301],
+            [-0.3775683045387268, 0.7685779929161072, -0.516459047794342],
+        ],
+        [
+            [-0.3775683045387268, 0.7685779929161072, -0.516459047794342],
+            [-0.12062954157590866, -0.8440634608268738, -0.522499144077301],
+            [-0.47620221972465515, -0.0791524201631546, 0.8757661581039429],
+        ],
+        [
+            [0.9744000434875488, 0.15463787317276, 0.16319207847118378],
+            [-0.47620221972465515, -0.0791524201631546, 0.8757661581039429],
+            [-0.12062954157590866, -0.8440634608268738, -0.522499144077301],
+        ],
+        [
+            [0.9744000434875488, 0.15463787317276, 0.16319207847118378],
+            [-0.3775683045387268, 0.7685779929161072, -0.516459047794342],
+            [-0.47620221972465515, -0.0791524201631546, 0.8757661581039429],
+        ],
+    ]
+    meshes = np.array([mesh1, mesh2])
+    pol = np.array([(1, 2, 3), (3, 2, 1)])
+    obs = np.array([(1, 2, 3), (0, 0, 0)])
+    B = magnet_trimesh_field(
+        field="B",
+        observers=obs,
+        mesh=meshes,
+        polarization=pol,
+    )
+    H = magnet_trimesh_field(
+        field="H",
+        observers=obs,
+        mesh=meshes,
+        polarization=pol,
+    )
+    J = np.array([(0, 0, 0), (3, 2, 1)])
+    np.testing.assert_allclose(B, MU0 * H + J)
+
+    Btest = [
+        [1.54452002e-03, 3.11861149e-03, 4.68477835e-03],
+        [2.00000002e00, 1.33333333e00, 6.66666685e-01],
+    ]
+    np.testing.assert_allclose(B, Btest)
+
+    Htest = [
+        [1229.08998194, 2481.71216888, 3728.02815642],
+        [-795774.70120171, -530516.47792526, -265258.22366805],
+    ]
+    np.testing.assert_allclose(H, Htest)
+
+
+def test_current_circle_field_BH():
+    """Test of current circle field core function"""
+    B = magpy.core.current_circle_field(
+        field="B",
+        observers=np.array([(1, 1, 1), (2, 2, 2), (3, 3, 3)]),
+        diameter=np.array([2, 4, 6]),
+        current=np.array([1, 1, 2]) * 1e3,
+    )
+    H = magpy.core.current_circle_field(
+        field="H",
+        observers=np.array([(1, 1, 1), (2, 2, 2), (3, 3, 3)]),
+        diameter=np.array([2, 4, 6]),
+        current=np.array([1, 1, 2]) * 1e3,
+    )
+    np.testing.assert_allclose(B, MU0 * H)
+
+    Btest = (
+        np.array(
+            [
+                [0.06235974, 0.06235974, 0.02669778],
+                [0.03117987, 0.03117987, 0.01334889],
+                [0.04157316, 0.04157316, 0.01779852],
+            ]
+        )
+        * 1e-3
+    )
+    np.testing.assert_allclose(B, Btest)
+
+    Htest = (
+        np.array(
+            [
+                [49624.3033947, 49624.3033947, 21245.41908818],
+                [24812.15169735, 24812.15169735, 10622.70954409],
+                [33082.8689298, 33082.8689298, 14163.61272545],
+            ]
+        )
+        * 1e-3
+    )
+    np.testing.assert_allclose(H, Htest)
+
+
+def test_current_polyline_field_BH():
+    """Test of current polyline field core function"""
+    vert = np.array([(-1.5, 0, 0), (-0.5, 0, 0), (0.5, 0, 0), (1.5, 0, 0)])
+    B = magpy.core.current_polyline_field(
+        field="B",
+        observers=np.array([(0, 0, 1)] * 3),
+        segment_start=vert[:-1],
+        segment_end=vert[1:],
+        current=np.array([1, 1, 1]),
+    )
+    H = magpy.core.current_polyline_field(
+        field="H",
+        observers=np.array([(0, 0, 1)] * 3),
+        segment_start=vert[:-1],
+        segment_end=vert[1:],
+        current=np.array([1, 1, 1]),
+    )
+    np.testing.assert_allclose(B, MU0 * H)
+
+    Btest = (
+        np.array(
+            [
+                [0.0, -0.03848367, 0.0],
+                [0.0, -0.08944272, 0.0],
+                [0.0, -0.03848367, 0.0],
+            ]
+        )
+        * 1e-6
+    )
+    np.testing.assert_allclose(B, Btest, rtol=0, atol=1e-7)
+
+    Htest = (
+        np.array(
+            [
+                [0.0, -30624.33145161, 0.0],
+                [0.0, -71176.25434172, 0.0],
+                [0.0, -30624.33145161, 0.0],
+            ]
+        )
+        * 1e-6
+    )
+    np.testing.assert_allclose(H, Htest, rtol=0, atol=1e-7)
+
+
+def test_dipole_field_BH():
+    """Test of dipole field core function"""
+    obs = np.array([(1, 2, 3), (-1, -2, -3), (3, 3, -1)])
+    pol = np.array([(0, 0, 1), (1, 0, 1), (-1, 0.321, 0.123)])
+    mom = pol * 4 * np.pi / 3 / MU0
+
+    B = magpy.core.dipole_field(
+        field="B",
+        observers=obs,
+        moment=mom,
+    )
+    H = magpy.core.dipole_field(
+        field="H",
+        observers=obs,
+        moment=mom,
+    )
+    np.testing.assert_allclose(B, MU0 * H)
+
+    Btest = [
+        [4.09073329e-03, 8.18146659e-03, 5.90883698e-03],
+        [-9.09051843e-04, 1.09086221e-02, 9.99957028e-03],
+        [-9.32067617e-05, -5.41001702e-03, 8.77626395e-04],
+    ]
+    np.testing.assert_allclose(B, Btest)
+
+    Htest = [
+        [3255.30212351, 6510.60424703, 4702.1030673],
+        [-723.40047189, 8680.8056627, 7957.40519081],
+        [-74.17158426, -4305.1547508, 698.3928945],
+    ]
+    np.testing.assert_allclose(H, Htest)
+
+
+#######################################################################################
+#######################################################################################
+#######################################################################################
+
+# OTHER TESTS AND V4 TESTS
+
+
+def test_line_deprecation():
+    """test line deprecation"""
+    kw = {
+        "field": "B",
+        "observers": np.array([(0, 0, 1)]),
+        "segment_start": np.array([(0, 0, 1)]),
+        "segment_end": np.array([(0, 0, 1)]),
+        "current": np.array([1]),
+    }
+    B1 = current_polyline_field(**kw)
+    with pytest.warns(MagpylibDeprecationWarning):
+        B2 = current_line_field(**kw)
+
+    np.testing.assert_allclose(B1, B2)
+
+
+def test_loop_deprecation():
+    """test loop deprecation"""
+    kw = {
+        "field": "B",
+        "observers": np.array([(0, 0, 1)]),
+        "diameter": np.array([1]),
+        "current": np.array([1]),
+    }
+    B1 = current_circle_field(**kw)
+    with pytest.warns(MagpylibDeprecationWarning):
+        B2 = current_loop_field(**kw)
+
+    np.testing.assert_allclose(B1, B2)
+
+
+def test_field_loop_specials():
+    """test loop special cases"""
+    cur = np.array([1, 1, 1, 1, 0, 2])
+    dia = np.array([2, 2, 0, 0, 2, 2])
+    obs = np.array([(0, 0, 0), (1, 0, 0), (0, 0, 0), (1, 0, 0), (1, 0, 0), (0, 0, 0)])
+
+    B = (
+        current_circle_field(
+            field="B",
+            observers=obs,
+            diameter=dia,
+            current=cur,
+        )
+        * 1e6
+    )
+    Btest = [
+        [0, 0, 0.62831853],
+        [0, 0, 0],
+        [0, 0, 0],
+        [0, 0, 0],
+        [0, 0, 0],
+        [0, 0, 1.25663706],
+    ]
+    assert_allclose(B, Btest)
+
+
+def test_field_line_special_cases():
+    """test line current for all cases"""
+
+    c1 = np.array([1])
+    po1 = np.array([(1, 2, 3)])
+    ps1 = np.array([(0, 0, 0)])
+    pe1 = np.array([(2, 2, 2)])
+
+    # only normal
+    B1 = (
+        current_polyline_field(
+            field="B",
+            observers=po1,
+            current=c1,
+            segment_start=ps1,
+            segment_end=pe1,
+        )
+        * 1e6
+    )
+    x1 = np.array([[0.02672612, -0.05345225, 0.02672612]])
+    assert_allclose(x1, B1, rtol=1e-6)
+
+    # only on_line
+    po1b = np.array([(1, 1, 1)])
+    B2 = (
+        current_polyline_field(
+            field="B",
+            observers=po1b,
+            current=c1,
+            segment_start=ps1,
+            segment_end=pe1,
+        )
+        * 1e6
+    )
+    x2 = np.zeros((1, 3))
+    assert_allclose(x2, B2, rtol=1e-6)
+
+    # only zero-segment
+    B3 = (
+        current_polyline_field(
+            field="B",
+            observers=po1,
+            current=c1,
+            segment_start=ps1,
+            segment_end=ps1,
+        )
+        * 1e6
+    )
+    x3 = np.zeros((1, 3))
+    assert_allclose(x3, B3, rtol=1e-6)
+
+    # only on_line and zero_segment
+    c2 = np.array([1] * 2)
+    ps2 = np.array([(0, 0, 0)] * 2)
+    pe2 = np.array([(0, 0, 0), (2, 2, 2)])
+    po2 = np.array([(1, 2, 3), (1, 1, 1)])
+    B4 = (
+        current_polyline_field(
+            field="B",
+            observers=po2,
+            current=c2,
+            segment_start=ps2,
+            segment_end=pe2,
+        )
+        * 1e6
+    )
+    x4 = np.zeros((2, 3))
+    assert_allclose(x4, B4, rtol=1e-6)
+
+    # normal + zero_segment
+    po2b = np.array([(1, 2, 3), (1, 2, 3)])
+    B5 = (
+        current_polyline_field(
+            field="B",
+            observers=po2b,
+            current=c2,
+            segment_start=ps2,
+            segment_end=pe2,
+        )
+        * 1e6
+    )
+    x5 = np.array([[0, 0, 0], [0.02672612, -0.05345225, 0.02672612]])
+    assert_allclose(x5, B5, rtol=1e-6)
+
+    # normal + on_line
+    pe2b = np.array([(2, 2, 2)] * 2)
+    B6 = (
+        current_polyline_field(
+            field="B",
+            observers=po2,
+            current=c2,
+            segment_start=ps2,
+            segment_end=pe2b,
+        )
+        * 1e6
+    )
+    x6 = np.array([[0.02672612, -0.05345225, 0.02672612], [0, 0, 0]])
+    assert_allclose(x6, B6, rtol=1e-6)
+
+    # normal + zero_segment + on_line
+    c4 = np.array([1] * 3)
+    ps4 = np.array([(0, 0, 0)] * 3)
+    pe4 = np.array([(0, 0, 0), (2, 2, 2), (2, 2, 2)])
+    po4 = np.array([(1, 2, 3), (1, 2, 3), (1, 1, 1)])
+    B7 = (
+        current_polyline_field(
+            field="B",
+            observers=po4,
+            current=c4,
+            segment_start=ps4,
+            segment_end=pe4,
+        )
+        * 1e6
+    )
+    x7 = np.array([[0, 0, 0], [0.02672612, -0.05345225, 0.02672612], [0, 0, 0]])
+    assert_allclose(x7, B7, rtol=1e-6)
+
+
+def test_field_loop2():
+    """test if field function accepts correct inputs"""
+    curr = np.array([1])
+    dia = np.array([2])
+    obs = np.array([[0, 0, 0]])
+    B = current_circle_field(
+        field="B",
+        observers=obs,
+        current=curr,
+        diameter=dia,
+    )
+
+    curr = np.array([1] * 2)
+    dia = np.array([2] * 2)
+    obs = np.array([[0, 0, 0]] * 2)
+    B2 = current_circle_field(
+        field="B",
+        observers=obs,
+        current=curr,
+        diameter=dia,
+    )
+
+    assert_allclose(B, (B2[0],))
+    assert_allclose(B, (B2[1],))
+
+
+def test_field_line_from_vert():
+    """test the Polyline field from vertex input"""
+    observers = np.array([(1, 2, 2), (1, 2, 3), (-1, 0, -3)])
+    current = np.array([1, 5, -3])
+
+    vertices = np.array(
+        [
+            np.array(
+                [(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (1, 2, 3), (-3, 4, -5)]
+            ),
+            np.array([(0, 0, 0), (3, 3, 3), (-3, 4, -5)]),
+            np.array([(1, 2, 3), (-2, -3, 3), (3, 2, 1), (3, 3, 3)]),
+        ],
+        dtype="object",
+    )
+
+    B_vert = current_vertices_field(
+        field="B",
+        observers=observers,
+        vertices=vertices,
+        current=current,
+    )
+
+    B = []
+    for obs, vert, curr in zip(observers, vertices, current):
+        p1 = vert[:-1]
+        p2 = vert[1:]
+        po = np.array([obs] * (len(vert) - 1))
+        cu = np.array([curr] * (len(vert) - 1))
+        B += [
+            np.sum(
+                current_polyline_field(
+                    field="B",
+                    observers=po,
+                    current=cu,
+                    segment_start=p1,
+                    segment_end=p2,
+                ),
+                axis=0,
+            )
+        ]
+    B = np.array(B)
+
+    assert_allclose(B_vert, B)
+
+
+def test_field_line_v4():
+    """test current_line_Bfield() for all cases"""
+    cur = np.array([1] * 7)
+    start = np.array([(-1, 0, 0)] * 7)
+    end = np.array([(1, 0, 0), (-1, 0, 0), (1, 0, 0), (-1, 0, 0)] + [(1, 0, 0)] * 3)
+    obs = np.array(
+        [
+            (0, 0, 1),
+            (0, 0, 0),
+            (0, 0, 0),
+            (0, 0, 0),
+            (0, 0, 1e-16),
+            (2, 0, 1),
+            (-2, 0, 1),
+        ]
+    )
+    B = (
+        current_polyline_field(
+            field="B",
+            observers=obs,
+            current=cur,
+            segment_start=start,
+            segment_end=end,
+        )
+        * 1e6
+    )
+    Btest = np.array(
+        [
+            [0, -0.14142136, 0],
+            [0, 0.0, 0],
+            [0, 0.0, 0],
+            [0, 0.0, 0],
+            [0, 0.0, 0],
+            [0, -0.02415765, 0],
+            [0, -0.02415765, 0],
+        ]
+    )
+    np.testing.assert_allclose(B, Btest)
+
+
+def test_triangle5():
+    """special case tests on edges - result is continuous and 0 for vertical component"""
+    btest1 = [
+        [26.29963526814195, 15.319834473660082, 0.0],
+        [54.91549594789228, 41.20535983076747, 0.0],
+        [32.25241487782939, 15.087161660417559, 0.0],
+        [10.110611199952707, -11.41176203622237, 0.0],
+        [-3.8084378251737285, -30.875600143560657, -0.0],
+        [-15.636505140623612, -50.00854548249858, -0.0],
+        [-27.928308992688645, -72.80800891847107, -0.0],
+        [-45.34417750711242, -109.5871836961927, -0.0],
+        [-36.33970306054345, 12.288824457077656, 0.0],
+        [-16.984738462958845, 4.804383318447626, 0.0],
+    ]
+
+    btest2 = [
+        [15.31983447366009, 26.299635268142033, 0.0],
+        [41.20535983076747, 54.91549594789104, 0.0],
+        [-72.61316618947018, 32.25241487782958, 0.0],
+        [-54.07597251255013, 10.110611199952693, 0.0],
+        [-44.104089712909634, -3.808437825173785, -0.0],
+        [-36.78005591314963, -15.636505140623605, -0.0],
+        [-30.143798442143236, -27.92830899268858, -0.0],
+        [-21.886855846306176, -45.34417750711366, -0.0],
+        [12.288824457077965, -36.33970306054315, 0.0],
+        [4.80438331844773, -16.98473846295874, 0.0],
+    ]
+
+    n = 10
+    ts = np.linspace(-1, 6, n)
+    obs1 = np.array([(t, 0, 0) for t in ts])
+    obs2 = np.array([(0, t, 0) for t in ts])
+    mag = np.array([(111, 222, 333)] * n)
+    ver = np.array([[(0, 0, 0), (0, 5, 0), (5, 0, 0)]] * n)
+
+    b1 = (
+        magpy.core.triangle_field(
+            field="H",
+            observers=obs1,
+            polarization=mag,
+            vertices=ver,
+        )
+        * 1e-6
+    )
+    np.testing.assert_allclose(btest1, b1)
+    b2 = (
+        magpy.core.triangle_field(
+            field="H",
+            observers=obs2,
+            polarization=mag,
+            vertices=ver,
+        )
+        * 1e-6
+    )
+    np.testing.assert_allclose(btest2, b2)
+
+
+def test_triangle6():
+    """special case tests on corners - result is nan"""
+    obs1 = np.array([(0, 0, 0)])
+    obs2 = np.array([(0, 5, 0)])
+    obs3 = np.array([(5, 0, 0)])
+    mag = np.array([(1, 2, 3)])
+    ver = np.array([[(0, 0, 0), (0, 5, 0), (5, 0, 0)]])
+    b1 = magpy.core.triangle_field(
+        field="B",
+        observers=obs1,
+        polarization=mag,
+        vertices=ver,
+    )
+    b2 = magpy.core.triangle_field(
+        field="B",
+        observers=obs2,
+        polarization=mag,
+        vertices=ver,
+    )
+    b3 = magpy.core.triangle_field(
+        field="B",
+        observers=obs3,
+        polarization=mag,
+        vertices=ver,
+    )
+    for b in [b1, b2, b3]:
+        np.testing.assert_equal(b, np.array([[np.nan] * 3]))
diff --git a/tests/test_core_physics_consistency.py b/tests/test_core_physics_consistency.py
new file mode 100644
index 000000000..610d90c72
--- /dev/null
+++ b/tests/test_core_physics_consistency.py
@@ -0,0 +1,611 @@
+import numpy as np
+
+import magpylib as magpy
+from magpylib._src.utility import MU0
+
+# PHYSICS CONSISTENCY TESTING
+#
+# Magnetic moment of a current loop with current I and surface A:
+#   mom = I * A
+#
+# Magnetic moment of a homogeneous magnet with magnetization mag and volume vol
+#   mom = vol * mag
+#
+# Current replacement picture: A magnet generates a similar field as a current sheet
+#   on its surface with current density j = M = J/MU0. Such a current generates
+#   the same B-field. The H-field generated by is H-M!
+#
+# Geometric approximation testing should give similar results for different
+# implementations when one geometry is constructed from another
+#
+# ----------> Circle          # webpage numbers
+# Circle   <> Dipole          # mom = I*A (far field approx)
+# Polyline <> Dipole          # mom = I*A (far field approx)
+# Dipole   <> Sphere          # mom = vol*mag (similar outside of sphere)
+# Dipole   <> all Magnets     # mom = vol*mag (far field approx)
+# Circle   <> Cylinder        # j = I*N/L == J/MU0 current replacement picture
+# Polyline <> Cuboid          # j = I*N/L == J/MU0 current replacement picture
+# Circle   <> Polyline        # geometric approx
+# Cylinder <> CylinderSegment # geometric approx
+# Triangle <> Cuboid          # geometric approx
+# Triangle <> Triangle        # geometric approx
+# Cuboid   <> Tetrahedron     # geometric approx
+
+
+# Circle<>Dipole
+def test_core_phys_moment_of_current_circle():
+    """
+    test dipole vs circular current loop
+    moment = current * surface
+    far field test
+    """
+    obs = np.array([(10, 20, 30), (-10, -20, 30)])
+    dia = np.array([2, 2])
+    curr = np.array([1e3, 1e3])
+    mom = ((dia / 2) ** 2 * np.pi * curr * np.array([(0, 0, 1)] * 2).T).T
+
+    B1 = magpy.core.current_circle_field(
+        field="B",
+        observers=obs,
+        diameter=dia,
+        current=curr,
+    )
+    B2 = magpy.core.dipole_field(
+        field="B",
+        observers=obs,
+        moment=mom,
+    )
+    np.testing.assert_allclose(B1, B2, rtol=1e-02)
+
+    H1 = magpy.core.current_circle_field(
+        field="H",
+        observers=obs,
+        diameter=dia,
+        current=curr,
+    )
+    H2 = magpy.core.dipole_field(
+        field="H",
+        observers=obs,
+        moment=mom,
+    )
+    np.testing.assert_allclose(H1, H2, rtol=1e-02)
+
+
+# Polyline <> Dipole
+def test_core_phys_moment_of_current_square():
+    """
+    test dipole VS square current loop
+    moment = I x A, far field test
+    """
+    obs1 = np.array([(10, 20, 30)])
+    obs4 = np.array([(10, 20, 30)] * 4)
+    vert = np.array([(1, 1, 0), (1, -1, 0), (-1, -1, 0), (-1, 1, 0), (1, 1, 0)])
+    curr1 = 1e3
+    curr4 = np.array([curr1] * 4)
+    mom = (4 * curr1 * np.array([(0, 0, 1)]).T).T
+
+    B1 = magpy.core.current_polyline_field(
+        field="B",
+        observers=obs4,
+        segment_start=vert[:-1],
+        segment_end=vert[1:],
+        current=curr4,
+    )
+    B1 = np.sum(B1, axis=0)
+    B2 = magpy.core.dipole_field(
+        field="B",
+        observers=obs1,
+        moment=mom,
+    )[0]
+    np.testing.assert_allclose(B1, -B2, rtol=1e-03)
+
+    H1 = magpy.core.current_polyline_field(
+        field="H",
+        observers=obs4,
+        segment_start=vert[:-1],
+        segment_end=vert[1:],
+        current=curr4,
+    )
+    H1 = np.sum(H1, axis=0)
+    H2 = magpy.core.dipole_field(
+        field="H",
+        observers=obs1,
+        moment=mom,
+    )[0]
+    np.testing.assert_allclose(H1, -H2, rtol=1e-03)
+
+
+# Circle <> Polyline
+def test_core_phys_circle_polyline():
+    """approximate circle with polyline"""
+    ts = np.linspace(0, 2 * np.pi, 300)
+    vert = np.array([(np.sin(t), np.cos(t), 0) for t in ts])
+    curr = np.array([1])
+    curr99 = np.array([1] * 299)
+    obs = np.array([(1, 2, 3)])
+    obs99 = np.array([(1, 2, 3)] * 299)
+    dia = np.array([2])
+
+    H1 = magpy.core.current_circle_field(
+        field="H",
+        observers=obs,
+        diameter=dia,
+        current=curr,
+    )[0]
+    H2 = magpy.core.current_polyline_field(
+        field="H",
+        observers=obs99,
+        segment_start=vert[:-1],
+        segment_end=vert[1:],
+        current=curr99,
+    )
+    H2 = np.sum(H2, axis=0)
+    np.testing.assert_allclose(H1, -H2, rtol=1e-4)
+
+    B1 = magpy.core.current_circle_field(
+        field="B",
+        observers=obs,
+        diameter=dia,
+        current=curr,
+    )[0]
+    B2 = magpy.core.current_polyline_field(
+        field="B",
+        observers=obs99,
+        segment_start=vert[:-1],
+        segment_end=vert[1:],
+        current=curr99,
+    )
+    B2 = np.sum(B2, axis=0)
+    np.testing.assert_allclose(B1, -B2, rtol=1e-4)
+
+
+# Dipole <> Sphere
+def test_core_physics_dipole_sphere():
+    """
+    dipole and sphere field must be similar outside of sphere
+    moment = magnetization * volume
+    near field tests
+    """
+    obs = np.array([(1, 2, 3), (-2, -2, -2), (3, 5, -4), (5, 4, 0.1)])
+    dia = np.array([2, 3, 0.1, 3.3])
+    pol = np.array([(1, 2, 3), (0, 0, 1), (-1, -2, 0), (1, -1, 0.1)])
+    mom = np.array([4 * (d / 2) ** 3 * np.pi / 3 * p / MU0 for d, p in zip(dia, pol)])
+
+    B1 = magpy.core.magnet_sphere_field(
+        field="B",
+        observers=obs,
+        diameter=dia,
+        polarization=pol,
+    )
+    B2 = magpy.core.dipole_field(
+        field="B",
+        observers=obs,
+        moment=mom,
+    )
+    np.testing.assert_allclose(B1, B2, rtol=0, atol=1e-16)
+
+    H1 = magpy.core.magnet_sphere_field(
+        field="H",
+        observers=obs,
+        diameter=dia,
+        polarization=pol,
+    )
+    H2 = magpy.core.dipole_field(
+        field="H",
+        observers=obs,
+        moment=mom,
+    )
+    np.testing.assert_allclose(H1, H2, rtol=0, atol=1e-11)
+
+
+# -> Circle, Cylinder
+def test_core_physics_long_solenoid():
+    """
+    Test if field from solenoid converges to long-solenoid field in the center
+        Bz_long = MU0*I*N/L
+        Hz_long = I*N/L
+    I = current, N=windings, L=length, holds true if L >> radius R
+
+    This can also be tested with magnets using the current replacement picture
+        where Jz = MU0 * I * N / L, and holds for B and for H-M.
+    """
+
+    I = 134
+    N = 5000
+    R = 1.543
+    L = 1234
+
+    for field in ["B", "H"]:
+        BHz_long = N * I / L
+        if field == "B":
+            BHz_long *= MU0
+
+        # SOLENOID TEST constructed from circle fields
+        BH = magpy.core.current_circle_field(
+            field=field,
+            observers=np.linspace((0, 0, -L / 2), (0, 0, L / 2), N),
+            diameter=np.array([2 * R] * N),
+            current=np.array([I] * N),
+        )
+        BH_sol = np.sum(BH, axis=0)[2]
+
+        np.testing.assert_allclose(BHz_long, BH_sol, rtol=1e-3)
+
+        # MAGNET TEST using the current replacement picture
+        Mz = I * N / L
+        Jz = Mz * MU0
+        pol = np.array([(0, 0, Jz)])
+        obs = np.array([(0, 0, 0)])
+
+        # cylinder
+        BHz_cyl = magpy.core.magnet_cylinder_field(
+            field=field,
+            observers=obs,
+            dimension=np.array([(2 * R, L)]),
+            polarization=pol,
+        )[0, 2]
+        if field == "H":
+            BHz_cyl += Mz
+        np.testing.assert_allclose(BHz_long, BHz_cyl, rtol=1e-5)
+
+        # cuboid
+        BHz_cub = magpy.core.magnet_cuboid_field(
+            field=field,
+            observers=obs,
+            dimension=np.array([(2 * R, 2 * R, L)]),
+            polarization=pol,
+        )[0, 2]
+        if field == "H":
+            BHz_cub += Mz
+        np.testing.assert_allclose(BHz_long, BHz_cub, rtol=1e-5)
+
+
+# Circle<>Cylinder
+def test_core_physics_current_replacement():
+    """
+    test if the Cylinder field is given by a replacement current sheet
+    that carries a current density of j=magnetization
+    It follows:
+        j = I*N/L == J/MU0
+          -> I = J/MU0/N*L
+    near-field test
+    """
+    L = 0.5
+    R = 0.987
+    obs = np.array([(1.5, -2, -1.123)])
+
+    Jz = 1
+    Hz_cyl = magpy.core.magnet_cylinder_field(
+        field="H",
+        observers=obs,
+        dimension=np.array([(2 * R, L)]),
+        polarization=np.array([(0, 0, Jz)]),
+    )[0, 2]
+
+    N = 1000  # current discretization
+    I = Jz / MU0 / N * L
+    H = magpy.core.current_circle_field(
+        field="H",
+        observers=np.linspace((0, 0, -L / 2), (0, 0, L / 2), N) + obs,
+        diameter=np.array([2 * R] * N),
+        current=np.array([I] * N),
+    )
+    Hz_curr = np.sum(H, axis=0)[2]
+
+    np.testing.assert_allclose(Hz_curr, Hz_cyl, rtol=1e-4)
+
+
+# Cylinder<>CylinderSegment
+def test_core_physics_geometry_cylinder_from_segments():
+    """test if multiple Cylinder segments create the same field as fully cylinder"""
+    r = 1.23
+    h = 3
+    obs = np.array([(1, 2, 3), (0.23, 0.132, 0.123)])
+    pol = np.array([(2, 0.123, 3), (-0.23, -1, 0.434)])
+
+    B_cyl = magpy.core.magnet_cylinder_field(
+        field="B",
+        observers=obs,
+        dimension=np.array([(2 * r, h)] * 2),
+        polarization=pol,
+    )
+    sections = np.array([-12, 65, 123, 180, 245, 348])
+
+    Bseg = np.zeros((2, 3))
+    for phi1, phi2 in zip(sections[:-1], sections[1:]):
+        B_part = magpy.core.magnet_cylinder_segment_field(
+            field="B",
+            observers=obs,
+            dimension=np.array([(0, r, h, phi1, phi2)] * 2),
+            polarization=pol,
+        )
+        Bseg[0] += B_part[0]
+        Bseg[1] += B_part[1]
+    np.testing.assert_allclose(B_cyl, Bseg)
+
+
+# Dipole<>Cuboid, Cylinder, CylinderSegment, Tetrahedron
+def test_core_physics_dipole_approximation_magnet_far_field():
+    """test if all magnets satisfy the dipole approximation"""
+    obs = np.array([(100, 200, 300), (-200, -200, -200)])
+
+    mom = np.array([(1e6, 2e6, 3e6)] * 2)
+    Bdip = magpy.core.dipole_field(
+        field="H",
+        observers=obs,
+        moment=mom,
+    )
+
+    dim = np.array([(2, 2, 2)] * 2)
+    vol = 8
+    pol = mom / vol * MU0
+    Bcub = magpy.core.magnet_cuboid_field(
+        field="H",
+        observers=obs,
+        dimension=dim,
+        polarization=pol,
+    )
+    np.testing.assert_allclose(Bdip, Bcub)
+
+    dim = np.array([(0.5, 0.5)] * 2)
+    vol = 0.25**2 * np.pi * 0.5
+    pol = mom / vol * MU0
+    Bcyl = magpy.core.magnet_cylinder_field(
+        field="H",
+        observers=obs,
+        dimension=dim,
+        polarization=pol,
+    )
+    np.testing.assert_allclose(Bdip, Bcyl)
+
+    vert = np.array([[(0, 0, 0), (0, 0, 0.1), (0.1, 0, 0), (0, 0.1, 0)]] * 2)
+    vol = 1 / 6 * 1e-3
+    pol = mom / vol * MU0
+    Btetra = magpy.core.magnet_tetrahedron_field(
+        field="H",
+        observers=obs,
+        vertices=vert,
+        polarization=pol,
+    )
+    np.testing.assert_allclose(Bdip, Btetra, rtol=1e-3)
+
+    dim = np.array([(0.1, 0.2, 0.1, -25, 25)] * 2)
+    vol = 3 * np.pi * (50 / 360) * 1e-3
+    pol = mom / vol * MU0
+    Bcys = magpy.core.magnet_cylinder_segment_field(
+        field="H",
+        observers=obs + np.array((0.15, 0, 0)),
+        dimension=dim,
+        polarization=pol,
+    )
+    np.testing.assert_allclose(Bdip, Bcys, rtol=1e-4)
+
+
+# --> Circle
+def test_core_physics_circle_VS_webpage_numbers():
+    """
+    Compare Circle on-axis field vs e-magnetica & hyperphysics
+    """
+    dia = np.array([2] * 4)
+    curr = np.array([1e3] * 4)  # A
+    zs = [0, 1, 2, 3]
+    obs = np.array([(0, 0, z) for z in zs])
+
+    # values from e-magnetica
+    Hz = [500, 176.8, 44.72, 15.81]
+    Htest = [(0, 0, hz) for hz in Hz]
+
+    H = magpy.core.current_circle_field(
+        field="H",
+        observers=obs,
+        diameter=dia,
+        current=curr,
+    )
+    np.testing.assert_allclose(H, Htest, rtol=1e-3)
+
+    # values from hyperphysics
+    Bz = [
+        0.6283185307179586e-3,
+        2.2214414690791835e-4,
+        5.619851784832581e-5,
+        1.9869176531592205e-5,
+    ]
+    Btest = [(0, 0, bz) for bz in Bz]
+
+    B = magpy.core.current_circle_field(
+        field="B",
+        observers=obs,
+        diameter=dia,
+        current=curr,
+    )
+    np.testing.assert_allclose(B, Btest, rtol=1e-7)
+
+
+# Cuboid <> Polyline
+def test_core_physics_cube_current_replacement():
+    """compare cuboid field with current replacement"""
+    obs = np.array([(2, 2, 3.13), (-2.123, -4, 2)])
+    h = 1
+    Jz = 1.23
+    dim = np.array([(2, 2, h)] * 2)
+    pol = np.array([(0, 0, Jz)] * 2)
+    Hcub = magpy.core.magnet_cuboid_field(
+        field="H",
+        observers=obs,
+        dimension=dim,
+        polarization=pol,
+    )
+
+    # construct from polylines
+    n = 1000
+    vert = np.array([(1, 1, 0), (1, -1, 0), (-1, -1, 0), (-1, 1, 0), (1, 1, 0)])
+    curr = h / n * Jz / MU0
+    hs = np.linspace(-h / 2, h / 2, n)
+    hpos = np.array([(0, 0, h) for h in hs])
+
+    obs1 = np.array([obs[0] + hp for hp in hpos] * 4)
+    obs2 = np.array([obs[1] + hp for hp in hpos] * 4)
+
+    start = np.repeat(vert[:-1], n, axis=0)
+    end = np.repeat(vert[1:], n, axis=0)
+
+    Hcurr = np.zeros((2, 3))
+    for i, obss in enumerate([obs1, obs2]):
+        h = magpy.core.current_polyline_field(
+            field="H",
+            observers=obss,
+            segment_start=start,
+            segment_end=end,
+            current=np.array([curr] * 4 * n),
+        )
+        Hcurr[i] = np.sum(h, axis=0)
+
+    np.testing.assert_allclose(Hcub, -Hcurr, rtol=1e-4)
+
+
+def test_core_physics_triangle_cube_geometry():
+    """test core triangle VS cube"""
+    obs = np.array([(3, 4, 5)] * 4)
+    mag = np.array([(0, 0, 333)] * 4)
+    fac = np.array(
+        [
+            [(-1, -1, 1), (1, -1, 1), (-1, 1, 1)],  # top1
+            [(1, -1, -1), (-1, -1, -1), (-1, 1, -1)],  # bott1
+            [(1, -1, 1), (1, 1, 1), (-1, 1, 1)],  # top2
+            [(1, 1, -1), (1, -1, -1), (-1, 1, -1)],  # bott2
+        ]
+    )
+    b = magpy.core.triangle_field(
+        field="B",
+        observers=obs,
+        vertices=fac,
+        polarization=mag,
+    )
+    b = np.sum(b, axis=0)
+
+    obs = np.array([(3, 4, 5)])
+    mag = np.array([(0, 0, 333)])
+    dim = np.array([(2, 2, 2)])
+    bb = magpy.core.magnet_cuboid_field(
+        field="B",
+        observers=obs,
+        dimension=dim,
+        polarization=mag,
+    )[0]
+
+    np.testing.assert_allclose(b, bb)
+
+
+def test_core_physics_triangle_VS_itself():
+    """test core single triangle vs same surface split up into 4 triangular faces"""
+    obs = np.array([(3, 4, 5)])
+    mag = np.array([(111, 222, 333)])
+    fac = np.array(
+        [
+            [(0, 0, 0), (10, 0, 0), (0, 10, 0)],
+        ]
+    )
+    b = magpy.core.triangle_field(
+        field="B",
+        observers=obs,
+        polarization=mag,
+        vertices=fac,
+    )
+    b = np.sum(b, axis=0)
+
+    obs = np.array([(3, 4, 5)] * 4)
+    mag = np.array([(111, 222, 333)] * 4)
+    fac = np.array(
+        [
+            [(0, 0, 0), (3, 0, 0), (0, 10, 0)],
+            [(3, 0, 0), (5, 0, 0), (0, 10, 0)],
+            [(5, 0, 0), (6, 0, 0), (0, 10, 0)],
+            [(6, 0, 0), (10, 0, 0), (0, 10, 0)],
+        ]
+    )
+    bb = magpy.core.triangle_field(
+        field="B",
+        observers=obs,
+        polarization=mag,
+        vertices=fac,
+    )
+    bb = np.sum(bb, axis=0)
+
+    np.testing.assert_allclose(b, bb)
+
+
+def test_core_physics_Tetrahedron_VS_Cuboid():
+    """test core tetrahedron vs cube"""
+    ver = np.array(
+        [
+            [(1, 1, -1), (1, 1, 1), (-1, 1, 1), (1, -1, 1)],
+            [(-1, -1, 1), (-1, 1, 1), (1, -1, 1), (1, -1, -1)],
+            [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (1, -1, -1)],
+            [(-1, 1, -1), (1, -1, -1), (-1, -1, 1), (-1, 1, 1)],
+            [(1, -1, -1), (1, 1, -1), (1, -1, 1), (-1, 1, 1)],
+            [(-1, 1, -1), (-1, 1, 1), (1, 1, -1), (1, -1, -1)],
+        ]
+    )
+
+    mags = [
+        [1.03595366, 0.42840487, 0.10797529],
+        [0.33513152, 1.61629547, 0.15959791],
+        [0.29904441, 1.32185041, 1.81218046],
+        [0.82665456, 1.86827489, 1.67338911],
+        [0.97619806, 1.52323106, 1.63628455],
+        [1.70290645, 1.49610608, 0.13878711],
+        [1.49886747, 1.55633919, 1.41351862],
+        [0.9959534, 0.62059942, 1.28616663],
+        [0.60114354, 0.96120344, 0.32009221],
+        [0.83133901, 0.7925518, 0.64574592],
+    ]
+
+    obss = [
+        [0.82811352, 1.77818627, 0.19819379],
+        [0.84147235, 1.10200857, 1.51687527],
+        [0.30751474, 0.89773196, 0.56468564],
+        [1.87437889, 1.55908581, 1.10579983],
+        [0.64810548, 1.38123846, 1.90576802],
+        [0.48981034, 0.09376294, 0.53717129],
+        [1.42826412, 0.30246674, 0.57649909],
+        [1.58376758, 1.70420478, 0.22894022],
+        [0.26791832, 0.36839769, 0.67934335],
+        [1.15140149, 0.10549875, 0.98304184],
+    ]
+
+    for mag in mags:
+        for obs in obss:
+            obs6 = np.tile(obs, (6, 1))
+            mag6 = np.tile(mag, (6, 1))
+            b = magpy.core.magnet_tetrahedron_field(
+                field="B",
+                observers=obs6,
+                polarization=mag6,
+                vertices=ver,
+            )
+            h = magpy.core.magnet_tetrahedron_field(
+                field="H",
+                observers=obs6,
+                polarization=mag6,
+                vertices=ver,
+            )
+            b = np.sum(b, axis=0)
+            h = np.sum(h, axis=0)
+
+            obs1 = np.reshape(obs, (1, 3))
+            mag1 = np.reshape(mag, (1, 3))
+            dim = np.array([(2, 2, 2)])
+            bb = magpy.core.magnet_cuboid_field(
+                field="B",
+                observers=obs1,
+                polarization=mag1,
+                dimension=dim,
+            )[0]
+            hh = magpy.core.magnet_cuboid_field(
+                field="H",
+                observers=obs1,
+                polarization=mag1,
+                dimension=dim,
+            )[0]
+            np.testing.assert_allclose(b, bb)
+            np.testing.assert_allclose(h, hh)
diff --git a/tests/test_display_matplotlib.py b/tests/test_display_matplotlib.py
index bdac098bc..472eb3a28 100644
--- a/tests/test_display_matplotlib.py
+++ b/tests/test_display_matplotlib.py
@@ -26,7 +26,7 @@
 
 def test_Cuboid_display():
     """testing display"""
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     src.move(np.linspace((0.1, 0.1, 0.1), (2, 2, 2), 20), start=-1)
     src.show(
         style_path_frames=5,
@@ -46,7 +46,7 @@ def test_Cylinder_display():
     """testing display"""
     # path should revert to True
     ax = plt.subplot(projection="3d")
-    src = magpy.magnet.Cylinder((1, 2, 3), (1, 2))
+    src = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(1, 2))
     src.show(canvas=ax, style_path_frames=15, backend="matplotlib")
 
     # hide path
@@ -68,7 +68,9 @@ def test_Cylinder_display():
 def test_CylinderSegment_display():
     """testing display"""
     ax = plt.subplot(projection="3d")
-    src = magpy.magnet.CylinderSegment((1, 2, 3), (2, 4, 5, 30, 40))
+    src = magpy.magnet.CylinderSegment(
+        polarization=(1, 2, 3), dimension=(2, 4, 5, 30, 40)
+    )
     src.show(canvas=ax, style_path_frames=15, return_fig=True)
 
     src.move(np.linspace((0.4, 0.4, 0.4), (13.2, 13.2, 13.2), 33), start=-1)
@@ -79,7 +81,7 @@ def test_Sphere_display():
     """testing display"""
     # path should revert to True
     ax = plt.subplot(projection="3d")
-    src = magpy.magnet.Sphere((1, 2, 3), 2)
+    src = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=2)
     src.show(canvas=ax, style_path_frames=15, return_fig=True)
 
     src.move(np.linspace((0.4, 0.4, 0.4), (8, 8, 8), 20), start=-1)
@@ -94,7 +96,7 @@ def test_Sphere_display():
 def test_Tetrahedron_display():
     """testing Tetrahedron display"""
     verts = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]
-    src = magpy.magnet.Tetrahedron(magnetization=(100, 200, 300), vertices=verts)
+    src = magpy.magnet.Tetrahedron(polarization=(0.1, 0.2, 0.3), vertices=verts)
     src.show(return_fig=True, style_magnetization_mode="color+arrow")
 
 
@@ -141,7 +143,7 @@ def test_Triangle_display():
     triangles = np.array([v for k, v in mesh3d["kwargs"].items() if k in "ijk"]).T
     src = magpy.Collection(
         [
-            magpy.misc.Triangle(magnetization=(1000, 1000, 0), vertices=v)
+            magpy.misc.Triangle(polarization=(1, 1, 0), vertices=v)
             for v in points[triangles]
         ]
     )
@@ -169,10 +171,7 @@ def test_Triangle_display_from_convexhull():
     points = np.array([v for k, v in mesh3d["kwargs"].items() if k in "xyz"]).T
     faces = np.array([v for k, v in mesh3d["kwargs"].items() if k in "ijk"]).T
     src = magpy.Collection(
-        [
-            magpy.misc.Triangle(magnetization=(1000, 0, 0), vertices=v)
-            for v in points[faces]
-        ]
+        [magpy.misc.Triangle(polarization=(1, 0, 0), vertices=v) for v in points[faces]]
     )
     magpy.show(
         *src,
@@ -186,13 +185,13 @@ def test_Triangle_display_from_convexhull():
     )
 
 
-def test_TringularMesh_display():
+def test_TriangularMesh_display():
     """testing display for TriangleMesh source built from vertices"""
     # test  classic trimesh display
     points = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]
 
     src = magpy.magnet.TriangularMesh.from_ConvexHull(
-        magnetization=(1000, 0, 0), points=points
+        polarization=(1, 0, 0), points=points
     )
     src.show(
         backend="matplotlib",
@@ -211,9 +210,9 @@ def test_TringularMesh_display():
     faces = polydata.faces.reshape(-1, 4)[:, 1:]
     faces = faces[1:]  # open the mesh
     src = magpy.magnet.TriangularMesh(
-        (0, 0, 1000),
-        vertices,
-        faces,
+        polarization=(0, 0, 1000),
+        vertices=vertices,
+        faces=faces,
         check_open="ignore",
         check_disconnected="ignore",
         reorient_faces=False,
@@ -231,9 +230,9 @@ def test_TringularMesh_display():
 
     with pytest.warns(UserWarning) as record:
         magpy.magnet.TriangularMesh(
-            (0, 0, 1000),
-            vertices,
-            faces,
+            polarization=(0, 0, 1000),
+            vertices=vertices,
+            faces=faces,
             check_open="skip",
             check_disconnected="skip",
             reorient_faces=False,
@@ -267,7 +266,7 @@ def test_TringularMesh_display():
     faces = np.array([v for k, v in selfintersecting_mesh3d.items() if k in "ijk"]).T
     with pytest.warns(UserWarning) as record:
         magpy.magnet.TriangularMesh(
-            (0, 0, 1000),
+            polarization=(0, 0, 1000),
             vertices=vertices,
             faces=faces,
             check_open="warn",
@@ -293,7 +292,7 @@ def test_col_display():
     """testing display"""
     # pylint: disable=assignment-from-no-return
     ax = plt.subplot(projection="3d")
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     pm2 = pm1.copy(position=(2, 0, 0))
     pm3 = pm1.copy(position=(4, 0, 0))
     nested_col = (pm1 + pm2 + pm3).set_children_styles(color="magenta")
@@ -315,11 +314,11 @@ def test_circular_line_display():
     """testing display"""
     # pylint: disable=assignment-from-no-return
     ax2 = plt.subplot(projection="3d")
-    src1 = magpy.current.Circle(1, 2)
-    src2 = magpy.current.Circle(1, 2)
+    src1 = magpy.current.Circle(current=1, diameter=2)
+    src2 = magpy.current.Circle(current=1, diameter=2)
     src1.move(np.linspace((0.4, 0.4, 0.4), (2, 2, 2), 5), start=-1)
-    src3 = magpy.current.Polyline(1, [(0, 0, 0), (1, 1, 1), (2, 2, 2)])
-    src4 = magpy.current.Polyline(1, [(0, 0, 0), (1, 1, 1), (2, 2, 2)])
+    src3 = magpy.current.Polyline(current=1, vertices=[(0, 0, 0), (1, 1, 1), (2, 2, 2)])
+    src4 = magpy.current.Polyline(current=1, vertices=[(0, 0, 0), (1, 1, 1), (2, 2, 2)])
     src3.move([(0.4, 0.4, 0.4)] * 5, start=-1)
     src1.show(canvas=ax2, style_path_frames=2, style_arrow_size=0, return_fig=True)
     src2.show(canvas=ax2, style_arrow_sizemode="absolute", return_fig=True)
@@ -431,7 +430,7 @@ def test_empty_display():
 def test_graphics_model_mpl():
     """test base extra graphics with mpl"""
     ax = plt.subplot(projection="3d")
-    c = magpy.magnet.Cuboid((0, 1, 0), (1, 1, 1))
+    c = magpy.magnet.Cuboid(polarization=(0, 1, 0), dimension=(1, 1, 1))
     c.rotate_from_angax(33, "x", anchor=0)
     c.style.model3d.add_trace(**make_Cuboid("matplotlib", position=(2, 0, 0)))
     c.show(canvas=ax, style_path_frames=1, backend="matplotlib", return_fig=True)
@@ -439,7 +438,7 @@ def test_graphics_model_mpl():
 
 def test_graphics_model_generic_to_mpl():
     """test generic base extra graphics with mpl"""
-    c = magpy.magnet.Cuboid((0, 1, 0), (1, 1, 1))
+    c = magpy.magnet.Cuboid(polarization=(0, 1, 0), dimension=(1, 1, 1))
     c.move([[i, 0, 0] for i in range(2)])
     model3d = make_Cuboid(position=(2, 0, 0))
     model3d["kwargs"]["facecolor"] = np.array(["blue"] * 12)
@@ -450,7 +449,7 @@ def test_graphics_model_generic_to_mpl():
 
 def test_mpl_animation():
     """test animation with matplotib"""
-    c = magpy.magnet.Cuboid((0, 1, 0), (1, 1, 1))
+    c = magpy.magnet.Cuboid(polarization=(0, 1, 0), dimension=(1, 1, 1))
     c.move([[i, 0, 0] for i in range(2)])
     fig, anim = c.show(
         backend="matplotlib", animation=True, return_animation=True, return_fig=True
@@ -468,7 +467,7 @@ def test_subplots():
     )
     sensor.style.label = "Sensor1"
     cyl1 = magpy.magnet.Cylinder(
-        magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+        polarization=(0.1, 0, 0), dimension=(1, 2), style_label="Cylinder1"
     )
 
     # define paths
@@ -497,7 +496,7 @@ def test_bad_show_inputs():
     """bad show inputs"""
 
     cyl1 = magpy.magnet.Cylinder(
-        magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+        polarization=(0.1, 0, 0), dimension=(1, 2), style_label="Cylinder1"
     )
 
     # test bad canvas
@@ -521,7 +520,7 @@ def test_bad_show_inputs():
         pixel=np.linspace((0, 0, -0.2), (0, 0, 0.2), 2), style_size=1.5
     )
     cyl1 = magpy.magnet.Cylinder(
-        magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+        polarization=(0.1, 0, 0), dimension=(1, 2), style_label="Cylinder1"
     )
     with pytest.raises(
         ValueError,
@@ -606,3 +605,14 @@ def test_unset_objs():
         *objs,
         return_fig=True,
     )
+
+
+def test_show_legend():
+    """test legend (and multi shape pixel)"""
+    pixel = np.arange(27).reshape(3, 3, 3) * 1e-2
+    s1 = magpy.Sensor(pixel=pixel, style_label="s1")
+    s2 = s1.copy().move((1, 0, 0))
+    s3 = s2.copy().move((1, 0, 0))
+    s2.style.legend = "full legend replace"
+    s3.style.description = "description replace only"
+    magpy.show(s1, s2, s3, return_fig=True)
diff --git a/tests/test_display_plotly.py b/tests/test_display_plotly.py
index 6a09f5752..f6e5256ef 100644
--- a/tests/test_display_plotly.py
+++ b/tests/test_display_plotly.py
@@ -13,7 +13,7 @@ def test_Cylinder_display():
     """testing display"""
     magpy.defaults.display.backend = "plotly"
     fig = go.Figure()
-    src = magpy.magnet.Cylinder((1, 2, 3), (1, 2))
+    src = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(1, 2))
     x = src.show(canvas=fig, style_path_frames=15)
     assert x is None, "path should revert to True"
 
@@ -31,7 +31,9 @@ def test_CylinderSegment_display():
     """testing display"""
     magpy.defaults.display.backend = "plotly"
     fig = go.Figure()
-    src = magpy.magnet.CylinderSegment((1, 2, 3), (2, 4, 5, 30, 40))
+    src = magpy.magnet.CylinderSegment(
+        polarization=(1, 2, 3), dimension=(2, 4, 5, 30, 40)
+    )
     x = src.show(canvas=fig, style_path_frames=15)
     assert x is None, "path should revert to True"
 
@@ -49,7 +51,7 @@ def test_Sphere_display():
     """testing display"""
     magpy.defaults.display.backend = "plotly"
     fig = go.Figure()
-    src = magpy.magnet.Sphere((1, 2, 3), 2)
+    src = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=2)
     x = src.show(canvas=fig, style_path_frames=15)
     assert x is None, "path should revert to True"
 
@@ -61,7 +63,7 @@ def test_Sphere_display():
 def test_Cuboid_display():
     """testing display"""
     magpy.defaults.display.backend = "plotly"
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     src.move(np.linspace((0.1, 0.1, 0.1), (2, 2, 2), 20), start=-1)
     x = src.show(style_path_frames=5, style_magnetization_show=True, renderer="json")
     assert x is None, "display test fail"
@@ -106,7 +108,7 @@ def test_Triangle_display():
     # this test is necessary to cover the case where the backend can display mag arrows and
     # color gradient must be deactivated
     verts = [(0, 0, 0), (1, 0, 0), (0, 1, 0)]
-    src = magpy.misc.Triangle(magnetization=(100, 200, 300), vertices=verts)
+    src = magpy.misc.Triangle(polarization=(0.1, 0.2, 0.3), vertices=verts)
     src.show(style_magnetization_mode="arrow", return_fig=True)
 
 
@@ -115,7 +117,7 @@ def test_col_display():
     # pylint: disable=assignment-from-no-return
     magpy.defaults.display.backend = "plotly"
     fig = go.Figure()
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     pm2 = pm1.copy(position=(2, 0, 0))
     pm3 = pm1.copy(position=(4, 0, 0))
     nested_col = (pm1 + pm2 + pm3).set_children_styles(color="magenta")
@@ -145,11 +147,11 @@ def test_circular_line_display():
     # pylint: disable=assignment-from-no-return
     magpy.defaults.display.backend = "plotly"
     fig = go.Figure()
-    src1 = magpy.current.Circle(1, 2)
-    src2 = magpy.current.Circle(1, 2)
+    src1 = magpy.current.Circle(current=1, diameter=2)
+    src2 = magpy.current.Circle(current=1, diameter=2)
     src1.move(np.linspace((0.4, 0.4, 0.4), (2, 2, 2), 5), start=-1)
-    src3 = magpy.current.Polyline(1, [(0, 0, 0), (1, 1, 1), (2, 2, 2)])
-    src4 = magpy.current.Polyline(1, [(0, 0, 0), (1, 1, 1), (2, 2, 2)])
+    src3 = magpy.current.Polyline(current=1, vertices=[(0, 0, 0), (1, 1, 1), (2, 2, 2)])
+    src4 = magpy.current.Polyline(current=1, vertices=[(0, 0, 0), (1, 1, 1), (2, 2, 2)])
     src3.move([(0.4, 0.4, 0.4)] * 5, start=-1)
     x = src1.show(canvas=fig, style_path_frames=2, style_arrow_show=False)
     assert x is None, "display test fail"
@@ -172,7 +174,7 @@ def test_display_bad_style_kwargs():
 def test_extra_model3d():
     """test diplay when object has an extra model object attached"""
     magpy.defaults.display.backend = "plotly"
-    cuboid = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    cuboid = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     cuboid.move(np.linspace((0.4, 0.4, 0.4), (12.4, 12.4, 12.4), 33), start=-1)
     cuboid.style.model3d.showdefault = False
     cuboid.style.model3d.data = [
@@ -260,7 +262,7 @@ def test_display_warnings():
     magpy.defaults.display.backend = "plotly"
     magpy.defaults.display.animation.maxfps = 2
     magpy.defaults.display.animation.maxframes = 2
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     src.move(np.linspace((0.4, 0.4, 0.4), (4, 4, 4), 10), start=-1)
     fig = go.Figure()
 
@@ -268,7 +270,7 @@ def test_display_warnings():
         src.show(canvas=fig, animation=5, animation_fps=3)
     with pytest.warns(UserWarning):  # max frames surpassed
         src.show(canvas=fig, animation=True, animation_time=2, animation_fps=1)
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     with pytest.warns(UserWarning):  # no object path detected
         src.show(canvas=fig, style_path_frames=[], animation=True)
 
@@ -278,7 +280,7 @@ def test_bad_animation_value():
     magpy.defaults.display.backend = "plotly"
     magpy.defaults.display.animation.maxfps = 2
     magpy.defaults.display.animation.maxframes = 2
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     src.move(np.linspace((0.4, 0.4, 0.4), (4, 4, 4), 10), start=-1)
     fig = go.Figure()
 
@@ -296,7 +298,7 @@ def test_subplots():
             for x in np.linspace(0, 10, 11)
         ]
     )
-    cyl1 = magpy.magnet.Cylinder(magnetization=(100, 0, 0), dimension=(1, 2))
+    cyl1 = magpy.magnet.Cylinder(polarization=(0.1, 0, 0), dimension=(1, 2))
 
     # define paths
     sensors.position = np.linspace((0, 0, -3), (0, 0, 3), 100)
@@ -332,7 +334,9 @@ def test_legends():
         "constructor": "scatter3d",
         "kwargs": {"x": xs, "y": ys, "z": zs, "mode": "lines"},
     }
-    c = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1), style_label="Plotly extra trace")
+    c = magpy.magnet.Cuboid(
+        polarization=(0, 0, 1), dimension=(1, 1, 1), style_label="Plotly extra trace"
+    )
     c.style.model3d.add_trace(trace_plotly)
 
     fig = magpy.show(
@@ -343,7 +347,7 @@ def test_legends():
         # style_model3d_showdefault=False,
         return_fig=True,
     )
-    assert [t.name for t in fig.data] == ["Plotly extra trace (1mm|1mm|1mm)"] * 2
+    assert [t.name for t in fig.data] == ["Plotly extra trace (1m|1m|1m)"] * 2
     assert [t.showlegend for t in fig.data] == [False, False]
 
     fig = magpy.show(
@@ -354,7 +358,7 @@ def test_legends():
         # style_model3d_showdefault=False,
         return_fig=True,
     )
-    assert [t.name for t in fig.data] == ["Plotly extra trace (1mm|1mm|1mm)"] * 2
+    assert [t.name for t in fig.data] == ["Plotly extra trace (1m|1m|1m)"] * 2
     assert [t.showlegend for t in fig.data] == [True, False]
 
     fig = magpy.show(
@@ -365,7 +369,7 @@ def test_legends():
         style_model3d_showdefault=False,
         return_fig=True,
     )
-    assert [t.name for t in fig.data] == ["Plotly extra trace (1mm|1mm|1mm)"]
+    assert [t.name for t in fig.data] == ["Plotly extra trace (1m|1m|1m)"]
     assert [t.showlegend for t in fig.data] == [True]
 
     c.rotate_from_angax([10 * i for i in range(N)], "y", start=0, anchor=(0, 0, 10))
@@ -377,5 +381,5 @@ def test_legends():
         # style_model3d_showdefault=False,
         return_fig=True,
     )
-    assert [t.name for t in fig.data] == ["Plotly extra trace (1mm|1mm|1mm)"] * 4
+    assert [t.name for t in fig.data] == ["Plotly extra trace (1m|1m|1m)"] * 4
     assert [t.showlegend for t in fig.data] == [True, False, False, False]
diff --git a/tests/test_display_pyvista.py b/tests/test_display_pyvista.py
index a77747b5a..cb6623510 100644
--- a/tests/test_display_pyvista.py
+++ b/tests/test_display_pyvista.py
@@ -1,3 +1,5 @@
+import os
+import sys
 import tempfile
 from unittest.mock import patch
 
@@ -17,7 +19,7 @@
 # pylint: disable=no-member
 
 # pylint: disable=broad-exception-caught
-ffmpeg_failed = False
+FFMPEG_FAILED = False
 try:
     try:
         import imageio_ffmpeg
@@ -30,31 +32,17 @@
             raise err
 except Exception:  # noqa: E722
     # skip test if ffmpeg cannot be loaded
-    ffmpeg_failed = True
+    FFMPEG_FAILED = True
 
 
 def test_Cuboid_display():
     "test simple display with path"
-    src = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
+    src = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
     src.move([[i, 0, 0] for i in range(2)], start=0)
     fig = src.show(return_fig=True, style_path_numbering=True, backend="pyvista")
     assert isinstance(fig, pv.Plotter)
 
 
-def test_animation():
-    "animation not supported, should warn and display static"
-    pl = pv.Plotter()
-    src = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
-    with pytest.warns(UserWarning):
-        src.show(canvas=pl, animation=True, backend="pyvista")
-
-
-def test_ipygany_jupyter_backend():
-    """ipygany backend does not support custom colorscales"""
-    src = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
-    src.show(return_fig=True, backend="pyvista", jupyter_backend="ipygany")
-
-
 def test_extra_model3d():
     """test extra model 3d"""
     trace_mesh3d = {
@@ -76,12 +64,7 @@ def test_extra_model3d():
     magpy.show(coll, return_fig=True, backend="pyvista")
 
 
-@pytest.mark.parametrize("is_notebook_result", (True, False))
-@pytest.mark.parametrize("extension", ("mp4", "gif"))
-@pytest.mark.parametrize("filename", (True, False))
-@pytest.mark.skipif(ffmpeg_failed, reason="Requires imageio-ffmpeg")
-@pytest.mark.skipif(not HAS_IMAGEIO, reason="Requires imageio")
-def test_pyvista_animation(is_notebook_result, extension, filename):
+def test_subplots():
     """Test pyvista animation"""
     # define sensor and source
     magpy.defaults.reset()
@@ -90,7 +73,7 @@ def test_pyvista_animation(is_notebook_result, extension, filename):
     )
     sensor.style.label = "Sensor1"
     cyl1 = magpy.magnet.Cylinder(
-        magnetization=(100, 0, 0), dimension=(1, 2), style_label="Cylinder1"
+        polarization=(0.1, 0, 0), dimension=(1, 2), style_label="Cylinder1"
     )
 
     # define paths
@@ -101,35 +84,59 @@ def test_pyvista_animation(is_notebook_result, extension, filename):
     cyl2 = cyl1.copy().move((0, 0, 5))
     objs = cyl1, cyl2, sensor
 
+    magpy.show(
+        {"objects": objs, "col": 1, "output": ("Bx", "By", "Bz")},
+        {"objects": objs, "col": 2},
+        backend="pyvista",
+        sumup=True,
+        return_fig=True,
+    )
+
+
+def test_animation_warning():
+    "animation not supported, should warn and display static"
+    pl = pv.Plotter()
+    src = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
+    with pytest.warns(UserWarning):
+        src.show(canvas=pl, animation=True, backend="pyvista")
+
+
+@pytest.mark.parametrize("is_notebook_result", (True, False))
+@pytest.mark.parametrize("extension", ("mp4", "gif"))
+@pytest.mark.parametrize("filename", (True, False))
+def test_pyvista_animation(is_notebook_result, extension, filename):
+    """Test pyvista animation"""
+    # define sensor and source
+    pv.OFF_SCREEN = True
+    if sys.platform == "linux":
+        pv.start_xvfb()  #  needed for unix systems or it will test will crash with fatal error
+    if not HAS_IMAGEIO and extension == "gif":
+        pytest.skip("Extension gif skipped because imageio failed to load")
+    if FFMPEG_FAILED and extension == "mp4":
+        pytest.skip("Extension mp4 skipped because ffmpeg failed to load")
+    sens = magpy.Sensor()
+    src = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
+    src.move([[0, 0, 0], [0, 0, 1]], start=0)
+    objs = [src, sens]
+
     with patch("magpylib._src.utility.is_notebook", return_value=is_notebook_result):
         with patch("webbrowser.open"):
-            with tempfile.NamedTemporaryFile(suffix=f".{extension}") as temp:
-                animation_output = temp.name if filename else extension
+            try:
+                temp = os.path.join(tempfile.gettempdir(), os.urandom(24).hex())
+                temp += f".{extension}"
+                animation_output = temp if filename else extension
                 magpy.show(
                     {"objects": objs, "col": 1, "output": ("Bx", "By", "Bz")},
                     {"objects": objs, "col": 2},
                     backend="pyvista",
                     animation=True,
-                    sumup=True,
                     animation_output=animation_output,
                     mp4_quality=1,
                     return_fig=True,
                 )
-
-
-def test_incompatible_jupyter_backend_for2d():
-    """test_incompatible_pyvista_backend"""
-    src = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
-    sens = magpy.Sensor()
-    with pytest.warns(
-        UserWarning,
-        match=r"The set `jupyter_backend=ipygany` is incompatible with 2D plots.*",
-    ):
-        magpy.show(
-            src,
-            sens,
-            output="Bx",
-            return_fig=True,
-            backend="pyvista",
-            jupyter_backend="ipygany",
-        )
+            finally:
+                try:
+                    os.unlink(temp)
+                except FileNotFoundError:
+                    # avoid exception if file is not found
+                    pass
diff --git a/tests/test_display_utility.py b/tests/test_display_utility.py
index e9b94d5cc..4197d316e 100644
--- a/tests/test_display_utility.py
+++ b/tests/test_display_utility.py
@@ -65,7 +65,7 @@ def test_draw_arrow_from_vertices():
 def test_bad_backend():
     """test bad plotting input name"""
     with pytest.raises(MagpylibBadUserInput):
-        c = magpy.magnet.Cuboid((0, 0, 1), (1, 1, 1))
+        c = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
         c.show(backend="asdf")
 
 
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
index 01caa8d85..3c9c0ffb8 100644
--- a/tests/test_exceptions.py
+++ b/tests/test_exceptions.py
@@ -6,9 +6,9 @@
 from magpylib._src.exceptions import MagpylibBadUserInput
 from magpylib._src.fields.field_wrap_BH import getBH_level2
 from magpylib._src.input_checks import check_format_input_observers
+from magpylib._src.utility import check_path_format
 from magpylib._src.utility import format_obj_input
 from magpylib._src.utility import format_src_inputs
-from magpylib._src.utility import test_path_format as tpf
 
 GETBH_KWARGS = {"sumup": False, "squeeze": True, "pixel_agg": None, "output": "ndarray"}
 
@@ -18,7 +18,7 @@ def getBHv_unknown_source_type():
     getBH_level2(
         sources="badName",
         observers=(0, 0, 0),
-        magnetization=(1, 0, 0),
+        polarization=(1, 0, 0),
         dimension=(0, 2, 1, 0, 360),
         position=(0, 0, -0.5),
         field="B",
@@ -28,7 +28,7 @@ def getBHv_unknown_source_type():
 
 def getBH_level2_bad_input1():
     """test BadUserInput error at getBH_level2"""
-    src = magpy.magnet.Cuboid((1, 1, 2), (1, 1, 1))
+    src = magpy.magnet.Cuboid(polarization=(1, 1, 2), dimension=(1, 1, 1))
     sens = magpy.Sensor()
     getBH_level2(
         [src, sens],
@@ -41,11 +41,9 @@ def getBH_level2_bad_input1():
     )
 
 
-def getBH_level2_bad_input2():
+def getBH_different_pixel_shapes():
     """different pixel shapes"""
-    mag = (1, 2, 3)
-    dim_cuboid = (1, 2, 3)
-    pm1 = magpy.magnet.Cuboid(mag, dim_cuboid)
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     sens1 = magpy.Sensor()
     sens2 = magpy.Sensor(pixel=[(0, 0, 0), (0, 0, 1), (0, 0, 2)])
     magpy.getB(pm1, [sens1, sens2])
@@ -57,21 +55,21 @@ def getBHv_missing_input1():
     x = np.array([(1, 2, 3)])
     # pylint: disable=missing-kwoa
     getBH_level2(
-        sources="Cuboid", observers=x, magnetization=x, dimension=x, **GETBH_KWARGS
+        sources="Cuboid", observers=x, polarization=x, dimension=x, **GETBH_KWARGS
     )
 
 
 def getBHv_missing_input2():
     """missing source_type"""
     x = np.array([(1, 2, 3)])
-    getBH_level2(observers=x, field="B", magnetization=x, dimension=x, **GETBH_KWARGS)
+    getBH_level2(observers=x, field="B", polarization=x, dimension=x, **GETBH_KWARGS)
 
 
 def getBHv_missing_input3():
     """missing observer"""
     x = np.array([(1, 2, 3)])
     getBH_level2(
-        sources="Cuboid", field="B", magnetization=x, dimension=x, **GETBH_KWARGS
+        sources="Cuboid", field="B", polarization=x, dimension=x, **GETBH_KWARGS
     )
 
 
@@ -85,7 +83,7 @@ def getBHv_missing_input5_cuboid():
     """missing Cuboid dim"""
     x = np.array([(1, 2, 3)])
     getBH_level2(
-        sources="Cuboid", observers=x, field="B", magnetization=x, **GETBH_KWARGS
+        sources="Cuboid", observers=x, field="B", polarization=x, **GETBH_KWARGS
     )
 
 
@@ -102,7 +100,7 @@ def getBHv_missing_input5_cyl():
     """missing Cylinder dim"""
     x = np.array([(1, 2, 3)])
     getBH_level2(
-        sources="Cylinder", observers=x, field="B", magnetization=x, **GETBH_KWARGS
+        sources="Cylinder", observers=x, field="B", polarization=x, **GETBH_KWARGS
     )
 
 
@@ -116,7 +114,7 @@ def getBHv_missing_input5_sphere():
     """missing Sphere dim"""
     x = np.array([(1, 2, 3)])
     getBH_level2(
-        sources="Sphere", observers=x, field="B", magnetization=x, **GETBH_KWARGS
+        sources="Sphere", observers=x, field="B", polarization=x, **GETBH_KWARGS
     )
 
 
@@ -129,7 +127,7 @@ def getBHv_bad_input1():
         sources="Cuboid",
         observers=x,
         field="B",
-        magnetization=x2,
+        polarization=x2,
         dimension=x,
         **GETBH_KWARGS,
     )
@@ -142,7 +140,7 @@ def getBHv_bad_input2():
         sources="Cubooid",
         observers=x,
         field="B",
-        magnetization=x,
+        polarization=x,
         dimension=x,
         **GETBH_KWARGS,
     )
@@ -156,7 +154,7 @@ def getBHv_bad_input3():
         sources="Cuboid",
         observers=s,
         field="B",
-        magnetization=x,
+        polarization=x,
         dimension=x,
         **GETBH_KWARGS,
     )
@@ -164,15 +162,15 @@ def getBHv_bad_input3():
 
 def utility_format_obj_input():
     """bad input object"""
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm2 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     format_obj_input([pm1, pm2, 333])
 
 
 def utility_format_src_inputs():
     """bad src input"""
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm2 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     format_src_inputs([pm1, pm2, 1])
 
 
@@ -184,12 +182,12 @@ def utility_format_obs_inputs():
     check_format_input_observers([sens1, sens2, possis, "whatever"])
 
 
-def utility_test_path_format():
+def utility_check_path_format():
     """bad path format input"""
     # pylint: disable=protected-access
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     pm1._position = [(1, 2, 3), (1, 2, 3)]
-    tpf(pm1)
+    check_path_format(pm1)
 
 
 ###############################################################################
@@ -209,7 +207,7 @@ def bad_input_shape_cuboid_dim():
 
 
 def bad_input_shape_cuboid_mag():
-    """bad cuboid magnetization shape"""
+    """bad cuboid polarization shape"""
     vec3 = (1, 2, 3)
     vec4 = (1, 2, 3, 4)
     magpy.magnet.Cuboid(vec4, vec3)
@@ -223,14 +221,14 @@ def bad_input_shape_cyl_dim():
 
 
 def bad_input_shape_cyl_mag():
-    """bad cylinder magnetization shape"""
+    """bad cylinder polarization shape"""
     vec3 = (1, 2, 3)
     vec4 = (1, 2, 3, 4)
     magpy.magnet.Cylinder(vec4, vec3)
 
 
 def bad_input_shape_sphere_mag():
-    """bad sphere magnetization shape"""
+    """bad sphere polarization shape"""
     vec4 = (1, 2, 3, 4)
     magpy.magnet.Sphere(vec4, 1)
 
@@ -243,7 +241,7 @@ def bad_input_shape_sensor_pix_pos():
 
 
 def bad_input_shape_dipole_mom():
-    """bad sphere magnetization shape"""
+    """bad sphere polarization shape"""
     vec4 = (1, 2, 3, 4)
     magpy.misc.Dipole(moment=vec4)
 
@@ -254,7 +252,7 @@ class TestExceptions(unittest.TestCase):
 
     def test_except_utility(self):
         """utility"""
-        self.assertRaises(MagpylibBadUserInput, utility_test_path_format)
+        self.assertRaises(MagpylibBadUserInput, utility_check_path_format)
         self.assertRaises(MagpylibBadUserInput, utility_format_obj_input)
         self.assertRaises(MagpylibBadUserInput, utility_format_src_inputs)
         self.assertRaises(MagpylibBadUserInput, utility_format_obs_inputs)
@@ -278,7 +276,7 @@ def test_except_getBHv(self):
     def test_except_getBH_lev2(self):
         """getBH_level2 exception testing"""
         self.assertRaises(MagpylibBadUserInput, getBH_level2_bad_input1)
-        self.assertRaises(MagpylibBadUserInput, getBH_level2_bad_input2)
+        self.assertRaises(MagpylibBadUserInput, getBH_different_pixel_shapes)
 
     def test_except_bad_input_shape_basegeo(self):
         """BaseGeo bad input shapes"""
diff --git a/tests/test_field_cylinder.py b/tests/test_field_cylinder.py
index 7848b8674..8aa13eb5c 100644
--- a/tests/test_field_cylinder.py
+++ b/tests/test_field_cylinder.py
@@ -206,14 +206,18 @@ def test_cylinder_field1():
     eins = np.ones(N)
     d, h, _ = dim.T
     dim5 = np.array([nulll, d / 2, h, nulll, eins * 360]).T
-    B1 = magnet_cylinder_segment_field("B", poso, magg, dim5)
+    B1 = magnet_cylinder_segment_field(
+        field="B", observers=poso, polarization=magg, dimension=dim5
+    )
 
     assert np.allclose(B1, B0)
 
 
 def test_cylinder_slanovc_field2():
     """testing B for all input combinations in/out/surface of Tile solution"""
-    src = magpy.magnet.CylinderSegment((22, 33, 44), (0.5, 1, 2, 0, 90))
+    src = magpy.magnet.CylinderSegment(
+        polarization=(22, 33, 44), dimension=(0.5, 1, 2, 0, 90)
+    )
 
     binn = (5.52525937, 13.04561569, 40.11111556)
     bout = (0.0177018, 0.1277188, 0.27323195)
@@ -264,10 +268,12 @@ def test_cylinder_slanovc_field2():
 
 def test_cylinder_slanovc_field3():
     """testing H for all input combinations in/out/surface of Tile solution"""
-    src = magpy.magnet.CylinderSegment((22, 33, 44), (0.5, 1, 2, 0, 90))
+    src = magpy.magnet.CylinderSegment(
+        polarization=(22, 33, 44), dimension=(0.5, 1, 2, 0, 90)
+    )
 
-    hinn = (-13.11018204, -15.87919449, -3.09467591)
-    hout = (0.01408664, 0.1016354, 0.21743108)
+    hinn = np.array((-13.11018204, -15.87919449, -3.09467591)) * 1e6
+    hout = np.array((0.01408664, 0.1016354, 0.21743108)) * 1e6
     nulll = (0, 0, 0)
 
     # only inside
@@ -317,7 +323,7 @@ def test_cylinder_rauber_field4():
     """
     test continuity across indefinite form in cylinder_rauber field when observer at r=r0
     """
-    src = magpy.magnet.Cylinder((22, 33, 0), (2, 2))
+    src = magpy.magnet.Cylinder(polarization=(22, 33, 0), dimension=(2, 2))
     es = list(10 ** -np.linspace(11, 15, 50))
     xs = np.r_[1 - np.array(es), 1, 1 + np.array(es)[::-1]]
     possis = [(x, 0, 1.5) for x in xs]
@@ -328,8 +334,12 @@ def test_cylinder_rauber_field4():
 
 def test_cylinder_tile_negative_phi():
     """same result for phi>0 and phi<0 inputs"""
-    src1 = magpy.magnet.CylinderSegment((11, 22, 33), (2, 4, 4, 0, 45))
-    src2 = magpy.magnet.CylinderSegment((11, 22, 33), (2, 4, 4, -360, -315))
+    src1 = magpy.magnet.CylinderSegment(
+        polarization=(11, 22, 33), dimension=(2, 4, 4, 0, 45)
+    )
+    src2 = magpy.magnet.CylinderSegment(
+        polarization=(11, 22, 33), dimension=(2, 4, 4, -360, -315)
+    )
     B1 = src1.getB((1, 0.5, 0.1))
     B2 = src2.getB((1, 0.5, 0.1))
     assert np.allclose(B1, B2)
@@ -345,9 +355,18 @@ def test_cylinder_tile_vs_fem():
     mag3 = np.array((0, 1, -1)) / np.sqrt(2) * 1000
 
     # Magpylib magnet collection
-    m1 = magpy.magnet.CylinderSegment(mag1, (1, 2, 1, -90, 0))
-    m2 = magpy.magnet.CylinderSegment(mag2, (1, 2.5, 1.5, 200, 250))
-    m3 = magpy.magnet.CylinderSegment(mag3, (0.75, 3, 0.5, 70, 180))
+    m1 = magpy.magnet.CylinderSegment(
+        polarization=mag1,
+        dimension=(1, 2, 1, -90, 0),
+    )
+    m2 = magpy.magnet.CylinderSegment(
+        polarization=mag2,
+        dimension=(1, 2.5, 1.5, 200, 250),
+    )
+    m3 = magpy.magnet.CylinderSegment(
+        polarization=mag3,
+        dimension=(0.75, 3, 0.5, 70, 180),
+    )
     col = m1 + m2 + m3
 
     # create observer circles (see FEM screen shot)
@@ -378,7 +397,7 @@ def test_cylinder_tile_vs_fem():
 def test_cylinder_corner():
     """test corner =0 behavior"""
     a = 1
-    s = magpy.magnet.Cylinder((10, 10, 1000), (2 * a, 2 * a))
+    s = magpy.magnet.Cylinder(polarization=(10, 10, 1000), dimension=(2 * a, 2 * a))
     B = s.getB(
         [
             [0, a, a],
@@ -398,7 +417,7 @@ def test_cylinder_corner_scaling():
     """test corner=0 scaling"""
     a = 1
     obs = [[a, 0, a + 1e-14], [a + 1e-14, 0, a]]
-    s = magpy.magnet.Cylinder((10, 10, 1000), (2 * a, 2 * a))
+    s = magpy.magnet.Cylinder(polarization=(10, 10, 1000), dimension=(2 * a, 2 * a))
     Btest = [
         [5.12553286e03, -2.26623480e00, 2.59910242e02],
         [5.12803286e03, -2.26623480e00, 9.91024238e00],
@@ -407,7 +426,7 @@ def test_cylinder_corner_scaling():
 
     a = 1000
     obs = [[a, 0, a + 1e-14], [a + 1e-14, 0, a]]
-    s = magpy.magnet.Cylinder((10, 10, 1000), (2 * a, 2 * a))
+    s = magpy.magnet.Cylinder(polarization=(10, 10, 1000), dimension=(2 * a, 2 * a))
     np.testing.assert_allclose(s.getB(obs), np.zeros((2, 3)))
 
 
@@ -429,15 +448,15 @@ def test_cylinder_scaling_invariance():
     )
 
     a = 1e-6
-    s1 = magpy.magnet.Cylinder((10, 10, 1000), (2 * a, 2 * a))
+    s1 = magpy.magnet.Cylinder(polarization=(10, 10, 1000), dimension=(2 * a, 2 * a))
     Btest1 = s1.getB(obs * a)
 
     a = 1
-    s2 = magpy.magnet.Cylinder((10, 10, 1000), (2 * a, 2 * a))
+    s2 = magpy.magnet.Cylinder(polarization=(10, 10, 1000), dimension=(2 * a, 2 * a))
     Btest2 = s2.getB(obs)
 
     a = 1e7
-    s3 = magpy.magnet.Cylinder((10, 10, 1000), (2 * a, 2 * a))
+    s3 = magpy.magnet.Cylinder(polarization=(10, 10, 1000), dimension=(2 * a, 2 * a))
     Btest3 = s3.getB(obs * a)
 
     np.testing.assert_allclose(Btest1, Btest2)
@@ -450,10 +469,10 @@ def test_cylinder_diametral_small_r():
     test if the gneral case fluctuations are small
     """
     B = magpy.core.magnet_cylinder_field(
-        "B",
-        np.array([(x, 0, 3) for x in np.logspace(-1.4, -1.2, 1000)]),
-        np.array([(1, 1, 0)] * 1000),
-        np.array([(2, 2)] * 1000),
+        field="B",
+        observers=np.array([(x, 0, 3) for x in np.logspace(-1.4, -1.2, 1000)]),
+        polarization=np.array([(1, 1, 0)] * 1000),
+        dimension=np.array([(2, 2)] * 1000),
     )
 
     dB = np.log(abs(B[1:] - B[:-1]))
@@ -475,12 +494,12 @@ def test_cyl_vs_cylseg_axial_H_inside_mask():
         field=field,
         observers=obs,
         dimension=dims,
-        magnetization=pols,
+        polarization=pols,
     )
     Bcs = magpy.core.magnet_cylinder_segment_field(
         field=field,
         observers=obs,
         dimension=dims_cs,
-        magnetization=pols,
+        polarization=pols,
     )
     np.testing.assert_allclose(Bc, Bcs)
diff --git a/tests/test_getBH_dict.py b/tests/test_getBH_dict.py
index ff338160d..17f44107a 100644
--- a/tests/test_getBH_dict.py
+++ b/tests/test_getBH_dict.py
@@ -13,7 +13,7 @@ def test_getB_dict1():
     mag = [111, 222, 333]
     dim = [3, 3]
 
-    pm = magpy.magnet.Cylinder(mag, dim)
+    pm = magpy.magnet.Cylinder(polarization=mag, dimension=dim)
     pm.move(np.linspace((0.5, 0, 0), (7.5, 0, 0), 15), start=-1)
     pm.rotate_from_angax(np.linspace(0, 666, 25), "y", anchor=0)
     pm.move([(0, x, 0) for x in np.linspace(0, 5, 5)], start=-1)
@@ -22,7 +22,7 @@ def test_getB_dict1():
     pos = pm.position
     rot = pm.orientation
 
-    dic = {"magnetization": mag, "dimension": dim, "position": pos, "orientation": rot}
+    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)
@@ -35,10 +35,10 @@ def test_getB_dict2():
     dim = [3, 3]
     pos = [(1, 1, 1), (2, 2, 2), (3, 3, 3), (5, 5, 5)]
 
-    dic = {"magnetization": mag, "dimension": dim, "position": pos}
+    dic = {"polarization": mag, "dimension": dim, "position": pos}
     B1 = magpy.getB("Cylinder", pos_obs, **dic)
 
-    pm = magpy.magnet.Cylinder(mag, dim, position=pos)
+    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)
@@ -50,13 +50,10 @@ def test_getH_dict1():
     mag = [111, 222, 333]
     dim = [3, 3]
 
-    dic = {
-        "magnetization": mag,
-        "dimension": dim,
-    }
+    dic = {"polarization": mag, "dimension": dim}
     B1 = magpy.getH("Cylinder", pos_obs, **dic)
 
-    pm = magpy.magnet.Cylinder(mag, dim)
+    pm = magpy.magnet.Cylinder(polarization=mag, dimension=dim)
     B2 = pm.getH(pos_obs)
 
     assert np.allclose(B1, B2, rtol=1e-12, atol=1e-12)
@@ -73,12 +70,14 @@ def test_getB_dict3():
     pos = np.array([0, 0, 0])
     rot = R.from_quat([(t, 0.2, 0.3, 0.4) for t in np.linspace(0, 0.1, n)])
 
-    dic = {"magnetization": mag, "dimension": dim, "position": pos, "orientation": rot}
+    dic = {"polarization": mag, "dimension": dim, "position": pos, "orientation": rot}
     B1 = magpy.getB("Cuboid", pos_obs, **dic)
 
     B2 = []
     for i in range(n):
-        pm = magpy.magnet.Cuboid(mag[i], dim, pos, rot[i])
+        pm = magpy.magnet.Cuboid(
+            polarization=mag[i], dimension=dim, position=pos, orientation=rot[i]
+        )
         B2 += [pm.getB(pos_obs)]
     B2 = np.array(B2)
     print(B1 - B2)
@@ -91,12 +90,12 @@ def test_getH_dict3():
     mag = [[111, 222, 333], [22, 2, 2], [22, -33, -44]]
     dim = 3
 
-    dic = {"magnetization": mag, "diameter": dim}
+    dic = {"polarization": mag, "diameter": dim}
     B1 = magpy.getH("Sphere", pos_obs, **dic)
 
     B2 = []
     for i in range(3):
-        pm = magpy.magnet.Sphere(mag[i], dim)
+        pm = magpy.magnet.Sphere(polarization=mag[i], diameter=dim)
         B2 += [magpy.getH([pm], pos_obs)]
     B2 = np.array(B2)
 
@@ -114,12 +113,14 @@ def test_getB_dict4():
     pos = np.array([0, 0, 0])
     rot = R.from_quat([(t, 0.2, 0.3, 0.4) for t in np.linspace(0, 0.1, n)])
 
-    dic = {"magnetization": mag, "diameter": dim, "position": pos, "orientation": rot}
+    dic = {"polarization": mag, "diameter": dim, "position": pos, "orientation": rot}
     B1 = magpy.getB("Sphere", pos_obs, **dic)
 
     B2 = []
     for i in range(n):
-        pm = magpy.magnet.Sphere(mag[i], dim, pos, rot[i])
+        pm = magpy.magnet.Sphere(
+            polarization=mag[i], diameter=dim, position=pos, orientation=rot[i]
+        )
         B2 += [pm.getB(pos_obs)]
     B2 = np.array(B2)
     print(B1 - B2)
@@ -129,18 +130,18 @@ def test_getB_dict4():
 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([0.07657346, 0.06125877, 0.04594407])
+    Btest = np.array([9.62250449e-08, 7.69800359e-08, 5.77350269e-08])
     assert np.allclose(B, Btest)
 
     H = magpy.getH("Dipole", (1, 1, 1), moment=(1, 2, 3))
-    Htest = np.array([0.06093522, 0.04874818, 0.03656113])
+    Htest = np.array([0.07657346, 0.06125877, 0.04594407])
     assert np.allclose(H, Htest)
 
 
 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])
+    Btest = np.array([0, 0, 0.6283185307179586 * 1e-6])
     assert np.allclose(B, Btest)
 
     H = magpy.getH("Circle", (0, 0, 0), current=1, diameter=2)
@@ -185,7 +186,7 @@ def test_getBH_polyline():
 
 def test_getBH_polyline2():
     """test line with pos and rot arguments"""
-    x = 0.14142136
+    x = 0.14142136 * 1e-6
 
     # z-line on x=1
     def getB_line(name):
@@ -260,7 +261,7 @@ def getB_line(name):
         vertices=np.linspace((0, 5, 5), (5, 5, 5), 6),
     )
     np.testing.assert_allclose(
-        B, np.array([[0.0, 0.0057735, -0.0057735]] * 5), rtol=1e-6
+        B, np.array([[0.0, 0.0057735, -0.0057735]] * 5) * 1e-6, rtol=1e-6
     )
 
     # ragged sequence of vertices
@@ -338,7 +339,7 @@ def test_getBH_Cylinder_FEM():
         "CylinderSegment",
         obsp,
         dimension=(1, 2, 1, 90, 360),
-        magnetization=np.array((1, 2, 3)) * 1000 / np.sqrt(14),
+        polarization=np.array((1, 2, 3)) * 1000 / np.sqrt(14),
         position=(0, 0, 0.5),
     )
 
@@ -353,7 +354,7 @@ def test_getBH_solid_cylinder():
         "CylinderSegment",
         (1, 2, 3),
         dimension=[(0, 1, 2, 20, 120), (0, 1, 2, 120, 220), (0, 1, 2, 220, 380)],
-        magnetization=(22, 33, 44),
+        polarization=(22, 33, 44),
     )
     B1 = np.sum(B1, axis=0)
 
@@ -362,7 +363,7 @@ def test_getBH_solid_cylinder():
         "CylinderSegment",
         (1, 2, 3),
         dimension=(0, 1, 2, 0, 360),
-        magnetization=(22, 33, 44),
+        polarization=(22, 33, 44),
     )
 
     # compute with solid cylinder code
@@ -370,7 +371,7 @@ def test_getBH_solid_cylinder():
         "Cylinder",
         (1, 2, 3),
         dimension=(2, 2),
-        magnetization=(22, 33, 44),
+        polarization=(22, 33, 44),
     )
 
     assert np.allclose(B1, B2)
@@ -383,7 +384,7 @@ def test_getB_dict_over_getB():
     mag = [111, 222, 333]
     dim = [3, 3]
 
-    pm = magpy.magnet.Cylinder(mag, dim)
+    pm = magpy.magnet.Cylinder(polarization=mag, dimension=dim)
     pm.move(np.linspace((0.5, 0, 0), (7.5, 0, 0), 15))
     pm.rotate_from_angax(np.linspace(0, 666, 25), "y", anchor=0)
     pm.move([(0, x, 0) for x in np.linspace(0, 5, 5)])
@@ -395,7 +396,7 @@ def test_getB_dict_over_getB():
     dic = {
         "sources": "Cylinder",
         "observers": pos_obs,
-        "magnetization": mag,
+        "polarization": mag,
         "dimension": dim,
         "position": pos,
         "orientation": rot,
@@ -417,8 +418,8 @@ def test_subclassing():
     class MyCuboid(magpy.magnet.Cuboid):
         """Test subclass"""
 
-    MyCuboid((0, 0, 1000), (1, 1, 1))
-    B1 = magpy.getB("Cuboid", (0, 0, 0), magnetization=(1, 1, 1), dimension=(1, 1, 1))
-    B2 = magpy.getB("MyCuboid", (0, 0, 0), magnetization=(1, 1, 1), dimension=(1, 1, 1))
+    MyCuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
+    B1 = magpy.getB("Cuboid", (0, 0, 0), polarization=(1, 1, 1), dimension=(1, 1, 1))
+    B2 = magpy.getB("MyCuboid", (0, 0, 0), polarization=(1, 1, 1), dimension=(1, 1, 1))
 
     np.testing.assert_allclose(B1, B2)
diff --git a/tests/test_getBH_interfaces.py b/tests/test_getBH_interfaces.py
index 81ebbaceb..89c0473e0 100644
--- a/tests/test_getBH_interfaces.py
+++ b/tests/test_getBH_interfaces.py
@@ -2,13 +2,14 @@
 import pytest
 
 import magpylib as magpy
+from magpylib._src.exceptions import MagpylibMissingInput
 
 # pylint: disable=unnecessary-lambda-assignment
 
 
 def test_getB_interfaces1():
     """self-consistent test of different possibilities for computing the field"""
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     src.move(np.linspace((0.1, 0.2, 0.3), (1, 2, 3), 10), start=-1)
     poso = [[(-1, -1, -1)] * 2] * 2
     sens = magpy.Sensor(pixel=poso)
@@ -16,7 +17,7 @@ def test_getB_interfaces1():
         "Cuboid",
         (-1, -1, -1),
         position=src.position,
-        magnetization=(1, 2, 3),
+        polarization=(1, 2, 3),
         dimension=(1, 2, 3),
     )
     B1 = np.tile(B, (2, 2, 1, 1))
@@ -37,7 +38,7 @@ def test_getB_interfaces1():
 
 def test_getB_interfaces2():
     """self-consistent test of different possibilities for computing the field"""
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     src.move(np.linspace((0.1, 0.2, 0.3), (1, 2, 3), 10), start=-1)
     poso = [[(-1, -1, -1)] * 2] * 2
     sens = magpy.Sensor(pixel=poso)
@@ -45,7 +46,7 @@ def test_getB_interfaces2():
         "Cuboid",
         (-1, -1, -1),
         position=src.position,
-        magnetization=(1, 2, 3),
+        polarization=(1, 2, 3),
         dimension=(1, 2, 3),
     )
 
@@ -61,7 +62,7 @@ def test_getB_interfaces2():
 
 def test_getB_interfaces3():
     """self-consistent test of different possibilities for computing the field"""
-    src = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     src.move(np.linspace((0.1, 0.2, 0.3), (1, 2, 3), 10), start=-1)
     poso = [[(-1, -1, -1)] * 2] * 2
     sens = magpy.Sensor(pixel=poso)
@@ -69,7 +70,7 @@ def test_getB_interfaces3():
         "Cuboid",
         (-1, -1, -1),
         position=src.position,
-        magnetization=(1, 2, 3),
+        polarization=(1, 2, 3),
         dimension=(1, 2, 3),
     )
 
@@ -90,7 +91,7 @@ def test_getH_interfaces1():
     """self-consistent test of different possibilities for computing the field"""
     mag = (22, -33, 44)
     dim = (3, 2, 3)
-    src = magpy.magnet.Cuboid(mag, dim)
+    src = magpy.magnet.Cuboid(polarization=mag, dimension=dim)
     src.move(np.linspace((0.1, 0.2, 0.3), (1, 2, 3), 10), start=-1)
 
     poso = [[(-1, -2, -3)] * 2] * 2
@@ -100,7 +101,7 @@ def test_getH_interfaces1():
         "Cuboid",
         (-1, -2, -3),
         position=src.position,
-        magnetization=mag,
+        polarization=mag,
         dimension=dim,
     )
     H1 = np.tile(H, (2, 2, 1, 1))
@@ -123,7 +124,7 @@ def test_getH_interfaces2():
     """self-consistent test of different possibilities for computing the field"""
     mag = (22, -33, 44)
     dim = (3, 2, 3)
-    src = magpy.magnet.Cuboid(mag, dim)
+    src = magpy.magnet.Cuboid(polarization=mag, dimension=dim)
     src.move(np.linspace((0.1, 0.2, 0.3), (1, 2, 3), 10), start=-1)
 
     poso = [[(-1, -2, -3)] * 2] * 2
@@ -133,7 +134,7 @@ def test_getH_interfaces2():
         "Cuboid",
         (-1, -2, -3),
         position=src.position,
-        magnetization=mag,
+        polarization=mag,
         dimension=dim,
     )
 
@@ -151,7 +152,7 @@ def test_getH_interfaces3():
     """self-consistent test of different possibilities for computing the field"""
     mag = (22, -33, 44)
     dim = (3, 2, 3)
-    src = magpy.magnet.Cuboid(mag, dim)
+    src = magpy.magnet.Cuboid(polarization=mag, dimension=dim)
     src.move(np.linspace((0.1, 0.2, 0.3), (1, 2, 3), 10), start=-1)
 
     poso = [[(-1, -2, -3)] * 2] * 2
@@ -161,7 +162,7 @@ def test_getH_interfaces3():
         "Cuboid",
         (-1, -2, -3),
         position=src.position,
-        magnetization=mag,
+        polarization=mag,
         dimension=dim,
     )
 
@@ -184,12 +185,12 @@ def test_dataframe_ouptut():
     num_of_pix = 2
 
     sources = [
-        magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1)).move(
+        magpy.magnet.Cuboid(polarization=(0, 0, 1000), dimension=(1, 1, 1)).move(
             np.linspace((-4, 0, 0), (4, 0, 0), max_path_len), start=0
         ),
-        magpy.magnet.Cylinder((0, 1000, 0), (1, 1), style_label="Cylinder1").move(
-            np.linspace((0, -4, 0), (0, 4, 0), max_path_len), start=0
-        ),
+        magpy.magnet.Cylinder(
+            polarization=(0, 1000, 0), dimension=(1, 1), style_label="Cylinder1"
+        ).move(np.linspace((0, -4, 0), (0, 4, 0), max_path_len), start=0),
     ]
     pixel = np.linspace((0, 0, 0), (0, 3, 0), num_of_pix)
     sens1 = magpy.Sensor(position=(0, 0, 1), pixel=pixel, style_label="sens1")
@@ -224,8 +225,8 @@ def test_dataframe_ouptut():
 def test_dataframe_ouptut_sumup():
     """test pandas dataframe output when sumup is True"""
     sources = [
-        magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1)),
-        magpy.magnet.Cylinder((0, 1000, 0), (1, 1)),
+        magpy.magnet.Cuboid(polarization=(0, 0, 1000), dimension=(1, 1, 1)),
+        magpy.magnet.Cylinder(polarization=(0, 1000, 0), dimension=(1, 1)),
     ]
     df = magpy.getB(sources, (0, 0, 0), sumup=True, output="dataframe")
     np.testing.assert_allclose(
@@ -236,7 +237,7 @@ def test_dataframe_ouptut_sumup():
 
 def test_dataframe_ouptut_pixel_agg():
     """test pandas dataframe output when sumup is True"""
-    src1 = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
+    src1 = magpy.magnet.Cuboid(polarization=(0, 0, 1000), dimension=(1, 1, 1))
     sens1 = magpy.Sensor(position=(0, 0, 1), pixel=np.zeros((4, 5, 3)))
     sens2 = sens1.copy(position=(0, 0, 2))
     sens3 = sens1.copy(position=(0, 0, 3))
@@ -254,7 +255,7 @@ def test_dataframe_ouptut_pixel_agg():
 
 def test_getBH_bad_output_type():
     """test bad output in `getBH`"""
-    src = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
+    src = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
     with pytest.raises(ValueError):
         src.getB((0, 0, 0), output="bad_output_type")
 
@@ -266,7 +267,9 @@ def test_sensor_handedness():
     ls = lambda n: np.linspace(-k / 2, k / 2, n)
     pixel = np.array([[x, y, z] for x in ls(N[0]) for y in ls(N[1]) for z in ls(N[2])])
     pixel = pixel.reshape((*N, 3))
-    c = magpy.magnet.Cuboid((1000, 0, 0), (1, 1, 1), (0, 1, 0))
+    c = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(0, 1, 0)
+    )
     sr = magpy.Sensor(
         pixel=pixel,
         position=(-1, 0, 0),
@@ -288,3 +291,73 @@ def test_sensor_handedness():
 
     # second index is sensor index, ...,0 -> x from sl must opposite of x from sr
     np.testing.assert_allclose(B[:, 0, ..., 0], -B[:, 1, ..., 0])
+
+
+@pytest.mark.parametrize(
+    ("module", "class_", "missing_arg"),
+    [
+        ("magnet", "Cuboid", "dimension"),
+        ("magnet", "Cylinder", "dimension"),
+        ("magnet", "CylinderSegment", "dimension"),
+        ("magnet", "Sphere", "diameter"),
+        ("magnet", "Tetrahedron", "vertices"),
+        ("magnet", "TriangularMesh", "vertices"),
+        ("current", "Circle", "diameter"),
+        ("current", "Polyline", "vertices"),
+        ("misc", "Triangle", "vertices"),
+    ],
+)
+def test_getB_on_missing_dimensions(module, class_, missing_arg):
+    """test_getB_on_missing_dimensions"""
+    with pytest.raises(
+        MagpylibMissingInput,
+        match=rf"Parameter `{missing_arg}` of .* must be set.",
+    ):
+        getattr(getattr(magpy, module), class_)().getB([0, 0, 0])
+
+
+@pytest.mark.parametrize(
+    ("module", "class_", "missing_arg", "kwargs"),
+    [
+        ("magnet", "Cuboid", "polarization", {"dimension": (1, 1, 1)}),
+        ("magnet", "Cylinder", "polarization", {"dimension": (1, 1)}),
+        (
+            "magnet",
+            "CylinderSegment",
+            "polarization",
+            {"dimension": (0, 1, 1, 45, 120)},
+        ),
+        ("magnet", "Sphere", "polarization", {"diameter": 1}),
+        (
+            "magnet",
+            "Tetrahedron",
+            "polarization",
+            {"vertices": [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]},
+        ),
+        (
+            "magnet",
+            "TriangularMesh",
+            "polarization",
+            {
+                "vertices": ((0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)),
+                "faces": ((0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)),
+            },
+        ),
+        ("current", "Circle", "current", {"diameter": 1}),
+        ("current", "Polyline", "current", {"vertices": [[0, -1, 0], [0, 1, 0]]}),
+        (
+            "misc",
+            "Triangle",
+            "polarization",
+            {"vertices": [(0, 0, 0), (1, 0, 0), (0, 1, 0)]},
+        ),
+        ("misc", "Dipole", "moment", {}),
+    ],
+)
+def test_getB_on_missing_excitations(module, class_, missing_arg, kwargs):
+    """test_getB_on_missing_excitations"""
+    with pytest.raises(
+        MagpylibMissingInput,
+        match=rf"Parameter `{missing_arg}` of .* must be set.",
+    ):
+        getattr(getattr(magpy, module), class_)(**kwargs).getB([0, 0, 0])
diff --git a/tests/test_getBH_level2.py b/tests/test_getBH_level2.py
index fefe63154..43dad817f 100644
--- a/tests/test_getBH_level2.py
+++ b/tests/test_getBH_level2.py
@@ -12,10 +12,10 @@ def test_getB_level2_input_simple():
     mag = (1, 2, 3)
     dim_cuboid = (1, 2, 3)
     dim_cyl = (1, 2)
-    pm1 = magpy.magnet.Cuboid(mag, dim_cuboid)
-    pm2 = magpy.magnet.Cuboid(mag, dim_cuboid)
-    pm3 = magpy.magnet.Cylinder(mag, dim_cyl)
-    pm4 = magpy.magnet.Cylinder(mag, dim_cyl)
+    pm1 = magpy.magnet.Cuboid(polarization=mag, dimension=dim_cuboid)
+    pm2 = magpy.magnet.Cuboid(polarization=mag, dimension=dim_cuboid)
+    pm3 = magpy.magnet.Cylinder(polarization=mag, dimension=dim_cyl)
+    pm4 = magpy.magnet.Cylinder(polarization=mag, dimension=dim_cyl)
     col1 = magpy.Collection(pm1.copy())
     col2 = magpy.Collection(pm1.copy(), pm2.copy())
     col3 = magpy.Collection(pm1.copy(), pm2.copy(), pm3.copy())
@@ -66,16 +66,16 @@ def test_getB_level2_input_shape22():
     dim_cyl = (1, 2)
 
     def pm1():
-        return magpy.magnet.Cuboid(mag, dim_cuboid)
+        return magpy.magnet.Cuboid(polarization=mag, dimension=dim_cuboid)
 
     def pm2():
-        return magpy.magnet.Cuboid(mag, dim_cuboid)
+        return magpy.magnet.Cuboid(polarization=mag, dimension=dim_cuboid)
 
     def pm3():
-        return magpy.magnet.Cylinder(mag, dim_cyl)
+        return magpy.magnet.Cylinder(polarization=mag, dimension=dim_cyl)
 
     def pm4():
-        return magpy.magnet.Cylinder(mag, dim_cyl)
+        return magpy.magnet.Cylinder(polarization=mag, dimension=dim_cyl)
 
     col1 = magpy.Collection(pm1())
     col2 = magpy.Collection(pm1(), pm2())
@@ -125,8 +125,8 @@ def test_getB_level2_input_path():
     """
     mag = (1, 2, 3)
     dim_cuboid = (1, 2, 3)
-    pm1 = magpy.magnet.Cuboid(mag, dim_cuboid)
-    pm2 = magpy.magnet.Cuboid(mag, dim_cuboid)
+    pm1 = magpy.magnet.Cuboid(polarization=mag, dimension=dim_cuboid)
+    pm2 = magpy.magnet.Cuboid(polarization=mag, dimension=dim_cuboid)
     sens1 = magpy.Sensor()
     sens2 = magpy.Sensor(pixel=[(0, 0, 0), (0, 0, 1), (0, 0, 2)])
 
@@ -168,8 +168,8 @@ def test_path_tile():
     """Test if auto-tiled paths of objects will properly be reset
     in getB_level2 before returning
     """
-    pm1 = magpy.magnet.Cuboid((11, 22, 33), (1, 2, 3))
-    pm2 = magpy.magnet.Cuboid((11, 22, 33), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(11, 22, 33), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cuboid(polarization=(11, 22, 33), dimension=(1, 2, 3))
     poz = np.linspace((10 / 33, 10 / 33, 10 / 33), (10, 10, 10), 33)
     pm2.move(poz)
 
@@ -193,7 +193,7 @@ def test_path_tile():
 
 def test_sensor_rotation1():
     """Test simple sensor rotation using sin/cos"""
-    src = magpy.magnet.Cuboid((1000, 0, 0), (1, 1, 1))
+    src = magpy.magnet.Cuboid(polarization=(1, 0, 0), dimension=(1, 1, 1))
     sens = magpy.Sensor(position=(1, 0, 0))
     sens.rotate_from_angax(np.linspace(0, 360, 56)[1:], "z", start=1, anchor=None)
     B = src.getB(sens)
@@ -211,8 +211,12 @@ def test_sensor_rotation1():
 
 def test_sensor_rotation2():
     """test sensor rotations with different combinations of inputs mag/col + sens/pos"""
-    src = magpy.magnet.Cuboid((1000, 0, 0), (1, 1, 1), (0, 0, 2))
-    src2 = magpy.magnet.Cuboid((1000, 0, 0), (1, 1, 1), (0, 0, 2))
+    src = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(0, 0, 2)
+    )
+    src2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(0, 0, 2)
+    )
     col = magpy.Collection(src, src2)
 
     poss = (0, 0, 0)
@@ -222,25 +226,25 @@ def test_sensor_rotation2():
     sens2 = magpy.Sensor(pixel=poss)
     sens2.rotate_from_angax(-45, "z")
 
-    x1 = np.array([-9.82, 0, 0])
-    x2 = np.array([-6.94, 6.94, 0])
-    x3 = np.array([0, 9.82, 0])
-    x1b = np.array([-19.64, 0, 0])
-    x2b = np.array([-13.89, 13.89, 0])
-    x3b = np.array([0, 19.64, 0])
+    x1 = np.array([-9.82, 0, 0]) * 1e-3
+    x2 = np.array([-6.94, 6.94, 0]) * 1e-3
+    x3 = np.array([0, 9.82, 0]) * 1e-3
+    x1b = np.array([-19.64, 0, 0]) * 1e-3
+    x2b = np.array([-13.89, 13.89, 0]) * 1e-3
+    x3b = np.array([0, 19.64, 0]) * 1e-3
 
     B = magpy.getB(src, poss, squeeze=True)
     Btest = x1
-    assert np.allclose(np.around(B, decimals=2), Btest), "FAIL: mag  +  pos"
+    assert np.allclose(np.around(B, decimals=5), Btest), "FAIL: mag  +  pos"
 
     B = magpy.getB([src], [sens], squeeze=True)
     Btest = np.array([x1, x2, x3])
-    assert np.allclose(np.around(B, decimals=2), Btest), "FAIL: mag  +  sens_rot_path"
+    assert np.allclose(np.around(B, decimals=5), Btest), "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=2), Btest
+        np.around(B, decimals=5), Btest
     ), "FAIL: mag  +  sens_rot_path, pos"
 
     B = magpy.getB([src, col], [sens, poss], squeeze=True)
@@ -248,14 +252,14 @@ def test_sensor_rotation2():
         [[[x1, x1], [x2, x1], [x3, x1]], [[x1b, x1b], [x2b, x1b], [x3b, x1b]]]
     )
     assert np.allclose(
-        np.around(B, decimals=2), Btest
+        np.around(B, decimals=5), Btest
     ), "FAIL: mag,col  +  sens_rot_path, pos"
 
 
 def test_sensor_rotation3():
     """testing rotated static sensor path"""
     # case static sensor rot
-    src = magpy.magnet.Cuboid((1000, 0, 0), (1, 1, 1))
+    src = magpy.magnet.Cuboid(polarization=(1, 0, 0), dimension=(1, 1, 1))
     sens = magpy.Sensor()
     sens.rotate_from_angax(45, "z")
     B0 = magpy.getB(src, sens)
@@ -274,15 +278,15 @@ def test_object_tiling():
     src1.rotate_from_angax(np.linspace(1, 31, 31), "x", anchor=(0, 1, 0), start=-1)
 
     src2 = magpy.magnet.Cuboid(
-        magnetization=(1, 1, 1), dimension=(1, 1, 1), position=(1, 1, 1)
+        polarization=(1, 1, 1), dimension=(1, 1, 1), position=(1, 1, 1)
     )
     src2.move([(1, 1, 1)] * 21, start=-1)
 
     src3 = magpy.magnet.Cuboid(
-        magnetization=(1, 1, 1), dimension=(1, 1, 1), position=(1, 1, 1)
+        polarization=(1, 1, 1), dimension=(1, 1, 1), position=(1, 1, 1)
     )
     src4 = magpy.magnet.Cuboid(
-        magnetization=(1, 1, 1), dimension=(1, 1, 1), position=(1, 1, 1)
+        polarization=(1, 1, 1), dimension=(1, 1, 1), position=(1, 1, 1)
     )
 
     col = magpy.Collection(src3, src4)
@@ -327,12 +331,12 @@ def test_superposition_vs_tiling():
     loop.rotate_from_angax([45, 90], "x")
 
     sphere1 = magpy.magnet.Sphere(
-        magnetization=(0, 0, 1), diameter=1, position=(20, 10, 1)
+        polarization=(0, 0, 1), diameter=1, position=(20, 10, 1)
     )
     sphere1.rotate_from_angax([45, 90], "y")
 
     sphere2 = magpy.magnet.Sphere(
-        magnetization=(1, 0, 0), diameter=2, position=(10, 20, 1)
+        polarization=(1, 0, 0), diameter=2, position=(10, 20, 1)
     )
     sphere2.rotate_from_angax([45, 90], "y")
 
@@ -354,7 +358,7 @@ def test_squeeze_sumup():
     """make sure that sumup does not lead to false output shape"""
 
     s = magpy.Sensor(pixel=(1, 2, 3))
-    ss = magpy.magnet.Sphere((1, 2, 3), 1)
+    ss = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=1)
 
     B1 = magpy.getB(ss, s, squeeze=False)
     B2 = magpy.getB(ss, s, squeeze=False, sumup=True)
@@ -364,7 +368,9 @@ def test_squeeze_sumup():
 
 def test_pixel_agg():
     """test pixel aggregator"""
-    src1 = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1)).move([[1, 0, 0]])
+    src1 = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1)).move(
+        [[1, 0, 0]]
+    )
     sens1 = magpy.Sensor(
         position=(0, 0, 1), pixel=np.zeros((4, 5, 3)), style_label="sens1 pixel(4,5)"
     )
@@ -387,8 +393,8 @@ def test_pixel_agg():
 
 def test_pixel_agg_heterogeneous_pixel_shapes():
     """test pixel aggregator with heterogeneous pixel shapes"""
-    src1 = magpy.magnet.Cuboid((0, 0, 1000), (1, 1, 1))
-    src2 = magpy.magnet.Sphere((0, 0, 1000), 1, position=(2, 0, 0))
+    src1 = magpy.magnet.Cuboid(polarization=(0, 0, 1), dimension=(1, 1, 1))
+    src2 = magpy.magnet.Sphere(polarization=(0, 0, 1), diameter=1, position=(2, 0, 0))
     sens1 = magpy.Sensor(
         position=(0, 0, 1), pixel=[0, 0, 0], style_label="sens1, pixel.shape = (3,)"
     )
@@ -461,10 +467,10 @@ def test_pixel_agg3():
     e2 = [(1, 1, 1)] * 2
     e3 = [(1, 1, 1)] * 3
 
-    s0 = magpy.magnet.Cuboid(e0, e0)
+    s0 = magpy.magnet.Cuboid(polarization=e0, dimension=e0)
     c0 = magpy.Collection(s0)
-    s1 = magpy.magnet.Cuboid(e0, e0)
-    s2 = magpy.magnet.Cuboid(-e0, e0)
+    s1 = magpy.magnet.Cuboid(polarization=e0, dimension=e0)
+    s2 = magpy.magnet.Cuboid(polarization=-e0, dimension=e0)
     c1 = magpy.Collection(c0, s1, s2)
 
     x0 = magpy.Sensor(pixel=e0)
diff --git a/tests/test_input_checks.py b/tests/test_input_checks.py
index ccad65d9c..1def8caf1 100644
--- a/tests/test_input_checks.py
+++ b/tests/test_input_checks.py
@@ -4,8 +4,10 @@
 
 import magpylib as magpy
 from magpylib._src.exceptions import MagpylibBadUserInput
+from magpylib._src.exceptions import MagpylibDeprecationWarning
 from magpylib._src.exceptions import MagpylibMissingInput
 
+
 # pylint: disable=unnecessary-lambda-assignment
 
 ###########################################################
@@ -93,7 +95,7 @@ def test_input_objects_pixel_bad(pixel):
     """bad input: magpy.Sensor(pixel=pixel)"""
 
     with pytest.raises(MagpylibBadUserInput):
-        magpy.Sensor((0, 0, 0), pixel=pixel)
+        magpy.Sensor(position=(0, 0, 0), pixel=pixel)
 
 
 @pytest.mark.parametrize(
@@ -135,7 +137,9 @@ def test_input_objects_orientation_bad(orientation_rotvec):
     """bad input: magpy.Sensor(orientation=orientation_rotvec)"""
 
     with pytest.raises(MagpylibBadUserInput):
-        magpy.Sensor((0, 0, 0), (0, 0, 0), orientation=orientation_rotvec)
+        magpy.Sensor(
+            position=(0, 0, 0), pixel=(0, 0, 0), orientation=orientation_rotvec
+        )
 
 
 @pytest.mark.parametrize(
@@ -154,7 +158,7 @@ def test_input_objects_orientation_bad(orientation_rotvec):
 def test_input_objects_current_good(current):
     """good input: magpy.current.Circle(current)"""
 
-    src = magpy.current.Circle(current)
+    src = magpy.current.Circle(current=current)
     if current is None:
         assert src.current is None
     else:
@@ -261,7 +265,7 @@ def test_input_objects_vertices_bad(vertices):
 
 
 @pytest.mark.parametrize(
-    "moment",
+    "pol_or_mom",
     [
         None,
         (1, 2, 3),
@@ -270,21 +274,21 @@ def test_input_objects_vertices_bad(vertices):
         np.array((1, 2, 3)),
     ],
 )
-def test_input_objects_magnetization_moment_good(moment):
+def test_input_objects_magnetization_moment_good(pol_or_mom):
     """
     good input:
         magpy.magnet.Cuboid(magnetization=moment),
         magpy.misc.Dipole(moment=moment)
     """
 
-    src = magpy.magnet.Cuboid(moment)
-    src2 = magpy.misc.Dipole(moment)
-    if moment is None:
-        assert src.magnetization is None
+    src = magpy.magnet.Cuboid(polarization=pol_or_mom)
+    src2 = magpy.misc.Dipole(moment=pol_or_mom)
+    if pol_or_mom is None:
+        assert src.polarization is None
         assert src2.moment is None
     else:
-        np.testing.assert_allclose(src.magnetization, moment)
-        np.testing.assert_allclose(src2.moment, moment)
+        np.testing.assert_allclose(src.polarization, pol_or_mom)
+        np.testing.assert_allclose(src2.moment, pol_or_mom)
 
 
 @pytest.mark.parametrize(
@@ -514,8 +518,10 @@ def fff(field, observers):
 )
 def test_input_objects_field_func_bad(func):
     """bad input: magpy.misc.CustomSource(field_func=f)"""
-    with pytest.raises(MagpylibBadUserInput):
-        magpy.misc.CustomSource(func)
+    with pytest.raises(
+        MagpylibBadUserInput, match=r"Input parameter `field_func` must .*."
+    ):
+        magpy.misc.CustomSource(field_func=func)
 
 
 def test_missing_input_triangular_mesh():
@@ -718,7 +724,7 @@ def test_input_rotate_axis_bad(axis):
 )
 def test_input_observers_good(observers):
     """good observers input"""
-    src = magpy.misc.Dipole((1, 2, 3))
+    src = magpy.misc.Dipole(moment=(1, 2, 3))
     B = src.getB(observers)
     assert isinstance(B, np.ndarray)
 
@@ -731,7 +737,7 @@ def test_input_observers_good(observers):
         [],
         ("a", "b", "c"),
         [("a", "b", "c")],
-        magpy.misc.Dipole((1, 2, 3)),
+        magpy.misc.Dipole(moment=(1, 2, 3)),
         [(1, 2, 3), [(1, 2, 3)] * 2],
         [magpy.Sensor(), [(1, 2, 3)] * 2],
         [[(1, 2, 3)] * 2, magpy.Collection(magpy.Sensor())],
@@ -740,7 +746,7 @@ def test_input_observers_good(observers):
 )
 def test_input_observers_bad(observers):
     """bad observers input"""
-    src = magpy.misc.Dipole((1, 2, 3))
+    src = magpy.misc.Dipole(moment=(1, 2, 3))
     with pytest.raises(MagpylibBadUserInput):
         src.getB(observers)
 
@@ -930,7 +936,7 @@ def test_input_getBH_field_good(field):
     """good getBH field inputs"""
     moms = np.array([[1, 2, 3]])
     obs = np.array([[1, 2, 3]])
-    B = magpy.core.dipole_field(field, obs, moms)
+    B = magpy.core.dipole_field(field=field, observers=obs, moment=moms)
     assert isinstance(B, np.ndarray)
 
 
@@ -954,4 +960,40 @@ def test_input_getBH_field_bad(field):
     moms = np.array([[1, 2, 3]])
     obs = np.array([[1, 2, 3]])
     with pytest.raises(MagpylibBadUserInput):
-        magpy.core.dipole_field(field, obs, moms)
+        magpy.core.dipole_field(field=field, observers=obs, moment=moms)
+
+
+def test_sensor_handedness():
+    """Test if handedness input"""
+    magpy.Sensor(handedness="right")
+    magpy.Sensor(handedness="left")
+    with pytest.raises(
+        MagpylibBadUserInput,
+        match=r"Sensor `handedness` must be either `'right'` or `'left'`",
+    ):
+        magpy.Sensor(handedness="not_right_or_left")
+
+
+def test_magnet_polarization_magnetization_input():
+    """test codependency and magnetization polarization inputs"""
+    # warning when magnetization is too low -> polarization confusion
+    mag = np.array([1, 2, 3]) * 1e6
+
+    with pytest.warns(
+        MagpylibDeprecationWarning,
+        match=r".* received a very low magnetization. .*",
+    ):
+        magpy.magnet.Cuboid(magnetization=[1, 2, 3])
+
+    # both polarization and magnetization at the same time
+    with pytest.raises(
+        ValueError,
+        match=r"The attributes magnetization and polarization are dependent. .*",
+    ):
+        magpy.magnet.Cuboid(polarization=[1, 2, 3], magnetization=mag)
+
+    # setting magnetization afterwards
+    c = magpy.magnet.Cuboid()
+    c.magnetization = mag
+    np.testing.assert_allclose(mag, c.magnetization)
+    np.testing.assert_allclose(mag * (4 * np.pi * 1e-7), c.polarization)
diff --git a/tests/test_numerical_stability.py b/tests/test_numerical_stability.py
index a182d2bfd..7ef03fb25 100644
--- a/tests/test_numerical_stability.py
+++ b/tests/test_numerical_stability.py
@@ -11,7 +11,7 @@ def test_loop_field():
     the field become instable. This is a result of small displacements from the axis
     where the field is evaluated due to floating-point errors. see paper Leitner2021.
     """
-    lop = magpy.current.Circle(1000, 1)
+    lop = magpy.current.Circle(current=1000, diameter=1)
 
     anch = (0, 0, 1)
     B = []
diff --git a/tests/test_obj_BaseGeo.py b/tests/test_obj_BaseGeo.py
index 49c069198..c48038cc6 100644
--- a/tests/test_obj_BaseGeo.py
+++ b/tests/test_obj_BaseGeo.py
@@ -280,7 +280,7 @@ def test_scipy_from_methods():
     """test all rotation methods inspired from scipy implemented in BaseTransform"""
 
     def cube():
-        return magpy.magnet.Cuboid((11, 22, 33), (1, 1, 1))
+        return magpy.magnet.Cuboid(polarization=(11, 22, 33), dimension=(1, 1, 1))
 
     angs_deg = np.linspace(0, 360, 10)
     angs = np.deg2rad(angs_deg)
@@ -415,7 +415,7 @@ def test_describe():
     # pylint: disable=protected-access
     x1 = magpy.magnet.Cuboid(style_label="x1")
     x2 = magpy.magnet.Cylinder(
-        style_label="x2", dimension=(1, 3), magnetization=(2, 3, 4)
+        style_label="x2", dimension=(1, 3), polarization=(2, 3, 4)
     )
     s1 = magpy.Sensor(position=[(1, 2, 3)] * 3, pixel=[(1, 2, 3)] * 15)
 
@@ -424,8 +424,8 @@ def test_describe():
 
     test = (
         "<pre>Cuboid(id=REGEX, label='x1')<br>  • parent: None <br>  • "
-        "position: [0. 0. 0.] mm<br>  • orientation: [0. 0. 0.] degrees<br>  • "
-        "dimension: None mm<br>  • magnetization: None mT</pre>"
+        "position: [0. 0. 0.] m<br>  • orientation: [0. 0. 0.] deg<br>  • "
+        "dimension: None m<br>  • magnetization: None A/m<br>  • polarization: None T</pre>"
     )
     rep = x1._repr_html_()
     rep = re.sub("id=[0-9]*[0-9]", "id=REGEX", rep)
@@ -435,10 +435,11 @@ def test_describe():
     test = [
         "Cuboid(id=REGEX, label='x1')",
         "  • parent: Collection(id=REGEX) ",  # INVISIBLE SPACE
-        "  • position: [0. 0. 0.] mm",
-        "  • orientation: [0. 0. 0.] degrees",
-        "  • dimension: None mm",
-        "  • magnetization: None mT",
+        "  • position: [0. 0. 0.] m",
+        "  • orientation: [0. 0. 0.] deg",
+        "  • dimension: None m",
+        "  • magnetization: None A/m",
+        "  • polarization: None T",
     ]
     desc = x1.describe(return_string=True)
     desc = re.sub("id=*[0-9]*[0-9]", "id=REGEX", desc)
@@ -447,10 +448,11 @@ def test_describe():
     test = [
         "Cylinder(id=REGEX, label='x2')",
         "  • parent: Collection(id=REGEX) ",  # INVISIBLE SPACE
-        "  • position: [0. 0. 0.] mm",
-        "  • orientation: [0. 0. 0.] degrees",
-        "  • dimension: [1. 3.] mm",
-        "  • magnetization: [2. 3. 4.] mT",
+        "  • position: [0. 0. 0.] m",
+        "  • orientation: [0. 0. 0.] deg",
+        "  • dimension: [1. 3.] m",
+        "  • magnetization: [1591549.43091895 2387324.14637843 3183098.86183791] A/m",
+        "  • polarization: [2. 3. 4.] T",
     ]
     desc = x2.describe(return_string=True)
     desc = re.sub("id=*[0-9]*[0-9]", "id=REGEX", desc)
@@ -460,8 +462,8 @@ def test_describe():
         "Sensor(id=REGEX)",
         "  • parent: None ",  # INVISIBLE SPACE
         "  • path length: 3",
-        "  • position (last): [1. 2. 3.] mm",
-        "  • orientation (last): [0. 0. 0.] degrees",
+        "  • position (last): [1. 2. 3.] m",
+        "  • orientation (last): [0. 0. 0.] deg",
         "  • handedness: right ",
         "  • pixel: 15 ",  # INVISIBLE SPACE
     ]
@@ -475,14 +477,14 @@ def test_describe():
     test = (
         "Sensor(id=REGEX)\n"
         + "  • parent: None \n"
-        + "  • position: [0. 0. 0.] mm\n"
-        + "  • orientation: [0. 0. 0.] degrees\n"
+        + "  • position: [0. 0. 0.] m\n"
+        + "  • orientation: [0. 0. 0.] deg\n"
         + "  • handedness: right \n"
-        + "  • pixel: 1 \n"
+        + "  • pixel: None \n"
         + "  • style: SensorStyle(arrows=ArrowCS(x=ArrowSingle(color=None, show=True), "
         + "y=ArrowSingle(color=None, show=True), z=ArrowSingle(color=None, show=True)),"
         + " color=None, description=Description(show=None, text=None), label=None, "
-        + "legend=Legend(show=None), "
+        + "legend=Legend(show=None, text=None), "
         + "model3d=Model3d(data=[], showdefault=True), opacity=None, path=Path(frames=None,"
         + " line=Line(color=None, style=None, width=None), marker=Marker(color=None,"
         + " size=None, symbol=None), numbering=None, show=None), pixel=Pixel(color=None,"
@@ -497,8 +499,8 @@ def test_describe():
     test = (
         "Sensor(id=REGEX)\n"
         + "  • parent: None \n"
-        + "  • position: [0. 0. 0.] mm\n"
-        + "  • orientation: [0. 0. 0.] degrees\n"
+        + "  • position: [0. 0. 0.] m\n"
+        + "  • orientation: [0. 0. 0.] deg\n"
         + "  • handedness: left \n"
         + "  • pixel: 75 (3x5x5) "
     )
@@ -514,7 +516,7 @@ def test_describe():
         (0, 0, 2),
     ]
     s = magpy.magnet.TriangularMesh.from_ConvexHull(
-        magnetization=(0, 0, 1000),
+        polarization=(0, 0, 1),
         points=points,
         check_selfintersecting="skip",
     )
@@ -522,9 +524,10 @@ def test_describe():
     test = (
         "TriangularMesh(id=REGEX)\n"
         "  • parent: None \n"
-        "  • position: [0. 0. 0.] mm\n"
-        "  • orientation: [0. 0. 0.] degrees\n"
-        "  • magnetization: [   0.    0. 1000.] mT\n"
+        "  • position: [0. 0. 0.] m\n"
+        "  • orientation: [0. 0. 0.] deg\n"
+        "  • magnetization: [     0.              0.         795774.71545948] A/m\n"
+        "  • polarization: [0. 0. 1.] T\n"
         "  • barycenter: [0.         0.         0.46065534] \n"
         "  • faces: shape(6, 3) \n"
         "  • mesh: shape(6, 3, 3) \n"
diff --git a/tests/test_obj_BaseGeo_v4motion.py b/tests/test_obj_BaseGeo_v4motion.py
index 46480ca33..6a5939e03 100644
--- a/tests/test_obj_BaseGeo_v4motion.py
+++ b/tests/test_obj_BaseGeo_v4motion.py
@@ -90,8 +90,8 @@ def test_BaseGeo_init(
     if init_orientation_rotvec is None:
         init_orientation_rotvec = (0, 0, 0)
     src = magpy.magnet.Cuboid(
-        (1, 0, 0),
-        (1, 1, 1),
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
         position=init_position,
         orientation=R.from_rotvec(init_orientation_rotvec),
     )
@@ -168,7 +168,12 @@ def test_BaseGeo_setting_position(
     test_ori,
 ):
     """test position and orientation initialization"""
-    src = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), init_pos, R.from_rotvec(init_ori))
+    src = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        position=init_pos,
+        orientation=R.from_rotvec(init_ori),
+    )
     src.position = test_pos
     validate_pos_orient(src, test_pos, test_ori)
 
@@ -185,7 +190,12 @@ def test_BaseGeo_setting_orientation(
     test_ori,
 ):
     """test position and orientation initialization"""
-    src = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), init_pos, R.from_rotvec(init_ori))
+    src = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        position=init_pos,
+        orientation=R.from_rotvec(init_ori),
+    )
     src.orientation = R.from_rotvec(test_ori)
     validate_pos_orient(src, test_pos, test_ori)
 
@@ -355,8 +365,8 @@ def test_BaseGeo_multianchor_rotation(
     if init_orientation_rotvec is None:
         init_orientation_rotvec = (0, 0, 0)
     src = magpy.magnet.Cuboid(
-        (1, 0, 0),
-        (1, 1, 1),
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
         position=init_position,
         orientation=R.from_rotvec(init_orientation_rotvec),
     )
diff --git a/tests/test_obj_Circle.py b/tests/test_obj_Circle.py
index e3c4be4b6..711474b75 100644
--- a/tests/test_obj_Circle.py
+++ b/tests/test_obj_Circle.py
@@ -11,7 +11,7 @@ def test_Circle_basic_B():
     sens = magpy.Sensor(position=(1, 2, 3))
 
     B = src.getB(sens)
-    Btest = np.array([0.44179833, 0.88359665, 0.71546231])
+    Btest = np.array([0.44179833, 0.88359665, 0.71546231]) * 1e-6
     assert np.allclose(B, Btest)
 
 
@@ -19,20 +19,20 @@ def test_current_circle_field():
     """test explicit field output values"""
     s = magpy.current.Circle(current=1, diameter=1)
 
-    B_c1d1z0 = 1.2566370614359172
+    B_c1d1z0 = 1.2566370614359172 * 1e-6
     B_test = s.getB([0, 0, 0])
     assert abs(B_c1d1z0 - B_test[2]) < 1e-14
 
-    B_c1d1z1 = 0.11239703569665165
+    B_c1d1z1 = 0.11239703569665165 * 1e-6
     B_test = s.getB([0, 0, 1])
     assert abs(B_c1d1z1 - B_test[2]) < 1e-14
 
     s = magpy.current.Circle(current=1, diameter=2)
-    B_c1d2z0 = 0.6283185307179586
+    B_c1d2z0 = 0.6283185307179586 * 1e-6
     B_test = s.getB([0, 0, 0])
     assert abs(B_c1d2z0 - B_test[2]) < 1e-14
 
-    B_c1d2z1 = 0.22214414690791835
+    B_c1d2z1 = 0.22214414690791835 * 1e-6
     B_test = s.getB([0, 0, 1])
     assert abs(B_c1d2z1 - B_test[2]) < 1e-14
 
diff --git a/tests/test_obj_Collection.py b/tests/test_obj_Collection.py
index 996456972..f50121533 100644
--- a/tests/test_obj_Collection.py
+++ b/tests/test_obj_Collection.py
@@ -61,19 +61,19 @@ def test_Collection_basics():
     ):
         rot = R.from_rotvec(rv)
 
-        pm1b = magpy.magnet.Cuboid(mag[0], dim3[0])
-        pm2b = magpy.magnet.Cuboid(mag[1], dim3[1])
-        pm3b = magpy.magnet.Cuboid(mag[2], dim3[2])
-        pm4b = magpy.magnet.Cylinder(mag[3], dim2[0])
-        pm5b = magpy.magnet.Cylinder(mag[4], dim2[1])
-        pm6b = magpy.magnet.Cylinder(mag[5], dim2[2])
-
-        pm1 = magpy.magnet.Cuboid(mag[0], dim3[0])
-        pm2 = magpy.magnet.Cuboid(mag[1], dim3[1])
-        pm3 = magpy.magnet.Cuboid(mag[2], dim3[2])
-        pm4 = magpy.magnet.Cylinder(mag[3], dim2[0])
-        pm5 = magpy.magnet.Cylinder(mag[4], dim2[1])
-        pm6 = magpy.magnet.Cylinder(mag[5], dim2[2])
+        pm1b = magpy.magnet.Cuboid(polarization=mag[0], dimension=dim3[0])
+        pm2b = magpy.magnet.Cuboid(polarization=mag[1], dimension=dim3[1])
+        pm3b = magpy.magnet.Cuboid(polarization=mag[2], dimension=dim3[2])
+        pm4b = magpy.magnet.Cylinder(polarization=mag[3], dimension=dim2[0])
+        pm5b = magpy.magnet.Cylinder(polarization=mag[4], dimension=dim2[1])
+        pm6b = magpy.magnet.Cylinder(polarization=mag[5], dimension=dim2[2])
+
+        pm1 = magpy.magnet.Cuboid(polarization=mag[0], dimension=dim3[0])
+        pm2 = magpy.magnet.Cuboid(polarization=mag[1], dimension=dim3[1])
+        pm3 = magpy.magnet.Cuboid(polarization=mag[2], dimension=dim3[2])
+        pm4 = magpy.magnet.Cylinder(polarization=mag[3], dimension=dim2[0])
+        pm5 = magpy.magnet.Cylinder(polarization=mag[4], dimension=dim2[1])
+        pm6 = magpy.magnet.Cylinder(polarization=mag[5], dimension=dim2[2])
 
         col1 = magpy.Collection(pm1, pm2, pm3)
         col1.add(pm4, pm5, pm6)
@@ -121,10 +121,10 @@ def test_Collection_basics():
 def test_col_getB(test_input, expected):
     """testing some Collection stuff with getB"""
     src1 = magpy.magnet.Cuboid(
-        magnetization=(1, 0, 1), dimension=(8, 4, 6), position=(0, 0, 0)
+        polarization=(1, 0, 1), dimension=(8, 4, 6), position=(0, 0, 0)
     )
     src2 = magpy.magnet.Cylinder(
-        magnetization=(0, 1, 0), dimension=(8, 5), position=(-15, 0, 0)
+        polarization=(0, 1, 0), dimension=(8, 5), position=(-15, 0, 0)
     )
     sens1 = magpy.Sensor(position=(0, 0, 6))
     sens2 = magpy.Sensor(position=(0, 0, 6))
@@ -195,11 +195,11 @@ def test_bad_col_getB_inputs(test_input):
     # pylint: disable=eval-used
 
     src1 = magpy.magnet.Cuboid(
-        magnetization=(1, 0, 1), dimension=(8, 4, 6), position=(0, 0, 0)
+        polarization=(1, 0, 1), dimension=(8, 4, 6), position=(0, 0, 0)
     )
 
     src2 = magpy.magnet.Cylinder(
-        magnetization=(0, 1, 0), dimension=(8, 5), position=(-15, 0, 0)
+        polarization=(0, 1, 0), dimension=(8, 5), position=(-15, 0, 0)
     )
 
     sens1 = magpy.Sensor(position=(0, 0, 6))
@@ -228,9 +228,9 @@ def test_bad_col_getB_inputs(test_input):
 
 def test_col_get_item():
     """test get_item with collections"""
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm2 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm3 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm3 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
 
     col = magpy.Collection(pm1, pm2, pm3)
     assert col[1] == pm2, "get_item failed"
@@ -239,8 +239,8 @@ def test_col_get_item():
 
 def test_col_getH():
     """test collection getH"""
-    pm1 = magpy.magnet.Sphere((1, 2, 3), 3)
-    pm2 = magpy.magnet.Sphere((1, 2, 3), 3)
+    pm1 = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=3)
+    pm2 = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=3)
     col = magpy.Collection(pm1, pm2)
     H = col.getH((0, 0, 0))
     H1 = pm1.getH((0, 0, 0))
@@ -250,8 +250,8 @@ def test_col_getH():
 def test_col_reset_path():
     """testing display"""
     # pylint: disable=no-member
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm2 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     col = magpy.Collection(pm1, pm2)
     col.move([(1, 2, 3)] * 10)
     col.reset_path()
@@ -262,8 +262,8 @@ def test_col_reset_path():
 
 def test_Collection_squeeze():
     """testing squeeze output"""
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm2 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     col = magpy.Collection(pm1, pm2)
     sensor = magpy.Sensor(pixel=[(1, 2, 3), (1, 2, 3)])
     B = col.getB(sensor)
@@ -284,7 +284,7 @@ def test_Collection_with_Dipole():
     sens = magpy.Sensor()
 
     B = magpy.getB(col, sens)
-    Btest = np.array([0.00303828, 0.00607656, 0.00911485])
+    Btest = np.array([3.81801774e-09, 7.63603548e-09, 1.14540532e-08])
     assert np.allclose(B, Btest)
 
 
@@ -313,8 +313,8 @@ def test_adding_sources():
 
 def test_set_children_styles():
     """test if styles get applied"""
-    src1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    src2 = magpy.magnet.Cylinder((1, 2, 3), (1, 2))
+    src1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    src2 = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(1, 2))
     col = src1 + src2
     col.set_children_styles(magnetization_show=False)
     assert (
@@ -332,7 +332,7 @@ def test_reprs():
     c = magpy.Collection()
     assert repr(c)[:10] == "Collection"
 
-    s1 = magpy.magnet.Sphere((1, 2, 3), 5)
+    s1 = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=5)
     c = magpy.Collection(s1)
     assert repr(c)[:10] == "Collection"
 
@@ -341,7 +341,7 @@ def test_reprs():
     assert repr(c)[:10] == "Collection"
 
     x1 = magpy.Sensor()
-    s1 = magpy.magnet.Sphere((1, 2, 3), 5)
+    s1 = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=5)
     c = magpy.Collection(s1, x1)
     assert repr(c)[:10] == "Collection"
 
@@ -431,18 +431,20 @@ def test_collection_describe():
     desc = cc.describe(format="label, properties", return_string=True).split("\n")
     test = [
         "Collection",
-        "│   • position: [0. 0. 0.] mm",
-        "│   • orientation: [0. 0. 0.] degrees",
+        "│   • position: [0. 0. 0.] m",
+        "│   • orientation: [0. 0. 0.] deg",
         "├── x",
-        "│       • position: [0. 0. 0.] mm",
-        "│       • orientation: [0. 0. 0.] degrees",
-        "│       • dimension: None mm",
-        "│       • magnetization: None mT",
+        "│       • position: [0. 0. 0.] m",
+        "│       • orientation: [0. 0. 0.] deg",
+        "│       • dimension: None m",
+        "│       • magnetization: None A/m",
+        "│       • polarization: None T",
         "└── y",
-        "        • position: [0. 0. 0.] mm",
-        "        • orientation: [0. 0. 0.] degrees",
-        "        • dimension: None mm",
-        "        • magnetization: None mT",
+        "        • position: [0. 0. 0.] m",
+        "        • orientation: [0. 0. 0.] deg",
+        "        • dimension: None m",
+        "        • magnetization: None A/m",
+        "        • polarization: None T",
     ]
     assert "".join(test) == re.sub("id=*[0-9]*[0-9]", "id=REGEX", "".join(desc))
 
diff --git a/tests/test_obj_Collection_child_parent.py b/tests/test_obj_Collection_child_parent.py
index 4fd94abed..b33ab3eda 100644
--- a/tests/test_obj_Collection_child_parent.py
+++ b/tests/test_obj_Collection_child_parent.py
@@ -311,10 +311,10 @@ def test_collection_remove():
 
 def test_collection_nested_getBH():
     """test if getBH functionality is self-consistent with nesting"""
-    s1 = magpy.current.Circle(1, 1)
-    s2 = magpy.current.Circle(1, 1)
-    s3 = magpy.current.Circle(1, 1)
-    s4 = magpy.current.Circle(1, 1)
+    s1 = magpy.current.Circle(current=1, diameter=1)
+    s2 = magpy.current.Circle(current=1, diameter=1)
+    s3 = magpy.current.Circle(current=1, diameter=1)
+    s4 = magpy.current.Circle(current=1, diameter=1)
 
     obs = [(1, 2, 3), (-2, -3, 1), (2, 2, -4), (4, 2, -4)]
     coll = s1 + s2 + s3 + s4  # nasty nesting
diff --git a/tests/test_obj_Collection_v4motion.py b/tests/test_obj_Collection_v4motion.py
index bd5aacdc9..5518b05f2 100644
--- a/tests/test_obj_Collection_v4motion.py
+++ b/tests/test_obj_Collection_v4motion.py
@@ -110,7 +110,10 @@ def test_Collection_setting_position(
 ):
     """Test position and orientation setters on Collection"""
     src = magpy.magnet.Cuboid(
-        (1, 0, 0), (1, 1, 1), src_pos_init, R.from_rotvec(src_ori_init)
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        position=src_pos_init,
+        orientation=R.from_rotvec(src_ori_init),
     )
     col = magpy.Collection(
         src, position=col_pos_init, orientation=R.from_rotvec(col_ori_init)
@@ -218,7 +221,10 @@ def test_Collection_setting_orientation(
 ):
     """test_Collection_setting_orientation"""
     src = magpy.magnet.Cuboid(
-        (1, 0, 0), (1, 1, 1), src_pos_init, R.from_rotvec(src_ori_init)
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        position=src_pos_init,
+        orientation=R.from_rotvec(src_ori_init),
     )
     col = magpy.Collection(
         src, position=col_pos_init, orientation=R.from_rotvec(col_ori_init)
@@ -240,7 +246,12 @@ def test_Collection_setter():
     #     ):
     #     col = magpy.Collection()
     #     for i,color in enumerate(['r', 'orange', 'gold', 'green', 'cyan']):
-    #         src = magpy.magnet.Cuboid((1,0,0), (.5,.5,.5), (1,0,0), style_color=color)
+    #         src = magpy.magnet.Cuboid(
+    #             polarization=(1,0,0),
+    #             dimension=(.5,.5,.5),
+    #             position=(1,0,0),
+    #             style_color=color
+    #         )
     #         src.rotate_from_angax(72*i, 'z', (0,0,0))
     #         col = col + src
     #     base = magpy.Sensor()
@@ -258,7 +269,9 @@ def test_Collection_setter():
     ):
         col = magpy.Collection()
         for i in range(5):
-            src = magpy.magnet.Cuboid((1, 0, 0), (0.5, 0.5, 0.5), (1, 0, 0))
+            src = magpy.magnet.Cuboid(
+                polarization=(1, 0, 0), dimension=(0.5, 0.5, 0.5), position=(1, 0, 0)
+            )
             src.rotate_from_angax(72 * i, "z", (0, 0, 0))
             col.add(src)
         col.position = poz
@@ -282,7 +295,9 @@ def test_Collection_setter():
 
 def test_compound_motion_00():
     """init Collection should not change source pos and ori"""
-    src = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(1, 2, 3), (2, 3, 4)])
+    src = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(1, 2, 3), (2, 3, 4)]
+    )
     validate_pos_orient(src, [(1, 2, 3), (2, 3, 4)], [(0, 0, 0)] * 2)
     col = magpy.Collection(src, position=[(1, 1, 1)])
     validate_pos_orient(src, [(1, 2, 3), (2, 3, 4)], [(0, 0, 0)] * 2)
@@ -291,8 +306,12 @@ def test_compound_motion_00():
 
 def test_compound_motion_01():
     """very sensible Compound behavior with rotation anchor"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (1, 1, 1))
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (-1, -1, -1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 1, 1)
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(-1, -1, -1)
+    )
     col = magpy.Collection(s1, s2)
     col.move((0, 0, 1))
     validate_pos_orient(s1, (1, 1, 2), (0, 0, 0))
@@ -310,8 +329,12 @@ def test_compound_motion_01():
 
 def test_compound_motion_02():
     """very sensible Compound behavior with vector anchor"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (1, 0, 1))
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (-1, 0, -1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 0, 1)
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(-1, 0, -1)
+    )
     col = magpy.Collection(s1, s2, position=(3, 0, 3))
     col.rotate_from_rotvec(
         (0, 0, np.pi / 2), anchor=[(1, 0, 0), (2, 0, 0)], degrees=False
@@ -335,12 +358,14 @@ def test_compound_motion_02():
 
 def test_compound_motion_03():
     """very sensible Compound behavior with vector path and anchor and start=0"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(3, 0, 0), (1, 0, 0)])
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(3, 0, 0), (1, 0, 0)]
+    )
     s2 = magpy.magnet.Cuboid(
-        (1, 0, 0),
-        (1, 1, 1),
-        [(2, 0, 2), (2, 0, 2)],
-        R.from_rotvec([(0, 0, -0.1), (0, 0, -0.2)]),
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        position=[(2, 0, 2), (2, 0, 2)],
+        orientation=R.from_rotvec([(0, 0, -0.1), (0, 0, -0.2)]),
     )
     col = magpy.Collection(s1, s2, position=[(3, 0, 2), (3, 0, 3)])
     col.rotate_from_rotvec(
@@ -363,9 +388,13 @@ def test_compound_motion_03():
 def test_compound_motion_04():
     """nonsensical but correct Collection behavior when col and children
     all have different path formats"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), position=(1, 1, 1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 1, 1)
+    )
     s2 = magpy.magnet.Cuboid(
-        (1, 0, 0), (1, 1, 1), orientation=R.from_rotvec([(0, 0, -0.1), (0, 0, -0.2)])
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        orientation=R.from_rotvec([(0, 0, -0.1), (0, 0, -0.2)]),
     )
     col = magpy.Collection(s1, s2, position=[(1, 2, 3), (1, 3, 4)])
     col.rotate_from_angax(90, "z", anchor=(1, 0, 0))
@@ -378,9 +407,13 @@ def test_compound_motion_04():
 
 def test_compound_motion_05():
     """nonsensical but correct Collection behavior with vector anchor"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), position=(1, 0, 1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 0, 1)
+    )
     s2 = magpy.magnet.Cuboid(
-        (1, 0, 0), (1, 1, 1), orientation=R.from_rotvec([(0, 0, -0.1), (0, 0, -0.2)])
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        orientation=R.from_rotvec([(0, 0, -0.1), (0, 0, -0.2)]),
     )
     col = magpy.Collection(s1, s2, position=[(3, 0, 3), (4, 0, 4)])
     col.rotate_from_angax(90, "z", anchor=[(1, 0, 0), (2, 0, 0)])
@@ -403,8 +436,12 @@ def test_compound_motion_05():
 
 def test_compound_motion_06():
     """Compound rotation (anchor=None), scalar input, scalar pos"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (1, 0, 1))
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (0, -1, -1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 0, 1)
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(0, -1, -1)
+    )
     col = magpy.Collection(s1, s2)
     col.rotate_from_angax(90, "z")
     validate_pos_orient(s1, (0, 1, 1), (0, 0, np.pi / 2))
@@ -414,8 +451,12 @@ def test_compound_motion_06():
 
 def test_compound_motion_07():
     """Compound rotation (anchor=None), scalar input, vector pos, start=auto"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(1, 0, 0), (2, 0, 0)])
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(-1, 0, 0), (-2, 0, 0)])
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(1, 0, 0), (2, 0, 0)]
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(-1, 0, 0), (-2, 0, 0)]
+    )
     col = magpy.Collection(s1, s2, position=((0, 0, 0), (1, 0, 0)))
     col.rotate_from_angax(90, "z")
     validate_pos_orient(
@@ -431,8 +472,12 @@ def test_compound_motion_07():
 
 def test_compound_motion_08():
     """Compound rotation (anchor=None), scalar input, vector pos, start=1"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(1, 0, 0), (2, 0, 0)])
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(-1, 0, 0), (-2, 0, 0)])
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(1, 0, 0), (2, 0, 0)]
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(-1, 0, 0), (-2, 0, 0)]
+    )
     col = magpy.Collection(s1, s2, position=((0, 0, 0), (1, 0, 0)))
     col.rotate_from_angax(90, "z", start=1)
     validate_pos_orient(s1, [(1, 0, 0), (1, 1, 0)], [(0, 0, 0), (0, 0, np.pi / 2)])
@@ -442,8 +487,12 @@ def test_compound_motion_08():
 
 def test_compound_motion_09():
     """Compound rotation (anchor=None), scalar input, vector pos, start=-1"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(1, 0, 0), (2, 0, 0)])
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(-1, 0, 0), (-2, 0, 0)])
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(1, 0, 0), (2, 0, 0)]
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(-1, 0, 0), (-2, 0, 0)]
+    )
     col = magpy.Collection(s1, s2, position=((0, 0, 0), (1, 0, 0)))
     col.rotate_from_angax(90, "z", start=-1)
     validate_pos_orient(s1, [(1, 0, 0), (1, 1, 0)], [(0, 0, 0), (0, 0, np.pi / 2)])
@@ -453,8 +502,12 @@ def test_compound_motion_09():
 
 def test_compound_motion_10():
     """Compound rotation (anchor=None), scalar input, vector pos, start->pad before"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(1, 0, 0), (2, 0, 0)])
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(-1, 0, 0), (-2, 0, 0)])
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(1, 0, 0), (2, 0, 0)]
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(-1, 0, 0), (-2, 0, 0)]
+    )
     col = magpy.Collection(s1, s2, position=((2, 0, 0), (1, 0, 0)))
     col.rotate_from_angax(90, "z", start=-4)
     validate_pos_orient(
@@ -476,8 +529,12 @@ def test_compound_motion_10():
 
 def test_compound_motion_11():
     """Compound rotation (anchor=None), scalar input, vector pos, start->pad behind"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(1, 0, 0), (2, 0, 0)])
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), [(-1, 0, 0), (-2, 0, 0)])
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(1, 0, 0), (2, 0, 0)]
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(-1, 0, 0), (-2, 0, 0)]
+    )
     col = magpy.Collection(s1, s2, position=((2, 0, 0), (1, 0, 0)))
     col.rotate_from_angax(90, "z", start=3)
     validate_pos_orient(
@@ -499,8 +556,12 @@ def test_compound_motion_11():
 
 def test_compound_motion_12():
     """Compound rotation (anchor=None), vector input, simple pos, start=auto"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (1, 0, 1))
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (0, -1, -1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 0, 1)
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(0, -1, -1)
+    )
     col = magpy.Collection(s1, s2)
     col.rotate_from_angax([90, -90], "z")
     validate_pos_orient(
@@ -522,8 +583,12 @@ def test_compound_motion_12():
 
 def test_compound_motion_13():
     """Compound rotation (anchor=None), vector input, vector pos, start=1"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (1, 0, 1))
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (0, -1, -1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 0, 1)
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(0, -1, -1)
+    )
     col = magpy.Collection(s1, s2)
     col.rotate_from_angax([90, -90], "z")
     col.rotate_from_angax([-90, 180], "z", start=1)
@@ -544,8 +609,12 @@ def test_compound_motion_13():
 
 def test_compound_motion_14():
     """Compound rotation (anchor=None), vector input, vector pos, start=1, pad_behind"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (1, 0, 1))
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (0, -1, -1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 0, 1)
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(0, -1, -1)
+    )
     col = magpy.Collection(s1, s2)
     col.rotate_from_angax([90, -90], "z")
     col.rotate_from_angax([-90, 180], "z", start=1)
@@ -569,8 +638,12 @@ def test_compound_motion_14():
 
 def test_compound_motion_15():
     """Compound rotation (anchor=None), vector input, simple pos, start=-3, pad_before"""
-    s1 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (1, 0, 1))
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), (-1, 0, -1))
+    s1 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(1, 0, 1)
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(-1, 0, -1)
+    )
     col = magpy.Collection(s1, s2, position=(2, 0, 0))
     col.rotate_from_angax([90, -90], "z", start=-3)
     validate_pos_orient(
@@ -594,9 +667,13 @@ def test_compound_motion_16():
     """Compound rotation (anchor=None), vector input, vector pos, start=-3,
     pad_before AND pad_behind"""
     s1 = magpy.magnet.Cuboid(
-        (1, 0, 0), (1, 1, 1), orientation=R.from_rotvec([(0, 0, 0.1), (0, 0, 0.2)])
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        orientation=R.from_rotvec([(0, 0, 0.1), (0, 0, 0.2)]),
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=[(-1, 0, 0), (-2, 0, 0)]
     )
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), position=[(-1, 0, 0), (-2, 0, 0)])
     col = magpy.Collection(s1, s2, position=[(1, 0, 0), (0, 0, 0)])
     col.rotate_from_angax([90, -90, 90, -90], "z", start=-3)
     validate_pos_orient(
@@ -624,9 +701,13 @@ def test_compound_motion_16():
 def test_compound_motion_17():
     """CRAZY Compound rotation (anchor=None) with messy path formats"""
     s1 = magpy.magnet.Cuboid(
-        (1, 0, 0), (1, 1, 1), orientation=R.from_rotvec([(0, 0, 0.1), (0, 0, 0.2)])
+        polarization=(1, 0, 0),
+        dimension=(1, 1, 1),
+        orientation=R.from_rotvec([(0, 0, 0.1), (0, 0, 0.2)]),
+    )
+    s2 = magpy.magnet.Cuboid(
+        polarization=(1, 0, 0), dimension=(1, 1, 1), position=(-1, 0, 0)
     )
-    s2 = magpy.magnet.Cuboid((1, 0, 0), (1, 1, 1), position=(-1, 0, 0))
     col = magpy.Collection(s1, s2, position=[(1, 0, 0), (0, 0, 0), (3, 0, 3)])
     col.rotate_from_angax([90, -90], "z", start="auto")
     validate_pos_orient(
diff --git a/tests/test_obj_Cuboid.py b/tests/test_obj_Cuboid.py
index eb8e91462..ce8c7ef33 100644
--- a/tests/test_obj_Cuboid.py
+++ b/tests/test_obj_Cuboid.py
@@ -47,7 +47,7 @@ def test_Cuboid_basics():
     for mag, dim, ang, ax, anch, mov, poso in zip(
         mags, dims, angs, axs, anchs, movs, posos
     ):
-        pm = magpy.magnet.Cuboid(mag, np.abs(dim))
+        pm = magpy.magnet.Cuboid(polarization=mag, dimension=np.abs(dim))
 
         # 18 subsequent operations
         for a, aa, aaa, mv in zip(ang, ax, anch, mov):
@@ -61,15 +61,15 @@ def test_Cuboid_basics():
 
 def test_Cuboid_add():
     """testing __add__"""
-    src1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    src2 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    src1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    src2 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     col = src1 + src2
     assert isinstance(col, magpy.Collection), "adding cuboides fail"
 
 
 def test_Cuboid_squeeze():
     """testing squeeze output"""
-    src1 = magpy.magnet.Cuboid((1, 1, 1), (1, 1, 1))
+    src1 = magpy.magnet.Cuboid(polarization=(1, 1, 1), dimension=(1, 1, 1))
     sensor = Sensor(pixel=[(1, 2, 3), (1, 2, 3)])
     B = src1.getB(sensor)
     assert B.shape == (2, 3)
@@ -84,7 +84,7 @@ def test_Cuboid_squeeze():
 
 def test_repr_cuboid():
     """test __repr__"""
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
     pm1.style.label = "cuboid_01"
     assert repr(pm1)[:6] == "Cuboid", "Cuboid repr failed"
     assert "label='cuboid_01'" in repr(pm1), "Cuboid repr failed"
@@ -96,13 +96,17 @@ def test_cuboid_object_vs_lib():
     """
 
     a = 1
-    mag = np.array([(10, 20, 30)])
+    pol = np.array([(10, 20, 30)])
     dim = np.array([(a, a, a)])
     pos = np.array([(2 * a, 2 * a, 2 * a)])
-    B0 = magpy.core.magnet_cuboid_field("B", pos, mag, dim)
-    H0 = magpy.core.magnet_cuboid_field("H", pos, mag, dim)
-
-    src = magpy.magnet.Cuboid(mag[0], dim[0])
+    B0 = magpy.core.magnet_cuboid_field(
+        field="B", observers=pos, polarization=pol, dimension=dim
+    )
+    H0 = magpy.core.magnet_cuboid_field(
+        field="H", observers=pos, polarization=pol, dimension=dim
+    )
+
+    src = magpy.magnet.Cuboid(polarization=pol[0], dimension=dim[0])
     B1 = src.getB(pos)
     H1 = src.getH(pos)
 
diff --git a/tests/test_obj_Cylinder.py b/tests/test_obj_Cylinder.py
index e06943058..c7a9cef69 100644
--- a/tests/test_obj_Cylinder.py
+++ b/tests/test_obj_Cylinder.py
@@ -5,15 +5,15 @@
 
 def test_Cylinder_add():
     """testing __add__"""
-    src1 = magpy.magnet.Cylinder((1, 2, 3), (1, 2))
-    src2 = magpy.magnet.Cylinder((1, 2, 3), (1, 2))
+    src1 = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(1, 2))
+    src2 = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(1, 2))
     col = src1 + src2
     assert isinstance(col, magpy.Collection), "adding cylinder fail"
 
 
 def test_Cylinder_squeeze():
     """testing squeeze output"""
-    src1 = magpy.magnet.Cylinder((1, 1, 1), (1, 1))
+    src1 = magpy.magnet.Cylinder(polarization=(1, 1, 1), dimension=(1, 1))
     sensor = magpy.Sensor(pixel=[(1, 2, 3), (1, 2, 3)])
     B = src1.getB(sensor)
     assert B.shape == (2, 3)
@@ -28,13 +28,15 @@ def test_Cylinder_squeeze():
 
 def test_repr():
     """test __repr__"""
-    pm2 = magpy.magnet.Cylinder((1, 2, 3), (2, 3))
+    pm2 = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(2, 3))
     assert repr(pm2)[:8] == "Cylinder", "Cylinder repr failed"
 
 
 def test_repr2():
     """test __repr__"""
-    pm2 = magpy.magnet.CylinderSegment((1, 2, 3), (2, 3, 1, 0, 45))
+    pm2 = magpy.magnet.CylinderSegment(
+        polarization=(1, 2, 3), dimension=(2, 3, 1, 0, 45)
+    )
     assert repr(pm2)[:15] == "CylinderSegment", "CylinderSegment repr failed"
 
 
@@ -43,7 +45,7 @@ def test_Cylinder_getBH():
     test Cylinder getB and getH with different inputs
     vs the vectorized form
     """
-    mag = (22, 33, 44)
+    pol = (22, 33, 44)
     poso = [
         (0.123, 0.234, 0.345),
         (-0.123, 0.234, 0.345),
@@ -67,8 +69,8 @@ def test_Cylinder_getBH():
     dim5 = [(0, 0.5, 2, 0, 360), (0, 1, 3, 0, 360), (0.0000001, 1.5, 4, 0, 360)]
 
     for d2, d5 in zip(dim2, dim5):
-        src1 = magpy.magnet.Cylinder(mag, d2)
-        src2 = magpy.magnet.CylinderSegment(mag, d5)
+        src1 = magpy.magnet.Cylinder(polarization=pol, dimension=d2)
+        src2 = magpy.magnet.CylinderSegment(polarization=pol, dimension=d5)
         B0 = src1.getB(poso)
         H0 = src1.getH(poso)
 
@@ -78,26 +80,26 @@ def test_Cylinder_getBH():
         B2 = magpy.getB(
             "Cylinder",
             poso,
-            magnetization=mag,
+            polarization=pol,
             dimension=d2,
         )
         H2 = magpy.getH(
             "Cylinder",
             poso,
-            magnetization=mag,
+            polarization=pol,
             dimension=d2,
         )
 
         B3 = magpy.getB(
             "CylinderSegment",
             poso,
-            magnetization=mag,
+            polarization=pol,
             dimension=d5,
         )
         H3 = magpy.getH(
             "CylinderSegment",
             poso,
-            magnetization=mag,
+            polarization=pol,
             dimension=d5,
         )
 
diff --git a/tests/test_obj_CylinderSegment.py b/tests/test_obj_CylinderSegment.py
index 34ce904f5..679aa7e4a 100644
--- a/tests/test_obj_CylinderSegment.py
+++ b/tests/test_obj_CylinderSegment.py
@@ -5,14 +5,16 @@
 
 def test_repr():
     """test __repr__"""
-    pm2 = magpy.magnet.CylinderSegment((1, 2, 3), (1, 2, 3, 0, 90))
+    pm2 = magpy.magnet.CylinderSegment(
+        polarization=(1, 2, 3), dimension=(1, 2, 3, 0, 90)
+    )
     assert repr(pm2)[:15] == "CylinderSegment", "CylinderSegment repr failed"
 
 
 def test_barycenter():
     """test if barycenter is computed correctly"""
     cs = magpy.magnet.CylinderSegment(
-        magnetization=(100, 0, 0), dimension=(1, 2, 1, 85, 170)
+        polarization=(100, 0, 0), dimension=(1, 2, 1, 85, 170)
     )
 
     expected_barycenter_squeezed = np.array([-0.86248133, 1.12400755, 0.0])
diff --git a/tests/test_obj_Dipole.py b/tests/test_obj_Dipole.py
index 714e25e24..8c4c725c0 100644
--- a/tests/test_obj_Dipole.py
+++ b/tests/test_obj_Dipole.py
@@ -9,7 +9,7 @@ def test_Dipole_basicB():
     sens = magpy.Sensor()
 
     B = src.getB(sens)
-    Btest = np.array([0.00303828, 0.00607656, 0.00911485])
+    Btest = np.array([3.81801774e-09, 7.63603548e-09, 1.14540532e-08])
     assert np.allclose(B, Btest)
 
 
@@ -18,7 +18,7 @@ def test_Dipole_basicH():
     src = magpy.misc.Dipole(moment=(1, 2, 3), position=(1, 2, 3))
     sens = magpy.Sensor()
     H = src.getH(sens)
-    Htest = np.array([0.00241779, 0.00483558, 0.00725336])
+    Htest = np.array([0.00303828, 0.00607656, 0.00911485])
     assert np.allclose(H, Htest)
 
 
diff --git a/tests/test_obj_Polyline.py b/tests/test_obj_Polyline.py
index fcadb7d7c..f8224ae84 100644
--- a/tests/test_obj_Polyline.py
+++ b/tests/test_obj_Polyline.py
@@ -11,7 +11,7 @@ def test_Polyline_basic1():
     sens = magpy.Sensor()
     B = src.getB(sens)
 
-    x = 5.77350269
+    x = 5.77350269 * 1e-6
     Btest = np.array([x, -x, 0])
 
     assert np.allclose(B, Btest)
@@ -38,7 +38,7 @@ def test_Polyline_basic3():
     sens = magpy.Sensor()
     B = magpy.getB([line1, line2], sens)
 
-    x = 5.77350269
+    x = 5.77350269 * 1e-6
     Btest = np.array([(x, -x, 0)] * 2)
 
     assert np.allclose(B, Btest)
diff --git a/tests/test_obj_Sensor.py b/tests/test_obj_Sensor.py
index 8b49c3f6e..9be750f99 100644
--- a/tests/test_obj_Sensor.py
+++ b/tests/test_obj_Sensor.py
@@ -5,7 +5,7 @@
 
 def test_sensor1():
     """self-consistent test of the sensor class"""
-    pm = magpy.magnet.Cuboid((11, 22, 33), (1, 2, 3))
+    pm = magpy.magnet.Cuboid(polarization=(11, 22, 33), dimension=(1, 2, 3))
     angs = np.linspace(0, 555, 44)
     possis = [
         (3 * np.cos(t / 180 * np.pi), 3 * np.sin(t / 180 * np.pi), 1) for t in angs
@@ -24,7 +24,7 @@ def test_sensor1():
 
 def test_sensor2():
     """self-consistent test of the sensor class"""
-    pm = magpy.magnet.Cuboid((11, 22, 33), (1, 2, 3))
+    pm = magpy.magnet.Cuboid(polarization=(11, 22, 33), dimension=(1, 2, 3))
     poz = np.linspace(0, 5, 33)
     poss1 = [(t, 0, 2) for t in poz]
     poss2 = [(t, 0, 3) for t in poz]
@@ -43,7 +43,7 @@ def test_sensor2():
 def test_Sensor_getB_specs():
     """test input of sens getB"""
     sens1 = magpy.Sensor(pixel=(4, 4, 4))
-    pm1 = magpy.magnet.Cylinder((111, 222, 333), (1, 2))
+    pm1 = magpy.magnet.Cylinder(polarization=(111, 222, 333), dimension=(1, 2))
 
     B1 = sens1.getB(pm1)
     B2 = magpy.getB(pm1, sens1)
@@ -52,7 +52,7 @@ def test_Sensor_getB_specs():
 
 def test_Sensor_squeeze():
     """testing squeeze output"""
-    src = magpy.magnet.Sphere((1, 1, 1), 1)
+    src = magpy.magnet.Sphere(polarization=(1, 1, 1), diameter=1)
     sensor = magpy.Sensor(pixel=[(1, 2, 3), (1, 2, 3)])
     B = sensor.getB(src)
     assert B.shape == (2, 3)
@@ -77,7 +77,7 @@ def test_pixel1():
     logic: single sensor, scalar path, single source all generate
     1 for squeeze=False Bshape. Bare pixel should do the same
     """
-    src = magpy.misc.Dipole((1, 2, 3))
+    src = magpy.misc.Dipole(moment=(1, 2, 3))
 
     # squeeze=False Bshape of nbare pixel must be (1,1,1,1,3)
     np.testing.assert_allclose(
@@ -86,7 +86,7 @@ def test_pixel1():
     )
 
     # squeeze=False Bshape of [(1,2,3)] must then also be (1,1,1,1,3)
-    src = magpy.misc.Dipole((1, 2, 3))
+    src = magpy.misc.Dipole(moment=(1, 2, 3))
     np.testing.assert_allclose(
         src.getB(magpy.Sensor(pixel=[(1, 2, 3)]), squeeze=False).shape,
         (1, 1, 1, 1, 3),
@@ -121,7 +121,7 @@ def test_pixel3():
     There should be complete equivalence between pos_vec and
     Sensor(pixel=pos_vec) inputs
     """
-    src = magpy.misc.Dipole((1, 2, 3))
+    src = magpy.misc.Dipole(moment=(1, 2, 3))
 
     p0 = (1, 2, 3)
     p1 = [(1, 2, 3)]
diff --git a/tests/test_obj_Sphere.py b/tests/test_obj_Sphere.py
index 5a7ee3732..a72915650 100644
--- a/tests/test_obj_Sphere.py
+++ b/tests/test_obj_Sphere.py
@@ -20,7 +20,7 @@
 
 # # B = []
 # # for mag,dim,ang,ax,anch,mov,poso in zip(mags,dims,angs,axs,anchs,movs,posos):
-# #     pm = magpy.magnet.Sphere(mag,dim)
+# #     pm = magpy.magnet.Sphere(polarization=mag, dimension=dim)
 
 # #     # 18 subsequent operations
 # #     for a,aa,aaa,mv in zip(ang,ax,anch,mov):
@@ -45,7 +45,7 @@ def test_Sphere_basics():
     for mag, dim, ang, ax, anch, mov, poso in zip(
         mags, dims, angs, axs, anchs, movs, posos
     ):
-        pm = magpy.magnet.Sphere(mag, dim)
+        pm = magpy.magnet.Sphere(polarization=mag, diameter=dim)
 
         # 18 subsequent operations
         for a, aa, aaa, mv in zip(ang, ax, anch, mov):
@@ -59,15 +59,15 @@ def test_Sphere_basics():
 
 def test_Sphere_add():
     """testing __add__"""
-    src1 = magpy.magnet.Sphere(magnetization=(1, 2, 3), diameter=11)
-    src2 = magpy.magnet.Sphere((1, 2, 3), 11)
+    src1 = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=11)
+    src2 = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=11)
     col = src1 + src2
     assert isinstance(col, magpy.Collection), "adding cuboids fail"
 
 
 def test_Sphere_squeeze():
     """testing squeeze output"""
-    src1 = magpy.magnet.Sphere((1, 1, 1), 1)
+    src1 = magpy.magnet.Sphere(polarization=(1, 1, 1), diameter=1)
     sensor = magpy.Sensor(pixel=[(1, 2, 3), (1, 2, 3)])
     B = src1.getB(sensor)
     assert B.shape == (2, 3)
@@ -82,7 +82,7 @@ def test_Sphere_squeeze():
 
 def test_repr():
     """test __repr__"""
-    pm3 = magpy.magnet.Sphere((1, 2, 3), 3)
+    pm3 = magpy.magnet.Sphere(polarization=(1, 2, 3), diameter=3)
     assert repr(pm3)[:6] == "Sphere", "Sphere repr failed"
 
 
@@ -91,12 +91,14 @@ def test_sphere_object_vs_lib():
     tests object vs lib computation
     this also checks if np.int (from array slice) is allowed as input
     """
-    mag = np.array([(10, 20, 30)])
+    pol = np.array([(10, 20, 30)])
     dia = np.array([1])
     pos = np.array([(2, 2, 2)])
-    B1 = magpy.core.magnet_sphere_field("B", pos, mag, dia)[0]
+    B1 = magpy.core.magnet_sphere_field(
+        field="B", observers=pos, polarization=pol, diameter=dia
+    )[0]
 
-    src = magpy.magnet.Sphere(mag[0], dia[0])
+    src = magpy.magnet.Sphere(polarization=pol[0], diameter=dia[0])
     B2 = src.getB(pos)
 
     np.testing.assert_allclose(B1, B2)
diff --git a/tests/test_obj_Tetrahedron.py b/tests/test_obj_Tetrahedron.py
index 3fde50732..d24bf402e 100644
--- a/tests/test_obj_Tetrahedron.py
+++ b/tests/test_obj_Tetrahedron.py
@@ -14,7 +14,7 @@ def test_Tetrahedron_repr():
 def test_tetra_input():
     """test obj-oriented triangle vs cube"""
     obs = (1, 2, 3)
-    mag = (111, 222, 333)
+    pol = (111, 222, 333)
     vert_list = [
         [(1, 1, -1), (1, 1, 1), (-1, 1, 1), (1, -1, 1)],
         [(-1, -1, 1), (-1, 1, 1), (1, -1, 1), (1, -1, -1)],
@@ -26,9 +26,9 @@ def test_tetra_input():
 
     coll = magpy.Collection()
     for v in vert_list:
-        coll.add(magpy.magnet.Tetrahedron(mag, v))
+        coll.add(magpy.magnet.Tetrahedron(polarization=pol, vertices=v))
 
-    cube = magpy.magnet.Cuboid(mag, (2, 2, 2))
+    cube = magpy.magnet.Cuboid(polarization=pol, dimension=(2, 2, 2))
 
     b = coll.getB(obs)
     bb = cube.getB(obs)
@@ -52,12 +52,12 @@ def test_tetra_bad_inputs(vertices):
     """test obj-oriented triangle vs cube"""
 
     with pytest.raises(MagpylibBadUserInput):
-        magpy.magnet.Tetrahedron((111, 222, 333), vertices)
+        magpy.magnet.Tetrahedron(polarization=(0.111, 0.222, 0.333), vertices=vertices)
 
 
 def test_tetra_barycenter():
     """get barycenter"""
-    mag = (111, 222, 333)
+    pol = (0.111, 0.222, 0.333)
     vert = [(1, 1, -1), (1, 1, 1), (-1, 1, 1), (1, -1, 1)]
-    tetra = magpy.magnet.Tetrahedron(mag, vert)
+    tetra = magpy.magnet.Tetrahedron(polarization=pol, vertices=vert)
     np.testing.assert_allclose(tetra.barycenter, (0.5, 0.5, 0.5))
diff --git a/tests/test_obj_Triangle.py b/tests/test_obj_Triangle.py
index a65ff0d9e..7cecd60d3 100644
--- a/tests/test_obj_Triangle.py
+++ b/tests/test_obj_Triangle.py
@@ -13,7 +13,7 @@ def test_Triangle_repr():
 def test_triangle_input1():
     """test obj-oriented triangle vs cube"""
     obs = (1, 2, 3)
-    mag = (0, 0, 333)
+    pol = (0, 0, 333)
     vert = np.array(
         [
             [(-1, -1, 1), (1, -1, 1), (-1, 1, 1)],  # top1
@@ -24,8 +24,8 @@ def test_triangle_input1():
     )
     coll = magpy.Collection()
     for v in vert:
-        coll.add(magpy.misc.Triangle(mag, v))
-    cube = magpy.magnet.Cuboid(mag, (2, 2, 2))
+        coll.add(magpy.misc.Triangle(polarization=pol, vertices=v))
+    cube = magpy.magnet.Cuboid(polarization=pol, dimension=(2, 2, 2))
 
     b = coll.getB(obs)
     bb = cube.getB(obs)
@@ -37,7 +37,7 @@ def test_triangle_input3():
     """test core triangle vs objOriented triangle"""
 
     obs = np.array([(3, 4, 5)] * 4)
-    mag = np.array([(111, 222, 333)] * 4)
+    pol = np.array([(111, 222, 333)] * 4)
     vert = np.array(
         [
             [(0, 0, 0), (3, 0, 0), (0, 10, 0)],
@@ -46,13 +46,15 @@ def test_triangle_input3():
             [(6, 0, 0), (10, 0, 0), (0, 10, 0)],
         ]
     )
-    b = magpy.core.triangle_field("B", obs, mag, vert)
+    b = magpy.core.triangle_field(
+        field="B", observers=obs, polarization=pol, vertices=vert
+    )
     b = np.sum(b, axis=0)
 
-    tri1 = magpy.misc.Triangle(mag[0], vertices=vert[0])
-    tri2 = magpy.misc.Triangle(mag[0], vertices=vert[1])
-    tri3 = magpy.misc.Triangle(mag[0], vertices=vert[2])
-    tri4 = magpy.misc.Triangle(mag[0], vertices=vert[3])
+    tri1 = magpy.misc.Triangle(polarization=pol[0], vertices=vert[0])
+    tri2 = magpy.misc.Triangle(polarization=pol[0], vertices=vert[1])
+    tri3 = magpy.misc.Triangle(polarization=pol[0], vertices=vert[2])
+    tri4 = magpy.misc.Triangle(polarization=pol[0], vertices=vert[3])
 
     bb = magpy.getB([tri1, tri2, tri3, tri4], obs[0], sumup=True)
 
@@ -73,8 +75,8 @@ def call_getB():
 
 def test_Triangle_barycenter():
     """test Triangle barycenter"""
-    mag = (0, 0, 333)
+    pol = (0, 0, 0.333)
     vert = ((-1, -1, 0), (1, -1, 0), (0, 2, 0))
-    face = magpy.misc.Triangle(mag, vert)
+    face = magpy.misc.Triangle(polarization=pol, vertices=vert)
     bary = np.array([0, 0, 0])
     np.testing.assert_allclose(face.barycenter, bary)
diff --git a/tests/test_obj_TriangularMesh.py b/tests/test_obj_TriangularMesh.py
index ef966e4b5..bd59b0bbc 100644
--- a/tests/test_obj_TriangularMesh.py
+++ b/tests/test_obj_TriangularMesh.py
@@ -16,16 +16,18 @@
 
 def test_TriangularMesh_repr():
     """TriangularMesh repr test"""
-    trimesh = magpy.magnet.TriangularMesh.from_pyvista((0, 0, 1000), pv.Octahedron())
+    trimesh = magpy.magnet.TriangularMesh.from_pyvista(
+        polarization=(0, 0, 1), polydata=pv.Octahedron()
+    )
     assert repr(trimesh).startswith("TriangularMesh"), "TriangularMesh repr failed"
 
 
 def test_TriangularMesh_barycenter():
     """test TriangluarMesh barycenter"""
-    mag = (0, 0, 333)
-    trimesh = magpy.magnet.TriangularMesh.from_pyvista(mag, pv.Octahedron()).move(
-        (1, 2, 3)
-    )
+    pol = (0, 0, 333)
+    trimesh = magpy.magnet.TriangularMesh.from_pyvista(
+        polarization=pol, polydata=pv.Octahedron()
+    ).move((1, 2, 3))
     bary = np.array([1, 2, 3])
     np.testing.assert_allclose(trimesh.barycenter, bary)
 
@@ -33,21 +35,21 @@ def test_TriangularMesh_barycenter():
 def test_TriangularMesh_getBH():
     """Compare meshed cube to magpylib cube"""
     dimension = (1, 1, 1)
-    magnetization = (100, 200, 300)
+    polarization = (100, 200, 300)
     mesh3d = magpy.graphics.model3d.make_Cuboid()
     vertices = np.array([v for k, v in mesh3d["kwargs"].items() if k in "xyz"]).T
     faces = np.array([v for k, v in mesh3d["kwargs"].items() if k in "ijk"]).T
 
     faces[0] = faces[0][[0, 2, 1]]  # flip one triangle in wrong orientation
 
-    cube = magpy.magnet.Cuboid(magnetization=magnetization, dimension=dimension)
+    cube = magpy.magnet.Cuboid(polarization=polarization, dimension=dimension)
     cube.rotate_from_angax(19, (1, 2, 3))
     cube.move((1, 2, 3))
 
     cube_facet_reorient_true = magpy.magnet.TriangularMesh(
         position=cube.position,
         orientation=cube.orientation,
-        magnetization=magnetization,
+        polarization=polarization,
         vertices=vertices,
         faces=faces,
         reorient_faces=True,
@@ -56,7 +58,7 @@ def test_TriangularMesh_getBH():
     cube_facet_reorient_false = magpy.magnet.TriangularMesh(
         position=cube.position,
         orientation=cube.orientation,
-        magnetization=magnetization,
+        polarization=polarization,
         vertices=vertices,
         faces=faces,
         reorient_faces=False,
@@ -87,12 +89,14 @@ def test_TriangularMesh_getB_different_facet_shapes_mixed():
     shape (12,3,3) vs (4,3,3) for facet tetrahedron"""
     tetra_pv = pv.Tetrahedron()
     tetra = (
-        magpy.magnet.Tetrahedron((444, 555, 666), vertices=tetra_pv.points)
+        magpy.magnet.Tetrahedron(
+            polarization=(0.444, 0.555, 0.666), vertices=tetra_pv.points
+        )
         .move((-1, 1, 1))
         .rotate_from_angax([14, 65, 97], (4, 6, 9), anchor=0)
     )
     tetra_kwargs = {
-        "magnetization": tetra.magnetization,
+        "polarization": tetra.polarization,
         "position": tetra.position,
         "orientation": tetra.orientation,
     }
@@ -101,12 +105,12 @@ def test_TriangularMesh_getB_different_facet_shapes_mixed():
     )
     assert tmesh_tetra.status_reoriented is True
     cube = (
-        magpy.magnet.Cuboid((111, 222, 333), (1, 1, 1))
+        magpy.magnet.Cuboid(polarization=(0.111, 0.222, 0.333), dimension=(1, 1, 1))
         .move((1, 1, 1))
         .rotate_from_angax([14, 65, 97], (4, 6, 9), anchor=0)
     )
     cube_kwargs = {
-        "magnetization": cube.magnetization,
+        "polarization": cube.polarization,
         "position": cube.position,
         "orientation": cube.orientation,
     }
@@ -127,21 +131,21 @@ def test_TriangularMesh_getB_different_facet_shapes_mixed():
 
 def test_magnet_trimesh_func():
     """test on manual inside"""
-    mag = (111, 222, 333)
+    pol = (0.111, 0.222, 0.333)
     dim = (10, 10, 10)
-    cube = magpy.magnet.Cuboid(mag, dim)
+    cube = magpy.magnet.Cuboid(polarization=pol, dimension=dim)
     tmesh_cube = magpy.magnet.TriangularMesh.from_pyvista(
-        mag, pv.Cube(cube.position, *dim)
+        polarization=pol, polydata=pv.Cube(cube.position, *dim)
     )
 
     pts_inside = np.array([[0, 0, 1]])
     B0 = cube.getB(pts_inside)
     B1 = tmesh_cube.getB(pts_inside)
     B2 = magnet_trimesh_field(
-        "B",
-        pts_inside,
-        np.array([mag]),
-        np.array([tmesh_cube.mesh]),
+        field="B",
+        observers=pts_inside,
+        polarization=np.array([pol]),
+        mesh=np.array([tmesh_cube.mesh]),
         in_out="inside",
     )[0]
     np.testing.assert_allclose(B0, B1)
@@ -154,7 +158,7 @@ def test_bad_triangle_indices():
     faces = [[1, 2, 3]]  # index 3 >= len(vertices)
     with pytest.raises(IndexError):
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
         )
@@ -174,14 +178,14 @@ def test_open_mesh():
     faces = np.array([v for k, v in open_mesh.items() if k in "ijk"]).T
     with pytest.raises(ValueError, match=r"Open mesh detected in .*."):
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_open="raise",
         )
     with pytest.raises(ValueError, match=r"Open mesh in .* detected."):
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_open="ignore",
@@ -189,7 +193,7 @@ def test_open_mesh():
         )
     with pytest.warns(UserWarning) as record:
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_open="warn",
@@ -200,7 +204,7 @@ def test_open_mesh():
 
     with pytest.warns(UserWarning) as record:
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_open="skip",
@@ -217,7 +221,7 @@ def test_open_mesh():
     with warnings.catch_warnings():  # no warning should be issued!
         warnings.simplefilter("error")
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_open="ignore",
@@ -229,7 +233,7 @@ def test_open_mesh():
         match=r"Open mesh of .* detected",
     ):
         mesh = magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_open="ignore",
@@ -239,7 +243,7 @@ def test_open_mesh():
 
     with pytest.warns(UserWarning, match=r"Unchecked mesh status of .* detected"):
         mesh = magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_open="skip",
@@ -253,7 +257,7 @@ def test_disconnected_mesh():
     #  Multiple Text3D letters are disconnected
     with pytest.raises(ValueError, match=r"Disconnected mesh detected in .*."):
         magpy.magnet.TriangularMesh.from_pyvista(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             polydata=pv.Text3D("AB"),
             check_disconnected="raise",
         )
@@ -274,14 +278,14 @@ def test_selfintersecting_triangular_mesh():
     faces = np.array([v for k, v in selfintersecting_mesh3d.items() if k in "ijk"]).T
     with pytest.raises(ValueError, match=r"Self-intersecting mesh detected in .*."):
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_selfintersecting="raise",
         )
     with pytest.warns(UserWarning, match=r"Self-intersecting mesh detected in .*."):
         magpy.magnet.TriangularMesh(
-            magnetization=(0, 0, 1000),
+            polarization=(0, 0, 1),
             vertices=vertices,
             faces=faces,
             check_selfintersecting="warn",
@@ -292,7 +296,9 @@ def test_TriangularMesh_from_pyvista():
     """Test from_pyvista classmethod"""
 
     def get_tri_from_pv(obj):
-        return magpy.magnet.TriangularMesh.from_pyvista((0, 0, 1000), obj)
+        return magpy.magnet.TriangularMesh.from_pyvista(
+            polarization=(0, 0, 1), polydata=obj
+        )
 
     # shoud work
     get_tri_from_pv(pv.Cube())
@@ -309,12 +315,12 @@ def get_tri_from_pv(obj):
 
 def test_TriangularMesh_from_faces_bad_inputs():
     """Test from_faces classmethod bad inputs"""
-    mag = (0, 0, 1000)
+    pol = (0, 0, 1)
 
     def get_tri_from_triangles(trias):
         return magpy.magnet.TriangularMesh.from_triangles(
-            mag,
-            trias,
+            polarization=pol,
+            triangles=trias,
             check_open=False,
             check_disconnected=False,
             reorient_faces=False,
@@ -322,14 +328,16 @@ def get_tri_from_triangles(trias):
 
     def get_tri_from_mesh(mesh):
         return magpy.magnet.TriangularMesh.from_mesh(
-            mag,
-            mesh,
+            polarization=pol,
+            mesh=mesh,
             check_open=False,
             check_disconnected=False,
             reorient_faces=False,
         )
 
-    triangle = magpy.misc.Triangle(mag, [(0, 0, 0), (1, 0, 0), (0, 1, 0)])
+    triangle = magpy.misc.Triangle(
+        polarization=pol, vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0)]
+    )
 
     # good element type but not array-like
     with pytest.raises(TypeError):
@@ -356,26 +364,38 @@ def get_tri_from_mesh(mesh):
 
 def test_TriangularMesh_from_faces_good_inputs():
     """Test from_faces classmethod good inputs"""
-    mag = (0, 0, 1000)
+    pol = (0, 0, 1)
 
     # create Tetrahedron and move/orient randomly
-    tetra = magpy.magnet.Tetrahedron(mag, [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)])
+    tetra = magpy.magnet.Tetrahedron(
+        polarization=pol, vertices=[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)]
+    )
     tetra.move((3, 4, 5)).rotate_from_angax([13, 37], (1, 2, 3), anchor=0)
     pos_ori = {"orientation": tetra.orientation, "position": tetra.position}
 
-    tmesh1 = magpy.magnet.TriangularMesh.from_ConvexHull(mag, tetra.vertices, **pos_ori)
+    tmesh1 = magpy.magnet.TriangularMesh.from_ConvexHull(
+        polarization=pol, points=tetra.vertices, **pos_ori
+    )
 
     # from triangle list
-    trias = [magpy.misc.Triangle(mag, face) for face in tmesh1.mesh]
-    tmesh2 = magpy.magnet.TriangularMesh.from_triangles(mag, trias, **pos_ori)
+    trias = [
+        magpy.misc.Triangle(polarization=pol, vertices=face) for face in tmesh1.mesh
+    ]
+    tmesh2 = magpy.magnet.TriangularMesh.from_triangles(
+        polarization=pol, triangles=trias, **pos_ori
+    )
 
     # from collection
     coll = magpy.Collection(trias)
-    tmesh3 = magpy.magnet.TriangularMesh.from_triangles(mag, coll, **pos_ori)
+    tmesh3 = magpy.magnet.TriangularMesh.from_triangles(
+        polarization=pol, triangles=coll, **pos_ori
+    )
 
     # from mesh
     msh = [t.vertices for t in coll]
-    tmesh4 = magpy.magnet.TriangularMesh.from_mesh(mag, msh, **pos_ori)
+    tmesh4 = magpy.magnet.TriangularMesh.from_mesh(
+        polarization=pol, mesh=msh, **pos_ori
+    )
 
     points = [0, 0, 0]
     B0 = tetra.getB(points)
@@ -443,7 +463,7 @@ def test_bad_mode_input():
         match=r"The `check_open mode` argument .*, instead received 'badinput'.",
     ):
         magpy.magnet.TriangularMesh.from_pyvista(
-            magnetization=(0, 0, 1000), polydata=pv.Octahedron(), check_open="badinput"
+            polarization=(0, 0, 1), polydata=pv.Octahedron(), check_open="badinput"
         )
 
 
@@ -457,7 +477,11 @@ def points(r0):
         return [(r0 * np.cos(t), r0 * np.sin(t), 10) for t in ts] + [(0, 0, 0)]
 
     ts = np.linspace(0, 2 * np.pi, 5)
-    cone1 = magpy.magnet.TriangularMesh.from_ConvexHull((0, 0, 1), points(12))
-    cone2 = magpy.magnet.TriangularMesh.from_ConvexHull((0, 0, 1), points(13))
+    cone1 = magpy.magnet.TriangularMesh.from_ConvexHull(
+        polarization=(0, 0, 1), points=points(12)
+    )
+    cone2 = magpy.magnet.TriangularMesh.from_ConvexHull(
+        polarization=(0, 0, 1), points=points(13)
+    )
 
     np.testing.assert_array_equal(cone1.faces, cone2.faces)
diff --git a/tests/test_path.py b/tests/test_path.py
index 8f7d57eac..6827076cd 100644
--- a/tests/test_path.py
+++ b/tests/test_path.py
@@ -9,12 +9,16 @@ def test_path_old_new_move():
     s_pos = (0, 0, 0)
 
     # path style code translation
-    pm1 = magpy.magnet.Cylinder((0, 0, 1000), (3, 3), position=(-5, 0, 3))
+    pm1 = magpy.magnet.Cylinder(
+        polarization=(0, 0, 1), dimension=(3, 3), position=(-5, 0, 3)
+    )
     pm1.move([(x, 0, 0) for x in np.linspace(0, 10, 100)], start=-1)
     B1 = pm1.getB(s_pos)
 
     # old style code translation
-    pm2 = magpy.magnet.Cylinder((0, 0, 1000), (3, 3), position=(0, 0, 3))
+    pm2 = magpy.magnet.Cylinder(
+        polarization=(0, 0, 1), dimension=(3, 3), position=(0, 0, 3)
+    )
     ts = np.linspace(-5, 5, n)
     possis = np.array([(t, 0, 0) for t in ts])
     B2 = pm2.getB(possis[::-1])
@@ -33,13 +37,17 @@ def test_path_old_new_rotate():
     anch = (0, 0, 10)
 
     # path style code rotation
-    pm1 = magpy.magnet.Cuboid((0, 0, 1000), (1, 2, 3), position=(0, 0, 3))
+    pm1 = magpy.magnet.Cuboid(
+        polarization=(0, 0, 1), dimension=(1, 2, 3), position=(0, 0, 3)
+    )
     pm1.rotate_from_angax(-30, ax, anch)
     pm1.rotate_from_angax(np.linspace(0, 60, n), "x", anch, start=-1)
     B1 = pm1.getB(s_pos)
 
     # old style code rotation
-    pm2 = magpy.magnet.Cuboid((0, 0, 1000), (1, 2, 3), position=(0, 0, 3))
+    pm2 = magpy.magnet.Cuboid(
+        polarization=(0, 0, 1), dimension=(1, 2, 3), position=(0, 0, 3)
+    )
     pm2.rotate_from_angax(-30, ax, anch)
     B2 = []
     for _ in range(n):
diff --git a/tests/test_physics_consistency.py b/tests/test_physics_consistency.py
index c9f831850..e68cf465a 100644
--- a/tests/test_physics_consistency.py
+++ b/tests/test_physics_consistency.py
@@ -5,27 +5,27 @@
 
 def test_dipole_approximation():
     """test if all source fields converge towards the correct dipole field at distance"""
-    mag = np.array([111, 222, 333])
+    pol = np.array([0.111, 0.222, 0.333])
     pos = (1234, -234, 345)
 
-    # cuboid with volume = 1 mm^3
-    src1 = magpy.magnet.Cuboid(mag, dimension=(1, 1, 1))
+    # cuboid with volume = 1 m^3
+    src1 = magpy.magnet.Cuboid(polarization=pol, dimension=(1, 1, 1))
     B1 = src1.getB(pos)
 
-    # Cylinder with volume = 1 mm^3
+    # Cylinder with volume = 1 m^3
     dia = np.sqrt(4 / np.pi)
-    src2 = magpy.magnet.Cylinder(mag, dimension=(dia, 1))
+    src2 = magpy.magnet.Cylinder(polarization=pol, dimension=(dia, 1))
     B2 = src2.getB(pos)
     assert np.allclose(B1, B2)
 
-    # Sphere with volume = 1 mm^3
+    # Sphere with volume = 1 m^3
     dia = (6 / np.pi) ** (1 / 3)
-    src3 = magpy.magnet.Sphere(mag, dia)
+    src3 = magpy.magnet.Sphere(polarization=pol, diameter=dia)
     B3 = src3.getB(pos)
     assert np.allclose(B1, B3)
 
-    #  Dipole with mom=mag
-    src4 = magpy.misc.Dipole(moment=mag)
+    #  Dipole with mom=pol
+    src4 = magpy.misc.Dipole(moment=pol)
     B4 = src4.getB(pos)
     assert np.allclose(B1, B4)
 
@@ -42,8 +42,8 @@ def test_dipole_approximation():
 
 def test_Circle_vs_Cylinder_field():
     """
-    The H-field of a loop with radius r0 (mm) and current i0 (A) is the same
-    as the H-field of a cylinder with radius r0 (mm), height h0 (mm) and
+    The H-field of a loop with radius r0 (m) and current i0 (A) is the same
+    as the H-field of a cylinder with radius r0 (m), height h0 (m) and
     magnetization (0, 0, 4pi/10*i0/h0) !!!
     """
 
@@ -169,7 +169,7 @@ def test_Circle_vs_Cylinder_field():
     h0 = 1e-4
     i0 = 1
     src1 = magpy.magnet.Cylinder(
-        magnetization=(0, 0, i0 / h0 * 4 * np.pi / 10), dimension=(r0, h0)
+        polarization=(0, 0, i0 / h0 * 4 * np.pi / 10 * 1e-6), dimension=(r0, h0)
     )
     src2 = magpy.current.Circle(current=i0, diameter=r0)
 
@@ -218,7 +218,7 @@ def Binf(i0, pos):
         e_phi = np.array([-y, x, 0])
         e_phi = e_phi / np.linalg.norm(e_phi)
         mu0 = 4 * np.pi * 1e-7
-        return i0 * mu0 / 2 / np.pi / r * e_phi * 1000 * 1000  # mT mm
+        return i0 * mu0 / 2 / np.pi / r * e_phi * 1000 * 1000
 
     ps = (0, 0, -1000000)
     pe = (0, 0, 1000000)
@@ -227,6 +227,6 @@ def Binf(i0, pos):
         Bls += [magpy.getB("Polyline", p, current=1, segment_start=ps, segment_end=pe)]
         Binfs += [Binf(1, p)]
     Bls = np.array(Bls)
-    Binfs = np.array(Binfs)
+    Binfs = np.array(Binfs) * 1e-6
 
     assert np.allclose(Bls, Binfs)
diff --git a/tests/test_scaling.py b/tests/test_scaling.py
index b6773d388..afcc1e783 100644
--- a/tests/test_scaling.py
+++ b/tests/test_scaling.py
@@ -8,13 +8,13 @@ def test_scaling_loop():
     The field of a current loop must satisfy
     B(i0,d,x,y,z) = B(a*i0,a*d,a*x,a*y,a*z)
     """
-    c1 = magpy.current.Circle(123, 10)
+    c1 = magpy.current.Circle(current=123, diameter=10)
     B1 = c1.getB([1, 2, 3])
-    c2 = magpy.current.Circle(1230, 100)
+    c2 = magpy.current.Circle(current=1230, diameter=100)
     B2 = c2.getB([10, 20, 30])
-    c3 = magpy.current.Circle(12300, 1000)
+    c3 = magpy.current.Circle(current=12300, diameter=1000)
     B3 = c3.getB([100, 200, 300])
-    c4 = magpy.current.Circle(123000, 10000)
+    c4 = magpy.current.Circle(current=123000, diameter=10000)
     B4 = c4.getB([1000, 2000, 3000])
 
     assert np.allclose(B1, B2)
diff --git a/tests/test_utility.py b/tests/test_utility.py
index 365698b58..7f1555341 100644
--- a/tests/test_utility.py
+++ b/tests/test_utility.py
@@ -9,8 +9,8 @@
 
 def test_duplicates():
     """test duplicate elimination and sorting"""
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm2 = magpy.magnet.Cylinder((1, 2, 3), (1, 2))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(1, 2))
     src_list = [pm1, pm2, pm1]
     src_list_new = check_duplicates(src_list)
     assert src_list_new == [pm1, pm2], "duplicate elimination failed"
@@ -18,8 +18,8 @@ def test_duplicates():
 
 def test_filter_objects():
     """tests elimination of unwanted types"""
-    pm1 = magpy.magnet.Cuboid((1, 2, 3), (1, 2, 3))
-    pm2 = magpy.magnet.Cylinder((1, 2, 3), (1, 2))
+    pm1 = magpy.magnet.Cuboid(polarization=(1, 2, 3), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cylinder(polarization=(1, 2, 3), dimension=(1, 2))
     sens = magpy.Sensor()
     src_list = [pm1, pm2, sens]
     list_new = filter_objects(src_list, allow="sources")
@@ -30,8 +30,8 @@ def test_format_getBH_class_inputs():
     """special case testing of different input formats"""
     possis = [3, 3, 3]
     sens = magpy.Sensor(position=(3, 3, 3))
-    pm1 = magpy.magnet.Cuboid((11, 22, 33), (1, 2, 3))
-    pm2 = magpy.magnet.Cuboid((11, 22, 33), (1, 2, 3))
+    pm1 = magpy.magnet.Cuboid(polarization=(11, 22, 33), dimension=(1, 2, 3))
+    pm2 = magpy.magnet.Cuboid(polarization=(11, 22, 33), dimension=(1, 2, 3))
     col = pm1 + pm2
 
     B1 = pm1.getB(possis)
diff --git a/tests/test_vs_mag2.py b/tests/test_vs_mag2.py
index 5b340aa1b..c5068edad 100644
--- a/tests/test_vs_mag2.py
+++ b/tests/test_vs_mag2.py
@@ -10,16 +10,16 @@
 # import magpylib as magpy
 
 # # linear motionfrom (0,0,0) to (3,-3,3) in 100 steps
-# pm = magpy.source.magnet.Cuboid(magnetization=(111,222,333), dimension=(1,2,3))
+# pm = magpy.source.magnet.Cuboid(polarization=(111,222,333), dimension=(1,2,3))
 # B1 = np.array([pm.getB((i,-i,i)) for i in np.linspace(0,3,100)])
 
 # # rotation (pos_obs around magnet) from 0 to 444 deg, starting pos_obs at (0,3,0) about 'z'
-# pm = magpy.source.magnet.Cuboid(magnetization=(111,222,333), dimension=(1,2,3))
+# pm = magpy.source.magnet.Cuboid(polarization=(111,222,333), dimension=(1,2,3))
 # possis = [(3*np.sin(t/180*np.pi),3*np.cos(t/180*np.pi),0) for t in np.linspace(0,444,100)]
 # B2 = np.array([pm.getB(p) for p in possis])
 
 # # spiral (magnet around pos_obs=0) from 0 to 297 deg, about 'z' in 100 steps
-# pm = magpy.source.magnet.Cuboid(magnetization=(111,222,333), dimension=(1,2,3), pos=(3,0,0))
+# pm = magpy.source.magnet.Cuboid(polarization=(111,222,333), dimension=(1,2,3), pos=(3,0,0))
 # B = []
 # for i in range(100):
 #     B += [pm.getB((0,0,0))]
@@ -37,7 +37,7 @@ def test_vs_mag2_linear():
     with open(os.path.abspath("tests/testdata/testdata_vs_mag2.p"), "rb") as f:
         data = pickle.load(f)[0]
     poso = [(t, -t, t) for t in np.linspace(0, 3, 100)]
-    pm = magpy.magnet.Cuboid(magnetization=(111, 222, 333), dimension=(1, 2, 3))
+    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"
@@ -47,7 +47,7 @@ def test_vs_mag2_rotation():
     """test against magpylib v2"""
     with open(os.path.abspath("tests/testdata/testdata_vs_mag2.p"), "rb") as f:
         data = pickle.load(f)[1]
-    pm = magpy.magnet.Cuboid(magnetization=(111, 222, 333), dimension=(1, 2, 3))
+    pm = magpy.magnet.Cuboid(polarization=(111, 222, 333), dimension=(1, 2, 3))
     possis = [
         (3 * np.sin(t / 180 * np.pi), 3 * np.cos(t / 180 * np.pi), 0)
         for t in np.linspace(0, 444, 100)
@@ -61,7 +61,7 @@ def test_vs_mag2_spiral():
     with open(os.path.abspath("tests/testdata/testdata_vs_mag2.p"), "rb") as f:
         data = pickle.load(f)[2]
     pm = magpy.magnet.Cuboid(
-        magnetization=(111, 222, 333), dimension=(1, 2, 3), position=(3, 0, 0)
+        polarization=(111, 222, 333), dimension=(1, 2, 3), position=(3, 0, 0)
     )
 
     angs = np.linspace(0, 297, 100)
@@ -74,7 +74,7 @@ def test_vs_mag2_spiral():
 
 def test_vs_mag2_line():
     """test line current vs mag2 results"""
-    Btest = np.array([1.47881931, -1.99789688, 0.2093811])
+    Btest = np.array([1.47881931, -1.99789688, 0.2093811]) * 1e-6
 
     src = magpy.current.Polyline(
         current=10,