Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 180a34f

Browse files
committedAug 2, 2023
doku
1 parent 0ad604a commit 180a34f

7 files changed

+300
-178
lines changed
 

‎docs/_pages/docu/docu_magpylib.md

+121-174
Original file line numberDiff line numberDiff line change
@@ -632,20 +632,16 @@ The tutorial {ref}`gallery-tutorial-paths` shows intuative good practice example
632632
<!-- ################################################################## -->
633633
<!-- ################################################################## -->
634634
<!-- ################################################################## -->
635-
636-
637635
<br/><br/>
638636
<hr style="border:3px solid gray">
639637

640-
(docu-direct-interface)=
641-
(docu-field-comp-core)=
642638
(docu-field-computation)=
643639
# Field Computation
644640

645-
Magnetic field computation is the central functionality of Magpylib. It evolves about the two functions
641+
Magnetic field computation is the central functionality of Magpylib. It evolves about the two top-level functions
646642

647643
::::{grid}
648-
:gutter: 2
644+
:gutter: 4
649645

650646
:::{grid-item}
651647
:columns: 1
@@ -668,7 +664,7 @@ Magnetic field computation is the central functionality of Magpylib. It evolves
668664
:::{grid-item-card}
669665
:shadow: none
670666
:columns: 10
671-
<span style="color: orange">**getH(**</span>`sources`, `observers`, `squeeze=True`, `pixel_agg=None`, `output="ndarray"`<span style="color: orange">**)**</span> computes the H-field seen by `observers` generated by `sources`.
667+
<span style="color: orange">**getH(**</span>`sources`, `observers`, `squeeze=True`, `pixel_agg=None`, `output="ndarray"`<span style="color: orange">**)**</span>
672668
:::
673669

674670
:::{grid-item}
@@ -677,225 +673,176 @@ Magnetic field computation is the central functionality of Magpylib. It evolves
677673

678674
::::
679675

680-
which compute the magnetic field seen by `observers` in their local coordinates generated by `sources`.
681-
682-
The argument `observers` can be an array_like of position vectors with shape $(n_1,n_2,n_3,...,3)$, any Magpylib **observer object** or a flat list thereof.
683-
684-
The output of a field computation `getB(sources, observers)` is a Numpy ndarray (alternatively a Pandas DataFrame, see below) 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 sensors, `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)$.
685-
686-
With `squeeze=True` the output is squeezed, i.e. all axes of length 1 in the output (e.g. only a single source) are eliminated.
687-
688-
With the argument `pixel_agg` a compatible numpy aggregator function like "min" or "mean" is applied to the observer output values. For example, with `pixel_agg="mean"` the mean field measured at all observer points is returned. Only with this option it is possible to supply `getB` and `getH` with observers that have different pixel shapes.
689-
690-
With `output` it is possible to choose the output format. Options are "ndarray" (returns a numpy array) and "dataframe" (returns a 2D-table pandas DataFrame).
676+
which 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.
691677

678+
::::{grid}
679+
:gutter: 5
692680

693-
## Direct interface
681+
:::{grid-item}
682+
:columns: 2
683+
:::
694684

695-
## Core
685+
:::{grid-item}
686+
:columns: 8
687+
```python
688+
import magpylib as magpy
696689

697-
T
698-
<!--
699-
The output of a field computation `getB(sources, observers)` is a Numpy ndarray (alternatively a Pandas DataFrame, see below) 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 sensors, `n1,n2,n3,...` the sensor pixel shape or the shape of the observer position vector input and `3` the three magnetic field components $(B_x, B_y, B_z)$.
690+
# define source and observer
691+
loop = magpy.current.Loop(current=1, diameter=1)
692+
sens = magpy.Sensor()
700693

701-
**Example 1:** As expressed by the old v2 slogan *"The magnetic field is only three lines of code away"*, this example demonstrates the most fundamental field computation:
694+
# compute field
695+
B = magpy.getB(loop, sens)
702696

703-
```{code-cell} ipython3
704-
import magpylib as magpy
705-
loop = magpy.current.Loop(current=1, diameter=2)
706-
B = magpy.getB(loop, (1,2,3))
707697
print(B)
698+
# --> [0. 0. 1.2566]
708699
```
700+
:::
701+
::::
709702

710-
**Example 2:** When handed with multiple observer positions, `getB` and `getH` will return the field in the shape of the observer input. In the following example, B- and H-field of a cuboid magnet are computed on a position grid, and then displayed using Matplotlib:
703+
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)$.
711704

712-
```{code-cell} ipython3
713-
import numpy as np
714-
import matplotlib.pyplot as plt
715-
import magpylib as magpy
705+
With `squeeze=True` all axes of length 1 in the output (e.g. only a single source) are eliminated.
716706

717-
fig, [ax1,ax2] = plt.subplots(1, 2, figsize=(10,5))
707+
With `pixel_agg` one can select a compatible numpy aggregator function (e.g. `"min"`, `"mean"`) that is applied to the output. For example, with `pixel_agg="mean"` the mean field of all observer points is returned. Only with this option it is possible to supply `getB` and `getH` with multiple observers that have different pixel shapes.
718708

719-
# create an observer grid in the xz-symmetry plane
720-
ts = np.linspace(-3, 3, 30)
721-
grid = np.array([[(x,0,z) for x in ts] for z in ts])
709+
With `output` it is possible to choose the output format. Options are `"ndarray"` (returns a numpy array) and `"dataframe"` (returns a 2D-table pandas DataFrame).
722710

723-
# compute B- and H-fields of a cuboid magnet on the grid
724-
cube = magpy.magnet.Cuboid(magnetization=(500,0,500), dimension=(2,2,2))
725-
B = cube.getB(grid)
726-
H = cube.getH(grid)
711+
```{note}
712+
Magpylib collects all inputs (object parameters), and vectorizes them for the computation which reduces the computation time dramatically for large inputs.
727713
728-
# display field with Pyplot
729-
ax1.streamplot(grid[:,:,0], grid[:,:,2], B[:,:,0], B[:,:,2], density=2,
730-
color=np.log(np.linalg.norm(B, axis=2)), linewidth=1, cmap='autumn')
714+
Try to make all field computations with as few calls to `getB` and `getH` as possible. Avoid Python loops at all costs!
715+
```
731716

732-
ax2.streamplot(grid[:,:,0], grid[:,:,2], H[:,:,0], H[:,:,2], density=2,
733-
color=np.log(np.linalg.norm(B, axis=2)), linewidth=1, cmap='winter')
717+
The tutorial {ref}`gallery-tutorial-field-computation` shows good practices with Magpylib field computation.
734718

735-
# outline magnet boundary
736-
for ax in [ax1,ax2]:
737-
ax.plot([1,1,-1,-1,1], [1,-1,-1,1,1], 'k--')
738719

739-
plt.tight_layout()
740-
plt.show()
741-
```
720+
(docu-direct-interface)=
721+
## Direct interface
742722

743-
**Example 3:** The following example code shows how the field in a position system is computed with a sensor object. Both, magnet and sensor are moving. The 3D system and the field along the path are displayed with Plotly:
723+
Users can bypass the object oriented functionality of Magpylib and instead compute the field for n given parameter sets. This is achieved by providing the following inputs to the top level functions `getB` and `getH`,
744724

745-
```{code-cell} ipython3
746-
import numpy as np
747-
import plotly.graph_objects as go
748-
import magpylib as magpy
725+
1. `sources`: a string denoting the source type
726+
2. `observers`: array_like of shape (3,) or (n,3) giving the observer positions
727+
3. `kwargs`: a dictionary with inputs of shape (x,) or (n,x)
749728

750-
# reset defaults set in previous example
751-
magpy.defaults.reset()
729+
The allowed values for `sources` are similar to the Magpylib source class names, e.g. `"Cuboid"`, see {ref}`docu-classes`. The `kwargs` must include all mandatory class-specific inputs. 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).
752730

753-
# setup plotly figure and subplots
754-
fig = go.Figure().set_subplots(rows=1, cols=2, specs=[[{"type": "scene"}, {"type": "xy"}]])
731+
::::{grid}
732+
:gutter: 5
755733

756-
# define sensor and source
757-
sensor = magpy.Sensor(pixel=[(0,0,-.2), (0,0,.2)], style_size=1.5)
758-
magnet = magpy.magnet.Cylinder(magnetization=(100,0,0), dimension=(1,2))
734+
:::{grid-item}
735+
:columns: 2
736+
:::
759737

760-
# define paths
761-
sensor.position = np.linspace((0,0,-3), (0,0,3), 40)
762-
magnet.position = (4,0,0)
763-
magnet.rotate_from_angax(angle=np.linspace(0, 300, 40)[1:], axis='z', anchor=0)
738+
:::{grid-item}
739+
:columns: 8
740+
```python
741+
import magpylib as magpy
764742

765-
# display system in 3D
766-
temp_fig = go.Figure()
767-
magpy.show(magnet, sensor, canvas=temp_fig, backend='plotly')
768-
fig.add_traces(temp_fig.data, rows=1, cols=1)
743+
# compute the cuboid field for 3 input instances
744+
B = magpy.getB(
745+
sources='Cuboid',
746+
observers=[(0,0,x) for x in range(3)],
747+
dimension=[(d,d,d) for d in range(1,4)],
748+
magnetization=(0,0,1000),
749+
)
769750

770-
# compute field and plot
771-
B = magpy.getB(magnet, sensor)
772-
for i,plab in enumerate(['pixel1', 'pixel2']):
773-
for j,lab in enumerate(['_Bx', '_By', '_Bz']):
774-
fig.add_trace(go.Scatter(x=np.arange(40), y=B[:,i,j], name=plab+lab))
751+
print(B.round())
752+
# --> [[ 0. 0. 667.]
753+
# [ 0. 0. 436.]
754+
# [ 0. 0. 307.]]
755+
```
756+
:::
757+
::::
775758

776-
fig.show()
759+
```{note}
760+
The direct interface is potentially faster than the object oriented one if users know how to generate the input array efficiently with numpy (e.g. `np.arange`, `np.linspace`, `np.tile`, `np.repeat`, ...).
777761
```
778762

779763

780-
**Example 4:** The last example demonstrates the most general form of a `getB` computation with multiple source and sensor inputs. Specifically, 3 sources, one with path length 11, and two sensors, each with pixel shape (4,5). Note that, when input objects have different path lengths, objects with shorter paths are treated as static beyond their path end.
764+
(docu-field-comp-core)=
765+
## Core interface
781766

782-
```{code-cell} ipython3
783-
import magpylib as magpy
767+
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,
784768

785-
# 3 sources, one with length 11 path
786-
pos_path = [(i,0,1) for i in range(-1,1)]
787-
source1 = magpy.misc.Dipole(moment=(0,0,100), position=pos_path)
788-
source2 = magpy.current.Loop(current=10, diameter=3)
789-
source3 = source1 + source2
769+
::::{grid} 1
770+
:gutter: 1
790771

791-
# 2 observers, each with 4x5 pixel
792-
pixel = [[[(i,j,0)] for i in range(4)] for j in range(5)]
793-
sensor1 = magpy.Sensor(pixel=pixel, position=(-1,0,-1))
794-
sensor2 = sensor1.copy().move((2,0,0))
772+
:::{grid-item}
773+
<span style="color: orange">**current_line_field(**</span> `field`, `observers`, `current`, `segment_start`, `segment_end`<span style="color: orange">**)**</span>
774+
:::
775+
:::{grid-item}
776+
<span style="color: orange">**current_loop_field(**</span> `field`, `observers`, `current`, `diameter`<span style="color: orange">**)**</span>
777+
:::
778+
:::{grid-item}
779+
<span style="color: orange">**magnet_cuboid_field(**</span> `field`, `observers`, `magnetization`, `dimension`<span style="color: orange">**)**</span>
780+
:::
781+
:::{grid-item}
782+
<span style="color: orange">**magnet_cylinder_field(**</span> `field`, `observers`, `magnetization`, `dimension`<span style="color: orange">**)**</span>
783+
:::
784+
:::{grid-item}
785+
<span style="color: orange">**magnet_cylinder_segment_field(**</span> `field`, `observers`, `magnetization`, `dimension`<span style="color: orange">**)**</span>
786+
:::
787+
:::{grid-item}
788+
<span style="color: orange">**magnet_sphere_field(**</span> `field`, `observers`, `magnetization`, `diameter`<span style="color: orange">**)**</span>
789+
:::
790+
:::{grid-item}
791+
<span style="color: orange">**magnet_tetrahedron_field(**</span> `field`, `observers`, `magnetization`, `vertices`<span style="color: orange">**)**</span>
792+
:::
793+
:::{grid-item}
794+
<span style="color: orange">**dipole_field(**</span> `field`, `observers`, `moment`<span style="color: orange">**)**</span>
795+
:::
796+
:::{grid-item}
797+
<span style="color: orange">**triangle_field(**</span> `field`, `observers`, `magnetization`, `vertices`<span style="color: orange">**)**</span>
798+
:::
799+
::::
795800

796-
sources = [source1, source2, source3]
797-
sensors = [sensor1, sensor2]
798-
# compute field
799-
B = magpy.getB(sources, sensors)
800-
print(B.shape)
801-
```
801+
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.
802802

803+
::::{grid}
804+
:gutter: 5
803805

804-
Instead of a Numpy `ndarray`, the field computation can also return a [pandas](https://pandas.pydata.org/).[dataframe](https://pandas.pydata.org/docs/user_guide/dsintro.html#dataframe) using the `output='dataframe'` kwarg.
806+
:::{grid-item}
807+
:columns: 2
808+
:::
805809

806-
```{code-cell} ipython3
810+
:::{grid-item}
811+
:columns: 8
812+
```python
807813
import numpy as np
808814
import magpylib as magpy
809815

810-
cube = magpy.magnet.Cuboid(
811-
magnetization=(0, 0, 1000),
812-
dimension=(1, 1, 1),
813-
style_label='cube'
814-
)
815-
loop = magpy.current.Loop(
816-
current=200,
817-
diameter=2,
818-
style_label='loop',
819-
)
820-
sens1 = magpy.Sensor(
821-
pixel=[(0,0,0), (.5,0,0)],
822-
position=np.linspace((-4, 0, 2), (4, 0, 2), 30),
823-
style_label='sens1'
824-
)
825-
sens2 = sens1.copy(style_label='sens2').move((0,0,1))
826-
827-
B_as_df = magpy.getB(
828-
[cube, loop],
829-
[sens1, sens2],
830-
output='dataframe',
831-
)
832-
833-
B_as_df
834-
```
835-
816+
# prepare input
817+
mag = np.array([(1000,0,0)]*3)
818+
dim = np.array([(1,2)]*3)
819+
obs = np.array([(0,0,0)]*3)
836820

837-
Plotting libraries such as [plotly](https://plotly.com/python/plotly-express/) or [seaborn](https://seaborn.pydata.org/introduction.html) can take advantage of this feature, as they can deal with `dataframes` directly.
821+
# compute field with core functions
822+
B = magpy.core.magnet_cylinder_field('B', obs, mag, dim)
838823

839-
```{code-cell} ipython3
840-
import plotly.express as px
841-
fig = px.line(
842-
B_as_df,
843-
x="path",
844-
y="Bx",
845-
color="pixel",
846-
line_group="source",
847-
facet_col="source",
848-
symbol="sensor",
849-
)
850-
fig.show()
824+
print(B.round())
825+
# --> [[553. 0. 0.]
826+
# [553. 0. 0.]
827+
# [553. 0. 0.]]
851828
```
829+
:::
830+
::::
852831

853832

854-
In terms of **performance** it must be noted that Magpylib automatically vectorizes all computations when `getB` and `getH` are called. This reduces the computation time dramatically for large inputs. For maximal performance try to make all field computations with as few calls to `getB` and `getH` as possible.
855-
856-
(intro-direct-interface)=
857-
858-
## Direct interface and core
859-
860-
The **direct interface** allows users to bypass the object oriented functionality of Magpylib. The magnetic field is computed for a set of $n$ arbitrary input instances by providing the top level functions `getB` and `getH` with
861-
862-
1. `sources`: a string denoting the source type
863-
2. `observers`: array_like of shape (3,) or (n,3) giving the positions
864-
3. `kwargs`: a dictionary with array_likes of shape (x,) or (n,x) for all other inputs
865-
866-
All "scalar" inputs of shape (x,) are automatically tiled up to shape (n,x), and for every of the $n$ given instances the field is computed and returned with shape (n,3). The allowed source types are similar to the Magpylib source class names (see {ref}`intro-magpylib-objects`), and the required dictionary inputs are the respective class inputs.
867-
868-
In the following example we compute the cuboid field for 5 input instances, each with different position and orientation and similar magnetization:
869-
870-
```{code-cell} ipython3
871-
import magpylib as magpy
833+
## Field computation workflow
872834

873-
B = magpy.getB(
874-
sources='Cuboid',
875-
observers=[(0,0,x) for x in range(5)],
876-
dimension=[(d,d,d) for d in range(1,6)],
877-
magnetization=(0,0,1000),
878-
)
835+
![](../../_static/images/docu_field_comp_flow.png)
879836

880-
print(B)
881-
```
837+
## Superposition
882838

839+
<!--
883840
884-
The direct interface is convenient for users who work with complex inputs or favor a more functional programming paradigm. It is typically faster than the object oriented interface, but it also requires that users know how to generate the inputs efficiently with numpy (e.g. `np.arange`, `np.linspace`, `np.tile`, `np.repeat`, ...).
885841
886-
At the heart of Magpylib lies a set of **core functions** that are our implementations of the analytical field expressions, see {ref}`physcomp`. For users who are not interested in the position/orientation interface, the `magpylib.core` subpackage gives direct access to these functions. Inputs are ndarrays of shape (n,x). Details can be found in the respective function docstrings.
887842
888-
```{code-cell} ipython3
889-
import numpy as np
890-
import magpylib as magpy
891843
892-
mag = np.array([(100,0,0)]*5)
893-
dim = np.array([(1,2,3,45,90)]*5)
894-
obs = np.array([(0,0,0)]*5)
895844
896-
B = magpy.core.magnet_cylinder_segment_field('B', obs, mag, dim)
897-
print(B)
898-
```
845+
(intro-direct-interface)=
899846
900847
901848
(examples-complex-forms)=

‎docs/_pages/docu/docu_physics.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ TODO: explain remanence VS magnetization
1717

1818
(phys-remanence)=
1919

20-
(physcomp)=
21-
2220
# Physics and Computation
2321

2422
## When can you use Magpylib ?
25-
The expressions used in Magpylib describe perfectly homogeneous magnets, surface charges, and line currents with natural boundary conditions. Magpylib is at its best when dealing with static air-coils (no eddy currents, no soft-magnetic cores) and high grade permanent magnets (Ferrite, NdFeB, SmCo or similar materials). When **magnet** permeabilities are below $\mu_r < 1.1$ the error typically undercuts few % (long magnet shapes are better, large distance from magnet is better). Demagnetization factors are not included. The line **current** solutions give the exact same field as outside of a wire that carries a homogeneous current. For more details check out the :ref:`physComp` section.
23+
The expressions used in Magpylib describe perfectly homogeneous magnets, surface charges, and line currents with natural boundary conditions. Magpylib is at its best when dealing with static air-coils (no eddy currents, no soft-magnetic cores) and high grade permanent magnets (Ferrite, NdFeB, SmCo or similar materials). When **magnet** permeabilities are below $\mu_r < 1.1$ the error typically undercuts few % (long magnet shapes are better, large distance from magnet is better). Demagnetization factors are not included. The line **current** solutions give the exact same field as outside of a wire that carries a homogeneous current. For more details check out the :ref:`docu-physics` section.
2624

2725
## The analytical solutions
2826

‎docs/_pages/gallery/gallery_index.md

+8
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,12 @@ Notice that most examples use interactive notebooks via [sphinx-thebe](https://
143143
:img-bottom: ../../_static/images/gallery_icon_WIP.png
144144
:::
145145

146+
:::{grid-item-card} Field Computation
147+
:text-align: center
148+
:link: gallery-tutorial-field-computation
149+
:link-type: ref
150+
:link-alt: link to example
151+
:img-bottom: ../../_static/images/gallery_icon_WIP.png
152+
:::
153+
146154
::::
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
jupytext:
3+
text_representation:
4+
extension: .md
5+
format_name: myst
6+
format_version: 0.13
7+
jupytext_version: 1.14.5
8+
kernelspec:
9+
display_name: Python 3
10+
language: python
11+
name: python3
12+
---
13+
14+
(gallery-tutorial-field-computation)=
15+
16+
# Field Computation
17+
18+
19+
**Example 1:** As expressed by the old v2 slogan *"The magnetic field is only three lines of code away"*, this example demonstrates the most fundamental field computation:
20+
21+
```{code-cell} ipython3
22+
import magpylib as magpy
23+
loop = magpy.current.Loop(current=1, diameter=2)
24+
B = magpy.getB(loop, (1,2,3))
25+
print(B)
26+
```
27+
28+
**Example 2:** When handed with multiple observer positions, `getB` and `getH` will return the field in the shape of the observer input. In the following example, B- and H-field of a cuboid magnet are computed on a position grid, and then displayed using Matplotlib:
29+
30+
```{code-cell} ipython3
31+
import numpy as np
32+
import matplotlib.pyplot as plt
33+
import magpylib as magpy
34+
35+
fig, [ax1,ax2] = plt.subplots(1, 2, figsize=(10,5))
36+
37+
# create an observer grid in the xz-symmetry plane
38+
ts = np.linspace(-3, 3, 30)
39+
grid = np.array([[(x,0,z) for x in ts] for z in ts])
40+
41+
# compute B- and H-fields of a cuboid magnet on the grid
42+
cube = magpy.magnet.Cuboid(magnetization=(500,0,500), dimension=(2,2,2))
43+
B = cube.getB(grid)
44+
H = cube.getH(grid)
45+
46+
# display field with Pyplot
47+
ax1.streamplot(grid[:,:,0], grid[:,:,2], B[:,:,0], B[:,:,2], density=2,
48+
color=np.log(np.linalg.norm(B, axis=2)), linewidth=1, cmap='autumn')
49+
50+
ax2.streamplot(grid[:,:,0], grid[:,:,2], H[:,:,0], H[:,:,2], density=2,
51+
color=np.log(np.linalg.norm(B, axis=2)), linewidth=1, cmap='winter')
52+
53+
# outline magnet boundary
54+
for ax in [ax1,ax2]:
55+
ax.plot([1,1,-1,-1,1], [1,-1,-1,1,1], 'k--')
56+
57+
plt.tight_layout()
58+
plt.show()
59+
```
60+
61+
**Example 3:** The following example code shows how the field in a position system is computed with a sensor object. Both, magnet and sensor are moving. The 3D system and the field along the path are displayed with Plotly:
62+
63+
```{code-cell} ipython3
64+
import numpy as np
65+
import plotly.graph_objects as go
66+
import magpylib as magpy
67+
68+
# reset defaults set in previous example
69+
magpy.defaults.reset()
70+
71+
# setup plotly figure and subplots
72+
fig = go.Figure().set_subplots(rows=1, cols=2, specs=[[{"type": "scene"}, {"type": "xy"}]])
73+
74+
# define sensor and source
75+
sensor = magpy.Sensor(pixel=[(0,0,-.2), (0,0,.2)], style_size=1.5)
76+
magnet = magpy.magnet.Cylinder(magnetization=(100,0,0), dimension=(1,2))
77+
78+
# define paths
79+
sensor.position = np.linspace((0,0,-3), (0,0,3), 40)
80+
magnet.position = (4,0,0)
81+
magnet.rotate_from_angax(angle=np.linspace(0, 300, 40)[1:], axis='z', anchor=0)
82+
83+
# display system in 3D
84+
temp_fig = go.Figure()
85+
magpy.show(magnet, sensor, canvas=temp_fig, backend='plotly')
86+
fig.add_traces(temp_fig.data, rows=1, cols=1)
87+
88+
# compute field and plot
89+
B = magpy.getB(magnet, sensor)
90+
for i,plab in enumerate(['pixel1', 'pixel2']):
91+
for j,lab in enumerate(['_Bx', '_By', '_Bz']):
92+
fig.add_trace(go.Scatter(x=np.arange(40), y=B[:,i,j], name=plab+lab))
93+
94+
fig.show()
95+
```
96+
97+
98+
**Example 4:** The last example demonstrates the most general form of a `getB` computation with multiple source and sensor inputs. Specifically, 3 sources, one with path length 11, and two sensors, each with pixel shape (4,5). Note that, when input objects have different path lengths, objects with shorter paths are treated as static beyond their path end.
99+
100+
```{code-cell} ipython3
101+
import magpylib as magpy
102+
103+
# 3 sources, one with length 11 path
104+
pos_path = [(i,0,1) for i in range(-1,1)]
105+
source1 = magpy.misc.Dipole(moment=(0,0,100), position=pos_path)
106+
source2 = magpy.current.Loop(current=10, diameter=3)
107+
source3 = source1 + source2
108+
109+
# 2 observers, each with 4x5 pixel
110+
pixel = [[[(i,j,0)] for i in range(4)] for j in range(5)]
111+
sensor1 = magpy.Sensor(pixel=pixel, position=(-1,0,-1))
112+
sensor2 = sensor1.copy().move((2,0,0))
113+
114+
sources = [source1, source2, source3]
115+
sensors = [sensor1, sensor2]
116+
# compute field
117+
B = magpy.getB(sources, sensors)
118+
print(B.shape)
119+
```
120+
121+
122+
Instead of a Numpy `ndarray`, the field computation can also return a [pandas](https://pandas.pydata.org/).[dataframe](https://pandas.pydata.org/docs/user_guide/dsintro.html#dataframe) using the `output='dataframe'` kwarg.
123+
124+
```{code-cell} ipython3
125+
import numpy as np
126+
import magpylib as magpy
127+
128+
cube = magpy.magnet.Cuboid(
129+
magnetization=(0, 0, 1000),
130+
dimension=(1, 1, 1),
131+
style_label='cube'
132+
)
133+
loop = magpy.current.Loop(
134+
current=200,
135+
diameter=2,
136+
style_label='loop',
137+
)
138+
sens1 = magpy.Sensor(
139+
pixel=[(0,0,0), (.5,0,0)],
140+
position=np.linspace((-4, 0, 2), (4, 0, 2), 30),
141+
style_label='sens1'
142+
)
143+
sens2 = sens1.copy(style_label='sens2').move((0,0,1))
144+
145+
B_as_df = magpy.getB(
146+
[cube, loop],
147+
[sens1, sens2],
148+
output='dataframe',
149+
)
150+
151+
B_as_df
152+
```
153+
154+
155+
Plotting libraries such as [plotly](https://plotly.com/python/plotly-express/) or [seaborn](https://seaborn.pydata.org/introduction.html) can take advantage of this feature, as they can deal with `dataframes` directly.
156+
157+
```{code-cell} ipython3
158+
import plotly.express as px
159+
fig = px.line(
160+
B_as_df,
161+
x="path",
162+
y="Bx",
163+
color="pixel",
164+
line_group="source",
165+
facet_col="source",
166+
symbol="sensor",
167+
)
168+
fig.show()
169+
```
108 KB
Loading

‎docs/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ Magpylib |release| documentation
167167
***************************
168168
When can you use Magpylib ?
169169
***************************
170-
The expressions used in Magpylib describe perfectly homogeneous magnets, surface charges, and line currents with natural boundary conditions. Magpylib is at its best when dealing with static air-coils (no eddy currents, no soft-magnetic cores) and high grade permanent magnets (Ferrite, NdFeB, SmCo or similar materials). When **magnet** permeabilities are below $\mu_r < 1.1$ the error typically undercuts few % (long magnet shapes are better, large distance from magnet is better). Demagnetization factors are not included. The line **current** solutions give the exact same field as outside of a wire that carries a homogeneous current. For more details check out the :ref:`physComp` section.
170+
The expressions used in Magpylib describe perfectly homogeneous magnets, surface charges, and line currents with natural boundary conditions. Magpylib is at its best when dealing with static air-coils (no eddy currents, no soft-magnetic cores) and high grade permanent magnets (Ferrite, NdFeB, SmCo or similar materials). When **magnet** permeabilities are below $\mu_r < 1.1$ the error typically undercuts few % (long magnet shapes are better, large distance from magnet is better). Demagnetization factors are not included. The line **current** solutions give the exact same field as outside of a wire that carries a homogeneous current. For more details check out the :ref:`docu-physics section.
171171
172172
*****************************
173173
Installation and Dependencies

‎temp_data.npy

-928 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)
Please sign in to comment.