/** \file
 *
 *  Contains the Units class implementation.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#include "Units.h"

//// SI base Units
const BaseUnit Units::AMPERE( "ampere", "A" );
const BaseUnit Units::CANDELA( "candela", "cd" );
const BaseUnit Units::KELVIN( "kelvin", "K" );
const BaseUnit Units::KILOGRAM( "kilogram", "kg" );
const BaseUnit Units::METER( "meter", "m" );
const BaseUnit Units::MOLE( "mole", "mol" );
const BaseUnit Units::SECOND( "second", "s" );

//// SI named Units
const BaseUnit Units::BECQUEREL( "becquerel", "Bq" );
const BaseUnit Units::COULOMB( "coulomb", "C" );
const BaseUnit Units::FARAD( "farad", "farad" ); // Nist abbrev is "F"
const BaseUnit Units::GRAY( "gray", "Gy" );
const BaseUnit Units::HENRY( "henry", "H" );
const BaseUnit Units::HERTZ( "hertz", "Hz" );
const BaseUnit Units::JOULE( "joule", "J" );
const BaseUnit Units::KATAL( "katal", "kat" ); //Not in Udunits
const BaseUnit Units::LUMEN( "lumen", "lm" );
const BaseUnit Units::LUX( "lux", "lx" );
const BaseUnit Units::NEWTON( "newton", "N" );
const BaseUnit Units::OHM( "ohm", "ohm" );
const BaseUnit Units::PASCAL( "pascal", "Pa" );
const BaseUnit Units::RADIAN( "radian", "rad", DOUBLE4 );
const BaseUnit Units::SIEMENS( "siemens", "S" );
const BaseUnit Units::SIEVERT( "sievert", "Sv" );
const BaseUnit Units::STERADIAN( "steradian", "sr" );
const BaseUnit Units::TESLA( "tesla", "T" );
const BaseUnit Units::VOLT( "volt", "V" );
const BaseUnit Units::WATT( "watt", "W" );
const BaseUnit Units::WEBER( "weber", "Wb" );

//// derived SI Units
const BaseUnit Units::AMPERE_SECOND( "ampere_second", "As" );
const BaseUnit Units::AMPERE_SECOND_METER_SQUARED_PER_MOLE( "ampere_second_meter_squared_per_mole", "Asm2/M" );
const BaseUnit Units::AMPERE_PER_METER( "ampere_per_meter", "A/m" );
const BaseUnit Units::AMPERE_PER_SQUARE_METER( "ampere_per_square_meter", "A/m2" );
const BaseUnit Units::CANDELA_PER_SQUARE_METER( "candela_per_square_meter", "cd/m2" );
const BaseUnit Units::CUBIC_METER( "cubic_meter", "m3" );
const BaseUnit Units::CUBIC_METER_PER_KILOGRAM( "cubic_meter_per_kilogram", "m3/kg" );
const BaseUnit Units::CUBIC_METER_PER_SECOND( "cubic_meter_per_second", "m3/s" );
const BaseUnit Units::CUBIC_METER_SECOND( "cubic_meter_second", "m3s" );
const BaseUnit Units::KELVIN_PER_METER( "kelvin_per_meter", "K/m" );
const BaseUnit Units::KILOGRAM_METER( "kilogram_meter", "kg-m" );
const BaseUnit Units::KILOGRAM_METER_SQUARED( "kilogram_meter_squared", "kg-m2" );
const BaseUnit Units::KILOGRAM_PER_CUBIC_METER( "kilogram_per_cubic_meter", "kg/m3" );
const BaseUnit Units::KILOGRAM_PER_KILOGRAM( "kilogram_per_kilogram", "kg/kg" );
const BaseUnit Units::KILOGRAM_PER_METER( "kilogram_per_meter", "kg/m" );
const BaseUnit Units::METER_PER_RADIAN( "meter_per_radian", "m/rad" );
const BaseUnit Units::METER_PER_SECOND( "meter_per_second", "m/s" );
const BaseUnit Units::METER_PER_SECOND_SQUARED( "meter_per_second_squared", "m/s2" );
const BaseUnit Units::MOLE_PER_CUBIC_METER( "mole_per_cubic_meter", "mol/m3" );
const BaseUnit Units::MOLE_PER_SECOND_PER_SQUARE_METER( "mole_per_second_per_square_meter", "mol/s/m2" );
const BaseUnit Units::MOLE_PER_SECOND_PER_SQUARE_METER_PER_AMPERE( "mole_per_second_per_square_meter_per_more", "mol/s/m2/A" );
const BaseUnit Units::NEWTON_METER( "newton_meter", "N-m" );
const BaseUnit Units::PASCAL_PER_PASCAL( "pascal_per_pascal", "Pa/Pa" );
const BaseUnit Units::PASCAL_PER_VOLT( "pascal_per_volt", "Pa/V" );
const BaseUnit Units::RADIAN_PER_METER( "radian_per_meter", "rad/m" );
const BaseUnit Units::RADIAN_PER_SECOND( "radian_per_second", "rad/s" );
const BaseUnit Units::RADIAN_PER_SECOND_SQUARED( "radian_per_second_squared", "rad/s2" );
const BaseUnit Units::RADIAN_PER_SECOND_PER_METER( "radian_per_second_per_meter", "rad/s/m" );
const BaseUnit Units::RADIAN_SECOND_PER_METER( "radian_second_per_meter", "rad-s/m" );
const BaseUnit Units::RECIPROCAL_METER( "reciprocal_meter", "1/m" );
const BaseUnit Units::RECIPROCAL_METER_PER_STERADIAN( "reciprocal_meter_per_steradian", "1/m/sr" );
const BaseUnit Units::RECIPROCAL_SECOND( "reciprocal_second", "1/s" );
const BaseUnit Units::SIEMENS_PER_METER( "siemens_per_meter", "S/m" );
const BaseUnit Units::SQUARE_METER( "square_meter", "m2" );
const BaseUnit Units::SQUARE_METER_PER_SECOND( "square_meter_per_second", "m2/s" );

//// Non-SI Units accepted for use with the International System of Units
const Unit Units::ANGULAR_DEGREE( "angular_degree", "arcdeg", RADIAN, M_PI / 180.0 );
const Unit Units::ANGULAR_MINUTE( "angular_minute", "arcmin", RADIAN, M_PI / 10800.0 );
const Unit Units::ANGULAR_SECOND( "angular_second", "arcsec", RADIAN, M_PI / 648000.0 );
const Unit Units::CELSIUS( "celsius", "degC", KELVIN, 1.0, 273.15 );
const Unit Units::DAY( "day", "d", SECOND, 86400 );
const Unit Units::HOUR( "hour", "h", SECOND, 3600 );
const Unit Units::LITER( "liter", "L", CUBIC_METER, 1e-3 );
const Unit Units::LITRE( "litre", "L", CUBIC_METER, 1e-3 );
const Unit Units::MINUTE( "minute", "min", SECOND, 60 );
const Unit Units::HECTARE( "hectare", "ha", SQUARE_METER, 10000 ); // Abbreviation not in UDUNITS
const Unit Units::TONNE( "tonne", "t", KILOGRAM, 1000 );

//// prefixed SI (base, named, derived, & accepted non-SI) Units
const Unit Units::AMPERE_HOUR( "ampere_hour", "Ah", AMPERE_SECOND, 3600 );
const Unit Units::ANGULAR_DEGREE_PER_SECOND( "angular_degree_per_second", "arcdeg/s", RADIAN_PER_SECOND, M_PI / 180.0 );
const Unit Units::ANGULAR_DEGREE_PER_SECOND_SQUARED( "angular_degree_per_second_squared", "arcdeg/s2", RADIAN_PER_SECOND_SQUARED, M_PI / 180.0 );
const Unit Units::ANGULAR_MINUTE_PER_SECOND( "angular_minute_per_second", "arcmin/s", RADIAN_PER_SECOND, M_PI / 10800.0 );
const Unit Units::CENTIMETER( "centimeter", "cm", METER, 0.01 ); // Not explicitly in udunits
const Unit Units::CENTIMETER_PER_SECOND( "centimeter_per_second", "cm/s", METER_PER_SECOND, 0.01 );
const Unit Units::CUBIC_CENTIMETER( "cubic_centimeter", "cc", CUBIC_METER, 1e-6 );
const Unit Units::CUBIC_CENTIMETER_PER_METER( "cubic_centimeter_per_meter", "cc/m", SQUARE_METER, 1e-6 );
const Unit Units::CUBIC_CENTIMETER_PER_METER_PER_SECOND( "cubic_centimeter_per_meter_per_second", "cc/m/s", SQUARE_METER_PER_SECOND, 1e-6 );
const Unit Units::CUBIC_CENTIMETER_PER_SECOND( "cubic_centimeter_per_second", "cc/s", CUBIC_METER_PER_SECOND, 1e-6 );
const Unit Units::LITER_PER_SECOND( "liter_per_second", "l/s", CUBIC_METER_PER_SECOND, 1e-3 );
const Unit Units::CUBIC_CENTIMETER_SECOND( "cubic_centimeter_second", "ccs", CUBIC_METER_SECOND, 1e-6 );
const Unit Units::CUBIC_CENTIMETER_SECOND_PER_METER( "cubic_centimeter_second_per_meter", "ccs/m", CUBIC_METER_SECOND, 1e-6 );
const Unit Units::DEGREE( "degree", "arcdeg", RADIAN, M_PI / 180.0 );
const Unit Units::DEGREE_PER_SECOND( "degree_per_second", "arcdeg/s", RADIAN_PER_SECOND, M_PI / 180.0 );
const Unit Units::DECIBAR( "decibar", "db", PASCAL, 10000 );
const Unit Units::GRAM( "gram", "g", KILOGRAM, 0.001 );
const Unit Units::GRAM_PER_CUBIC_CENTIMETER( "gram_per_cubic_centimeter", "g/cm3", KILOGRAM_PER_CUBIC_METER, 0.001 );
const Unit Units::GRAM_PER_KILOGRAM( "gram_per_kilogram", "g/kg", KILOGRAM_PER_KILOGRAM, 1e-3 );
const Unit Units::KILOJOULE( "kilojoule", "kJ", JOULE, 1000 );
const Unit Units::KILOMETER( "kilometer", "km", METER, 1000 );
const Unit Units::KILOPASCAL( "kilopascal", "kPa", PASCAL, 1000 );
const Unit Units::KILOWATT( "kilowatt", "kW", WATT, 1000 );
const Unit Units::KILOWATT_HOUR( "kilowatt_hour", "kWh", JOULE, 3.6e6 );
const Unit Units::MEGAJOULE( "megajoule", "MJ", JOULE, 1e6 );
const Unit Units::MICROAMPERE( "microampere", "uA", AMPERE, 1e-6 );
const Unit Units::MICROBAR( "microbar", "ub", PASCAL, 0.1 );
const Unit Units::MICROGRAM( "microgram", "ug", KILOGRAM, 1e-9 );
const Unit Units::MICROGRAM_PER_LITER( "microgram_per_liter", "ug/l", KILOGRAM_PER_CUBIC_METER, 1e-6 );
const Unit Units::MICROJOULE( "microjoule", "uJ", JOULE, 1e-6 );
const Unit Units::MICROMOLE( "micromole", "umol", MOLE, 1e-6 );
const Unit Units::MICROMOLE_PER_CUBIC_METER( "micromole_per_cubic_meter", "umol/m3", MOLE_PER_CUBIC_METER, 1e-6 );
const Unit Units::MICROMOLE_PER_SECOND_PER_SQUARE_METER( "micromole_per_second_per_square_meter", "umol/s/m2", MOLE_PER_SECOND_PER_SQUARE_METER, 1e-6 );
const Unit Units::MICROMOLE_PER_SECOND_PER_SQUARE_METER_PER_MICROAMPERE( "micromole_per_second_per_square_meter_per_microampere", "umol/s/m2/uA", MOLE_PER_SECOND_PER_SQUARE_METER_PER_AMPERE, 1 );
const Unit Units::MICROMOLE_PER_LITER( "micromole_per_liter", "umol/l", MOLE_PER_CUBIC_METER, 1e-3 );
const Unit Units::MICROPASCAL( "micropascal", "uPa", PASCAL, 1e-6 );
const Unit Units::MICROSECOND( "microsecond", "us", SECOND, 1e-6 );
const Unit Units::MICROTESLA( "microtesla", "uT", TESLA, 1e-6 );
const Unit Units::MICROVOLT( "microvolt", "uV", VOLT, 1e-6 );
const Unit Units::MICROWATT( "microwatt", "uW", WATT, 1e-6 );
const Unit Units::MICROWATT_HOUR( "microwatt_hour", "uWh", JOULE, 3.6e-3 );
const Unit Units::MILLIAMPERE( "milliampere", "mA", AMPERE, 1e-3 );
const Unit Units::MILLIAMPERE_HOUR( "milliampere_hour", "mAh", AMPERE_SECOND, 3.6 );
const Unit Units::MILLIGRAM( "milligram", "mg", KILOGRAM, 1e-6 );
const Unit Units::MILLIGRAM_PER_CUBIC_METER( "milligram_per_cubic_meter", "mg/m3", KILOGRAM_PER_CUBIC_METER, 1e-6 );
const Unit Units::MILLIGRAM_PER_LITER( "milligram_per_liter", "mg/l", KILOGRAM_PER_CUBIC_METER, 1e-3 );
const Unit Units::MILLIJOULE( "millijoule", "mJ", JOULE, 1e-3 );
const Unit Units::MILLILITER( "milliliter", "ml", CUBIC_METER, 1e-6 );
const Unit Units::MILLIMETER( "millimeter", "mm", METER, 0.001 );
const Unit Units::MILLIMETER_PER_SECOND( "millimeter_per_second", "mm/s", METER_PER_SECOND, 0.001 );
const Unit Units::MILLIMHO_PER_CENTIMETER( "millimho_per_centimeter", "mmho/cm", SIEMENS_PER_METER, 0.1 );
const Unit Units::MILLISECOND( "millisecond", "ms", SECOND, 0.001 );
const Unit Units::MILLIVOLT( "millivolt", "mV", VOLT, 1e-3 );
const Unit Units::MILLIWATT( "milliwatt", "mW", WATT, 1e-3 );
const Unit Units::MILLIWATT_HOUR( "milliwatt_hour", "mWh", JOULE, 3.6 );
const Unit Units::PHOTON_PER_SECOND( "photon_per_second", "ph/s" );
const Unit Units::WATT_HOUR( "watt_hour", "Wh", JOULE, 3600 );

//// non-SI physical Units
const Unit Units::ATMOSPHERE( "atmosphere", "atm", PASCAL, 101325 );
const Unit Units::FAHRENHEIT( "fahrenheit", "degF", KELVIN, 5.0 / 9.0, 273.15 - 160.0 / 9.0 );
const Unit Units::CELSIUS_PER_METER( "celsius_per_meter", "degC/m", KELVIN_PER_METER, 1.0 );
const Unit Units::FLUID_OUNCE( "fluid_ounce", "oz", CUBIC_METER, 2.95735295625e-5 );
const Unit Units::FOOT( "foot", "ft", METER, 0.3048 );
const Unit Units::FOOT_PER_SECOND( "foot_per_second", "ft/s", METER_PER_SECOND, 0.3048 );
const Unit Units::GALLON( "gallon", "gallon", CUBIC_METER, 3.785411784e-3 );
const Unit Units::GAUSS( "gauss", "G", TESLA, 1e-4 );
const Unit Units::INCH( "inch", "in", METER, 0.0254 );
const Unit Units::INCH_PER_SECOND( "inch_per_second", "in/s", METER_PER_SECOND, 0.0254 );
const Unit Units::KILOGRAM_FORCE( "kilogram_force", "kgf", NEWTON, 9.80665 );
const Unit Units::KNOT( "knot", "kt", METER_PER_SECOND, 1852.0 / 3600.0 );
const Unit Units::MILE( "mile", "mi", METER, 1609.344 );
const Unit Units::MILE_PER_HOUR( "mile_per_hour", "mile/hr", METER_PER_SECOND, 0.44704 );
const Unit Units::MILLIGAUSS( "milligauss", "mG", TESLA, 1e-7 );
const Unit Units::NAUTICAL_MILE( "nautical_mile", "nmi", METER, 1852.0 );
const Unit Units::OUNCE_FORCE( "ounce_force", "ozf", NEWTON, 28.349523125e-3 * 9.80665 );
const Unit Units::OUNCE_MASS( "ounce_mass", "ozm", KILOGRAM, 28.349523125e-3 ); // not in UDUNITS
const Unit Units::PARTIAL_PRESSURE_PERCENT( "partial_pressure_percent", "%pp", PASCAL_PER_PASCAL, 0.01 );
const Unit Units::POUND_FORCE( "pound_force", "lbf", NEWTON, 0.45359237 * 9.80665 );
const Unit Units::POUND_MASS( "pound_mass", "lb", KILOGRAM, 0.45359237 );
const Unit Units::POUND_PER_SQUARE_INCH( "pound_per_square_inch", "psi", PASCAL, 6894.75729 );
const Unit Units::POUND_PER_SQUARE_INCH_PER_VOLT( "pound_per_square_inch_per_volt", "psi/V", PASCAL_PER_VOLT, 6894.75729 );
const Unit Units::PRACTICAL_SALINITY_UNIT( "practical_salinity_unit", "psu", KILOGRAM_PER_KILOGRAM, 1e-3 ); // revolution not in UDUNITS
const Unit Units::REVOLUTION_PER_MINUTE( "revolution_per_minute", "rpm", RADIAN_PER_SECOND, M_PI / 30.0 ); // revolution not in UDUNITS
const Unit Units::REVOLUTION_PER_SECOND( "revolution_per_second", "rps", RADIAN_PER_SECOND, 2 * M_PI ); // revolution not in UDUNITS
const Unit Units::SIGMA_T( "sigma_t", "kg/m3-1000)", KILOGRAM_PER_CUBIC_METER, 1.0, 1000 );

//// Non-physical Units
const BaseUnit Units::BYTE( "byte", "B", DOUBLE8 );
const BaseUnit Units::BYTE_PER_SECOND( "byte_per_second", "Bps", DOUBLE8 );
const BaseUnit Units::DECIBEL( "decibel", "dB" );
const BaseUnit Units::NONE_UCHAR( "none_uchar", "n/a uint8", UCHAR1 );
const BaseUnit Units::NONE_SHORT( "none_short", "n/a int16", SHORT2 );
const BaseUnit Units::NONE_USHORT( "none_ushort", "n/a uint16", USHORT2 );
const BaseUnit Units::NONE_INT( "none_int", "n/a int32", INT4 );
const BaseUnit Units::NONE_FLOAT( "none_float", "n/a float", FLOAT4 );
const BaseUnit Units::NONE_DOUBLE( "none_double", "n/a double", DOUBLE8 );
const BaseUnit Units::NONE( "none", "n/a", DOUBLE8 );
const BaseUnit Units::RATIO( "ratio", "1" );

// Derivatios of non-phisical Units
const Unit Units::BIT( "bit", "b", BYTE, 0.125 );
const Unit Units::BIT_PER_SECOND( "bit_per_second", "bps", BYTE_PER_SECOND, 0.125 );
const Unit Units::GIGABYTE( "gigabyte", "GB", BYTE, 1073741824.0 );
const Unit Units::KILOBIT_PER_SECOND( "kilobit_per_second", "kbps", BYTE_PER_SECOND, 128.0 );
const Unit Units::KILOBYTE( "kilobyte", "kB", BYTE, 1024.0 );
const Unit Units::KILOBYTE_PER_SECOND( "kilobyte_per_second", "kBps", BYTE_PER_SECOND, 1024.0 );
const Unit Units::MEGABIT_PER_SECOND( "megabit_per_second", "Mbps", BYTE_PER_SECOND, 131072.0 );
const Unit Units::MEGABYTE( "megabyte", "MB", BYTE, 1048576.0 );
const Unit Units::MEGABYTE_PER_SECOND( "megabyte_per_second", "MBps", BYTE_PER_SECOND, 1048576.0 );
const Unit Units::PART_PER_BILLION( "part_per_billion", "ppb", RATIO, 1e-9 );
const Unit Units::PART_PER_MILLION( "part_per_million", "ppm", RATIO, 1e-6 );
const Unit Units::PART_PER_THOUSAND( "part_per_thousand", "ppt", RATIO, 1e-3 );
const Unit Units::PERCENT( "percent", "%", RATIO, 0.01 );

//// Pure counting Units
const BaseUnit Units::BOOL( "bool", "bool", UCHAR1 );
const BaseUnit Units::COUNT( "count", "count", INT4 );
const BaseUnit Units::ENUM( "enum", "enum", UCHAR1 );

/// Combinations of physical and counting Units
const BaseUnit Units::AMPERE_PER_COUNT( "ampere_per_count", "A/count" );
const BaseUnit Units::COUNT_PER_CUBIC_METER( "count_per_cubic_meter", "count/m3" );
const BaseUnit Units::COUNT_PER_KILOGRAM( "count_per_kilogram", "count/Kg" );
const BaseUnit Units::COUNT_PER_METER( "count_per_meter", "count/m" );
const BaseUnit Units::COUNT_PER_NEWTON( "count_per_newton", "count/N" );
const BaseUnit Units::COUNT_PER_RADIAN( "count_per_radian", "count/rad" );
const BaseUnit Units::COUNT_PER_SECOND( "count_per_second", "count/s" );
const BaseUnit Units::PER_COUNT( "per_count", "1/count" );
const BaseUnit Units::RECIPROCAL_METER_PER_STERADIAN_PER_COUNT( "reciprocal_meter_per_steradian_count", "1/m/sr/count" );

/// Derivations involving counting Units
const Unit Units::COUNT_PER_ANGULAR_DEGREE( "count_per_angular_degree", "count/arcdeg", COUNT_PER_RADIAN, 180.0 / M_PI );
const Unit Units::COUNT_PER_CUBIC_CENTIMETER( "count_per_cubic_centimeter", "count/cc", COUNT_PER_CUBIC_METER, 1e-6 );
const Unit Units::COUNT_PER_GRAM( "count_per_gram", "count/g", COUNT_PER_KILOGRAM, 1e-3 );
const Unit Units::COUNT_PER_MILLIGRAM( "count_per_milligram", "count/mg", COUNT_PER_KILOGRAM, 1e-6 );
const Unit Units::COUNT_PER_MILLILITER( "count_per_milliliter", "count/ml", COUNT_PER_CUBIC_METER, 1e-6 );
const Unit Units::COUNT_PER_MILLIMETER( "count_per_millimeter", "count/mm", COUNT_PER_METER, 1000 );
const Unit Units::COUNT_PER_REVOLUTION( "count_per_revolution", "count/rev", COUNT_PER_RADIAN, 0.5 / M_PI );
const Unit Units::MICROAMPERE_PER_COUNT( "microampere_per_count", "uA/count", AMPERE_PER_COUNT, 1e-6 );
const Unit Units::MICROGRAM_PER_LITER_PER_COUNT( "microgram_per_liter_per_count", "ug/l/count" );
const Unit Units::PART_PER_BILLION_PER_COUNT( "part_per_billion_per_count", "ppb/count", PER_COUNT, 1e-9 );

// Time mappings
const Unit Units::EPOCH_SECOND( "epoch_second", "second since 1970/01/01T00:00:00Z", SECOND );
const Unit Units::MATLAB_TIME( "matlab_time", "day since -0001/12/31T00:00:00Z", SECOND, 86400.0, -62167305600.0 );
