001/*
002 * International System of Units (SI)
003 * Copyright (c) 2005-2019, 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-385, 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 tech.units.indriya.AbstractUnit.ONE;
033
034import javax.measure.Quantity;
035import javax.measure.Unit;
036import javax.measure.quantity.Acceleration;
037import javax.measure.quantity.Angle;
038import javax.measure.quantity.Dimensionless;
039import javax.measure.quantity.ElectricCharge;
040import javax.measure.quantity.Energy;
041import javax.measure.quantity.Length;
042import javax.measure.quantity.Mass;
043
044import si.uom.quantity.*;
045import tech.units.indriya.AbstractUnit;
046import tech.units.indriya.format.SimpleUnitFormat;
047import tech.units.indriya.function.MultiplyConverter;
048import tech.units.indriya.unit.AlternateUnit;
049import tech.units.indriya.unit.ProductUnit;
050import tech.units.indriya.unit.TransformedUnit;
051import tech.units.indriya.unit.Units;
052
053/**
054 * <p>
055 * This class defines all SI (Système International d'Unités) base units and
056 * derived units as well as units that are accepted for use with the SI units.
057 * </p>
058 *
059 * @see <a href=
060 *      "http://en.wikipedia.org/wiki/International_System_of_Units">Wikipedia:
061 *      International System of Units</a>
062 * @see <a href="http://physics.nist.gov/cuu/Units/outside.html">Units outside
063 *      the SI that are accepted for use with the SI</a>
064 * @see <a href="https://www.bipm.org/en/publications/si-brochure/">SI Brochure:
065 *      The International System of Units (SI)</a>
066 * @see MetricPrefix
067 * 
068 * @noextend This class is not intended to be extended by clients.
069 *
070 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
071 * @author <a href="mailto:werner@uom.si">Werner Keil</a>
072 * @version 2.4, September 12, 2019
073 */
074public final class SI extends Units {
075        /**
076         * The singleton instance.
077         */
078        private static final SI INSTANCE = new SI();
079
080        /**
081         * Default constructor (prevents this class from being instantiated).
082         */
083        private SI() {
084        }
085
086        /**
087         * Returns the singleton instance of this class.
088         *
089         * @return the metric system instance.
090         */
091        public static SI getInstance() {
092                return INSTANCE;
093        }
094
095        ////////////////////////////////
096        // SI DERIVED ALTERNATE UNITS //
097        ////////////////////////////////
098
099        /**
100         * The SI unit for magnetomotive force (standard name <code>At</code>).
101         */
102        public static final AlternateUnit<MagnetomotiveForce> AMPERE_TURN = addUnit(
103                        new AlternateUnit<MagnetomotiveForce>(AMPERE, "At"), MagnetomotiveForce.class);
104
105        //////////////////////////////
106        // SI DERIVED PRODUCT UNITS //
107        //////////////////////////////
108
109        /**
110         * The SI unit for acceleration quantities (standard name <code>m/s2</code>).
111         */
112        public static final Unit<Acceleration> METRE_PER_SQUARE_SECOND = addUnit(
113                        new ProductUnit<Acceleration>(METRE_PER_SECOND.divide(SECOND)), Acceleration.class);
114
115        /**
116         * The SI unit for action quantities (standard name <code>J.s</code>).
117         */
118        public static final Unit<Action> JOULE_SECOND = addUnit(new ProductUnit<Action>(JOULE.multiply(SECOND)),
119                        Action.class);
120
121        /**
122         * The SI unit for electric permittivity (standard name <code>ε</code>,
123         * <code>F/m </code> or <code>F·m−1</code>). In electromagnetism, absolute
124         * permittivity is the measure of resistance that is encountered when forming an
125         * electric field in a medium.
126         */
127        public static final Unit<ElectricPermittivity> FARAD_PER_METRE = addUnit(
128                        new AlternateUnit<ElectricPermittivity>(FARAD.divide(METRE), "ε"), ElectricPermittivity.class);
129
130        /**
131         * The SI unit for magnetic permeability quantities (standard name
132         * <code>N/A2</code>).
133         */
134        public static final Unit<MagneticPermeability> NEWTON_PER_SQUARE_AMPERE = addUnit(
135                        new ProductUnit<MagneticPermeability>(NEWTON.divide(AMPERE.pow(2))), MagneticPermeability.class);
136
137        /**
138         * The SI unit for wave number quantities (standard name <code>1/m</code>).
139         */
140        public static final Unit<WaveNumber> RECIPROCAL_METRE = addUnit(new ProductUnit<WaveNumber>(METRE.pow(-1)),
141                        WaveNumber.class);
142
143        /**
144         * The SI unit for dynamic viscosity quantities (standard name
145         * <code>Pa.s</code>).
146         */
147        public static final Unit<DynamicViscosity> PASCAL_SECOND = addUnit(
148                        new ProductUnit<DynamicViscosity>(PASCAL.multiply(SECOND)), DynamicViscosity.class);
149
150        /**
151         * Luminance is a photometric measure of the luminous intensity per unit area of
152         * light travelling in a given direction. It describes the amount of light that
153         * passes through, is emitted or reflected from a particular area, and falls
154         * within a given solid angle. The SI unit for luminance is candela per square
155         * metre (<code>cd/m2</code>).
156         * 
157         * @see <a href="https://en.wikipedia.org/wiki/Luminance"> Wikipedia:
158         *      Luminance</a>
159         */
160        public static final Unit<Luminance> CANDELA_PER_SQUARE_METRE = addUnit(
161                        new ProductUnit<Luminance>(CANDELA.divide(SQUARE_METRE)), Luminance.class);
162
163        /**
164         * The SI unit for kinematic viscosity quantities (standard name
165         * <code>m2/s"</code>).
166         */
167        public static final Unit<KinematicViscosity> SQUARE_METRE_PER_SECOND = addUnit(
168                        new ProductUnit<KinematicViscosity>(SQUARE_METRE.divide(SECOND)), KinematicViscosity.class);
169
170        /**
171         * The SI unit for magnetic field strength quantities (standard name
172         * <code>A/m"</code>).
173         */
174        public static final Unit<MagneticFieldStrength> AMPERE_PER_METRE = addUnit(
175                        new ProductUnit<MagneticFieldStrength>(AMPERE.divide(METRE)), MagneticFieldStrength.class);
176
177        /**
178         * The SI unit for ionizing radiation quantities (standard name
179         * <code>C/kg"</code>).
180         */
181        public static final Unit<IonizingRadiation> COULOMB_PER_KILOGRAM = addUnit(
182                        new ProductUnit<IonizingRadiation>(COULOMB.divide(KILOGRAM)), IonizingRadiation.class);
183
184        /**
185         * The SI unit for radiant intensity (standard name <code>W/sr</code>).
186         */
187        public static final Unit<RadiantIntensity> WATT_PER_STERADIAN = addUnit(
188                        WATT.divide(STERADIAN).asType(RadiantIntensity.class));
189
190        /**
191         * The SI unit for radiance (standard name <code>W⋅sr−1⋅m−2</code>).
192         */
193        public static final Unit<Radiance> WATT_PER_STERADIAN_PER_SQUARE_METRE = addUnit(
194                        WATT_PER_STERADIAN.divide(SQUARE_METRE).asType(Radiance.class));
195
196        /**
197         * The SI unit for intensity (standard name <code>W/m<sup>2</sup></code>).
198         */
199        public static final Unit<Intensity> WATT_PER_SQUARE_METRE = addUnit(
200                        WATT.divide(SQUARE_METRE).asType(Intensity.class));
201
202        /**
203         * The SI unit of angular speed (standard name <code>rad/s</code>).
204         * 
205         * @see AngularSpeed
206         */
207        public static final Unit<AngularSpeed> RADIAN_PER_SECOND = addUnit(
208                        new ProductUnit<AngularSpeed>(RADIAN.divide(SECOND)), "Radian per second", AngularSpeed.class);
209
210        /**
211         * The SI unit of angular acceleration (standard name <code>rad/s²</code>).
212         * 
213         * @see AngularAcceleration
214         */
215        public static final Unit<AngularAcceleration> RADIAN_PER_SQUARE_SECOND = addUnit(
216                        new ProductUnit<AngularAcceleration>(RADIAN_PER_SECOND.divide(SECOND)), "Radian per square second",
217                        AngularAcceleration.class);
218
219        /**
220         * An energy unit accepted for use with SI units (standard name
221         * <code>eV</code>). The electronvolt is the kinetic energy acquired by an
222         * electron passing through a potential difference of 1 V in vacuum. The value
223         * must be obtained by experiment, and is therefore not known exactly.
224         */
225        public static final Unit<Energy> ELECTRON_VOLT = addUnit(
226                        new TransformedUnit<Energy>(JOULE, MultiplyConverter.of(1.602176487E-19)));
227        // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
228
229        /**
230         * A mass unit accepted for use with SI units (standard name <code>u</code>).
231         * The unified atomic mass unit is equal to 1/12 of the mass of an unbound atom
232         * of the nuclide 12C, at rest and in its ground state. The value must be
233         * obtained by experiment, and is therefore not known exactly.
234         */
235        public static final Unit<Mass> UNIFIED_ATOMIC_MASS = addUnit(
236                        new TransformedUnit<Mass>(KILOGRAM, MultiplyConverter.of(1.660538782E-27)), "Unified atomic mass", "u",
237                        true);
238        // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
239
240        /**
241         * A length unit accepted for use with SI units (standard name <code>UA</code>).
242         * The astronomical unit is a unit of length. 
243         * Originally conceived as the average of Earth's aphelion and perihelion, 
244         * since 2012 it has been defined as exactly 149,597,870,700 metres, 
245         * or about 150 million kilometres (93 million miles).
246         * 
247         * @see <a href="https://en.wikipedia.org/wiki/Astronomical_unit"> Wikipedia: Astronomical unit</a>
248         */
249        public static final Unit<Length> ASTRONOMICAL_UNIT = addUnit(
250                        new TransformedUnit<Length>(METRE, MultiplyConverter.of(149597870700d)));
251
252        /**
253         * An angle unit accepted for use with SI units (standard name
254         * <code>rev</code>).
255         */
256        public static final Unit<Angle> REVOLUTION = addUnit(new TransformedUnit<Angle>(RADIAN,
257                        MultiplyConverter.ofPiExponent(1).concatenate(MultiplyConverter.ofRational(2, 1))));
258
259        ///////////////////////////
260        // Fundamental Constants //
261        ///////////////////////////
262
263        /**
264         * Holds the numeric value of the Avogadro constant.
265         */
266        static final double AVOGADRO_CONSTANT_VALUE = 6.02214199E23; // (1/mol).
267
268        /**
269         * Holds the numeric value of the Boltzmann constant.
270         */
271        static final double BOLTZMANN_CONSTANT_VALUE = 1.3806485279E-23;
272
273        /**
274         * Holds the electric charge value of one electron.
275         */
276        static final double ELEMENTARY_CHARGE_VALUE = 1.602176462E-19; // (C).
277
278        /**
279         * Holds the numeric value of the Planck constant.
280         */
281        static final double PLANCK_CONSTANT_VALUE = 6.62607015E-34; // (1/mol).
282
283        /**
284         * The Avogadro constant, named after scientist Amedeo Avogadro, is the number
285         * of constituent particles, usually molecules, atoms or ions that are contained
286         * in the amount of substance given by one mole. It is the proportionality
287         * factor that relates the molar mass of a substance to the mass of a sample, is
288         * designated with the symbol <code>N<sub>A<sub></code> or <code>L</code>, and has the
289         * value 6.022140857(74)×1023 mol−1 in the International System of Units (SI).
290         */
291        public static final Unit<Dimensionless> AVOGADRO_CONSTANT = addUnit(
292                        new AlternateUnit<Dimensionless>(ONE.divide(MOLE), "m-1").multiply(AVOGADRO_CONSTANT_VALUE), "NA", true); // (1/mol).
293
294        /**
295         * The Boltzmann constant (<code>k<sub>B<sub></code> or <code>k</code>) is a physical
296         * constant named after its discoverer, Ludwig Boltzmann, which relates the
297         * average relative kinetic energy of particles in a gas with the temperature of
298         * the gas and occurs in Planck's law of black-body radiation and in Boltzmann's
299         * entropy formula.
300         */
301        public static final Unit<Dimensionless> BOLTZMANN_CONSTANT = addUnit(
302                        new AlternateUnit<Dimensionless>(JOULE.divide(KELVIN), "J/K").multiply(BOLTZMANN_CONSTANT_VALUE), "kB",
303                        true);
304
305        /**
306         * The elementary charge, usually denoted by <code>e</code> or sometimes
307         * <code>qe</code>, is the electric charge carried by a single proton or,
308         * equivalently, the magnitude of the electric charge carried by a single
309         * electron, which has charge −1 e. This elementary charge is a fundamental
310         * physical constant. To avoid confusion over its sign, e is sometimes called
311         * the elementary positive charge.
312         */
313        public static final Unit<ElectricCharge> ELEMENTARY_CHARGE = addUnit(COULOMB.multiply(ELEMENTARY_CHARGE_VALUE), "e",
314                        true);
315
316        /**
317         * The Planck constant (denoted <code>ℎ</code>, also called Planck's constant)
318         * is a physical constant that is the quantum of electromagnetic action, which
319         * relates the energy carried by a photon to its frequency. A photon's energy is
320         * equal to its frequency multiplied by the Planck constant. The Planck constant
321         * is of fundamental importance in quantum mechanics, and in metrology it is the
322         * basis for the definition of the kilogram.
323         */
324        public static final Unit<Action> PLANCK_CONSTANT = addUnit(JOULE_SECOND.multiply(PLANCK_CONSTANT_VALUE), "\u210E", true);
325
326        /////////////////////
327        // Collection View //
328        /////////////////////
329
330        @Override
331        public String getName() {
332                return "SI";
333        }
334
335        /**
336         * Adds a new unit not mapped to any specified quantity type.
337         *
338         * @param unit the unit being added.
339         * @return <code>unit</code>.
340         */
341        private static <U extends Unit<?>> U addUnit(U unit) {
342                INSTANCE.units.add(unit);
343                return unit;
344        }
345
346        /**
347         * Adds a new unit not mapped to any specified quantity type and puts a text as
348         * symbol or label.
349         *
350         * @param unit    the unit being added.
351         * @param name    the string to use as name
352         * @param text    the string to use as label or symbol
353         * @param isLabel if the string should be used as a label or not
354         * @return <code>unit</code>.
355         */
356        private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) {
357                if (isLabel) {
358                        SimpleUnitFormat.getInstance().label(unit, text);
359                }
360                if (name != null && unit instanceof AbstractUnit) {
361                        return Helper.addUnit(INSTANCE.units, unit, name);
362                } else {
363                        INSTANCE.units.add(unit);
364                }
365                return unit;
366        }
367
368        /**
369         * Adds a new unit not mapped to any specified quantity type and puts a text as
370         * symbol or label.
371         *
372         * @param unit    the unit being added.
373         * @param text    the string to use as label or symbol
374         * @param isLabel if the string should be used as a label or not
375         * @return <code>unit</code>.
376         */
377        private static <U extends Unit<?>> U addUnit(U unit, String text, boolean isLabel) {
378                return addUnit(unit, null, text, isLabel);
379        }
380
381        /**
382         * Adds a new unit not mapped to any specified quantity type and puts a text as
383         * symbol or label.
384         *
385         * @param unit  the unit being added.
386         * @param name  the string to use as name
387         * @param label the string to use as label
388         * @return <code>unit</code>.
389         */
390        private static <U extends Unit<?>> U addUnit(U unit, String name, String label) {
391                return addUnit(unit, name, label, true);
392        }
393
394        /**
395         * Adds a new unit with name and label and maps it to the specified quantity
396         * type.
397         *
398         * @param unit  the unit being added.
399         * @param name  the string to use as name
400         * @param label the string to use as label
401         * @param type  the quantity type.
402         * @return <code>unit</code>.
403         */
404        @SuppressWarnings("unused")
405        private static <U extends AbstractUnit<?>> U addUnit(U unit, String name, String label,
406                        Class<? extends Quantity<?>> type) {
407                INSTANCE.quantityToUnit.put(type, unit);
408                return addUnit(unit, name, label);
409        }
410
411        /**
412         * Adds a new unit with a name and maps it to the specified quantity type.
413         *
414         * @param unit the unit being added.
415         * @param name the string to use as name
416         * @param type the quantity type.
417         * @return <code>unit</code>.
418         */
419        private static <U extends AbstractUnit<?>> U addUnit(U unit, String name, Class<? extends Quantity<?>> type) {
420                INSTANCE.quantityToUnit.put(type, unit);
421                return addUnit(unit, name, null, false);
422        }
423
424        /**
425         * Adds a new unit and maps it to the specified quantity type.
426         *
427         * @param unit the unit being added.
428         * @param type the quantity type.
429         * @return <code>unit</code>.
430         */
431        private static <U extends AbstractUnit<?>> U addUnit(U unit, Class<? extends Quantity<?>> type) {
432                INSTANCE.units.add(unit);
433                INSTANCE.quantityToUnit.put(type, unit);
434                return unit;
435        }
436}