UnitHandler

Most quantities of interest in physics have units, which means that the numeric value of the quantity depends on which unit it is measured in. Different sets of units are relevant in different situations. For example is meter (m) a relevant unit for length in macroscopic problems, while Ångström (Å) is more relevant on atomic scales. However, computers work with unitless numbers, which means that any piece of code that relies on hard coded numeric values for physical constants implicitly force the user to work in the same set of units. This is unacceptable for a library such as TBTK that aims at allowing physicist with different preferences for units to use the library to implement their own calculations. It is also very useful if the library can supply such constants in whatever units the developer prefer. To solve these issues, TBTK provides a UnitHandler that allows the user to specify what units are natural to the problem at hands, and all numbers passed to TBTK functions are assumed to be given in these natural units.

The UnitHandler borrows its terminology from the SI standard for units. Not by forcing the user to work in SI units, but rather through a clear division of units into base units and derived units. To understand what this means, consider distances and times. These are quantities that are defined independently from each other and can be measured in for example meters (m) and seconds (s). In comparison, a velocity is a measure of distance per time and cannot be defined independently from these two quantities. Rather, velocity can be considered a quantity that is derived from the more fundamental quantities distance and time. In principle, there is no reason why a given quantity has to be considered more fundamental than any other, and it is perfectly valid to e.g. view time as a quantity derived from the more fundamental quantities distance and velocity. However, the fact remains that for the three quantities distance, time, and velocity, only two at a time can be defined independently from each other. Further, among all the quantities encountered in physics, only seven can be defined independently from each other. By fixing seven such quantities, a set of seven corresponding base units can be defined. All other units are considered derived units.

The UnitHandler defines the fundamental quantities to be temperature, time, length, energy, charge, and count (amount). This is the first point where the UnitHandler deviates from the SI system since the SI system does not define the units for energy and charge as base units, but instead the units for mass, current, and luminosity. Note in particular that the UnitHandler currently only defines base units for six different quantities. The missing quantity is due to an ambiguity regarding whether an angle should be considered a unitful or unitless quantity. Units for angle may therefore be added to the UnitHandler in the future. The decision to make the units for energy and charge base units, rather than mass and current as in the SI system, is based on a subjective perception of the former being more generally relevant in quantum mechanical calculations.

Next, the UnitHandler also deviates from the SI system by only fixing the base quantities rather than the base units. While e.g. the SI unit for length is meter (m), the UnitHandler allows the base unit for length to be set to a range of different units such as meter (m), millimeter (mm), nanometer (nm), Ångström (Å), etc. Similarly a range of different options are available for other quantities, such as for example Joule (J) and electronvolt (eV) for energy, and Coulomb (C) and elementary charge (e) for charge.

By default the base units are

Quantity | Default base unit | UnitHandler symbol |
---|---|---|

Temperature | K (Kelvin) | Temperature |

Time | s (seconds) | Time |

Length | m (meter) | Length |

Energy | eV (electron Volt) | Energy |

Charge | C (Coulomb) | Charge |

Count | pcs (pieces) | Count |

Further, the available base units are

Quantity | Available base units |
---|---|

Temperature | kK, K, mK, uK, nK |

Time | s, ms, us, ns, ps, fs, as |

Length | m, mm, um, nm, pm, fm, am, Ao |

Energy | GeV, MeV, keV, eV, meV, ueV, J |

Charge | kC, C, mC, uC, nC, pC, fC, aC, Te, Ge, Me, ke, e |

Count | pcs, mol |

Most of these units should be self-explanatory, with Gx, Mx, kx, mx, etc. corresponds to giga, mega, kilo, milli, etc. Further, Ao corresponds to Ångström (Å), while pcs corresponds to pieces. If further base units are wanted, please do not hesitate to request additions.

If base units other than the default base units are wanted, it is recommended to set these at the very start of a program. For example at the first line in the main routine. This avoids ambiguities that results from changing base units in the middle of execution. To for example set the base units to mK, ps, Å, meV, C, and mol, type

UnitHandler::setTemperatureUnit(UnitHandler::TemeratureUnit::mK);

UnitHandler::setTimeUnit(UnitHandler::TimeUnit::ps);

UnitHandler::setLengthUnit(UnitHandler::LengthUnit::Ao);

UnitHandler::setEnergyUnit(UnitHandler::EnergyUnit::meV);

UnitHandler::setChargeUnit(UnitHandler::ChargeUnit::C);

UnitHandler::setCountUnit(UnitHandler::CountUnit::mol);

It is common in physics to use natural units in which for example \(\hbar = c = 1\). Such natural units simplify equations and allows mental effort to be concentrated on the physical phenomena rather than numerical details. The same is true when implementing numerical calculations and it is for example common in tight-binding calculations to measure energy in units of some hopping parameter \(t = 1\), while the actual unitful value can be some arbitrary value such as \(t = 724meV\). In TBTK all function calls are performed in natural units, except for the UnitHandler calls that specifies the natural units. This means that if the natural energy unit is set to e.g. \(724meV\), an energy variable with say the value 1.2 that is passed to a function is internally interpreted by TBTK to have the unitful value \(1.2\times724meV\). However, note that this conversion is not necessarily done at the point where the function call is made and may be repeatedly done at later points of execution if the variable is stored internally. This is why it is important to not reconfigure the UnitHandler in the middle of a program since this introduces ambiguities.

The natural unit is also known as the scale of the problem, and the code required to specify the natural energy unit (scale) to be \(724meV\) is

//Set the energy base unit

UnitHandler::setEnergyUnit(UnitHandler::EnergyUnit::meV);

//Set the natural energy unit (scale)

UnitHandler::setEnergyScale(724);

To simplify the notation, these two function calls can be replaced by the single call

UnitHandler::setEnergyUnit(724, UnitHandler::EnergyUnit::meV);

The code for setting the other five natural units is similar, with the word 'Energy' exchanged for the relevant quantity.

For further simplification, it is also possible to set all six units at the same time using

UnitHandler::setScales({"1 C", "1 pcs", "1 eV", "1 m", "1 K", "1 s"});

Note that the units in the brackets has to come in the order charge, count, energy, length, temperature, and time.

Because the input and output from TBTK functions are in natural units, it is convenient to have a simple way to convert between the two. The UnitHandler provides such functions through a set of functions on the form

double quantityInBaseUnits

= UnitHandler::convertQuantityNtB(quantityInNaturalUnits);

double quantityInNaturalUnits

= UnitHandler::convertQuantityBtN(quantityInBaseUnits);

Here 'Quantity' is to be replace by the corresponding UnitHandler symbol specified in the table above, and NtB and BtN should be read 'natural to base' and 'base to natural', respectively.

Since derived units are defined in terms of the base units, it is in principle possible to use the above method to perform conversion of arbitrary derived units to and from natural units. However, doing so would require decomposing the derived unit into the corresponding base units, convert the base units one by one, multiply them together with the appropriate exponents, and finally multiply the quantity itself by the result. Moreover, even though it e.g. may be most convenient to work in the base units \(eV\), \(m\), and \(s\) for energy, length, and time, in which case the corresponding mass unit is \(eVs^2/m^2\), it may be more convenient to actual specify mass using the unit \(kg\). For this reason the UnitHandler also has special support for certain derived units. Currently this is restricted to mass, magnetic field strength, and voltage, but if more units are wanted, please do not hesitate to request additional derived units. The full list of possible derived units are

Quantity | Available derived units | UnitHandler symbol |
---|---|---|

Mass | kg, g, mg, ug, ng, pg, fg, ag, u | Mass |

Magnetic field strength | MT, kT, T, mT, uT, nT, GG, MG, kG, G, mG, uG | MagneticField |

Voltage | GV, MV, kV, V, mV, uV, nV | Voltage |

To for example convert mass in the derived units \(kg\) to and from base and natural units the following function calls can be made

double massInBaseUnits = UnitHandler::convertMassDtB(

massInDerivedUnits,

UnitHandler::MassUnit::kg

);

double massInNaturalUnits = UnitHandler::convertMassDtN(

massInDerivedUnits,

UnitHandler::MassUnit::kg

);

double massInDerivedUnits = UnitHandler::convertMassBtD(

massInBaseUnits,

UnitHandler::MassUnit::kg

);

double massInDerivedUnits = UnitHandler::convertMassNtD(

massInNaturalUnits,

UnitHandler::MassUnit::kg

);

Here DtB, DtN, BtD, and NtD should be read 'derived to base', 'derived to natural', 'base to derived', and 'natural to derived', respectively. The function calls mimic the six corresponding combinations of calls for conversion between base and natural units, with the exception that for derived units the actual derived unit has to be passed as a second argument.

The specification of physical constants is prone to errors. Partly because physical constants more often than not are long strings of rather random digits, and partly because it is easy to make mistakes when converting the constants to the particular units used in the calculation. The UnitHandler alleviates this issue by providing a range of predefined constants that can be requested on the currently used base or natural units. The available constants are

Name | Symbol | UnitHandler symbol |
---|---|---|

Reduced Planck constant | \(\hbar\) | Hbar |

Boltzman constant | \(k_B\) | K_B |

Elementary charge | \(e\) | E |

Speed of light | \(c\) | C |

Avogadros number | \(N_A\) | N_A |

Electron mass | \(m_e\) | M_e |

Proton mass | \(m_p\) | M_p |

Bohr magneton | \(\mu_B\) | Mu_B |

Nuclear magneton | \(\mu_n\) | Mu_n |

Vacuum permeability | \(\mu_0\) | Mu_0 |

Vacuum permittivity | \(\epsilon_0\) | Epsilon_0 |

Please do not hesitate to request further constants.

Once the base and natural units have been specified using the calls described above, the physical constants can be requested using function calls on the form

double constantValueInBaseUnits = UnitHandler::getSymbolB();

double constantValueInNaturalUnits = UnitHandler::getSymbolN();

Here 'Symbol' is to be replaced by the corresponding symbol listed under 'UnitHandler symbol' in the table above.

When printing values, it is useful to also print the actual unit strings. The UnitHandler therefore also provides methods for requesting the base unit strings for different quantities, which is obtained through function calls on the form

string unitSring = UnitHandler::getSymbolUnitString();

Here 'Symbol' can be any of the symbols listed in the tables over base units, derived units, and constants.