001/* 002 * Units of Measurement Enum Implementation 003 * Copyright © 2005-2021, 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, Unit-API nor the names of their contributors may be used to endorse or promote products 017 * 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 tech.uom.impl.enums; 031 032import java.lang.ref.Reference; 033import java.lang.ref.WeakReference; 034import java.util.Map; 035 036import javax.measure.Dimension; 037import javax.measure.UnitConverter; 038 039import tech.uom.impl.enums.function.AbstractConverter; 040import tech.uom.impl.enums.unit.SimpleDimension; 041 042/** 043 * <p> This class represents the physical model used for dimensional analysis.</p> 044 * 045* <p> In principle, dimensions of physical quantities could be defined as "fundamental" 046 * (such as momentum or energy or electric current) making such quantities 047 * uncommensurate (not comparable). Modern physics has cast doubt on 048 * the very existence of incompatible fundamental dimensions of physical quantities. 049 * For example, most physicists do not recognize temperature, 050 * {@link QuantityDimension#TEMPERATURE Θ}, as a fundamental dimension since it 051 * essentially expresses the energy per particle per degree of freedom, 052 * which can be expressed in terms of energy (or mass, length, and time). 053 * To support, such model the method {@link #getConverter} may 054 * returns a non-null value for distinct dimensions.</p> 055 * 056 * <p> The default model is {@link StandardModel Standard}. Applications may 057 * use one of the predefined model or create their own. 058 * [code] 059 * DimensionalModel relativistic = new DimensionalModel() { 060 * public Dimension getFundamentalDimension(QuantityDimension dimension) { 061 * if (dimension.equals(QuantityDimension.LENGTH)) return QuantityDimension.TIME; // Consider length derived from time. 062 * return super.getDimension(dimension); // Returns product of fundamental dimension. 063 * } 064 * public UnitConverter getDimensionalTransform(QuantityDimension dimension) { 065 * if (dimension.equals(QuantityDimension.LENGTH)) return new RationalConverter(1, 299792458); // Converter (1/C) from LENGTH SI unit (m) to TIME SI unit (s). 066 * return super.getDimensionalTransform(dimension); 067 * } 068 * }; 069 * LocalContext.enter(); 070 * try { 071 * DimensionalModel.setCurrent(relativistic); // Current thread use the relativistic model. 072 * SI.KILOGRAM.getConverterToAny(SI.JOULE); // Allowed. 073 * ... 074 * } finally { 075 * LocalContext.exit(); 076 * } 077 * [/code]</p> 078 * 079 * @see <a href="http://en.wikipedia.org/wiki/Dimensional_analysis">Wikipedia: Dimensional Analysis</a> 080 * @author <a href="mailto:units@catmedia.us">Werner Keil</a> 081 * @version 0.2, $Date$ 082 */ 083public abstract class DimensionalModel { 084 085 /** 086 * Holds the current model. 087 */ 088 private static Reference<DimensionalModel> Current = new WeakReference<DimensionalModel>(new StandardModel()); 089 090 /** 091 * Returns the physics model used by the current thread 092 * (by default an instance of {@link StandardModel}). 093 * 094 * @return the getCurrent physical model. 095 * @see LocalContext 096 */ 097 public static DimensionalModel current() { 098 return DimensionalModel.Current.get(); 099 } 100 101// /** 102// * Sets the current physics model (local to the current thread when executing 103// * within a {@link LocalContext}). 104// * 105// * @param model the context-local physics model. 106// * @see #getCurrent 107// */ 108// public static void setCurrent(DimensionalModel model) { 109// DimensionalModel.Current. .Current set(model); 110// } 111 112 /** 113 * Default constructor (allows for derivation). 114 */ 115 protected DimensionalModel() { 116 } 117 118 /** 119 * Returns the fundamental dimension for the one specified. 120 * If the specified dimension is a dimensional product, the dimensional 121 * product of its fundamental dimensions is returned. 122 * Physical quantities are considered commensurate only if their 123 * fundamental dimensions are equals using the current physics model. 124 * 125 * @param dimension the dimension for which the fundamental dimension is returned. 126 * @return <code>this</code> or a rational product of fundamental dimension. 127 */ 128 public Dimension getFundamentalDimension(Dimension dimension) { 129 Map<? extends Dimension, Integer> dimensions = dimension.getBaseDimensions(); 130 if (dimensions == null) return dimension; // Fundamental dimension. 131 // Dimensional Product. 132 Dimension fundamentalProduct = SimpleDimension.INSTANCE; 133 for (Map.Entry<? extends Dimension, Integer> e : dimensions.entrySet()) { 134 fundamentalProduct = fundamentalProduct.multiply(this.getFundamentalDimension(e.getKey())).pow(e.getValue()); 135 } 136 return fundamentalProduct; 137 } 138 139 /** 140 * Returns the dimensional transform of the specified dimension. 141 * If the specified dimension is a fundamental dimension or 142 * a product of fundamental dimensions the identity converter is 143 * returned; otherwise the converter from the system unit (SI) of 144 * the specified dimension to the system unit (SI) of its fundamental 145 * dimension is returned. 146 * 147 * @param dimension the dimension for which the dimensional transform is returned. 148 * @return the dimensional transform (identity for fundamental dimensions). 149 */ 150 public UnitConverter getDimensionalTransform(Dimension dimension) { 151 Map<? extends Dimension, Integer> dimensions = dimension.getBaseDimensions(); 152 if (dimensions == null) return AbstractConverter.IDENTITY; // Fundamental dimension. 153 // Dimensional Product. 154 UnitConverter toFundamental = AbstractConverter.IDENTITY; 155 for (Map.Entry<? extends Dimension, Integer> e : dimensions.entrySet()) { 156 UnitConverter cvtr = this.getDimensionalTransform(e.getKey()); 157 if (!(cvtr.isLinear())) 158 throw new UnsupportedOperationException("Non-linear dimensional transform"); 159 int pow = e.getValue(); 160 if (pow < 0) { // Negative power. 161 pow = -pow; 162 cvtr = cvtr.inverse(); 163 } 164 for (int j = 0; j < pow; j++) { 165 toFundamental = toFundamental.concatenate(cvtr); 166 } 167 } 168 return toFundamental; 169 } 170 171}