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