blob: 8a8939dd4288a70e753b6210a5d7518906ead281 [file] [log] [blame]
/*
* Copyright (c) 2005, 2017, Werner Keil and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Werner Keil - initial API and implementation
*/
package org.eclipse.uomo.units.impl;
import javax.measure.Dimension;
import javax.measure.UnitConverter;
import org.eclipse.uomo.units.AbstractConverter;
import java.util.Map;
/**
* <p>
* This class represents the physical model used for dimensional analysis.
* </p>
*
* <p>
* In principle, dimensions of physical quantities could be defined as "fundamental" (such as momentum or energy or electric current) making such
* quantities uncommensurate (not comparable). Modern physics has cast doubt on the very existence of incompatible fundamental dimensions of physical
* quantities. For example, most physicists do not recognize temperature, {@link QuantityDimension#TEMPERATURE Θ}, as a fundamental dimension since it
* essentially expresses the energy per particle per degree of freedom, which can be expressed in terms of energy (or mass, length, and time). To
* support, such model the method {@link #getConverter} may returns a non-null value for distinct dimensions.
* </p>
*
* <p>
* The default model is {@link StandardModel Standard}. Applications may use one of the predefined model or create their own. <code>
* DimensionalModel relativistic = new DimensionalModel() {
* public Dimension getFundamentalDimension(Dimension dimension) {
* if (dimension.equals(QuantityDimension.LENGTH)) return QuantityDimension.TIME; // Consider length derived from time.
* return super.getDimension(dimension); // Returns product of fundamental dimension.
* }
* public UnitConverter getDimensionalTransform(Dimension dimension) {
* if (dimension.equals(QuantityDimension.LENGTH)) return new RationalConverter(1, 299792458); // Converter (1/C) from LENGTH SI unit (m) to TIME SI unit (s).
* return super.getDimensionalTransform(dimension);
* }
* };
* try {
* DimensionalModel.setCurrent(relativistic); // Current thread use the relativistic model.
* Units.KILOGRAM.getConverterToAny(Units.JOULE); // Allowed.
* ...
* } finally {
* cleanup();
* }
* </code>
* </p>
*
* @see <a href="http://en.wikipedia.org/wiki/Dimensional_analysis">Wikipedia: Dimensional Analysis</a>
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @author <a href="mailto:units@catmedia.us">Werner Keil</a>
* @version 0.5.5, $Date: 2015-07-25 $
*/
public abstract class DimensionalModel {
/**
* Holds the current model.
*/
private static DimensionalModel currentModel = new StandardModel();
/**
* Returns the current model (by default an instance of {@link StandardModel}).
*
* @return the current dimensional model.
*/
public static DimensionalModel current() {
return currentModel;
}
/**
* Sets the current dimensional model
*
* @param model
* the new current model.
* @see #current
*/
protected static void setCurrent(DimensionalModel model) {
currentModel = model;
}
/**
* DefaultQuantityFactory constructor (allows for derivation).
*/
protected DimensionalModel() {
}
/**
* Returns the fundamental dimension for the one specified. If the specified dimension is a dimensional product, the dimensional product of its
* fundamental dimensions is returned. Physical quantities are considered commensurate only if their fundamental dimensions are equals using the
* current physics model.
*
* @param dimension
* the dimension for which the fundamental dimension is returned.
* @return <code>this</code> or a rational product of fundamental dimension.
*/
public Dimension getFundamentalDimension(Dimension dimension) {
Map<? extends Dimension, Integer> dimensions = dimension.getBaseDimensions();
if (dimensions == null)
return dimension; // Fundamental dimension.
// Dimensional Product.
Dimension fundamentalProduct = DimensionImpl.NONE;
for (Map.Entry<? extends Dimension, Integer> e : dimensions.entrySet()) {
fundamentalProduct = fundamentalProduct.multiply(this.getFundamentalDimension(e.getKey())).pow(e.getValue());
}
return fundamentalProduct;
}
/**
* Returns the dimensional transform of the specified dimension. If the specified dimension is a fundamental dimension or a product of fundamental
* dimensions the identity converter is returned; otherwise the converter from the system unit (SI) of the specified dimension to the system unit
* (SI) of its fundamental dimension is returned.
*
* @param dimension
* the dimension for which the dimensional transform is returned.
* @return the dimensional transform (identity for fundamental dimensions).
*/
public UnitConverter getDimensionalTransform(Dimension dimension) {
Map<? extends Dimension, Integer> dimensions = dimension.getBaseDimensions();
if (dimensions == null)
return AbstractConverter.IDENTITY; // Fundamental dimension.
// Dimensional Product.
UnitConverter toFundamental = AbstractConverter.IDENTITY;
for (Map.Entry<? extends Dimension, Integer> e : dimensions.entrySet()) {
UnitConverter cvtr = this.getDimensionalTransform(e.getKey());
if (!(cvtr.isLinear()))
throw new UnsupportedOperationException("Non-linear dimensional transform");
int pow = e.getValue();
if (pow < 0) { // Negative power.
pow = -pow;
cvtr = cvtr.inverse();
}
for (int j = 0; j < pow; j++) {
toFundamental = toFundamental.concatenate(cvtr);
}
}
return toFundamental;
}
}