.. _structured_units: Structured Units **************** Numpy arrays can be :doc:`structured arrays `, where each element consists of multiple fields. These can be used with |Quantity| using a |StructuredUnit|, which provides a |Unit| for each field. For example, this allows constructing a single |Quantity| object with position and velocity fields that have different units, but are contained within the same object (as is needed to support units in the PyERFA_ wrappers around the ERFA_ routines that use position-velocity arrays). Creating Structured Quantities ============================== You can create structured quantities either directly or by multiplication with a |StructuredUnit|, with the latter in turn either created directly, or through `~astropy.units.Unit`. Example ------- .. EXAMPLE START: Creating Structured Quantities To create a structured quantity containing a position and velocity:: >>> import astropy.units as u, numpy as np >>> pv_values = np.array([([1., 0., 0.], [0., 0.125, 0.]), ... ([0., 1., 0.], [-0.125, 0., 0.])], ... dtype=[('p', '(3,)f8'), ('v', '(3,)f8')]) >>> pv = u.Quantity(pv_values, u.StructuredUnit((u.km, u.km/u.s))) >>> pv >>> pv_values * u.Unit('AU, AU/day') As for normal |Quantity| objects, you can access the value and the unit with the `~astropy.units.Quantity.value` and `~astropy.units.Quantity.unit` attribute, respectively. In addition, you can index any given field using its name:: >>> pv = pv_values * u.Unit('km, km/s') >>> pv.value array([([1., 0., 0.], [ 0. , 0.125, 0. ]), ([0., 1., 0.], [-0.125, 0. , 0. ])], dtype=[('p', '>> pv.unit Unit("(km, km / s)") >>> pv['v'] Structures can be nested, as in this example taken from an PyERFA_ test case for :func:`erfa.ldn`:: >>> ldbody = [ ... (0.00028574, 3e-10, ([-7.81014427, -5.60956681, -1.98079819], ... [0.0030723249, -0.00406995477, -0.00181335842])), ... (0.00095435, 3e-9, ([0.738098796, 4.63658692, 1.9693136], ... [-0.00755816922, 0.00126913722, 0.000727999001])), ... (1.0, 6e-6, ([-0.000712174377, -0.00230478303, -0.00105865966], ... [6.29235213e-6, -3.30888387e-7, -2.96486623e-7])) ... ] * u.Unit('Msun,radian,(AU,AU/day)') >>> ldbody # doctest: +FLOAT_CMP .. EXAMPLE END Converting to Different Units ============================= Like regular |Quantity| objects, structured quantities can be converted to different units, as long as they have the same structure and each unit is equivalent. Example ------- .. EXAMPLE START: Converting Structured Quantities to Different Units To convert a structured quantity to a different unit:: >>> pv.to((u.m, u.m / u.s)) # doctest: +FLOAT_CMP >>> pv.cgs .. EXAMPLE END Use with ERFA ============= The ERFA_ C routines make use of structured types, and these are exposed in the PyERFA_ interface. .. warning:: Not all PyERFA_ routines are wrapped yet. Help with adding wrappers will be appreciated. Example ------- .. EXAMPLE START: Using Structured Quantities with ERFA To use a position-velocity structured array with PyERFA_:: >>> import erfa >>> pv_values = np.array([([1., 0., 0.], [0., 0.125, 0.]), ... ([0., 1., 0.], [-0.125, 0., 0.])], ... dtype=erfa.dt_pv) >>> pv = pv_values << u.Unit('AU,AU/day') >>> erfa.pvu(86400*u.s, pv) >>> erfa.pv2s(pv) # doctest: +FLOAT_CMP (, , , , , ) >>> z_axis = np.array(([0, 0, 1], [0, 0, 0]), erfa.dt_pv) * u.Unit('1,1/s') >>> erfa.pvxpv(pv, z_axis) .. EXAMPLE END