/* * JaamSim Discrete Event Simulation * Copyright (C) 2011 Ausenco Engineering Canada Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jaamsim.units; import java.util.HashMap; import com.jaamsim.basicsim.Entity; import com.jaamsim.input.Keyword; public abstract class Unit extends Entity { @Keyword(description = "Factor to convert from the specified unit to the System International (SI) unit. " + "The factor is entered as A / B, where A is the first entry and B is the second. " + "For example, to convert from miles per hour to m/s, the first factor is 1609.344 (meters in one mile) and " + "the second factor is 3600 (seconds in one hour).", example = "mph ConversionFactorToSI { 1609.344 3600 }") private final SIUnitFactorInput conversionFactorToSI; { conversionFactorToSI = new SIUnitFactorInput("ConversionFactorToSI", "Key Inputs"); this.addInput(conversionFactorToSI); } private static final HashMap<Class<? extends Unit>, Unit> preferredUnit = new HashMap<>(); public Unit() {} private static final HashMap<Class<? extends Unit>, String> siUnit = new HashMap<>(); public static final void setSIUnit(Class<? extends Unit> unitType, String si) { siUnit.put(unitType, si); } /** * Get the SI unit for the given unit type. * @param unitType * @return a string describing the SI unit, or if one has not been defined: 'SI' */ public static final String getSIUnit(Class<? extends Unit> unitType) { String unit = siUnit.get(unitType); if (unit != null) return unit; return "SI"; } public static final void setPreferredUnit(Class<? extends Unit> type, Unit u) { preferredUnit.put(type, u); } public static final <T extends Unit> Unit getPreferredUnit(Class<T> type) { return preferredUnit.get(type); } public static final <T extends Unit> String getDisplayedUnit(Class<T> ut) { Unit u = Unit.getPreferredUnit(ut); if (u == null) return Unit.getSIUnit(ut); return u.getName(); } public static final <T extends Unit> double getDisplayedUnitFactor(Class<T> ut) { Unit u = Unit.getPreferredUnit(ut); if (u == null) return 1.0; return u.getConversionFactorToSI(); } /** * Return the conversion factor to SI units */ public double getConversionFactorToSI() { return conversionFactorToSI.getSIFactor(); } /** * Return the conversion factor to the given units */ public double getConversionFactorToUnit( Unit unit ) { double f1 = this.getConversionFactorToSI(); double f2 = unit.getConversionFactorToSI(); return f1 / f2 ; } private static class MultPair { Class<? extends Unit> a; Class<? extends Unit> b; public MultPair(Class<? extends Unit> a, Class<? extends Unit> b) { this.a = a; this.b = b; } @Override public int hashCode() { return a.hashCode() ^ b.hashCode(); } @Override public boolean equals(Object other) { if (!(other instanceof MultPair)) return false; MultPair op = (MultPair)other; return (a == op.a && b == op.b) || (a == op.b && b == op.a); // swapped order is still equal } } private static class DivPair { Class<? extends Unit> a; Class<? extends Unit> b; public DivPair(Class<? extends Unit> a, Class<? extends Unit> b) { this.a = a; this.b = b; } @Override public int hashCode() { return a.hashCode() ^ b.hashCode(); } @Override public boolean equals(Object other) { if (!(other instanceof DivPair)) return false; DivPair op = (DivPair)other; return (a == op.a && b == op.b); } } private static HashMap<MultPair, Class<? extends Unit>> multRules; private static HashMap<DivPair, Class<? extends Unit>> divRules; static { multRules = new HashMap<>(); divRules = new HashMap<>(); // Multiplication rules addMultRule( RateUnit.class, TimeUnit.class, DimensionlessUnit.class); addMultRule( SpeedUnit.class, TimeUnit.class, DistanceUnit.class); addMultRule( AccelerationUnit.class, TimeUnit.class, SpeedUnit.class); addMultRule( MassFlowUnit.class, TimeUnit.class, MassUnit.class); addMultRule( VolumeFlowUnit.class, TimeUnit.class, VolumeUnit.class); addMultRule( AngularSpeedUnit.class, TimeUnit.class, AngleUnit.class); addMultRule( PowerUnit.class, TimeUnit.class, EnergyUnit.class); addMultRule( CostRateUnit.class, TimeUnit.class, CostUnit.class); addMultRule( ViscosityUnit.class, TimeUnit.class, LinearDensityUnit.class); addMultRule( DistanceUnit.class, RateUnit.class, SpeedUnit.class); addMultRule( SpeedUnit.class, RateUnit.class, AccelerationUnit.class); addMultRule( MassUnit.class, RateUnit.class, MassFlowUnit.class); addMultRule( VolumeUnit.class, RateUnit.class, VolumeFlowUnit.class); addMultRule( AngleUnit.class, RateUnit.class, AngularSpeedUnit.class); addMultRule( EnergyUnit.class, RateUnit.class, PowerUnit.class); addMultRule( CostUnit.class, RateUnit.class, CostRateUnit.class); addMultRule( ViscosityUnit.class, RateUnit.class, PressureUnit.class); addMultRule( DistanceUnit.class, DistanceUnit.class, AreaUnit.class); addMultRule( LinearDensityUnit.class, DistanceUnit.class, MassUnit.class); addMultRule( LinearDensityVolumeUnit.class, DistanceUnit.class, VolumeUnit.class); addMultRule( AreaUnit.class, DistanceUnit.class, VolumeUnit.class); addMultRule( SpeedUnit.class, SpeedUnit.class, SpecificEnergyUnit.class); addMultRule( LinearDensityUnit.class, SpeedUnit.class, MassFlowUnit.class); addMultRule( LinearDensityVolumeUnit.class, SpeedUnit.class, VolumeFlowUnit.class); addMultRule( AreaUnit.class, SpeedUnit.class, VolumeFlowUnit.class); addMultRule( EnergyDensityUnit.class, VolumeUnit.class, EnergyUnit.class); addMultRule( DensityUnit.class, VolumeUnit.class, MassUnit.class); addMultRule( PressureUnit.class, VolumeUnit.class, EnergyUnit.class); addMultRule( EnergyDensityUnit.class, VolumeFlowUnit.class, PowerUnit.class); addMultRule( DensityUnit.class, VolumeFlowUnit.class, MassFlowUnit.class); addMultRule( PressureUnit.class, VolumeFlowUnit.class, PowerUnit.class); } public static void addMultRule(Class<? extends Unit> a, Class<? extends Unit> b, Class<? extends Unit> product) { MultPair key = new MultPair(a, b); multRules.put(key, product); // Add the corresponding division rules addDivRule(product, a, b); addDivRule(product, b, a); } public static void addDivRule(Class<? extends Unit> num, Class<? extends Unit> denom, Class<? extends Unit> product) { DivPair key = new DivPair(num, denom); divRules.put(key, product); } // Get the new unit type resulting from multiplying two unit types public static Class<? extends Unit> getMultUnitType(Class<? extends Unit> a, Class<? extends Unit> b) { if (a == DimensionlessUnit.class) return b; if (b == DimensionlessUnit.class) return a; return multRules.get(new MultPair(a, b)); } // Get the new unit type resulting from dividing two unit types public static Class<? extends Unit> getDivUnitType(Class<? extends Unit> num, Class<? extends Unit> denom) { if (denom == DimensionlessUnit.class) return num; if (num == denom) return DimensionlessUnit.class; return divRules.get(new DivPair(num, denom)); } }