UDUNITS(3)

NAME
udunits, utInit, utScan, utCalendar, utInvCalendar, utConvert, utPrint, utIsTime, utHasOrigin, utClear, utCopy, utScale, utDivide, utInvert, utMultiply, utRaise, utTerm - Unidata units library

SYNOPSIS
cc -Iunidata_inc ...

#include <udunits.h>

int utInit(
	const char	*path);

int utIsInit();

int utScan(
	const char	*spec,
	utUnit	*unit);

int utCalendar(
	double	value;
	utUnit	*unit,
	int	*year,
	int	*month,
	int	*day,
	int	*hour,
	int	*minute,
	float	*second);

int utInvCalendar(
	int	year,
	int	month,
	int	day,
	int	hour,
	int	minute,
	double	second,
	utUnit	*unit,
	double	*value);

int utConvert(
	const utUnit	*from,
	const utUnit	*to,
	double	*slope,
	double	*intercept);

int *utPrint(
	const utUnit	*unit,
	char		**s);

utUnit *utClear(
	utUnit	*unit);

int *utIsTime(
	const utUnit	*unit);

int *utHasOrigin(
	const utUnit	*unit);

utUnit *utCopy(
	const utUnit	*source,
	utUnit	*dest);

utUnit *utScale(
	utUnit	*source,
	double	factor,
	utUnit	*result);

utUnit *utDivide(
	utUnit	*numer,
	utUnit	*denom,
	utUnit	*result);

utUnit *utInvert(
	utUnit	*source,
	utUnit	*result);

utUnit *utMultiply(
	utUnit	*term1,
	utUnit	*term2,
	utUnit	*result);

utUnit *utRaise(
	utUnit	*source,
	int	power,
	utUnit	*result);

void utTerm();

DESCRIPTION

The Unidata units library, udunits, supports conversion of unit specifications between formatted and binary forms, arithmetic manipulation of unit specifications, and conversion of values between compatible scales of measurement.

A unit is the amount by which a physical quantity is measured. For example:

A unit can have an origin associated with it -- in which case the unit and origin together define a scale. For example, the phrase "the temperature is 25 degrees Celsius" specifies a particular point on a measurement scale; whereas the phrase "the temperature difference is 25 degrees Celsius" specifies a unit with no origin and, hence, no associated scale. If not remembered, this subtle distinction can cause problems when handling units.

utInit() initializes the units package. If path is non-NULL and not empty, then it specifies a units file containing initializing unit definitions; otherwise, the environment variable UDUNITS_PATH is checked and, if it exists and is not empty, then it is assumed to contain the pathname of the units file; otherwise, a compile-time default pathname is used.

The definitions in the units file are read into memory. This function returns 0 on success, UT_ENOFILE if the units file doesn't exist, UT_ESYNTAX if the units file contains a syntax error, UT_EUNKNOWN if the units file contains an unknown specification, UT_EIO if an I/O error occurred while accessing the units file, and UT_EALLOC if a memory allocation failure occurred.

utIsInit() indicates whether or not the units package has been initialized.

This function returns 0 if the package hasn't been initialized and !0 if the package has been initialized.

utScan() converts the formatted unit specification spec into a binary unit structure and stores the result in unit. The binary representation is used for algebraic manipulation. This function returns 0 on success, UT_ENOINIT if the package hasn't been initialized, UT_EINVALID if the unit argument is a null pointer, UT_EUNKNOWN if the specification contains an unknown unit, and UT_ESYNTAX if the specification contains a syntax error.

utCalendar() converts the amount, value, of the temporal unit, unit, into a UTC-referenced date and time (see, however, the section on HANDLING TIME). The reference unit shall be a time unit and have an origin. This function returns 0 on success, UT_ENOINIT if the package hasn't been initialized and UT_EINVALID if the unit structure is not a temporal one.

utInvCalendar() converts a UTC-referenced date and time into the amount, value, of the temporal unit, unit (see, however, the section on HANDLING TIME). The reference unit shall be a time unit and have an origin. This function returns 0 on success, UT_ENOINIT if the package hasn't been initialized and UT_EINVALID if the unit structure is not a temporal one.

utConvert() returns the coefficients of the Galilean transformation (i.e. y = a*x + b) necessary to convert the from unit into the to unit. The units must be compatible (i.e., their quotient must be dimensionless). On successful return, slope and intercept will contain the values for the slope and intercept coefficients, respectively. This function returns 0 on success, UT_ENOINIT if the package hasn't been initialized, UT_EINVALID if one of the unit structures is invalid, and UT_ECONVERT if the units are not convertible.

utPrint() converts the binary unit structure unit into a formatted unit specification and stores the string into a static buffer. The argument s is set to point to the static buffer. The string should not be modified (it may, however, be copied) and will be overwritten by subsequent calls to this function. This function returns 0 on success, UT_ENOINIT if the package hasn't been initialized, and UT_EINVALID if the unit structure is invalid. On error, the string argument is set to NULL.

utClear() clears a unit structure by setting it to the dimensionless value 1.

utIsTime() returns true if the given unit structure refers to a time unit and false otherwise. This function ignores whether or not the unit has an origin.

utHasOrigin() returns true of the given unit structure has an origin (i.e. defines a scale) and false otherwise.

utCopy() copies the unit structure source to the unit structure dest. This function correctly handles the case where the same unit structure is referenced by the source and destination units. The address of the destination unit structure is returned.

utScale() scales the unit structure source by factor, storing the result in the unit structure result. This function correctly handles the case where the same unit structure is referenced by the source and result units. The address of the result unit structure is returned.

utInvert() inverts the unit structure source, storing the result in unit structure result. Multiplying a unit by its reciprocal yields the dimensionless value 1. This function correctly handles the case where the source and result unit refer to the same structure. If successful, this function returns the address of the result unit structure; otherwise, it returns NULL.

utDivide() divides unit structure numer by unit structure denom and stores the result in unit structure result. This function correctly handles the case where the same unit structure is referenced by two or more arguments. If successful, this function returns the address of the result unit structure; otherwise, it returns NULL.

utMultiply() multiplies unit structure term1 by unit structure term2 and stores the result in unit structure result. This function correctly handles the case where the same unit structure is referenced by two or more arguments. If successful, this function returns the address of the result unit structure; otherwise, it returns NULL.

utRaise() raises the unit structure source by the power power, storing the result in the unit structure result. This function correctly handles the case where the same unit structure is referenced by the source and result units. If successful, this function returns the address of the result unit structure; otherwise, it returns NULL.

utTerm() terminates usage of this package. In particular, it frees all allocated memory. It should be called when the library is no longer needed.

HANDLING TIME

The udunits(3) package uses a mixed Gregorian/Julian calendar system. Dates prior to 1582-10-15 are assumed to use the Julian calendar, which was introduced by Julius Caesar in 46 BCE and is based on a year that is exactly 365.25 days long. Dates on and after 1582-10-15 are assumed to use the Gregorian calendar, which was introduced on that date and is based on a year that is exactly 365.2425 days long. (A year is actually approximately 365.242198781 days long.) Seemingly strange behavior of the udunits(3) package can result if a user-given time interval includes the changeover date. For example, utCalendar() and utInvCalendar() can be used to show that 1582-10-15 *preceeded* 1582-10-14 by 9 days.

EXAMPLES

Convert two data sets to a common unit, subtract one from the other, then save the result in a (different) output unit:

    if (utInit("") != 0) {
    	/* handle initialization error */
    } else {
    	char	*UnitString1, *UnitString2, *OutputUnitString;
    	utUnit	unit1, unit2, OutputUnit;
    	...
    	if (utScan(UnitString1, &unit1) != 0 ||
    		utScan(UnitString2, &unit2) != 0 ||
    		utScan(OutputUnitString2, &OutputUnit) != 0) {
    		/*
    		 * handle decode error
    		 */
    	} else {
    		double	InSlope, InIntercept;
    		double	OutSlope, OutIntercept;
    		...
    		if (utConvert(&unit2, &unit1, &InSlope,
    			&InIntercept) != 0 ||
    		    utConvert(&unit1, &OutputUnit, &OutSlope,
    			&OutIntercept) != 0) {
    			/*
    			 * handle data-incompatibility
    			 */
    		} else {
    			/*
    			 * process data using:
    			 *	OutputValue = OutSlope*(Data1Value -
    			 *		(InSlope*Data2Value + InIntercept))
    			 *		+ OutIntercept
    			 */
    		}
    	}
    	utTerm();
    }

the above example could be made more efficient by testing the returned conversion factors for nearness to 1 and 0 and using appropriately streamlined processing expressions.

Compute a threshold value corresponding to an input data value plus a user-specified delta (the units of the input data value and delta can differ):

    char	*input_unit_string, *delta_unit_string;
    float	input_value;
    utUnit	input_unit, delta_unit;
    ...
    if (utScan(input_unit_string, &input_unit) != 0 ||
    	utScan(delta_unit_string, &delta_unit) != 0) {
    	/*
    	 * handle decode error
    	 */
    } else {
    	double	slope, intercept;
    	...
    	if (utConvert(&delta_unit, &input_unit, &slope, &intercept) != 0) {
    		/*
    		 * handle units incompatibility
    		 */
    	} else {
    		float	threshold = input_value + slope*delta_value
    				    + intercept;
    		...
    	}
    }
    utTerm();

Compute the number of time intervals from a start time to a reference time:

    #include <stdio.h>
    #include <stdlib.h>
    #include "udunits.h"
    main()
    {
        if (utInit("/upc/cur/udunits/etc/udunits.dat") != 0) {
            (void) fputs("utInit() error, stderr);
        } else {
            utUnit  timecenters_unit;
            /*
             * NB: The following "time centers" specification gives both
             * the start time (January 1, 1990 at 00:00 UTC) and the
    	 * sampling interval (2 minutes).
             */
            if (utScan("2 minutes since 1990-1-1", &timecenters_unit)
                    != 0) {
                (void) fputs("utScan() error, stderr);
            } else {
                /*
                 * The following reference time is 1 hour later than
                 * the above start time.
                 */
                int         ref_year        = 1990;
                int         ref_month       = 1;
                int         ref_day         = 1;
                int         ref_hour        = 1;
                int         ref_minute      = 0;
                float       ref_second      = 0;	/* could be `double'
                double      ref_value;
                (void) utInvCalendar(ref_year, ref_month, ref_day,
                                     ref_hour, ref_minute, ref_second,
                                     &timecenters_unit, &ref_value);
                /*
                 * Exit successfully if the number of time intervals
                 * between the start and reference times is correct.
                 */
                if (30 == ref_value)
                    exit(0);
            }
        }
        abort();
    }

FORMATTED UNIT SPECIFICATIONS

The following are examples of formatted unit specifications that can be interpreted by the utScan() function:

    10 kilogram.meters/seconds2
    10 kg-m/sec2
    10 kg m/s^2
    (PI radian)2
    degF
    100rpm
    geopotential meters
    33 feet water

A unit is specified as an arbitrary product of constants and unit names raised to arbitrary integral powers. Division is indicated by a slash `/'. Multiplication is indicated by whitespace, a period `.', or a hyphen `-'. Exponentiation is indicated by an integer suffix or by the exponentiation operators `^' and `**'. Parentheses may be used for grouping and disambiguation.

Arbitrary Galilean transformations (i.e. y = ax + b) are supported. In particular, temperature and time conversions are correctly handled. The specification:

    degF @ 32

indicates a Fahrenheit scale with the origin shifted to thirty-two degrees Fahrenheit (i.e. to zero degrees Celsius). The Celsius scale is equivalent to the following unit:

    1.8 degR @ 273.15

Besides the character `@', the words `after', `from', `ref', and `since' may also be used. Note that multiplication takes precedence over origin-shift. In order of increasing precedence, the operations are origin-shift, division, multiplication, and exponentiation.

Units of time are similarly handled. The specification:

    seconds since 1992-10-8 15:15:42.5 -6:00

indicates seconds since October 8th, 1992 at 3 hours, 15 minutes and 42.5 seconds in the afternoon in the time zone which is six hours to the west of Coordinated Universal Time (i.e. Mountain Daylight Time). The time zone specification can also be written without a colon using one or two-digits (indicating hours) or three or four digits (indicating hours and minutes).

utScan() understands most conventional prefixes and abbreviations:

The function utPrint() always encodes a unit specification one way. To reduce misunderstandings, it is recommended that this encoding style be used as the default. In general, a unit is printed in terms of basic units, factors, and exponents. Basic units are separated by spaces; and any exponent directly appends its associated unit. The above examples would be printed as follows:

    10 kilogram meter second-2
    9.8696044 radian2
    0.555556 kelvin @ 255.372
    10.471976 radian second-1
    9.80665 meter2 second-2
    98636.5 kilogram meter-1 second-2

Note that the Fahrenheit unit is encoded as a deviation, in fractional kelvins, from an origin at 255.372 kelvin.

UNITS FILE

The units file is a formatted file containing unit definitions and is used to initialize this package. It is the first place to look to discover the set of valid names and symbols (of which there are many -- On October 9, 1992, it contained 446 entries).

The format for the units file is documented internally and the file may be modified by the user as necessary. In particular, additional units and constants may be easily added (including variant spellings of existing units or constants).

ENVIRONMENT

UDUNITS_PATH
    If utInit() is called without a pathname argument, and if this environment variable is non-empty, then its value overrides the default pathname for the units file.

DIAGNOSTICS

This package prints (hopefully) self-explanatory error-messages to standard error.

SEE ALSO

udunits(1).

BUGS AND RESTRICTIONS

utScan() is case-sensitive. If this causes difficulties, you might try making appropriate additional entries to the units file.

Some unit abbreviations in the default units file might seem counter-intuitive. In particular, note the following:

    For	Use	Not	Which Instead Means

    Celsius	`Celsius'	`C'	coulomb
    gram	`gram'	`g'	<standard free fall>
    gallon	`gallon'	`gal'	<acceleration>
    radian	`radian'	`rad'	<absorbed dose>
    Newton	`newton' or `N'	`nt'	nit (unit of photometry)

REFERENCES

NIST Special Publication 811, 1995 Edition: "Guide for the Use of the International System of Units (SI)" by Barry N. Taylor. URL <http://physics.nist.gov/Divisions/Div840/SI.html>.

ANSI/IEEE Std 260-1978: "IEEE Standard Letter Symbols for Units of Measurement".

ASTM Designation: E 380 - 85: "Standard for METRIC PRACTICE".

International Standard (ISO) 2955: "Information processing -- Representation of SI and other units in systems with limited character sets", Ref. No. ISO 2955-1983 (E).