Unit Conversions#

In this tutorial we give an example of how to deal with magnetic units in python. Including converting between CGS and SI units.

To do this, we use mammos_units which is built on top of astropy.units, a package aimed at the astrophysics community for its unit converting functionality.

[15]:
import mammos_units as u

In mammos_units we use astropy.units.Quantity: the combination of a value and a unit. The most convenient way to create a Quantity is to multiply or divide a value by one of the built-in units. It works with scalars, sequences, and numpy arrays.

[16]:
length = 1 * u.meter
length
[16]:
$1 \; \mathrm{m}$

A quantity is composed of a value and a unit

[17]:
print(length.value)
print(length.unit)
1.0
m

Most units in mammos_units support adding prefix to the unit e.g. k for kilo.

[18]:
length = 1 * u.km
length
[18]:
$1 \; \mathrm{km}$

You can perform operations on quantities. Units remain and combine through the set of operations.

[19]:
time = 2 * u.s

velocity = length / time
velocity
[19]:
$0.5 \; \mathrm{\frac{km}{s}}$

It is simple to convert between CGS and SI units by using the .cgs and .si properties.

[20]:
velocity.si
[20]:
$500 \; \mathrm{\frac{m}{s}}$
[21]:
velocity.cgs
[21]:
$50000 \; \mathrm{\frac{cm}{s}}$

It is also possible to specify explicitly which units you wish to convert to.

[22]:
velocity.to(u.um / u.Gs)  # micrometer per gigasecond
[22]:
$5 \times 10^{17} \; \mathrm{\frac{\mu m}{Gs}}$

As mammos_units also work with numpy arrays.

[23]:
import numpy as np

a = np.array([1, 2, 3]) * u.m
b = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) * u.cm

display(a)
display(b)
$[1,~2,~3] \; \mathrm{m}$
$[[1,~2,~3],~ [4,~5,~6],~ [7,~8,~9]] \; \mathrm{cm}$

They keep the units even through complex operations.

[24]:
out = np.matmul(b, a)
out.si
[24]:
$[0.14,~0.32,~0.5] \; \mathrm{m^{2}}$

Magnetic units#

Here we show how to use magnetic units with astropy. Often in the magnetism community, a mix of CGS and SI units are used. Here, we show a convenient way of converting between the two.

Quantity Symbol

SI Units

cgs Units

Length \((x)\)

\(10^{-2} \, \text{m}\)

\(1 \, \text{cm}\)

Mass \((m)\)

\(10^{-3} \, \text{kg}\)

\(1 \, \text{g}\)

Force \((F)\)

\(10^{-5} \, \text{N}\)

\(1 \, \text{dyne}\)

Energy \((E)\)

\(10^{-7} \, \text{J}\)

\(1 \, \text{erg}\)

Magnetic Induction \((B)\)

\(10^{-4} \, \text{T}\)

\(1 \, \text{G}\)

Magnetic Field Strength \((H)\)

\(\frac{10^{-4}}{\mu_0} \, \text{Am}^{-1}\)

\(1 \, \text{Oe}\)

Magnetic Moment \((\mu)\)

\(10^{-3} \, \text{JT}^{-1}\) or \(\text{Am}^2\)

\(1 \, \text{erg G}^{-1}\) or emu

Magnetization \((M)\)

\(10^3 \, \text{Am}^{-1}\) or \(\text{JT}^{-1} \, \text{m}^{-3}\)

\(1 \, \text{Oe}\) or emu cm \(^{-3}\)

Magnetic Susceptibility \((\chi)\)

\(4\pi\) (dimensionless)

\(1 \, \text{emu cm}^{-3} \, \text{Oe}^{-1}\)

Molar Susceptibility \((\chi_m)\)

\(4\pi \times 10^{-6} \, \text{m}^3 \, \text{mol}^{-1}\)

\(1 \, \text{emu mol}^{-1} \, \text{Oe}^{-1}\)

Mass Susceptibility \((\chi_g)\)

\(4\pi \times 10^{-3} \, \text{m}^3 \, \text{kg}^{-1}\)

\(1 \, \text{emu g}^{-1} \, \text{Oe}^{-1}\)

Magnetic Flux \((\phi)\)

\(10^{-8} \, \text{Tm}^2\) or \(\text{Wb}\)

\(1 \, \text{G cm}^2\) or \(\text{Mx}\)

Demagnetization Factor (N)

\(0 < N < 1\)

\(0 < N < 4\pi\)

[25]:
# Initialize quantities in cgs units
length = 1 * u.cm
mass = 1 * u.g
force = 1 * u.dyn
energy = 1 * u.erg
magnetic_induction = 1 * u.G
magnetic_field_strength = 1 * u.Oe
magnetic_moment = 1 * u.erg * u.G**-1
magnetization = 1 * u.Oe
magnetic_flux = 1 * u.Mx

# Print the results in a table format using conversions in the f-string
print("| Quantity               | cgs Unit       | Converted SI Unit")
print("|------------------------|----------------|--------------------")
print(f"| Length                 | 1 cm           | {length.to(u.m):.2g}")
print(f"| Mass                   | 1 g            | {mass.to(u.kg):.2g}")
print(f"| Force                  | 1 dyne         | {force.to(u.N):.2g}")
print(f"| Energy                 | 1 erg          | {energy.to(u.J):.2g}")
print(f"| Magnetic Induction     | 1 G            | {magnetic_induction.to(u.T):.2g}")
print(f"| Magnetic Field Strength| 1 Oe           | {magnetic_field_strength.to(u.A / u.m):.2g}")
print(f"| Magnetic Moment        | 1 erg G^-1     | {magnetic_moment.to(u.J * u.T**-1):.2g}")
print(f"| Magnetization          | 1 emu cm^-3    | {magnetization.to(u.A / u.m):.2g}")
print(f"| Magnetic Flux          | 1 Mx           | {magnetic_flux.to(u.Wb):.2g}")
| Quantity               | cgs Unit       | Converted SI Unit
|------------------------|----------------|--------------------
| Length                 | 1 cm           | 0.01 m
| Mass                   | 1 g            | 0.001 kg
| Force                  | 1 dyne         | 1e-05 N
| Energy                 | 1 erg          | 1e-07 J
| Magnetic Induction     | 1 G            | 0.0001 T
| Magnetic Field Strength| 1 Oe           | 80 A / m
| Magnetic Moment        | 1 erg G^-1     | 0.001 J / T
| Magnetization          | 1 emu cm^-3    | 80 A / m
| Magnetic Flux          | 1 Mx           | 1e-08 Wb

There are multiple aliases for certain units.

[26]:
u.G == u.Gauss == u.gauss
[26]:
True

Here is a list of all Astropy units. mammos_units defines some additional magnetic units as documented here.

Equivalency#

The mammos_units also enables conversions of units with different equivalencies, e.g. temperature and energy. To use this we can create a variable with the relevant units of temperature and use the to function to convert to the relevant units with the relevant equivalency.

For example, we can convert the exchange interaction energy given in Kelvin to Joules. Because Kelvin and Joule cannot be decomposed into the same base SI units, we have to use the equivalencies argument.

[27]:
exchange = 4.15 * u.K
exchange.to(u.J, equivalencies=u.temperature_energy())
[27]:
$5.7296934 \times 10^{-23} \; \mathrm{J}$

We can also do this with magnetic units such as converting magnetic field between magnetic field strength \((\mathbf{H})\) and magnetic flux density \((\mathbf{B})\) using the relationship:

\[\mathbf{B} = \mu_r \mu_0 \mathbf{H}.\]

Where:

  • \(\mu_0\) is the vacuum permeability, a physical constant,

  • \(\mu_r\) is the relative permeability of the medium, a dimensionless quantity.

Without this conversion we can see that these two quantities cannot be converted between each other.

[28]:
H = 1 * u.Oe
H.to(u.G)
---------------------------------------------------------------------------
UnitConversionError                       Traceback (most recent call last)
Cell In[28], line 2
      1 H = 1 * u.Oe
----> 2 H.to(u.G)

File /srv/conda/envs/notebook/lib/python3.12/site-packages/astropy/units/quantity.py:931, in Quantity.to(self, unit, equivalencies, copy)
    927 unit = Unit(unit)
    928 if copy:
    929     # Avoid using to_value to ensure that we make a copy. We also
    930     # don't want to slow down this method (esp. the scalar case).
--> 931     value = self._to_value(unit, equivalencies)
    932 else:
    933     # to_value only copies if necessary
    934     value = self.to_value(unit, equivalencies)

File /srv/conda/envs/notebook/lib/python3.12/site-packages/astropy/units/quantity.py:884, in Quantity._to_value(self, unit, equivalencies)
    881     equivalencies = self._equivalencies
    882 if not self.dtype.names or isinstance(self.unit, StructuredUnit):
    883     # Standard path, let unit to do work.
--> 884     return self.unit.to(
    885         unit, self.view(np.ndarray), equivalencies=equivalencies
    886     )
    888 else:
    889     # The .to() method of a simple unit cannot convert a structured
    890     # dtype, so we work around it, by recursing.
    891     # TODO: deprecate this?
    892     # Convert simple to Structured on initialization?
    893     result = np.empty_like(self.view(np.ndarray))

File /srv/conda/envs/notebook/lib/python3.12/site-packages/astropy/units/core.py:1208, in UnitBase.to(self, other, value, equivalencies)
   1206     return UNITY
   1207 else:
-> 1208     return self.get_converter(Unit(other), equivalencies)(value)

File /srv/conda/envs/notebook/lib/python3.12/site-packages/astropy/units/core.py:1137, in UnitBase.get_converter(self, other, equivalencies)
   1134             else:
   1135                 return lambda v: b(converter(v))
-> 1137 raise exc

File /srv/conda/envs/notebook/lib/python3.12/site-packages/astropy/units/core.py:1120, in UnitBase.get_converter(self, other, equivalencies)
   1118 # if that doesn't work, maybe we can do it with equivalencies?
   1119 try:
-> 1120     return self._apply_equivalencies(
   1121         self, other, self._normalize_equivalencies(equivalencies)
   1122     )
   1123 except UnitsError as exc:
   1124     # Last hope: maybe other knows how to do it?
   1125     # We assume the equivalencies have the unit itself as first item.
   1126     # TODO: maybe better for other to have a `_back_converter` method?
   1127     if hasattr(other, "equivalencies"):

File /srv/conda/envs/notebook/lib/python3.12/site-packages/astropy/units/core.py:1071, in UnitBase._apply_equivalencies(self, unit, other, equivalencies)
   1068 unit_str = get_err_str(unit)
   1069 other_str = get_err_str(other)
-> 1071 raise UnitConversionError(f"{unit_str} and {other_str} are not convertible")

UnitConversionError: 'Oe' (magnetic field strength) and 'G' (magnetic flux density) are not convertible

However, we can introduce the magnetic_flux_field equivalency to solve this issue.

[29]:
H.to(u.G, equivalencies=u.magnetic_flux_field())
[29]:
$1 \; \mathrm{G}$

By default, it is calculated for free space i.e. a vacuum with \(\mu_r=1\). However, the magnetic_flux_field also accepts the relative permeability of the medium as an argument for the conversion.

[30]:
H.to(u.G, equivalencies=u.magnetic_flux_field(mu_r=0.9))
[30]:
$0.9 \; \mathrm{G}$

If we are doing multiple conversions then it may be worth enabling this equivalency for a set of lines as shown below. This will only turn on the equivalency for things within the with block.

[31]:
with u.set_enabled_equivalencies(u.magnetic_flux_field(mu_r=0.9)):
    B = H.to(u.G)
    display(B)
$0.9 \; \mathrm{G}$

If you wish to turn on the equivalency for all of your document then you can run the following command. We recommend doing this straight after you import mammos_units e.g.

[34]:
u.set_enabled_equivalencies(u.magnetic_flux_field())
[34]:
<astropy.units.core._UnitContext at 0x70296114a3f0>
[35]:
H.to(u.G)
[35]:
$1 \; \mathrm{G}$

We can now convert between SI and CGS using the equivalency.

[36]:
display(H)
display(H.to(u.G))
display(H.to(u.T))
display(H.to(u.A / u.m))
$1 \; \mathrm{Oe}$
$1 \; \mathrm{G}$
$0.0001 \; \mathrm{T}$
$79.577472 \; \mathrm{\frac{A}{m}}$

Equivalencies can also be used to convert other common units in magnetism.

The magnetic moment can be converted to magnetic induction by providing the volume of the respective counting unit.

In the case of formula unit

[37]:
magnetic_moment = 8 * u.mu_B / u.f_u

vol_per_fu = (5 * u.Angstrom) ** 3

magnetic_moment.to(u.T, equivalencies=u.moment_induction(vol_per_fu))
[37]:
$0.74586015 \; \mathrm{T}$
[38]:
magnetic_induction = 1 * u.T

magnetic_induction.to(u.mu_B / u.f_u, equivalencies=u.moment_induction(vol_per_fu))
[38]:
$10.725871 \; \mathrm{\frac{\mu_B}{\mathrm{f.u.}}}$
[39]:
magnetic_moment = 2 * u.mu_B / u.atom

vol_per_atom = (3 * u.Angstrom) ** 3

magnetic_moment.to(u.T, equivalencies=u.moment_induction(vol_per_atom))
[39]:
$0.86326406 \; \mathrm{T}$
[40]:
magnetic_induction = 1 * u.T

magnetic_induction.to(u.mu_B / u.atom, equivalencies=u.moment_induction(vol_per_atom))
[40]:
$2.3167882 \; \mathrm{\frac{\mu_B}{\mathrm{atom}}}$

We can also convert using other forms of induction.

[42]:
magnetic_induction = 10000 * u.G

magnetic_induction.to(u.mu_B / u.atom, equivalencies=u.moment_induction(vol_per_atom))
[42]:
$2.3167882 \; \mathrm{\frac{\mu_B}{\mathrm{atom}}}$

However, we cannot use multiple equivalencies at once and need to chain them.

[43]:
magnetic_field_strength = 10000 * u.Oe

magnetic_field_strength.to(u.T, equivalencies=u.magnetic_flux_field()).to(
    u.mu_B / u.atom, equivalencies=u.moment_induction(vol_per_atom)
)
[43]:
$2.3167882 \; \mathrm{\frac{\mu_B}{\mathrm{atom}}}$

A comment on emu#

emu is not a unit in the conventional manner and can have many different meanings depending on context.

Within magnetism emu can represent the magnetic moment

\[1\, \text{emu} = 1\, \frac{\text{erg}}{\text{G}}.\]

However, it can sometimes have dimensions

\[1\, \text{emu} = 1\, \text{cm}^3,\]

such as representing emu in magnetic susceptibility if defined as (emu cm \(^{-3}\)).