Skip to content

Commit

Permalink
Merge pull request #236 from magpylib/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
OrtnerMichael committed Jan 17, 2020
2 parents d31e51c + 59adf92 commit 8ab6c31
Show file tree
Hide file tree
Showing 23 changed files with 1,019 additions and 180 deletions.
24 changes: 22 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ All notable changes to magpylib are documented here.

# Releases

## [2.3.0b] - 2020-01-17

### Changed
- Improved performance of getB for diametral magnetized Cylinders by 20%.
- GetB of Line current now uses vectorized code which leads to massive performance enhancement.
- **IMPORTANT:** position arguments of `getBv` functions have been flipped! First comes the source position POSm THEN the observer position POSo!
- - getB(pos) now takes single AND vector position arguments. If a vector is handed to getB it will automatically execute vectorized code from the vector module.

### Added
- completed the library vector functionality adding magnet Cylinder, moment Dipole, current Circular and Line. This includes adding several private vectorized functions (e.g. ellipticV) to mathLib_vector, adding respective tests and docu examples.

---

## [2.2.0b] - 2019-12-27
- unreleased version

---

## [2.1.0b] - 2019-12-06

### Added
Expand All @@ -23,19 +41,21 @@ All notable changes to magpylib are documented here.
- Restructuring
- displaySystem is now a top-level function, not a Collection method anymore.
- getBsweep and multiprocessing options have been completely removed, this functionality
should be overtaken by the new vector functionality which uses numpy native vectorized
should be overtaken by the new vector functionality which uses the numpy native vectorized
code paradigm. If mkl library is set (test by numpy.show_config()) numpy will also
automatically use multiporcessing. Code parallelization at magpylib level should be done
by hand.
- Docstrings are adjusted to work better with intellisense. (Problems with *.rst code)
- public rotatePosition() is now called angleAxisRotation(), former private angleAxisRotation
is now called angleAxisRotation_priv().
- Major rework of the documentation and exmples.
- Major rework of the documentation and examples.

### Added
- Performance computation trough vector functionality included in new top-level subpackge "vector"
- Vectorized versions of math functions added to "math" subpackage

---

## [1.2.1b0] - 2019-07-31
### Changed
- Optimized getB call (utility integrated)
Expand Down
8 changes: 5 additions & 3 deletions docs/_pages/0_documentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The top level of magpylib contains the sub-packages and :mod:`~magpylib.source`

4. The **Collection class** is used to group sources and for common manipulation.

5. The **Sensor Class** represents a 3D magnetic sensor.
5. The **Sensor class** represents a 3D magnetic sensor.

6. The **displaySystem function** is used to create a graphical output of the system geometry.

Expand All @@ -69,7 +69,7 @@ In magpylib all inputs and outputs are made in the physical units of
- **Millitesla** for magnetization/remanence, magnetic moment and magnetic field,
- **Ampere** for currents.

Unless specifically state otherwise in the docstring, **scalar input** can be of ``int`` or ``float`` type and **vector/matrix input** can be given either in the form of a ``list``, as a ``tuple`` or as a ``numpy.array``.
Unless specifically state otherwise in the docstring (see vector package), **scalar input** can be of ``int`` or ``float`` type and **vector/matrix input** can be given either in the form of a ``list``, as a ``tuple`` or as a ``numpy.array``.

The library output and all object attributes are either of ``numpy.float64`` or ``numpy.array64`` type.

Expand Down Expand Up @@ -133,7 +133,7 @@ The ``dimension`` input specifies the size of the source. However, as each sourc
:align: center
:scale: 50 %

**Figure:** Illustration of information given by the dimension-attribute. The source positions (typically the geometric center) is indicated by the red dot.
**Figure:** Illustration of information given by the dimension-attribute. The source positions (typically the geometric center) are indicated by the red dot.

The excitation of a source is either the ``magnetization``, the ``current`` or the magnetic ``moment``:

Expand Down Expand Up @@ -314,6 +314,8 @@ As a rule of thumb, ``s.getB()`` will be faster than ``getBv`` for ~5 or less fi
More examples of vectorized code can be found in the :ref:`examples-vector` section.

.. warning::
The functions included in the ``magpylib.vector`` package do not check the input format. All input must be in the form of numpy arrays.


.. _docu-collection:
Expand Down
7 changes: 6 additions & 1 deletion docs/_pages/1_how2install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ Installation
*************************

.. warning::
Magpylib works only with Python 3.6 or later !
magpylib works only with Python 3.6 or later !

**Dependencies:**
- numpy
- matplotlib
The latest versions will be installed automatically with magpylib.


Content
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def setup(app):
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
release = '2.1.0-beta'
release = '2.3.0-beta'


# -- General configuration ---------------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ What is magpylib ?

- Free Python package for calculating magnetic fields of magnets, currents and moments (sources).
- Provides convenient methods to create, geometrically manipulate, group and visualize assemblies of sources.
- The magnetic fields are determined from underlying (semi-analytical) solutions which results in fast computation times and requires little computation power.
- The magnetic fields are determined from underlying analytical solutions which results in fast computation times and requires little computation power.
- For high performance computation (e.g. for multivariate parameter space analysis) all functions are also available in vectorized form.

.. image:: _static/images/index/sourceFundamentals.png
:align: center
Expand Down
45 changes: 42 additions & 3 deletions magpylib/_lib/classes/currents.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
# page at https://www.github.com/magpylib/magpylib/issues.
# -------------------------------------------------------------------------------

from numpy import array, float64, ndarray
from numpy import array, float64, ndarray, shape, ones, tile
from magpylib._lib.mathLib import angleAxisRotation_priv
from magpylib._lib.fields.Current_Line import Bfield_CurrentLine
from magpylib._lib.fields.Current_Line_vector import Bfield_CurrentLineV, Bfield_CurrentLineVV
from magpylib._lib.fields.Current_CircularLoop import Bfield_CircularCurrentLoop
from magpylib._lib.fields.Current_CircularLoop_vector import Bfield_CircularCurrentLoopV
from magpylib._lib.classes.base import LineCurrent
from magpylib._lib.mathLib_vector import angleAxisRotationV_priv


# tool-tip / intellisense helpers ---------------------------------------------
Expand Down Expand Up @@ -116,6 +118,26 @@ def __init__(self, curr=I, dim=d, pos=(0.0, 0.0, 0.0), angle=0.0, axis=(0.0, 0.0
self.dimension = float(dim)

def getB(self, pos): # Particular Circular current B field calculation. Check RCS for getB() interface

# vectorized code if input is an Nx3 array
if type(pos) == ndarray:
if len(shape(pos))==2: # list of positions - use vectorized code
# vector size
NN = shape(pos)[0]
# prepare vector inputs
POSREL = pos - self.position
ANG = ones(NN)*self.angle
AX = tile(self.axis,(NN,1))
DIM = ones(NN)*self.dimension
CURR = ones(NN)*self.current
# compute rotations and field
ROTATEDPOS = angleAxisRotationV_priv(ANG, -AX, POSREL)
BB = Bfield_CircularCurrentLoopV(CURR,DIM,ROTATEDPOS)
BCM = angleAxisRotationV_priv(ANG, AX, BB)

return BCM


# secure input type and check input format
p1 = array(pos, dtype=float64, copy=False)
# relative position between mag and obs
Expand Down Expand Up @@ -231,14 +253,31 @@ def __init__(self, curr=I, vertices=listOfPos, pos=(0.0, 0.0, 0.0), angle=0.0, a
self.vertices = array(vertices, dtype=float64, copy=False)

def getB(self, pos): # Particular Line current B field calculation. Check RCS for getB() interface

# vectorized code if input is an Nx3 array
if type(pos) == ndarray:
if len(shape(pos))==2: # list of positions - use vectorized code
# vector size
NN = shape(pos)[0]
# prepare vector inputs
POSREL = pos - self.position
ANG = ones(NN)*self.angle
AX = tile(self.axis,(NN,1))
# compute rotations and field
ROTATEDPOS = angleAxisRotationV_priv(ANG, -AX, POSREL)
BB = Bfield_CurrentLineVV(self.vertices,self.current,ROTATEDPOS)
BCM = angleAxisRotationV_priv(ANG, AX, BB)

return BCM

# secure input type and check input format
p1 = array(pos, dtype=float64, copy=False)
# relative position between mag and obs
posRel = p1 - self.position
# rotate this vector into the CS of the magnet (inverse rotation)
rotatedPos = angleAxisRotation_priv(self.angle, -self.axis, posRel) # pylint: disable=invalid-unary-operand-type
# rotate field vector back
BCm = angleAxisRotation_priv(self.angle, self.axis, Bfield_CurrentLine(rotatedPos, self.vertices, self.current))
BCm = angleAxisRotation_priv(self.angle, self.axis, Bfield_CurrentLineV(self.vertices, self.current,rotatedPos))
# BCm is the obtained magnetic field in Cm
# the field is well known in the magnet coordinates.
return BCm
Expand Down
64 changes: 64 additions & 0 deletions magpylib/_lib/classes/magnets.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
from magpylib._lib.fields.PM_Sphere import Bfield_Sphere
from magpylib._lib.fields.PM_Cylinder import Bfield_Cylinder
from magpylib._lib.fields.PM_Box import Bfield_Box
from magpylib._lib.mathLib_vector import angleAxisRotationV_priv
import numpy as np
from magpylib._lib.fields.PM_Box_vector import Bfield_BoxV
from magpylib._lib.fields.PM_Cylinder_vector import Bfield_CylinderV
from magpylib._lib.fields.PM_Sphere_vector import Bfield_SphereV

# tool-tip / intellisense helpers ---------------------------------------------
# Class initialization is done purely by kwargs. While some # of these can be
Expand Down Expand Up @@ -110,6 +115,25 @@ def __init__(self, mag=(Mx, My, Mz), dim=(a, b, c), pos=(0.0, 0.0, 0.0), angle=0
self.dimension = checkDimensions(3, dim, "Bad dim for box")

def getB(self, pos):

# vectorized code if input is an Nx3 array
if type(pos) == ndarray:
if len(np.shape(pos))==2: # list of positions - use vectorized code
# vector size
NN = np.shape(pos)[0]
# prepare vector inputs
POSREL = pos - self.position
ANG = np.ones(NN)*self.angle
AX = np.tile(self.axis,(NN,1))
MAG = np.tile(self.magnetization,(NN,1))
DIM = np.tile(self.dimension,(NN,1))
# compute rotations and field
ROTATEDPOS = angleAxisRotationV_priv(ANG, -AX, POSREL)
BB = Bfield_BoxV(MAG,ROTATEDPOS,DIM)
BCM = angleAxisRotationV_priv(ANG, AX, BB)

return BCM

# secure input type and check input format
p1 = array(pos, dtype=float64, copy=False)
# relative position between mag and obs
Expand All @@ -120,6 +144,8 @@ def getB(self, pos):
BCm = angleAxisRotation_priv(self.angle, self.axis, Bfield_Box(self.magnetization, rotatedPos, self.dimension))
# BCm is the obtained magnetic field in Cm
# the field is well known in the magnet coordinates.


return BCm

def __repr__(self):
Expand Down Expand Up @@ -228,6 +254,25 @@ def __init__(self, mag=(Mx, My, Mz), dim=(d, h), pos=(0.0, 0.0, 0.0), angle=0.0,
self.iterDia = iterDia

def getB(self, pos): # Particular Cylinder B field calculation. Check RCS for getB() interface

# vectorized code if input is an Nx3 array
if type(pos) == ndarray:
if len(np.shape(pos))==2: # list of positions - use vectorized code
# vector size
NN = np.shape(pos)[0]
# prepare vector inputs
POSREL = pos - self.position
ANG = np.ones(NN)*self.angle
AX = np.tile(self.axis,(NN,1))
MAG = np.tile(self.magnetization,(NN,1))
DIM = np.tile(self.dimension,(NN,1))
# compute rotations and field
ROTATEDPOS = angleAxisRotationV_priv(ANG, -AX, POSREL)
BB = Bfield_CylinderV(MAG,ROTATEDPOS,DIM,self.iterDia)
BCM = angleAxisRotationV_priv(ANG, AX, BB)

return BCM

# secure input type and check input format
p1 = array(pos, dtype=float64, copy=False)
# relative position between mag and obs
Expand Down Expand Up @@ -331,6 +376,25 @@ def __init__(self, mag=(Mx, My, Mz), dim=d, pos=(0.0, 0.0, 0.0), angle=0.0, axis
assert self.dimension > 0, 'Bad dim<=0 for sphere'

def getB(self, pos):

# vectorized code if input is an Nx3 array
if type(pos) == ndarray:
if len(np.shape(pos))==2: # list of positions - use vectorized code
# vector size
NN = np.shape(pos)[0]
# prepare vector inputs
POSREL = pos - self.position
ANG = np.ones(NN)*self.angle
AX = np.tile(self.axis,(NN,1))
MAG = np.tile(self.magnetization,(NN,1))
DIM = np.ones(NN)*self.dimension
# compute rotations and field
ROTATEDPOS = angleAxisRotationV_priv(ANG, -AX, POSREL)
BB = Bfield_SphereV(MAG,ROTATEDPOS,DIM)
BCM = angleAxisRotationV_priv(ANG, AX, BB)

return BCM

# secure input type and check input format
p1 = array(pos, dtype=float64, copy=False)
# relative position between mag and obs
Expand Down
25 changes: 21 additions & 4 deletions magpylib/_lib/classes/moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
# page at https://www.github.com/magpylib/magpylib/issues.
# -------------------------------------------------------------------------------

from numpy import array, float64, ndarray
from numpy import array, float64, ndarray, ones, tile, shape
from magpylib._lib.mathLib import angleAxisRotation_priv
from magpylib._lib.classes.base import MagMoment
from magpylib._lib.fields.Moment_Dipole import Bfield_Dipole

from magpylib._lib.fields.Moment_Dipole_vector import Bfield_DipoleV
from magpylib._lib.mathLib_vector import angleAxisRotationV_priv

# tool-tip / intellisense helpers ---------------------------------------------
# Class initialization is done purely by kwargs. While some # of these can be
Expand All @@ -36,8 +37,6 @@
# these names are pre-initialzed:
Mx = My = Mz = 0.0



# -------------------------------------------------------------------------------
class Dipole(MagMoment):
"""
Expand Down Expand Up @@ -93,6 +92,24 @@ class Dipole(MagMoment):
"""

def getB(self, pos): # Particular Line current B field calculation. Check RCS for getB() interface

# vectorized code if input is an Nx3 array
if type(pos) == ndarray:
if len(shape(pos))==2: # list of positions - use vectorized code
# vector size
NN = shape(pos)[0]
# prepare vector inputs
POSREL = pos - self.position
ANG = ones(NN)*self.angle
AX = tile(self.axis,(NN,1))
MOM = tile(self.moment,(NN,1))
# compute rotations and field
ROTATEDPOS = angleAxisRotationV_priv(ANG, -AX, POSREL)
BB = Bfield_DipoleV(MOM,ROTATEDPOS)
BCM = angleAxisRotationV_priv(ANG, AX, BB)

return BCM

# secure input type and check input format
p1 = array(pos, dtype=float64, copy=False)
# relative position between mag and obs
Expand Down
2 changes: 1 addition & 1 deletion magpylib/_lib/fields/Current_CircularLoop.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
# page at https://www.github.com/magpylib/magpylib/issues.
# -------------------------------------------------------------------------------

from numpy import sqrt, array, cos, sin, NaN
from numpy import sqrt, array, NaN, cos, sin
from magpylib._lib.mathLib import getPhi, ellipticK, ellipticE
from warnings import warn

Expand Down

0 comments on commit 8ab6c31

Please sign in to comment.