em_app package

Submodules

em_app.plotting module

This module contains functions for plotting magnetic field data.

em_app.plotting.plot_1d_field(coil_instance, field_component: str, axis: str = 'x', start_point: ndarray | None = None, end_point: ndarray | None = None, num_points: int = 100, plot_type: str = 'line', log_scale: bool = False, ax=None, title: str = '', xlabel: str = '', ylabel: str = '', **kwargs)[source]

Plots a vector field component along a 1D line.

em_app.plotting.plot_2d_field(coil_instance, field_component: str = 'norm', plane: str = 'xy', center: ndarray | None = None, normal: ndarray | None = None, size_a: float | None = None, size_b: float | None = None, num_points_a: int = 50, num_points_b: int = 50, plot_type: str = 'heatmap', ax=None, title: str = '', offset_from_center: float = 0.0, **kwargs)[source]

Plots a vector field on a 2D plane.

Parameters:
  • coil_instance – The coil object to calculate the field from.

  • field_component (str) – Component to plot (‘x’, ‘y’, ‘z’, or ‘norm’).

  • plane (str) – Plane to plot on (‘xy’, ‘yz’, or ‘xz’).

  • center (np.ndarray, optional) – Center point of the plot. Defaults to coil center.

  • normal (np.ndarray, optional) – Normal vector for custom plane.

  • size_a (float, optional) – Size along the first axis of the plane.

  • size_b (float, optional) – Size along the second axis of the plane.

  • num_points_a (int) – Grid points along first axis.

  • num_points_b (int) – Grid points along second axis.

  • plot_type (str) – Type of plot (‘heatmap’, ‘quiver’, ‘streamline’).

  • ax (matplotlib.axes.Axes, optional) – Matplotlib axis to plot on.

  • title (str) – Plot title.

  • offset_from_center (float) – Offset from the center along the normal.

  • **kwargs – Additional arguments passed to the plotting function.

em_app.plotting.plot_field_vectors_3d(coil_instance, num_points_a: int = 10, num_points_b: int = 10, num_points_c: int = 10, title: str = '', ax=None, **kwargs)[source]

Generates a 3D quiver plot of the magnetic field vectors on a grid around the coil.

This method automatically creates a grid of field points based on the coil’s dimensions and then calculates and plots the magnetic field vectors at these points.

Parameters:
  • coil_instance (Coil) – An instance of a Coil subclass.

  • num_points_a (int) – Number of grid points along the x-dimension.

  • num_points_b (int) – Number of grid points along the y-dimension.

  • num_points_c (int) – Number of grid points along the z-dimension.

  • title (str, optional) – The title of the plot. Defaults to an auto-generated title.

  • ax (matplotlib.axes.Axes3D, optional) – The 3D axis to plot on. If None, a new figure is created.

  • **kwargs – Additional keyword arguments for the ax.quiver function.

em_app.solvers module

class em_app.solvers.Backend(value)[source]

Bases: str, Enum

C = 'c'
CPP = 'cpp'
CPP_V2 = 'cpp_v2'
MPI = 'mpi'
PYTHON = 'python'
em_app.solvers.calculate_b_field(coil_instance, field_points, backend=Backend.PYTHON)[source]

Calculates the magnetic field generated by a coil at a set of field points using the Biot-Savart law.

Parameters:
  • coil_instance (Coil) – An instance of a Coil subclass.

  • of (field_points (np.ndarray or np.ndarray) – mtf.MultivariateTaylorFunction): The points (x, y, z) where the magnetic field should be calculated. Can be a (M, 3) NumPy array of numbers or MTF objects.

  • backend (Backend or str, optional) – The backend to use for the calculation. Defaults to Backend.PYTHON.

Returns:

A VectorField object containing the field points and the

calculated FieldVector objects.

Return type:

VectorField

em_app.solvers.mpi_biot_savart(element_centers, element_lengths, element_directions, field_points, order=None)[source]

Parallel Biot-Savart calculation using mpi4py with element inputs.

Computes the magnetic field in parallel using MPI (mpi4py library). This function distributes the calculation of the magnetic field at different field points across multiple MPI processes to speed up computation.

Note

  • Requires mpi4py to be installed. If not installed, it will raise an ImportError.

  • Must be run in an MPI environment (e.g., using mpiexec or mpirun).

  • Input arrays element_centers, element_lengths, and element_directions are assumed to be the complete datasets and are broadcasted to all MPI processes.

  • field_points are distributed among processes. The result is gathered on rank 0.

Parameters:
  • element_centers (numpy.ndarray) – (N, 3) array of center coordinates of current elements. (Broadcasted to all MPI processes).

  • element_lengths (numpy.ndarray) – (N,) array of lengths of current elements (dl). (Broadcasted to all MPI processes).

  • element_directions (numpy.ndarray) – (N, 3) array of unit vectors for current directions. (Broadcasted to all MPI processes).

  • field_points (numpy.ndarray) – (M, 3) array of field point coordinates. (Distributed across MPI processes).

Returns:

On MPI rank 0: (M, 3) array of magnetic field vectors at each field point. On MPI ranks > 0: None.

Return type:

numpy.ndarray or None

Raises:

ImportError – if mpi4py is not installed.

Example (Run in MPI environment, e.g.,

mpiexec -n 4 python your_script.py):

>>> import numpy as np
>>> from applications.em.biot_savart import mpi_biot_savart
>>> element_centers = np.array([[0, 0, 0], [1, 0, 0]])
>>> element_lengths = np.array([0.1, 0.1])
>>> element_directions = np.array([[1, 0, 0], [0, 1, 0]])
>>> # More field points for MPI to distribute
>>> field_points = np.array(
...     [[0, 1, 0], [1, 1, 0], [2, 1, 0], [3, 1, 0]]
... )
>>> B_field = mpi_biot_savart(
...     element_centers,
...     element_lengths,
...     element_directions,
...     field_points,
... )
>>> if MPI.COMM_WORLD.Get_rank() == 0: # Rank 0 has the full result
>>>     print(B_field)
em_app.solvers.numpy_biot_savart(element_centers, element_lengths, element_directions, field_points, order=None)[source]

NumPy vectorized Biot-Savart calculation using element inputs.

Calculates the magnetic field at specified field points due to a set of current elements, using NumPy vectorization for efficiency. This function is designed for serial (single-processor) execution and takes element-based descriptions of the current source.

Parameters:
  • element_centers (numpy.ndarray) – (N, 3) array of center coordinates of current elements. Each row represents the (x, y, z) coordinates of the center of a current element.

  • element_lengths (numpy.ndarray) – (N,) array of lengths of current elements (dl). Each element represents the length of the corresponding current element.

  • element_directions (numpy.ndarray) – (N, 3) array of unit vectors representing the direction of current flow for each element. Each row is a unit vector.

  • field_points (numpy.ndarray) – (M, 3) array of field point coordinates. Each row represents the (x, y, z) coordinates where the magnetic field is to be calculated.

Returns:

(M, 3) array of magnetic field vectors at each field

point. Each row is a vector representing the (Bx, By, Bz) components of the magnetic field at the corresponding field point.

Return type:

numpy.ndarray

Raises:

ValueError – If input arrays do not have the expected dimensions or shapes.

Example

>>> element_centers = np.array([[0, 0, 0], [1, 0, 0]])
>>> element_lengths = np.array([0.1, 0.1])
>>> element_directions = np.array([[1, 0, 0], [0, 1, 0]])
>>> field_points = np.array([[0, 1, 0], [1, 1, 0]])
>>> B_field = numpy_biot_savart(
...     element_centers,
...     element_lengths,
...     element_directions,
...     field_points,
... )
>>> print(B_field)
[[ 0.00000000e+00  0.00000000e+00  1.00000000e-08]
 [ 0.00000000e+00  0.00000000e+00  5.00000000e-09]]
em_app.solvers.serial_biot_savart(element_centers, element_lengths, element_directions, field_points, order=None, backend=Backend.PYTHON)[source]

Serial Biot-Savart calculation with element inputs.

Computes the magnetic field serially (non-parallel), taking current element center points, lengths, and directions as input. This function is suitable for single-processor execution and serves as a serial counterpart to the mpi_biot_savart function.

Parameters:
  • element_centers (numpy.ndarray) – (N, 3) array of center coordinates of current elements.

  • element_lengths (numpy.ndarray) – (N,) array of lengths of current elements (dl).

  • element_directions (numpy.ndarray) – (N, 3) array of unit vectors for current directions.

  • field_points (numpy.ndarray) – (M, 3) array of field point coordinates.

  • order (int, optional) – The maximum order of the Taylor series to compute. If None, the global max order is used. Defaults to None.

Returns:

(M, 3) array of magnetic field vectors at each field

point.

Return type:

numpy.ndarray

Example

>>> element_centers = np.array([[0, 0, 0], [1, 0, 0]])
>>> element_lengths = np.array([0.1, 0.1])
>>> element_directions = np.array([[1, 0, 0], [0, 1, 0]])
>>> field_points = np.array([[0, 1, 0], [1, 1, 0]])
>>> B_field = serial_biot_savart(
...     element_centers,
...     element_lengths,
...     element_directions,
...     field_points,
...     order=0,
... )
>>> print(B_field)
[[ 0.00000000e+00  0.00000000e+00  1.00000000e-08]
 [ 0.00000000e+00  0.00000000e+00  5.00000000e-09]]

em_app.sources module

class em_app.sources.Coil(current, use_mtf_for_segments=True, wire_thickness=0.001)[source]

Bases: object

Base class for a current-carrying coil.

This class provides a common interface for different coil shapes, storing their properties (like current) and the discretized segments used for numerical calculations.

get_center_point() ndarray[source]

Calculates the approximate center point of the coil.

Returns:

A (3,) array representing the center of the coil.

Return type:

np.ndarray

get_max_size() ndarray[source]

Calculates the maximum extent of the coil in each dimension.

Returns:

A (3,) array of the maximum size of the coil

(width, height, depth).

Return type:

np.ndarray

get_segments()[source]

Returns the segments of the coil.

Returns:

A tuple containing:
  • segment_centers (np.ndarray): Array of MTF center points.

  • segment_lengths (np.ndarray): Array of MTF segment lengths.

  • segment_directions (np.ndarray): Array of MTF direction vectors.

Return type:

tuple

plot(ax=None, color='#B87333', num_interpolation_points=2, wire_thickness=None, show_axis=False)[source]

Plots the coil segments in a 3D matplotlib axis.

If a 3D axis is provided, the coil will be plotted on it. Otherwise, a new figure and a new 3D axis will be created.

Parameters:
  • ax (matplotlib.axes.Axes3D) – The 3D axis to plot on. Defaults to None.

  • color (str) – The color for the plotted segments. Defaults to a copper-like hex code.

  • num_interpolation_points (int) – The number of points to plot for each segment, including start and end points. This is only used when use_mtf_for_segments is True. Defaults to 2.

  • wire_thickness (float) – The thickness of the wire to plot. Defaults to the thickness specified at initialization.

  • show_axis (bool) – Whether to plot the central axis of the coil. Defaults to False.

class em_app.sources.RectangularCoil(current, p1, p2, p4, num_segments_per_side, use_mtf_for_segments=True, wire_thickness=0.001)[source]

Bases: Coil

Represents a rectangular current-carrying coil.

static generate_geometry(p1, p2, p4, num_segments_per_side, use_mtf_for_segments=True)[source]

(PRIVATE) Generates segments for a rectangular coil.

Parameters:
  • p1 (np.ndarray) – First corner of the rectangle.

  • p2 (np.ndarray) – Second corner, defining the first side from p1.

  • p4 (np.ndarray) – Fourth corner, defining the second side from p1.

  • num_segments_per_side (int) – Segments per side.

  • use_mtf_for_segments (bool) – Whether to use MTF for segments.

Returns:

A tuple containing:
  • segment_centers (np.ndarray): Array of MTF center points.

  • segment_lengths (np.ndarray): Array of segment lengths.

  • segment_directions (np.ndarray): Array of MTF direction vectors.

Return type:

tuple

class em_app.sources.RingCoil(current, radius, num_segments, center_point, axis_direction, use_mtf_for_segments=True, wire_thickness=0.001)[source]

Bases: Coil

Represents a circular current-carrying coil.

static generate_geometry(ring_radius, num_segments_ring, ring_center_point, ring_axis_direction, use_mtf_for_segments=True)[source]

(PRIVATE) Generates MTF representations for segments of a current ring.

This is a private helper function and should not be used directly.

Parameters:
  • ring_radius (float) – Radius of the current ring.

  • num_segments_ring (int) – Number of segments to discretize the ring into.

  • ring_center_point (numpy.ndarray) – (3,) array defining the center coordinates (x, y, z) of the ring.

  • ring_axis_direction (numpy.ndarray) – (3,) array defining the direction vector of the ring’s axis (normal to the plane of the ring).

Returns:

A tuple containing:
  • segment_representations (numpy.ndarray): (N,) array of MTFs or (N, 3) array of segment center points.

  • element_lengths_ring (numpy.ndarray): (N,) array of lengths of each ring segment (dl).

  • direction_vectors (numpy.ndarray): (N, 3) array of MTF direction vectors or NumPy direction vectors.

Return type:

tuple

class em_app.sources.StraightWire(current, start_point, end_point, num_segments=1, use_mtf_for_segments=True, wire_thickness=0.001)[source]

Bases: Coil

Represents a single straight current-carrying wire.

static generate_geometry(start_point, end_point, num_segments=1, use_mtf_for_segments=True)[source]

Discretizes the straight wire into segments.

em_app.vector_fields module

Vector and Vector Field representations.

This module provides classes for representing 3D vectors and vector fields, with support for numerical data and mtflib Multivariate Taylor Functions (MTFs). It includes classes like Vector, FieldVector, VectorField, and VectorFieldGrid.

class em_app.vector_fields.FieldVector(x, y, z)[source]

Bases: Vector

Represents a vector at a point in a field, with components that can be Multivariate Taylor Functions (MTFs).

curl()[source]

Calculates the curl of the B-field vector.

The curl of the B-field is given by the formula: $nabla times mathbf{B} = (frac{partial B_z}{partial y} - frac{partial B_y}{partial z}) mathbf{i} + (frac{partial B_x}{partial z} - frac{partial B_z}{partial x}) mathbf{j} + (frac{partial B_y}{partial x} - frac{partial B_x}{partial y}) mathbf{k}$

This method uses the derivative method from mtflib to compute the partial derivatives.

Returns:

A new FieldVector object representing the curl of the

field.

Return type:

FieldVector

divergence()[source]

Calculates the divergence of the B-field.

The divergence of a vector field is a scalar value given by the formula: $nabla cdot mathbf{B} = frac{partial B_x}{partial x} + frac{partial B_y}{partial y} + frac{partial B_z}{partial z}$

This method uses the derivative method from mtflib to compute the partial derivatives and then sums the resulting MTF objects.

Returns:

A single MTF representing the

scalar divergence of the field.

Return type:

mtf.MultivariateTaylorFunction

gradient()[source]

Calculates the Jacobian matrix of the B-field vector.

The gradient of a vector field is a 3x3 matrix where each element is the partial derivative of a component of B with respect to a spatial variable.

Returns:

A 3x3 array of MTFs representing the Jacobian matrix.

Return type:

np.ndarray

to_numpy_array()[source]

Converts the Bvec to a NumPy array by extracting the constant part of each component.

class em_app.vector_fields.Vector(*components)[source]

Bases: object

A generic class to represent a 3D vector. This class handles standard vector operations like addition, subtraction, scalar multiplication/division, dot product, and cross product.

cross(other)[source]

Calculates the cross product with another Vector object.

Parameters:

other (Vector) – The Vector object to take the cross product with.

Returns:

A new Vector object representing the resulting vector.

Return type:

Vector

dot(other)[source]

Calculates the dot product with another Vector object.

Parameters:

other (Vector) – The Vector object to take the dot product with.

Returns:

The scalar result of the

dot product.

Return type:

mtf.MultivariateTaylorFunction or float

classmethod from_array_of_vectors(array)[source]

Creates a NumPy array of Vector objects from a 2D NumPy array.

Parameters:

array (np.ndarray) – A NumPy array of shape (N, 3), where N is the number of vectors.

Returns:

A NumPy array of Vector objects.

Return type:

np.ndarray

is_mtf()[source]

Checks if any of the Vector’s components are MTF objects.

Returns:

True if any component is an MTF, False otherwise.

Return type:

bool

norm()[source]

Calculates the magnitude (L2-norm) of the vector.

Returns:

The scalar magnitude.

Return type:

float or mtf.MultivariateTaylorFunction

to_dataframe(column_names)[source]

Converts the Vector components into a pandas DataFrame.

This method is a helper for creating a clean, tabular representation of the vector, especially when components are MTF objects.

Parameters:

column_names (list of str) – A list of three strings to be used as the column names for the components.

Returns:

A DataFrame representing the vector’s components

and their coefficients if they are MTFs.

Return type:

pandas.DataFrame

to_numpy_array()[source]

Converts the vector to a NumPy array.

This method now handles components that are either numbers or Multivariate Taylor Function (MTF) objects. For MTFs, it extracts the constant part of the function.

class em_app.vector_fields.VectorField(vectors, field_points=None)[source]

Bases: object

A class to store a collection of FieldVector objects, representing a vector field at a set of discrete points in space.

This class can handle both numerical and MTF-based field data.

get_magnitude()[source]

Calculates and returns the magnitude of each B-vector in the field.

Returns:

A 1D NumPy array of the magnitudes.

Return type:

np.ndarray

max()[source]

Returns the maximum magnitude of the B-field vectors.

min()[source]

Returns the minimum magnitude of the B-field vectors.

quiver(dimension=3, title='Vector Field Quiver Plot', ax=None, **kwargs)[source]

Creates a 3D quiver plot of the vector field.

Parameters:
  • title (str, optional) – The title of the plot.

  • ax (matplotlib.axes.Axes, optional) – An existing 3D Axes object to plot on.

  • **kwargs – Additional keyword arguments passed to ax.quiver.

scatter(title='Vector Field Scatter Plot', ax=None, **kwargs)[source]

Creates a 3D scatter plot of the vector field with direction arrows. The color and length of the arrows represent the magnitude of the vectors. This method provides a way to visualize the raw vector field, where arrow lengths are proportional to the vector strength.

Parameters:
  • title (str, optional) – The title of the plot.

  • ax (matplotlib.axes.Axes, optional) – An existing 3D Axes object to plot on.

  • **kwargs – Additional keyword arguments passed to ax.quiver.

to_dataframe()[source]

Exports the field points and vector components to a pandas DataFrame.

Returns:

A DataFrame with columns

[‘x’, ‘y’, ‘z’, ‘vx’, ‘vy’, ‘vz’].

Return type:

pandas.DataFrame

class em_app.vector_fields.VectorFieldGrid(vectors, field_points, grid_shape, grid_axes)[source]

Bases: VectorField

A subclass of VectorField for data on a structured 1D, 2D, or 3D grid.

This class is designed to hold vector field data that is arranged on a structured grid. It stores grid metadata (shape and axes) to allow for easy reshaping of the data for grid-based analysis and plotting.

get_grid_points()[source]

Returns the field points reshaped into the grid dimensions.

Returns:

The field points as a grid. The shape will be

(*grid_shape, 3).

Return type:

np.ndarray

get_grid_vectors()[source]

Returns the B-field vectors reshaped into the grid dimensions.

Returns:

The B-field vectors as a grid. The shape will be

(*grid_shape, 3).

Return type:

np.ndarray