.. _units: Units ***** In Euphonic, units are handled by `Pint `_. Pint wraps Numpy arrays as a ``Quantity`` object, so you can easily see which units values are in. .. contents:: :local: Euphonic's ureg --------------- Units in euphonic are accessed through ``euphonic.ureg``, which is a ``Pint.UnitRegistry`` object that contains all required units. For example, to create temperature as a ``Quantity`` with units in Kelvin rather than a plain float: .. testcode:: from euphonic import ureg temperature = 5.0*ureg('K') This can also be done with Numpy arrays, to create an array with units. For example, to create an array of energy bins in meV: .. testcode:: from euphonic import ureg import numpy as np arr = np.arange(0, 100, 1) energy_bins = arr*ureg('meV') **Quantities as Function Arguments** Many Euphonic functions require ``Quantity`` wrapped values as arguments. Simply import the unit registry and create a ``Quantity``, then pass it to a function: .. testsetup:: quartz_phonon fnames = 'quartz.phonon' shutil.copyfile( get_castep_path('quartz', 'quartz_nosplit.phonon'), fnames) import numpy numpy.set_printoptions(precision=3, linewidth=52, suppress=True) .. testcode:: quartz_phonon from euphonic import QpointPhononModes, ureg phonons = QpointPhononModes.from_castep('quartz.phonon') fm = ureg('fm') scattering_lengths = {'Si': 4.1491*fm, 'O': 5.803*fm} sf = phonons.calculate_structure_factor(scattering_lengths) Object Attributes ----------------- Any dimensioned attributes (attributes with units) on a Euphonic object, for example ``cell_vectors`` or ``frequencies``, are actually properties. They are stored internally in atomic units, and only wrapped as a ``Quantity`` in user-friendly units once they are accessed. **Changing attribute units** When a Euphonic object is created, its dimensioned attributes will be in default units (e.g. meV for frequencies, angstrom for cell vectors). Each ``Quantity`` attribute has an associated string attribute that can be used to change the units. See the following example to change the units of frequency in ``QpointPhononModes``: .. doctest:: quartz_phonon >>> from euphonic import QpointPhononModes >>> phonons = QpointPhononModes.from_castep('quartz.phonon') >>> phonons.frequencies[5] >>> phonons.frequencies_unit = '1/cm' >>> phonons.frequencies[5] The pattern is the same for any ``Quantity`` attribute e.g. ``ForceConstants.force_constants`` has ``ForceConstants.force_constants_unit``, ``Crystal.cell_vectors`` has ``Crystal.cell_vectors_unit`` **Changing attribute values** Each dimensioned property also has a setter which allows it to be set. For example, to set new ``Crystal.cell_vectors``: .. testsetup:: quartz_fc fnames = 'quartz.castep_bin' shutil.copyfile( get_castep_path('quartz', 'quartz.castep_bin'), fnames) import numpy numpy.set_printoptions(precision=3, linewidth=52) .. doctest:: quartz_fc >>> import numpy as np >>> from euphonic import ForceConstants, ureg >>> fc = ForceConstants.from_castep('quartz.castep_bin') >>> fc.crystal.cell_vectors >>> fc.crystal.cell_vectors = np.ones((3, 3))*ureg('angstrom') >>> fc.crystal.cell_vectors However as dimensioned attributes are properties, individual elements can't be set by indexing, for example the following to set a single element of ``Crystal.atom_mass`` does not work: .. doctest:: quartz_fc >>> import numpy as np >>> from euphonic import ForceConstants, ureg >>> fc = ForceConstants.from_castep('quartz.castep_bin') >>> fc.crystal.atom_mass >>> fc.crystal.atom_mass[0] = 17.999*ureg('amu') >>> fc.crystal.atom_mass Nothing has changed! Instead, get the entire array, change any desired entries and then set the whole attribute as follows: .. doctest:: quartz_fc >>> from euphonic import ForceConstants, ureg >>> fc = ForceConstants.from_castep('quartz.castep_bin') >>> atom_mass = fc.crystal.atom_mass >>> atom_mass[0] = 17.999*ureg('amu') >>> fc.crystal.atom_mass = atom_mass >>> fc.crystal.atom_mass