001/*
002 * International System of Units (SI)
003 * Copyright (c) 2005-2021, 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 SI System, 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.8, May 20, 2021
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 absement quantities (standard name <code>m.s</code>).
117         * @see <a href="https://en.wikipedia.org/wiki/Absement"> Wikipedia:
118         *      Absement</a>
119         */
120        public static final Unit<Absement> METRE_SECOND = addUnit(
121                        new ProductUnit<Absement>(METRE.multiply(SECOND)), Absement.class);
122        
123        /**
124         * The SI unit for action quantities (standard name <code>J.s</code>).
125         */
126        public static final Unit<Action> JOULE_SECOND = addUnit(new ProductUnit<Action>(JOULE.multiply(SECOND)),
127                        Action.class);
128
129        /**
130         * The SI unit for electric permittivity (standard name <code>ε</code>,
131         * <code>F/m </code> or <code>F·m−1</code>). In electromagnetism, absolute
132         * permittivity is the measure of resistance that is encountered when forming an
133         * electric field in a medium.
134         */
135        public static final Unit<ElectricPermittivity> FARAD_PER_METRE = addUnit(
136                        new ProductUnit<ElectricPermittivity>(FARAD.divide(METRE)), ElectricPermittivity.class);
137
138        /**
139         * The SI unit for electrical conductivity, <code>S/m</code>).
140     * @see <a href="https://en.wikipedia.org/wiki/Electrical_resistivity_and_conductivity">Wikipedia: Electrical resistivity and conductivity</a>
141         */
142        public static final Unit<ElectricalConductivity> SIEMENS_PER_METRE = addUnit(
143                        new ProductUnit<ElectricalConductivity>(SIEMENS.divide(METRE)), ElectricalConductivity.class);
144
145        /**
146         * The SI unit for electrical resistivity, <code>Ω⋅m</code>).
147     * @see <a href="https://en.wikipedia.org/wiki/Electrical_resistivity_and_conductivity">Wikipedia: Electrical resistivity and conductivity</a>
148         */
149        public static final Unit<ElectricalResistivity> OHM_METRE = addUnit(
150                        new ProductUnit<ElectricalResistivity>(OHM.multiply(METRE)), ElectricalResistivity.class);
151        
152        /**
153         * The SI unit for magnetic permeability quantities (standard name
154         * <code>N/A2</code>).
155         */
156        public static final Unit<MagneticPermeability> NEWTON_PER_SQUARE_AMPERE = addUnit(
157                        new ProductUnit<MagneticPermeability>(NEWTON.divide(AMPERE.pow(2))), MagneticPermeability.class);
158
159        /**
160         * The SI unit for wave number quantities (standard name <code>1/m</code>).
161         */
162        public static final Unit<WaveNumber> RECIPROCAL_METRE = addUnit(new ProductUnit<WaveNumber>(METRE.pow(-1)),
163                        WaveNumber.class);
164
165        /**
166         * The SI unit for dynamic viscosity quantities (standard name
167         * <code>Pa.s</code>).
168         */
169        public static final Unit<DynamicViscosity> PASCAL_SECOND = addUnit(
170                        new ProductUnit<DynamicViscosity>(PASCAL.multiply(SECOND)), DynamicViscosity.class);
171
172        /**
173         * Luminance is a photometric measure of the luminous intensity per unit area of
174         * light travelling in a given direction. It describes the amount of light that
175         * passes through, is emitted or reflected from a particular area, and falls
176         * within a given solid angle. The SI unit for luminance is candela per square
177         * metre (<code>cd/m2</code>).
178         * 
179         * @see <a href="https://en.wikipedia.org/wiki/Luminance"> Wikipedia:
180         *      Luminance</a>
181         */
182        public static final Unit<Luminance> CANDELA_PER_SQUARE_METRE = addUnit(
183                        new ProductUnit<Luminance>(CANDELA.divide(SQUARE_METRE)), Luminance.class);
184
185        /**
186         * The SI unit for kinematic viscosity quantities (standard name
187         * <code>m2/s"</code>).
188         */
189        public static final Unit<KinematicViscosity> SQUARE_METRE_PER_SECOND = addUnit(
190                        new ProductUnit<KinematicViscosity>(SQUARE_METRE.divide(SECOND)), KinematicViscosity.class);
191
192        /**
193         * The SI unit for magnetic field strength quantities (standard name
194         * <code>A/m"</code>).
195         */
196        public static final Unit<MagneticFieldStrength> AMPERE_PER_METRE = addUnit(
197                        new ProductUnit<MagneticFieldStrength>(AMPERE.divide(METRE)), MagneticFieldStrength.class);
198
199        /**
200         * The SI unit for ionizing radiation quantities (standard name
201         * <code>C/kg"</code>).
202         */
203        public static final Unit<IonizingRadiation> COULOMB_PER_KILOGRAM = addUnit(
204                        new ProductUnit<IonizingRadiation>(COULOMB.divide(KILOGRAM)), IonizingRadiation.class);
205
206        /**
207         * The SI unit for radiant intensity (standard name <code>W/sr</code>).
208         */
209        public static final Unit<RadiantIntensity> WATT_PER_STERADIAN = addUnit(
210                        WATT.divide(STERADIAN).asType(RadiantIntensity.class));
211
212        /**
213         * The SI unit for radiance (standard name <code>W⋅sr−1⋅m−2</code>).
214         */
215        public static final Unit<Radiance> WATT_PER_STERADIAN_PER_SQUARE_METRE = addUnit(
216                        WATT_PER_STERADIAN.divide(SQUARE_METRE).asType(Radiance.class));
217
218        /**
219         * The SI unit for intensity (standard name <code>W/m<sup>2</sup></code>).
220         */
221        public static final Unit<Intensity> WATT_PER_SQUARE_METRE = addUnit(
222                        WATT.divide(SQUARE_METRE).asType(Intensity.class));
223
224        /**
225         * The SI unit of angular speed (standard name <code>rad/s</code>).
226         * 
227         * @see AngularSpeed
228         */
229        public static final Unit<AngularSpeed> RADIAN_PER_SECOND = addUnit(
230                        new ProductUnit<AngularSpeed>(RADIAN.divide(SECOND)), "Radian per second", AngularSpeed.class);
231
232        /**
233         * The SI unit of angular acceleration (standard name <code>rad/s²</code>).
234         * 
235         * @see AngularAcceleration
236         */
237        public static final Unit<AngularAcceleration> RADIAN_PER_SQUARE_SECOND = addUnit(
238                        new ProductUnit<AngularAcceleration>(RADIAN_PER_SECOND.divide(SECOND)), "Radian per square second",
239                        AngularAcceleration.class);
240
241        /**
242         * An energy unit accepted for use with SI units (standard name
243         * <code>eV</code>). The electronvolt is the kinetic energy acquired by an
244         * electron passing through a potential difference of 1 V in vacuum. The value
245         * must be obtained by experiment, and is therefore not known exactly.
246         */
247        public static final Unit<Energy> ELECTRON_VOLT = addUnit(
248                        new TransformedUnit<Energy>(JOULE, MultiplyConverter.of(1.602176487E-19)), "Electron Volt", "eV");
249        // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
250
251        /**
252         * A mass unit accepted for use with SI units (standard name <code>u</code>).
253         * The unified atomic mass unit is equal to 1/12 of the mass of an unbound atom
254         * of the nuclide 12C, at rest and in its ground state. The value must be
255         * obtained by experiment, and is therefore not known exactly.
256         */
257        public static final Unit<Mass> UNIFIED_ATOMIC_MASS = addUnit(
258                        new TransformedUnit<Mass>(KILOGRAM, MultiplyConverter.of(1.660538782E-27)), "Unified atomic mass", "u",
259                        true);
260        // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
261
262        /**
263         * A length unit accepted for use with SI units (standard name <code>UA</code>).
264         * The astronomical unit is a unit of length. 
265         * Originally conceived as the average of Earth's aphelion and perihelion, 
266         * since 2012 it has been defined as exactly 149,597,870,700 metres, 
267         * or about 150 million kilometres (93 million miles).
268         * 
269         * @see <a href="https://en.wikipedia.org/wiki/Astronomical_unit"> Wikipedia: Astronomical unit</a>
270         */
271        public static final Unit<Length> ASTRONOMICAL_UNIT = addUnit(
272                        new TransformedUnit<Length>(METRE, MultiplyConverter.of(149597870700d)),
273                        "Astronomical Unit", "UA");
274
275        /**
276         * An angle unit accepted for use with SI units (standard name
277         * <code>rev</code>).
278         */
279        public static final Unit<Angle> REVOLUTION = addUnit(new TransformedUnit<Angle>(RADIAN,
280                        MultiplyConverter.ofPiExponent(1).concatenate(MultiplyConverter.ofRational(2, 1))),
281                        "Revolution", "rev");
282
283        /**
284     * A kilogram per second (kg/s) is the derived SI unit of mass flow rate.<br>
285         * 
286         * @see <a href="https://en.wikipedia.org/wiki/Mass_flow_rate"> Wikipedia:
287         *      Mass flow rate</a>
288         */
289        public static final Unit<MassFlowRate> KILOGRAM_PER_SECOND = addUnit(
290                        new ProductUnit<MassFlowRate>(KILOGRAM.divide(SECOND)), MassFlowRate.class);
291        
292        /**
293     * The newton-second (also newton second; symbol: N⋅s or N s)[1] is the derived SI unit of impulse.<br>
294     * It is dimensionally equivalent to the momentum unit kilogram-metre per second (kg⋅m/s).<br>
295     * One newton-second corresponds to a one-newton force applied for one second.
296         * 
297         * @see <a href="https://en.wikipedia.org/wiki/Impulse_(physics)">Wikipedia: Impulse (physics)</a>
298         * @see #KILOGRAM_METRE_PER_SECOND
299         */
300        public static final Unit<Impulse> NEWTON_SECOND = addUnit(
301                        new ProductUnit<Impulse>(NEWTON.multiply(SECOND)), Impulse.class);
302        
303        /**
304     * A kilogram-metre per second (kg⋅m/s) is the derived SI unit of momentum.<br>
305     * It is dimensionally equivalent to the newton-second.<br>
306     * One newton-second corresponds to a one-newton force applied for one second.
307         * 
308         * @see #NEWTON_SECOND
309         * @see <a href="https://en.wikipedia.org/wiki/Momentum"> Wikipedia:
310         *      Momentum</a>
311         */
312        public static final Unit<Momentum> KILOGRAM_METRE_PER_SECOND = addUnit(
313                        new ProductUnit<Momentum>(KILOGRAM.multiply(METRE_PER_SECOND)), Momentum.class);
314        
315        /**
316     * A kilogram per second (kg/m2) is the derived SI unit of area density. 
317         * 
318     * @see <a href="https://en.wikipedia.org/wiki/Area_density"> Wikipedia:
319     *      Area density</a>
320         */
321        public static final Unit<AreaDensity> KILOGRAM_PER_SQUARE_METRE = addUnit(
322                        new ProductUnit<AreaDensity>(KILOGRAM.divide(SQUARE_METRE)), AreaDensity.class);
323        
324        /**
325     * A gray per second (kg⋅m/s) is the derived SI unit of radiation absorbed dose rate.<br> 
326         * 
327         * @see <a href="https://en.wikipedia.org/wiki/Absorbed_dose"> Wikipedia:
328         *      Absorbed dose</a>
329         */
330        public static final Unit<RadiationDoseAbsorbedRate> GRAY_PER_SECOND = addUnit(
331                        new ProductUnit<RadiationDoseAbsorbedRate>(GRAY.divide(SECOND)), RadiationDoseAbsorbedRate.class);
332
333                
334        ///////////////////////////
335        // Fundamental Constants //
336        ///////////////////////////
337
338        /**
339         * Holds the numeric value of the Avogadro constant.
340         */
341        static final double AVOGADRO_CONSTANT_VALUE = 6.02214199E23; // (1/mol).
342
343        /**
344         * Holds the numeric value of the Boltzmann constant.
345         */
346        static final double BOLTZMANN_CONSTANT_VALUE = 1.3806485279E-23;
347
348        /**
349         * Holds the electric charge value of one electron.
350         */
351        static final double ELEMENTARY_CHARGE_VALUE = 1.602176462E-19; // (C).
352
353        /**
354         * Holds the numeric value of the Planck constant.
355         */
356        static final double PLANCK_CONSTANT_VALUE = 6.62607015E-34; // (1/mol).
357
358        /**
359         * The Avogadro constant, named after scientist Amedeo Avogadro, is the number
360         * of constituent particles, usually molecules, atoms or ions that are contained
361         * in the amount of substance given by one mole. It is the proportionality
362         * factor that relates the molar mass of a substance to the mass of a sample, is
363         * designated with the symbol <code>N<sub>A<sub></code> or <code>L</code>, and has the
364         * value 6.022140857(74)×1023 mol−1 in the International System of Units (SI).
365         */
366        public static final Unit<Dimensionless> AVOGADRO_CONSTANT = addUnit(
367                        new AlternateUnit<Dimensionless>(ONE.divide(MOLE), "m-1").multiply(AVOGADRO_CONSTANT_VALUE), "NA", true); // (1/mol).
368
369        /**
370         * The Boltzmann constant (<code>k<sub>B</sub></code> or <code>k</code>) is a physical
371         * constant named after its discoverer, Ludwig Boltzmann, which relates the
372         * average relative kinetic energy of particles in a gas with the temperature of
373         * the gas and occurs in Planck's law of black-body radiation and in Boltzmann's
374         * entropy formula.
375         */
376        public static final Unit<Dimensionless> BOLTZMANN_CONSTANT = addUnit(
377                        new AlternateUnit<Dimensionless>(JOULE.divide(KELVIN), "J/K").multiply(BOLTZMANN_CONSTANT_VALUE), "kB",
378                        true);
379
380        /**
381         * The elementary charge, usually denoted by <code>e</code> or sometimes
382         * <code>qe</code>, is the electric charge carried by a single proton or,
383         * equivalently, the magnitude of the electric charge carried by a single
384         * electron, which has charge −1 e. This elementary charge is a fundamental
385         * physical constant. To avoid confusion over its sign, e is sometimes called
386         * the elementary positive charge.
387         */
388        public static final Unit<ElectricCharge> ELEMENTARY_CHARGE = addUnit(COULOMB.multiply(ELEMENTARY_CHARGE_VALUE), "e",
389                        true);
390
391        /**
392         * The Planck constant (denoted <code>ℎ</code>, also called Planck's constant)
393         * is a physical constant that is the quantum of electromagnetic action, which
394         * relates the energy carried by a photon to its frequency. A photon's energy is
395         * equal to its frequency multiplied by the Planck constant. The Planck constant
396         * is of fundamental importance in quantum mechanics, and in metrology it is the
397         * basis for the definition of the kilogram.
398         */
399        public static final Unit<Action> PLANCK_CONSTANT = addUnit(JOULE_SECOND.multiply(PLANCK_CONSTANT_VALUE), "\u210E", true);
400        
401        /////////////////////
402        // Collection View //
403        /////////////////////
404
405        @Override
406        public String getName() {
407                return "SI";
408        }
409
410        /**
411         * Adds a new unit not mapped to any specified quantity type.
412         *
413         * @param unit the unit being added.
414         * @return <code>unit</code>.
415         */
416        private static <U extends Unit<?>> U addUnit(U unit) {
417                INSTANCE.units.add(unit);
418                return unit;
419        }
420
421        /**
422         * Adds a new unit not mapped to any specified quantity type and puts a text as
423         * symbol or label.
424         *
425         * @param unit    the unit being added.
426         * @param name    the string to use as name
427         * @param text    the string to use as label or symbol
428         * @param isLabel if the string should be used as a label or not
429         * @return <code>unit</code>.
430         */
431        private static <U extends Unit<?>> U addUnit(U unit, String name, String text, boolean isLabel) {
432                if (isLabel) {
433                        SimpleUnitFormat.getInstance().label(unit, text);
434                }
435                if (name != null && unit instanceof AbstractUnit) {
436                        return Helper.addUnit(INSTANCE.units, unit, name);
437                } else {
438                        INSTANCE.units.add(unit);
439                }
440                return unit;
441        }
442
443        /**
444         * Adds a new unit not mapped to any specified quantity type and puts a text as
445         * symbol or label.
446         *
447         * @param unit    the unit being added.
448         * @param text    the string to use as label or symbol
449         * @param isLabel if the string should be used as a label or not
450         * @return <code>unit</code>.
451         */
452        private static <U extends Unit<?>> U addUnit(U unit, String text, boolean isLabel) {
453                return addUnit(unit, null, text, isLabel);
454        }
455
456        /**
457         * Adds a new unit not mapped to any specified quantity type and puts a text as
458         * symbol or label.
459         *
460         * @param unit  the unit being added.
461         * @param name  the string to use as name
462         * @param label the string to use as label
463         * @return <code>unit</code>.
464         */
465        private static <U extends Unit<?>> U addUnit(U unit, String name, String label) {
466                return addUnit(unit, name, label, true);
467        }
468
469        /**
470         * Adds a new unit with name and label and maps it to the specified quantity
471         * type.
472         *
473         * @param unit  the unit being added.
474         * @param name  the string to use as name
475         * @param label the string to use as label
476         * @param type  the quantity type.
477         * @return <code>unit</code>.
478         */
479        @SuppressWarnings("unused")
480        private static <U extends AbstractUnit<?>> U addUnit(U unit, String name, String label,
481                        Class<? extends Quantity<?>> type) {
482                INSTANCE.quantityToUnit.put(type, unit);
483                return addUnit(unit, name, label);
484        }
485
486        /**
487         * Adds a new unit with a name and maps it to the specified quantity type.
488         *
489         * @param unit the unit being added.
490         * @param name the string to use as name
491         * @param type the quantity type.
492         * @return <code>unit</code>.
493         */
494        private static <U extends AbstractUnit<?>> U addUnit(U unit, String name, Class<? extends Quantity<?>> type) {
495                INSTANCE.quantityToUnit.put(type, unit);
496                return addUnit(unit, name, null, false);
497        }
498
499        /**
500         * Adds a new unit and maps it to the specified quantity type.
501         *
502         * @param unit the unit being added.
503         * @param type the quantity type.
504         * @return <code>unit</code>.
505         */
506        private static <U extends AbstractUnit<?>> U addUnit(U unit, Class<? extends Quantity<?>> type) {
507                INSTANCE.units.add(unit);
508                INSTANCE.quantityToUnit.put(type, unit);
509                return unit;
510        }
511}