001/* 002 * SI Units for Java 003 * Copyright (c) 2005-2017, Jean-Marie Dautelle, Werner Keil, V2COM. 004 * 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 008 * 009 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 010 * 011 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 012 * 013 * 3. Neither the name of JSR-363 nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 014 * 015 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 016 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 017 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 018 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 019 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 020 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 021 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 022 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 023 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 024 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 025 */ 026package si.uom; 027 028import static tec.uom.se.unit.MetricPrefix.*; 029 030import javax.measure.Quantity; 031import javax.measure.Unit; 032import javax.measure.quantity.Acceleration; 033import javax.measure.quantity.Angle; 034import javax.measure.quantity.Area; 035import javax.measure.quantity.Energy; 036import javax.measure.quantity.Length; 037import javax.measure.quantity.Mass; 038 039import si.uom.quantity.Action; 040import si.uom.quantity.DynamicViscosity; 041import si.uom.quantity.ElectricPermittivity; 042import si.uom.quantity.IonizingRadiation; 043import si.uom.quantity.KinematicViscosity; 044import si.uom.quantity.Luminance; 045import si.uom.quantity.MagneticFieldStrength; 046import si.uom.quantity.MagneticPermeability; 047import si.uom.quantity.MagnetomotiveForce; 048import si.uom.quantity.Radiance; 049import si.uom.quantity.RadiantIntensity; 050import si.uom.quantity.WaveNumber; 051import tec.uom.se.AbstractSystemOfUnits; 052import tec.uom.se.AbstractUnit; 053import tec.uom.se.format.SimpleUnitFormat; 054import tec.uom.se.function.MultiplyConverter; 055import tec.uom.se.function.PiMultiplierConverter; 056import tec.uom.se.function.RationalConverter; 057import tec.uom.se.unit.AlternateUnit; 058import tec.uom.se.unit.ProductUnit; 059import tec.uom.se.unit.TransformedUnit; 060import tec.uom.se.unit.Units; 061 062/** 063 * <p> 064 * This class defines all SI (Système International d'Unités) base units and 065 * derived units as well as units that are accepted for use with the SI units. 066 * </p> 067 * 068 * @see <a href= 069 * "http://en.wikipedia.org/wiki/International_System_of_Units">Wikipedia: 070 * International System of Units</a> 071 * @see <a href="http://physics.nist.gov/cuu/Units/outside.html">Units outside 072 * the SI that are accepted for use with the SI</a> 073 * @see <a href="http://www.bipm.org/utils/common/pdf/si_brochure_8.pdf">SI 2006 074 * - Official Specification</a> 075 * @see tec.uom.se.unit.MetricPrefix 076 * 077 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a> 078 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 079 * @version 1.0.2, February 12, 2017 080 */ 081public final class SI extends Units { 082 083 /** 084 * The singleton instance. 085 */ 086 private static final SI INSTANCE = new SI(); 087 088 /** 089 * Holds the mapping quantity to unit. 090 */ 091 // private final HashMap<Class<? extends Quantity>, AbstractUnit> 092 // quantityToUnit = new HashMap<Class<? extends Quantity>, AbstractUnit>(); 093 094 /** 095 * Default constructor (prevents this class from being instantiated). 096 */ 097 private SI() { 098 } 099 100 /** 101 * Returns the singleton instance of this class. 102 * 103 * @return the metric system instance. 104 */ 105 public static SI getInstance() { 106 return INSTANCE; 107 } 108 109 //////////////////////////////// 110 // SI DERIVED ALTERNATE UNITS // 111 //////////////////////////////// 112 113 /** 114 * The SI unit for magnetomotive force (standard name <code>At</code>). 115 */ 116 public static final Unit<MagnetomotiveForce> AMPERE_TURN = addUnit( 117 new AlternateUnit<MagnetomotiveForce>(SI.AMPERE, "At"), MagnetomotiveForce.class); 118 119 ////////////////////////////// 120 // SI DERIVED PRODUCT UNITS // 121 ////////////////////////////// 122 123 /** 124 * The SI unit for acceleration quantities (standard name 125 * <code>m/s2</code>). 126 */ 127 public static final Unit<Acceleration> METRE_PER_SQUARE_SECOND = addUnit( 128 new ProductUnit<Acceleration>(METRE_PER_SECOND.divide(SECOND)), Acceleration.class); 129 /** 130 * Alias {@link #METRE_PER_SQUARE_SECOND} 131 * @deprecated use METRE_PER_SQUARE_SECOND 132 */ 133 public static final Unit<Acceleration> METRES_PER_SQUARE_SECOND = METRE_PER_SQUARE_SECOND; 134 135 /** 136 * The SI unit for action quantities (standard name <code>j.s</code>). 137 */ 138 public static final Unit<Action> JOULE_SECOND = addUnit(new ProductUnit<Action>(JOULE.multiply(SECOND)), 139 Action.class); 140 141 /** 142 * The SI unit for electric permittivity (standard name <code>ε</code>, 143 * <code>F/m </code> or <code>F·m−1</code>). In electromagnetism, absolute 144 * permittivity is the measure of resistance that is encountered when 145 * forming an electric field in a medium. 146 */ 147 public static final Unit<ElectricPermittivity> FARAD_PER_METRE = addUnit( 148 new AlternateUnit<ElectricPermittivity>(FARAD.divide(METRE), "ε"), ElectricPermittivity.class); 149 /** 150 * Alias for {@link #FARAD_PER_METRE} 151 * @deprecated use FARAD_PER_METRE 152 */ 153 public static final Unit<ElectricPermittivity> FARADS_PER_METRE = FARAD_PER_METRE; 154 155 /** 156 * The SI unit for magnetic permeability quantities (standard name 157 * <code>N/A2</code>). 158 */ 159 public static final Unit<MagneticPermeability> NEWTON_PER_SQUARE_AMPERE = addUnit( 160 new ProductUnit<MagneticPermeability>(NEWTON.divide(AMPERE.pow(2))), MagneticPermeability.class); 161 162 /** 163 * The SI unit for wave number quantities (standard name <code>1/m</code>). 164 */ 165 public static final Unit<WaveNumber> RECIPROCAL_METRE = addUnit(new ProductUnit<WaveNumber>(METRE.pow(-1)), 166 WaveNumber.class); 167 168 /** 169 * The SI unit for dynamic viscosity quantities (standard name 170 * <code>Pa.s</code>). 171 */ 172 public static final Unit<DynamicViscosity> PASCAL_SECOND = addUnit( 173 new ProductUnit<DynamicViscosity>(PASCAL.multiply(SECOND)), DynamicViscosity.class); 174 175 /** 176 * Luminance is a photometric measure of the luminous intensity per unit 177 * area of light travelling in a given direction. It describes the amount of 178 * light that passes through, is emitted or reflected from a particular 179 * area, and falls within a given solid angle. The SI unit for luminance is 180 * candela per square metre (<code>cd/m2</code>). 181 * 182 * @see <a href="https://en.wikipedia.org/wiki/Luminance"> Wikipedia: 183 * Luminance</a> 184 */ 185 public static final Unit<Luminance> CANDELA_PER_SQUARE_METRE = addUnit( 186 new ProductUnit<Luminance>(CANDELA.divide(SQUARE_METRE)), Luminance.class); 187 188 /** 189 * The SI unit for kinematic viscosity quantities (standard name 190 * <code>m2/s"</code>). 191 */ 192 public static final Unit<KinematicViscosity> SQUARE_METRE_PER_SECOND = addUnit( 193 new ProductUnit<KinematicViscosity>(SQUARE_METRE.divide(SECOND)), KinematicViscosity.class); 194 195 /** 196 * Alias for {@link #SQUARE_METRE_PER_SECOND} 197 * @deprecated use SQUARE_METRE_PER_SECOND 198 */ 199 public static final Unit<KinematicViscosity> SQUARE_METRES_PER_SECOND = SQUARE_METRE_PER_SECOND; 200 201 202 /** 203 * A magnetic field is the magnetic effect of electric currents and magnetic 204 * materials. The magnetic field at any given point is specified by both a 205 * direction and a magnitude (or strength); as such it is a vector field. 206 * The H-field is measured in amperes per metre (<code>A/m</code>) in SI 207 * units. 208 * 209 * @see <a href="https://en.wikipedia.org/wiki/Magnetic_field#The_H-field"> 210 * Wikipedia: Magnetic Field - The H Field</a> 211 */ 212 public static final Unit<MagneticFieldStrength> AMPERE_PER_METRE = addUnit( 213 new ProductUnit<MagneticFieldStrength>(AMPERE.divide(METRE)), MagneticFieldStrength.class); 214 215 /** 216 * Alias for AMPERE_PER_METRE 217 * 218 * @deprecated use AMPERE_PER_METRE. 219 */ 220 public static final Unit<MagneticFieldStrength> AMPERES_PER_METRE = AMPERE_PER_METRE; 221 222 /** 223 * The SI unit for ionizing radiation quantities (standard name 224 * <code>C/kg"</code>). 225 */ 226 public static final Unit<IonizingRadiation> COULOMB_PER_KILOGRAM = addUnit( 227 new ProductUnit<IonizingRadiation>(COULOMB.divide(KILOGRAM)), IonizingRadiation.class); 228 /** 229 * Alias for {@link #COULOMB_PER_KILOGRAM} 230 * @deprecated use COULOMB_PER_KILOGRAM 231 */ 232 public static final Unit<IonizingRadiation> COULOMBS_PER_KILOGRAM = COULOMB_PER_KILOGRAM; 233 234 235 /** 236 * The SI unit for radiant intensity (standard name <code>W/sr</code>). 237 */ 238 public static final Unit<RadiantIntensity> WATT_PER_STERADIAN = addUnit( 239 WATT.divide(STERADIAN).asType(RadiantIntensity.class)); 240 241 /** 242 * The SI unit for radiance (standard name <code>W⋅sr−1⋅m−2</code>). 243 */ 244 public static final Unit<Radiance> WATT_PER_STERADIAN_PER_SQUARE_METRE = addUnit( 245 WATT_PER_STERADIAN.divide(SQUARE_METRE).asType(Radiance.class)); 246 247 ///////////////////////////////////////////////////////////////// 248 // Units outside the SI that are accepted for use with the SI. // 249 ///////////////////////////////////////////////////////////////// 250 251 /** 252 * An angle unit accepted for use with SI units (standard name 253 * <code>deg</code>). 254 */ 255 public static final Unit<Angle> DEGREE_ANGLE = addUnit( 256 new TransformedUnit<Angle>(RADIAN, new PiMultiplierConverter().concatenate(new RationalConverter(1, 180)))); 257 258 /** 259 * An angle unit accepted for use with SI units (standard name 260 * <code>'</code>). 261 */ 262 public static final Unit<Angle> MINUTE_ANGLE = addUnit(new TransformedUnit<Angle>(RADIAN, 263 new PiMultiplierConverter().concatenate(new RationalConverter(1, 180 * 60)))); 264 265 /** 266 * An angle unit accepted for use with SI units (standard name 267 * <code>''</code>). 268 */ 269 public static final Unit<Angle> SECOND_ANGLE = addUnit(new TransformedUnit<Angle>(RADIAN, 270 new PiMultiplierConverter().concatenate(new RationalConverter(1, 180 * 60 * 60)))); 271 272 /** 273 * A mass unit accepted for use with SI units (standard name 274 * <code>t</code>). 275 */ 276 public static final Unit<Mass> TONNE = AbstractSystemOfUnits.Helper.addUnit(INSTANCE.units, 277 new TransformedUnit<Mass>(KILOGRAM, new RationalConverter(1000, 1)), "Tonne", "t"); 278 279 /** 280 * An energy unit accepted for use with SI units (standard name 281 * <code>eV</code>). The electronvolt is the kinetic energy acquired by an 282 * electron passing through a potential difference of 1 V in vacuum. The 283 * value must be obtained by experiment, and is therefore not known exactly. 284 */ 285 public static final Unit<Energy> ELECTRON_VOLT = new TransformedUnit<Energy>(JOULE, 286 new MultiplyConverter(1.602176487E-19)); 287 // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf 288 289 /** 290 * A mass unit accepted for use with SI units (standard name 291 * <code>u</code>). The unified atomic mass unit is equal to 1/12 of the 292 * mass of an unbound atom of the nuclide 12C, at rest and in its ground 293 * state. The value must be obtained by experiment, and is therefore not 294 * known exactly. 295 */ 296 public static final Unit<Mass> UNIFIED_ATOMIC_MASS = addUnit( 297 new TransformedUnit<Mass>(KILOGRAM, new MultiplyConverter(1.660538782E-27)), "Unified atomic mass", "u", true); 298 // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf 299 300 /** 301 * A length unit accepted for use with SI units (standard name 302 * <code>UA</code>). The astronomical unit is a unit of length. Its value is 303 * such that, when used to describe the motion of bodies in the solar 304 * system, the heliocentric gravitation constant is (0.017 202 098 95)2 305 * ua3·d-2. The value must be obtained by experiment, and is therefore not 306 * known exactly. 307 */ 308 public static final Unit<Length> ASTRONOMICAL_UNIT = addUnit( 309 new TransformedUnit<Length>(METRE, new MultiplyConverter(149597871000.0))); 310 // Best estimate source: http://maia.usno.navy.mil/NSFA/CBE.html 311 312 /** 313 * An angle unit accepted for use with SI units (standard name 314 * <code>rev</code>). 315 */ 316 public static final Unit<Angle> REVOLUTION = addUnit( 317 new TransformedUnit<Angle>(RADIAN, new PiMultiplierConverter().concatenate(new RationalConverter(2, 1)))); 318 319 /** 320 * An angle unit accepted for use with SI units (standard name 321 * <code>ha</code>). 322 */ 323 public static final Unit<Area> HECTARE = new TransformedUnit<Area>(SQUARE_METRE, new RationalConverter(10000, 1)); 324 325 ///////////////////// 326 // Collection View // 327 ///////////////////// 328 329 @Override 330 public String getName() { 331 return SI.class.getSimpleName(); // for Java SE this works 332 } 333 334 /** 335 * Adds a new unit not mapped to any specified quantity type and puts a text 336 * as symbol or label. 337 * 338 * @param unit 339 * the unit being added. 340 * @param name 341 * the string to use as name 342 * @param text 343 * the string to use as label or symbol 344 * @param isLabel 345 * if the string should be used as a label or not 346 * @return <code>unit</code>. 347 */ 348 private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) { 349 if (isLabel) { 350 SimpleUnitFormat.getInstance().label(unit, text); 351 } 352 if (name != null && unit instanceof AbstractUnit) { 353 return Helper.addUnit(INSTANCE.units, unit, name); 354 } else { 355 INSTANCE.units.add(unit); 356 } 357 return unit; 358 } 359 360 /** 361 * Adds a new unit not mapped to any specified quantity type and puts a text 362 * as symbol or label. 363 * 364 * @param unit 365 * the unit being added. 366 * @param text 367 * the string to use as label or symbol 368 * @param isLabel 369 * if the string should be used as a label or not 370 * @return <code>unit</code>. 371 */ 372 @SuppressWarnings("unused") 373 private static <U extends Unit<?>> U addUnit(U unit, String text, boolean isLabel) { 374 return addUnit(unit, null, text, isLabel); 375 } 376 377 /** 378 * Adds a new unit not mapped to any specified quantity type. 379 * 380 * @param unit 381 * the unit being added. 382 * @return <code>unit</code>. 383 */ 384 private static <U extends Unit<?>> U addUnit(U unit) { 385 INSTANCE.units.add(unit); 386 return unit; 387 } 388 389 /** 390 * Adds a new unit and maps it to the specified quantity type. 391 * 392 * @param unit 393 * the unit being added. 394 * @param type 395 * the quantity type. 396 * @return <code>unit</code>. 397 */ 398 private static <U extends AbstractUnit<?>> U addUnit(U unit, Class<? extends Quantity<?>> type) { 399 INSTANCE.units.add(unit); 400 INSTANCE.quantityToUnit.put(type, unit); 401 return unit; 402 } 403 404 // ////////////////////////////////////////////////////////////////////////// 405 // Label adjustments for SI 406 static { 407 SimpleUnitFormat.getInstance().label(TONNE, "t"); 408 SimpleUnitFormat.getInstance().label(MEGA(TONNE), "Mt"); 409 } 410}