001/* The Unit Library 002 003 Copyright (c) 2003-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_3 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.moml.unit; 028 029import java.net.URL; 030import java.util.Iterator; 031import java.util.Vector; 032 033import ptolemy.data.expr.Parameter; 034import ptolemy.data.unit.BaseUnit; 035import ptolemy.data.unit.UnitSystem; 036import ptolemy.data.unit.UnitUtilities; 037import ptolemy.kernel.util.InternalErrorException; 038import ptolemy.kernel.util.NamedObj; 039import ptolemy.moml.MoMLParser; 040import ptolemy.util.FileUtilities; 041 042/////////////////////////////////////////////////////////////////// 043//// UnitLibrary 044 045/** A Library containing definitions of commonly used units. 046 047 Currently, the Unit library is static in the sense that it is 048 loaded when the system starts and is hard-wired to a particular 049 Unit System (the System International Unit System). However, it 050 should be easy to change the architecture so that multiple Unit 051 Systems can be accommodated, and loaded on-the-fly. 052 053 @author Rowland R Johnson 054 @version $Id$ 055 @since Ptolemy II 8.0 056 @Pt.ProposedRating Red (rowland) 057 @Pt.AcceptedRating Red (rowland) 058 */ 059public class UnitLibrary { 060 public UnitLibrary() { 061 } 062 063 /////////////////////////////////////////////////////////////////// 064 //// public variables //// 065 066 /** The Identity Unit, i.e. 1.0*<0, 0, ..., 0> */ 067 public static final Unit Identity; 068 069 /////////////////////////////////////////////////////////////////// 070 //// public methods //// 071 072 /** Add a unit to the Library. 073 * @param unit Unit to add to the library. 074 */ 075 public static void addToLibrary(Unit unit) { 076 _unitsLibrary.add(unit); 077 } 078 079 /** Find the Unit in the library that is basic (scale equal to 1), 080 * singular (all but one dimensions equal to 0). 081 * @param catNum The category number. 082 * @return The basic, singular unit. 083 */ 084 public static Unit getBaseUnit(int catNum) { 085 Vector library = UnitLibrary.getLibrary(); 086 087 for (int i = 0; i < library.size(); i++) { 088 Unit lUnit = (Unit) library.elementAt(i); 089 090 if (lUnit.getScale() != 1.0) { 091 continue; 092 } 093 094 int[] ltype = lUnit.getType(); 095 096 if (ltype[catNum] != 1.0) { 097 continue; 098 } 099 100 // Findbugs says this is useless code. 101 //for (int j = 0; j < UnitLibrary.getNumCategories(); j++) { 102 // if ((j != catNum) && (ltype[j] != 0)) { 103 // continue; 104 // } 105 //} 106 107 return lUnit; 108 } 109 110 return null; 111 } 112 113 /** Search Library to find Unit that has the same type and is the 114 * closest to a unit in terms of the scalars. 115 * @param unit The unit for which to search. 116 * @return The Unit closest to this the argument. Null, if there are no 117 * Units in the Library with the same type. 118 */ 119 public static Unit getClosestUnit(Unit unit) { 120 Vector possibles = getUnitsByType(unit); 121 122 if (possibles.isEmpty()) { 123 return null; 124 } 125 126 double scalarDistance = Double.MAX_VALUE; 127 Unit retv = null; 128 129 for (int i = 0; i < possibles.size(); i++) { 130 Unit possible = (Unit) possibles.elementAt(i); 131 double distance = Math.abs(possible.getScale() - unit.getScale()); 132 133 if (distance < scalarDistance) { 134 scalarDistance = distance; 135 retv = possible; 136 } 137 } 138 139 return retv; 140 } 141 142 /** Return the Library. 143 * @return The Library 144 */ 145 public static Vector getLibrary() { 146 return _unitsLibrary; 147 } 148 149 /** Return the number of categories. 150 * @return Number of categories. 151 */ 152 public static int getNumCategories() { 153 return _numCats; 154 } 155 156 /** Return the Parser. 157 * @return The Parser. 158 */ 159 public static UParser getParser() { 160 return _parser; 161 } 162 163 /** Search Library for Unit equal to a particular unit. That is, both the 164 * type and scalar must be equal to the argument. 165 * @param unit The unit to search for. 166 * @return Unit in Library equal to this one. Null if none found. 167 */ 168 public static Unit getUnit(Unit unit) { 169 Unit retv = getClosestUnit(unit); 170 171 if (retv == null) { 172 return null; 173 } 174 175 if (Math.abs(retv.getScale() - unit.getScale()) < 1.0E-8) { 176 return retv; 177 } 178 179 return null; 180 } 181 182 /** Search the Library for a unit with a particular name. 183 * @param name The name of the desired unit. 184 * @return The unit with name equal to the argument. Null, if the Library 185 * doesn't have a unit with that name. 186 */ 187 public static Unit getUnitByName(String name) { 188 Vector library = getLibrary(); 189 190 for (int i = 0; i < library.size(); i++) { 191 Unit lUnit = (Unit) library.elementAt(i); 192 Vector names = lUnit.getLabels(); 193 194 for (int j = 0; j < names.size(); j++) { 195 if (((String) names.elementAt(j)).equals(name)) { 196 return lUnit; 197 } 198 } 199 } 200 201 return null; 202 } 203 204 /** Search Library for all Units with type equal to this one. 205 * @param unit The unit to search for. 206 * @return Vector of Units with type equal to the argument. 207 */ 208 public static Vector getUnitsByType(Unit unit) { 209 Vector retv = new Vector(); 210 Vector library = UnitLibrary.getLibrary(); 211 212 for (int i = 0; i < library.size(); i++) { 213 Unit lUnit = (Unit) library.elementAt(i); 214 215 if (lUnit.hasSameType(unit)) { 216 retv.add(lUnit); 217 } 218 } 219 220 return retv; 221 } 222 223 /////////////////////////////////////////////////////////////////// 224 //// private variables //// 225 private static boolean _debug = false; 226 227 private static int _numCats; 228 229 private static UParser _parser; 230 231 private static Vector _unitsLibrary; 232 233 static { 234 _parser = new UParser(); 235 236 MoMLParser momlParser = new MoMLParser(); 237 UnitSystem us = null; 238 239 try { 240 NamedObj container = new NamedObj(); 241 momlParser.setContext(container); 242 243 URL inURL = FileUtilities.nameToURL( 244 "$CLASSPATH/ptolemy/data/unit/SI.xml", null, null); 245 246 // Strangely, the XmlParser does not want as base the 247 // directory containing the file, but rather the 248 // file itself. 249 URL base = inURL; 250 251 momlParser.parse(base, inURL); 252 253 us = (UnitSystem) container.getAttribute("SI"); 254 } catch (Throwable throwable) { 255 throw new InternalErrorException(null, throwable, 256 "Failed to initialize statics in UnitLibrary"); 257 } 258 259 // Initialize the Library. 260 _unitsLibrary = new Vector(); 261 _numCats = UnitUtilities.getNumCategories(); 262 Identity = new Unit("Identity"); 263 _unitsLibrary.add(Identity); 264 265 Iterator oldStyleUnits = us.attributeList().iterator(); 266 //UnitLibrary enclosingObject = new UnitLibrary(); 267 Vector pairs = new Vector(); 268 269 while (oldStyleUnits.hasNext()) { 270 Object oldStyleUnit = oldStyleUnits.next(); 271 272 if (oldStyleUnit instanceof BaseUnit) { 273 BaseUnit baseUnit = (BaseUnit) oldStyleUnit; 274 Unit basicUnit = new Unit(baseUnit); 275 addToLibrary(basicUnit); 276 } else if (oldStyleUnit instanceof Parameter) { 277 String name = ((Parameter) oldStyleUnit).getName(); 278 String expr = ((Parameter) oldStyleUnit).getExpression(); 279 UnitNameExprPair pair = new UnitNameExprPair(name, expr); 280 pairs.add(pair); 281 } 282 } 283 284 boolean madeChange = true; 285 286 while (!pairs.isEmpty() && madeChange) { 287 madeChange = false; 288 289 Iterator iter = pairs.iterator(); 290 291 while (iter.hasNext()) { 292 UnitNameExprPair pair = (UnitNameExprPair) iter.next(); 293 String expr = pair.getUExpr(); 294 295 try { 296 UnitExpr uExpr = _parser.parseUnitExpr(expr); 297 Unit unit = uExpr.reduce().getSingleUnit(); 298 299 if (unit != null) { 300 unit.setPrimaryLabel(pair.getName()); 301 iter.remove(); 302 madeChange = true; 303 addToLibrary(unit); 304 } 305 } catch (ParseException e1) { 306 // OK here. 307 } 308 } 309 } 310 311 if (_debug) { 312 Vector units = getLibrary(); 313 314 for (int i = 0; i < units.size(); i++) { 315 System.out.println(((Unit) units.elementAt(i)).toString()); 316 } 317 } 318 } 319 320 /** UnitNameExprPair 321 * @author Rowland R Johnson 322 * @version $Id$ 323 * @since Ptolemy II 8.0 324 * @Pt.ProposedRating Red (cxh) 325 * @Pt.AcceptedRating Red (cxh) 326 * 327 */ 328 private static class UnitNameExprPair { 329 // FindBugs suggests making this class static so as to decrease 330 // the size of instances and avoid dangling references. 331 public UnitNameExprPair(String n, String ue) { 332 _name = n; 333 _uExpr = ue; 334 } 335 336 public String getName() { 337 return _name; 338 } 339 340 public String getUExpr() { 341 return _uExpr; 342 } 343 344 private String _name; 345 346 private String _uExpr; 347 } 348}