Magpylib objects all have position and orientation attributes in the global reference frame. These attributes can be single instances describing a single position and a single orientation of an object, but they can also be vectors of positions and orientations. In this case the attributes represent multiple object locations and orientaions and are referred to as a path. When the field of an object is computed, it is automatically computed for the whole path. The reason is that computation is much more efficient when all instances are computed in a single operation. The introduction to position and orientation attributes and path can be found in Position and orientation. Here we show how to work with paths properly.

Assigning absolute paths#

Absolute object paths are assigned at initialization or through the object properties.

import numpy as np
from scipy.spatial.transform import Rotation as R
import magpylib as magpy

ts = np.linspace(0, 10, 51)
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]))

# set path at initialization
sensor = magpy.Sensor(position=pos, orientation=ori)

# set path through properties
cube = magpy.magnet.Cuboid(magnetization=(0,0,1), dimension=(.5,.5,.5))
cube.position = pos + np.array((0,0,3))
cube.orientation = ori, cube, style_path_frames=10)

Move and rotate#

The attributes position and orientation can be either of “scalar” nature, i.e. a single position or a single rotation, or “vectors” when they are arrays of such scalars. The two attributes together define an object “path”.

The move and rotate methods obey the following rules:

  • 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 individual \(n\) 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.

import magpylib as magpy

sensor = magpy.Sensor()

sensor.move((1,1,1))                                      # scalar input is by default applied
print(sensor.position)                                    # to the whole path
# out: [1. 1. 1.]

sensor.move([(1,1,1), (2,2,2)])                           # vector input is by default appended
print(sensor.position)                                    # to the existing path
# out: [[1. 1. 1.]  [2. 2. 2.]  [3. 3. 3.]]

sensor.move((1,1,1), start=1)                             # scalar input and start=1 is applied
print(sensor.position)                                    # to whole path starting at index 1
# out: [[1. 1. 1.]  [3. 3. 3.]  [4. 4. 4.]]

sensor.move([(0,0,10), (0,0,20)], start=1)                # vector input and start=1 merges
print(sensor.position)                                    # the input with the existing path
# out: [[ 1.  1.  1.]  [ 3.  3. 13.]  [ 4.  4. 24.]]      # starting at index 1.

Relative paths#

move and rotate input is interpreted relative to the existing path. Vector input is by default appended:

import numpy as np
from magpylib.magnet import Sphere

x_path = np.linspace((0,0,0), (10,0,0), 10)[1:]
z_path = np.linspace((0,0,0), (0,0,10), 10)[1:]

sphere = Sphere(magnetization=(0,0,1), diameter=3)

for _ in range(3):

Merging paths#

Complex paths can be created by merging multiple path operations. This is done with vector input for the move and rotate methods, and choosing values for start that will make the paths overlap. In the following example we combine a linear path with a rotation about self (anchor=None) until path index 30. Thereon, a second rotation about the origin is applied, creating a spiral motion.

import numpy as np
from magpylib.magnet import Cuboid

cube =  Cuboid(magnetization=(0,0,100), dimension=(2,2,2))
cube.position = np.linspace((0,0,0), (10,0,0), 60)
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), anchor=0, start=30)'plotly', animation=True)