001/*
002 *  Unit-API - Units of Measurement API for Java
003 *  Copyright (c) 2005-2015, 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 systems.uom.ucum.internal;
027
028import java.util.HashMap;
029
030import javax.measure.Quantity;
031import javax.measure.Unit;
032import javax.measure.quantity.*; 
033
034import si.uom.quantity.Action;
035import si.uom.quantity.DynamicViscosity;
036import si.uom.quantity.ElectricPermittivity;
037import si.uom.quantity.IonizingRadiation;
038import si.uom.quantity.KinematicViscosity;
039import si.uom.quantity.Luminance;
040import si.uom.quantity.MagneticFieldStrength;
041import si.uom.quantity.MagneticPermeability;
042//import si.uom.quantity.*;
043import si.uom.quantity.MagnetomotiveForce;
044import si.uom.quantity.WaveNumber;
045import tec.uom.se.AbstractUnit;
046import tec.uom.se.function.LogConverter;
047import tec.uom.se.function.MultiplyConverter;
048import tec.uom.se.function.PiMultiplierConverter;
049import tec.uom.se.function.RationalConverter;
050import tec.uom.se.unit.AlternateUnit;
051import tec.uom.se.unit.ProductUnit;
052import tec.uom.se.unit.TransformedUnit;
053import tec.uom.se.unit.Units;
054
055/**
056 * <p> This class defines all SI (Système International d'Unités) base units and
057 *     derived units as well as units that are accepted for use with the
058 *     SI units.</p>
059 *
060 * @see <a href="http://en.wikipedia.org/wiki/International_System_of_Units">Wikipedia: International System of Units</a>
061 * @see <a href="http://physics.nist.gov/cuu/Units/outside.html>Units outside the SI that are accepted for use with the SI</a>
062 * @see <a href="http://www.bipm.org/utils/common/pdf/si_brochure_8.pdf>SI 2006 - Official Specification</a>
063 * @see SIPrefix
064 *
065 * @author  <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
066 * @author  <a href="mailto:units@catmedia.us">Werner Keil</a>
067 * @version 0.7.1, July 21, 2015
068*/
069public final class SI extends Units {
070
071    /**
072     * The singleton instance.
073     */
074    private static final SI INSTANCE = new SI();
075
076    /**
077     * Holds the mapping quantity to unit.
078     */
079    private final HashMap<Class<? extends Quantity>, AbstractUnit>
080            quantityToUnit = new HashMap<Class<? extends Quantity>, AbstractUnit>();
081
082    /**
083     * Default constructor (prevents this class from being instantiated).
084     */
085    private SI() {
086    }
087
088    /**
089     * Returns the singleton instance of this class.
090     *
091     * @return the metric system instance.
092     */
093    public static SI getInstance() {
094        return INSTANCE;
095    }
096 
097    ////////////////////////////////
098    // SI DERIVED ALTERNATE UNITS //
099    ////////////////////////////////
100
101    /**
102     * The SI unit for magnetomotive force (standard name <code>At</code>).
103     */
104    public static final AlternateUnit<MagnetomotiveForce> AMPERE_TURN
105            = addUnit(new AlternateUnit<MagnetomotiveForce>(SI.AMPERE, "At"), 
106                        MagnetomotiveForce.class);
107    
108    //////////////////////////////
109    // SI DERIVED PRODUCT UNITS //
110    //////////////////////////////
111
112    /**
113     * The SI unit for acceleration quantities (standard name <code>m/s2</code>).
114     */
115    public static final Unit<Acceleration> METRES_PER_SQUARE_SECOND
116            = addUnit(new ProductUnit<Acceleration>(
117            METRES_PER_SECOND.divide(SECOND)), Acceleration.class);
118
119    /**
120     * The SI unit for action quantities (standard name <code>j.s</code>).
121     */
122    public static final Unit<Action> JOULE_SECOND
123            = addUnit(new ProductUnit<Action>(
124            JOULE.multiply(SECOND)), Action.class);
125
126    /**
127     * The SI unit for electric permittivity quantities (standard name <code>F/m</code>).
128     */
129    public static final Unit<ElectricPermittivity> FARADS_PER_METRE
130            = addUnit(new ProductUnit<ElectricPermittivity>(
131            FARAD.divide(METRE)), ElectricPermittivity.class);
132    
133    /**
134     * The SI unit for magnetic permeability quantities (standard name <code>N/A2</code>).
135     */
136    public static final Unit<MagneticPermeability> NEWTONS_PER_SQUARE_AMPERE
137            = addUnit(new ProductUnit<MagneticPermeability>(
138            NEWTON.divide(AMPERE.pow(2))), MagneticPermeability.class);
139
140    /**
141     * The SI unit for wave number quantities (standard name <code>1/m</code>).
142     */
143    public static final Unit<WaveNumber> RECIPROCAL_METRE
144            = addUnit(new ProductUnit<WaveNumber>(
145            METRE.pow(-1)), WaveNumber.class);
146
147    /**
148     * The SI unit for dynamic viscosity quantities (standard name <code>Pa.s</code>).
149     */
150    public static final Unit<DynamicViscosity> PASCAL_SECOND
151            = addUnit(new ProductUnit<DynamicViscosity>(
152            PASCAL.multiply(SECOND)), DynamicViscosity.class);
153
154    /**
155     * The SI unit for kinematic viscosity quantities (standard name <code>m2/s"</code>).
156     */
157    public static final Unit<KinematicViscosity> SQUARE_METRES_PER_SECOND
158            = addUnit(new ProductUnit<KinematicViscosity>(
159            SQUARE_METRE.divide(SECOND)), KinematicViscosity.class);
160
161    /**
162     * The SI unit for magnetic field strength quantities (standard name <code>A/m"</code>).
163     */
164    public static final Unit<MagneticFieldStrength> AMPERES_PER_METRE
165            = addUnit(new ProductUnit<MagneticFieldStrength>(
166            AMPERE.divide(METRE)), MagneticFieldStrength.class);
167
168    /**
169     * The SI unit for ionizing radiation quantities (standard name <code>C/kg"</code>).
170     */
171    public static final Unit<IonizingRadiation> COULOMBS_PER_KILOGRAM
172            = addUnit(new ProductUnit<IonizingRadiation>(
173            COULOMB.divide(KILOGRAM)), IonizingRadiation.class);
174
175    /////////////////////////////////////////////////////////////////
176    // Units outside the SI that are accepted for use with the SI. //
177    /////////////////////////////////////////////////////////////////
178
179    /**
180     * An angle unit accepted for use with SI units (standard name <code>deg/code>).
181     */
182    public static final Unit<Angle> DEGREE_ANGLE
183        = new TransformedUnit<Angle>(RADIAN, new PiMultiplierConverter().concatenate(new RationalConverter(1, 180)));
184
185    /**
186     * An angle unit accepted for use with SI units (standard name <code>'/code>).
187     */
188    public static final Unit<Angle> MINUTE_ANGLE
189        = new TransformedUnit<Angle>(RADIAN, new PiMultiplierConverter().concatenate(new RationalConverter(1, 180 * 60)));
190
191    /**
192     * An angle unit accepted for use with SI units (standard name <code>''</code>).
193     */
194    public static final Unit<Angle> SECOND_ANGLE
195        = new TransformedUnit<Angle>(RADIAN,  new PiMultiplierConverter().concatenate(new RationalConverter(1, 180 * 60 * 60)));
196
197    /**
198     * A volume unit accepted for use with SI units (standard name <code>l</code>).
199     */
200    public static final Unit<Volume> LITRE
201        = new TransformedUnit<Volume>(CUBIC_METRE, new RationalConverter(1, 1000));
202
203    /**
204     * A mass unit accepted for use with SI units (standard name <code>t</code>).
205     */
206    public static final Unit<Mass> TONNE
207        = new TransformedUnit<Mass>(KILOGRAM, new RationalConverter(1000, 1));
208
209    /**
210     * A dimensionless unit accepted for use with SI units (standard name <code>Np</code>).
211     * Although the neper is coherent with SI units and is accepted by the CIPM,
212     * it has not been adopted by the General Conference on Weights and Measures
213     * (CGPM, Conférence Générale des Poids et Mesures) and is thus not an SI unit.
214     */
215    public static final Unit<Dimensionless> NEPER
216        = new TransformedUnit<Dimensionless>(ONE, new LogConverter(E).inverse());
217
218    /**
219     * A dimensionless unit accepted for use with SI units (standard name <code>B</code>).
220     * The bel is most commonly used with the SI prefix deci: 1 dB = 0.1 B
221     */
222    public static final Unit<Dimensionless> BEL
223        = new TransformedUnit<Dimensionless>(ONE, new LogConverter(10).inverse());
224
225    /**
226     * An energy unit accepted for use with SI units (standard name <code>eV</code>).
227     * The electronvolt is the kinetic energy acquired by an electron passing
228     * through a potential difference of 1 V in vacuum. 
229     * The value must be obtained by experiment, and is therefore not known exactly.
230     */
231    public static final Unit<Energy> ELECTRON_VOLT
232        = new TransformedUnit<Energy>(JOULE, new MultiplyConverter(1.602176487E-19));
233        // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
234            
235    /**
236     * A mass unit accepted for use with SI units (standard name <code>u</code>).
237     *  The unified atomic mass unit is equal to 1/12 of the mass of an unbound
238     * atom of the nuclide 12C, at rest and in its ground state. The value must
239     * be obtained by experiment, and is therefore not known exactly.
240     */
241    public static final Unit<Mass> UNIFIED_ATOMIC_MASS
242        = new TransformedUnit<Mass>(KILOGRAM, new MultiplyConverter(1.660538782E-27));
243        // CODATA 2006 - http://physics.nist.gov/cuu/Constants/codata.pdf
244
245    /**
246     * A length unit accepted for use with SI units (standard name <code>UA</code>).
247     * The astronomical unit is a unit of length. Its value is such that,
248     * when used to describe the motion of bodies in the solar system,
249     * the heliocentric gravitation constant is (0.017 202 098 95)2 ua3·d-2.
250     * The value must be obtained by experiment, and is therefore not known exactly.
251     */
252    public static final Unit<Length> ASTRONOMICAL_UNIT
253        = addUnit(new TransformedUnit<Length>(METRE, new MultiplyConverter(149597871000.0)));
254        // Best estimate source: http://maia.usno.navy.mil/NSFA/CBE.html
255    
256    /**
257     *  An angle unit accepted for use with SI units (standard name <code>rev</code>).
258     */
259    public static final Unit<Angle> REVOLUTION
260            = new TransformedUnit<Angle>(RADIAN, new PiMultiplierConverter().concatenate(new RationalConverter(2, 1)));
261
262    /**
263     *  An angle unit accepted for use with SI units (standard name <code>ha</code>).
264     */
265    public static final Unit<Area> HECTARE
266            = new TransformedUnit<Area>(SQUARE_METRE, new RationalConverter(10000, 1));
267
268    /////////////////////
269    // Collection View //
270    /////////////////////
271
272    @Override
273    public String getName() {
274        return "SI";
275    }
276    
277    @SuppressWarnings("unchecked")
278        @Override
279    public <Q extends Quantity<Q>> AbstractUnit<Q> getUnit(Class<Q> quantityType) {
280        return quantityToUnit.get(quantityType);
281    }
282
283    /**
284     * Adds a new unit not mapped to any specified quantity type.
285     *
286     * @param  unit the unit being added.
287     * @return <code>unit</code>.
288     */
289    private static <U extends Unit<?>>  U addUnit(U unit) {
290        INSTANCE.units.add(unit);
291        return unit;
292    }
293
294    /**
295     * Adds a new unit and maps it to the specified quantity type.
296     *
297     * @param  unit the unit being added.
298     * @param type the quantity type.
299     * @return <code>unit</code>.
300     */
301    private static <U extends AbstractUnit<?>>  U addUnit(U unit, Class<? extends Quantity<?>> type) {
302        INSTANCE.units.add(unit);
303        INSTANCE.quantityToUnit.put(type, unit);
304        return unit;
305    }
306}