Unit.java

Go to the documentation of this file.
00001 package cedar.hepdata.util;
00002 
00003 import java.util.regex.Pattern;
00004 import java.util.regex.Matcher;
00005 import java.util.Collection;
00006 import java.util.List;
00007 import java.util.Vector;
00008 
00009 import org.apache.log4j.*;
00010 
00035 public class Unit {
00036     static Logger log = Logger.getLogger(Unit.class);
00037 
00039     private List<UnitTerm> unitTerms = new Vector<UnitTerm>();
00040 
00041 
00043 
00044 
00046     public Unit() {}
00047 
00049     public Unit(String unitstr) throws HDUnitException {
00050         this.fromString(unitstr);
00051     }
00052 
00054     public Unit(Unit other) {
00055         for (UnitTerm term : other.getUnitTerms()) {
00056             this.addUnitTerm(new UnitTerm(term.baseunit, term.prefix, term.power));
00057         }
00058     }
00059 
00061     public Unit(UnitTerm term) {
00062         this.addUnitTerm(term);
00063     }
00064 
00066     public Unit(Collection<UnitTerm> terms) {
00067         for (UnitTerm term : terms) {
00068             this.addUnitTerm(term);
00069         }
00070     }
00071 
00073     public Unit(UnitTerm terms[]) {
00074         for (UnitTerm term : terms) {
00075             this.addUnitTerm(term);
00076         }
00077     }
00078 
00079 
00081 
00082 
00083     // Static methods for making common units
00084     public static Unit makeGeV() {
00085         return new Unit(new UnitTerm(BaseUnit.EV, SiPrefix.GIGA, 1));
00086     }
00087     public static Unit makeGeVc() {
00088         Unit gevc = makeGeV();
00089         gevc.addUnitTerm(new UnitTerm(BaseUnit.CLIGHT, SiPrefix.UNIT, -1));
00090         return gevc;
00091     }
00092     public static Unit makeGeVcsq() {
00093         Unit gevcsq = makeGeV();
00094         gevcsq.addUnitTerm(new UnitTerm(BaseUnit.CLIGHT, SiPrefix.UNIT, -2));
00095         return gevcsq;
00096     }
00097 
00098 
00100 
00101 
00103     public List<UnitTerm> getUnitTerms() {
00104         return unitTerms;
00105     }
00106 
00108 
00109     public void setUnitTerms(List<UnitTerm> unitTerms) {
00110         this.unitTerms = unitTerms;
00111     }
00112 
00114     public void addUnitTerm(UnitTerm unitTerm) {
00115         this.unitTerms.add(unitTerm);
00116     }
00117 
00119     public boolean equals(Object obj) {
00120         if (this == obj) return true;
00121         if (! (obj instanceof Unit)) return false;
00122 
00123         Unit test = (Unit) obj;
00124         List<UnitTerm> terms1 = getUnitTerms();
00125         List<UnitTerm> terms2 = test.getUnitTerms();
00126         if (terms1.size() != terms2.size()) return false;
00127 
00128         for (int i = 0; i < terms1.size(); ++i) {
00129             if (! terms1.get(i).equals(terms2.get(i)) ) return false;
00130         }
00131         return true;
00132     }
00133 
00135     public Unit canonicalUnit() {
00136         Unit cu = new Unit();
00137         for (UnitTerm term : getUnitTerms()) {
00138             UnitTerm cterm = new UnitTerm(term.baseunit, term.prefix, term.power);
00139             cterm.prefix = SiPrefix.UNIT;
00140             cu.addUnitTerm(cterm);
00141         }
00142         return cu;
00143     }
00144 
00146     public Double convFactorToCanonical() {
00147         Double cf = 1.0;
00148         for (UnitTerm term : getUnitTerms()) {
00149             cf *= term.convFactor();
00150         }
00151         return cf;
00152     }
00153 
00155     public Double convFactorFromCanonical() {
00156         return 1.0 / convFactorToCanonical();
00157     }
00158 
00160     public boolean isCompatible(Unit unit) {
00161         Unit myCU = canonicalUnit();
00162         Unit otherCU = unit.canonicalUnit();
00163 
00164         // First test if their canonical representations are the same: it
00165         // makes things a lot easier if they are!
00166         if ( myCU.equals(otherCU) ) return true;
00167 
00168         // If they aren't exactly equal, eliminate matching elements from each
00169         // list and then see what's left over. First we have to make independent
00170         // copies of the term lists which we can mangle:
00171         List<UnitTerm> terms1 = new Vector<UnitTerm>();
00172         List<UnitTerm> terms2 = new Vector<UnitTerm>();
00173         for (UnitTerm term : myCU.getUnitTerms()) { terms1.add(new UnitTerm(term)); }
00174         for (UnitTerm term : otherCU.getUnitTerms()) { terms2.add(new UnitTerm(term)); }
00175 
00176         // Now strip out the stuff that matches from terms1
00177         for (UnitTerm term2 : otherCU.getUnitTerms()) {
00178             for (UnitTerm term1 : terms1) {
00179                 log.debug(term1 + "-" + term2 + ": " + term2.equals(term1));
00180                 if (term2.equals(term1)) {
00181                     terms1.remove(term1);
00182                     break;
00183                 }
00184             }
00185         }
00186         // Now strip out the stuff that matches from terms2
00187         for (UnitTerm term1 : myCU.getUnitTerms()) {
00188             for (UnitTerm term2 : terms2) {
00189                 log.debug(term2 + "-" + term1 + ": " + term1.equals(term2));
00190                 if (term1.equals(term2)) {
00191                     terms2.remove(term2);
00192                     break;
00193                 }
00194             }
00195         }
00196         log.info("T1: " + myCU.getUnitTerms() + " -> " + terms1);
00197         log.info("T2: " + otherCU.getUnitTerms() + " -> " + terms2);
00198 
00199         // Seeing what's left over: if it isn't a c_light, number or rad/deg
00200         // then it's incompatible. We also remove c_light and number on this pass,
00201         // so that we can match up rad/deg elements next...
00202         for (UnitTerm term : terms1) {
00203             if (term.baseunit.equals(BaseUnit.NUMBER) || term.baseunit.equals(BaseUnit.CLIGHT)) {
00204                 terms1.remove(term);
00205             } else if (term.baseunit.equals(BaseUnit.RADIAN) || term.baseunit.equals(BaseUnit.DEGREE)) {
00206                 log.info("Found a remaining angular unit: " + term.toString());
00207             } else {
00208                 return false;
00209             }
00210         }
00211         for (UnitTerm term : terms2) {
00212             if (term.baseunit.equals(BaseUnit.NUMBER) || term.baseunit.equals(BaseUnit.CLIGHT)) {
00213                 terms2.remove(term);
00214             } else if (term.baseunit.equals(BaseUnit.RADIAN) || term.baseunit.equals(BaseUnit.DEGREE)) {
00215                 log.info("Found a remaining angular unit: " + term.toString());
00216             } else {
00217                 return false;
00218             }
00219         }
00220         if (terms1.size() == 0 && terms2.size() == 0) return true;
00221         if (terms1.size() != terms2.size()) return false;
00222 
00223         // Try to match up remaining elements: check that the summed powers of angular
00224         // units are the same for both units
00225         int angPower1 = 0;
00226         int angPower2 = 0;
00227         for (UnitTerm t : terms1) angPower1 += t.power;
00228         for (UnitTerm t : terms2) angPower2 += t.power;
00229         if (angPower1 != angPower2) return false;
00230 
00231         // Finally, the units must be compatible (at last!)
00232         return true;
00233     }
00234 
00236     public Double convFactorTo(Unit unit) throws HDUnitException {
00238         if (isCompatible(unit)) {
00239             Double sifactor = convFactorToCanonical() * unit.convFactorFromCanonical();
00240             if (canonicalUnit().equals(unit.canonicalUnit())) {
00241                 return sifactor;
00242             } else {
00243                 int degPower1 = 0;
00244                 for (UnitTerm t : this.getUnitTerms()) {
00245                     if (t.baseunit == BaseUnit.DEGREE) degPower1 += 1;
00246                     if (t.baseunit == BaseUnit.RADIAN) degPower1 -= 1;
00247                 }
00248                 int degPower2 = 0;
00249                 for (UnitTerm t : unit.getUnitTerms()) {
00250                     if (t.baseunit == BaseUnit.DEGREE) degPower2 += 1;
00251                     if (t.baseunit == BaseUnit.RADIAN) degPower2 -= 1;
00252                 }
00253                 int deltaDegPower = degPower2 - degPower1;
00254                 assert deltaDegPower % 2 == 0 : "Shift in number of powers of degree is not even. How?!?";
00255                 log.debug(degPower1 + " -> " + degPower2 + " so shift is " + deltaDegPower);
00256                 Double angfactor = Math.pow(180.0/Math.PI, deltaDegPower/2.0);
00257                 return sifactor * angfactor;
00258             }
00259         } else {
00260             throw new HDUnitException("Units " + toString() + " and " + unit.toString() + " are not compatible");
00261         }
00262     }
00263 
00265     public Double convFactorFrom(Unit unit) throws HDUnitException {
00266         return 1.0/ convFactorTo(unit);
00267     }
00268 
00270     public String toString() {
00271         StringBuffer s = new StringBuffer();
00272         for (UnitTerm term : getUnitTerms()) {
00273             s.append(term.toString());
00274             s.append(" ");
00275         }
00276         return s.toString().trim();
00277     }
00278 
00280     public Unit fromString(String unitstr) throws HDUnitException {
00281         unitTerms.clear();
00282         String myunitstr = unitstr;
00283         if (myunitstr.length() == 0) {
00284             return this;
00285         }
00286 
00287         // Replace ** with ^, replace " *\* *" with " ", replace " */ *" with " /"
00288         myunitstr = myunitstr.replaceAll("\\*\\*", "^");
00289         log.debug("1. " + unitstr + " vs. " + myunitstr);
00290         myunitstr = myunitstr.replaceAll("\\ *\\*\\ *", " ");
00291         log.debug("2. " + unitstr + " vs. " + myunitstr);
00292         myunitstr = myunitstr.replaceAll("\\ */\\ *", " /");
00293         log.debug("3. " + unitstr + " vs. " + myunitstr);
00294 
00295         String[] unitatoms = myunitstr.split(" ");
00296         for (String atom : unitatoms) {
00297             UnitTerm term = new UnitTerm(atom);
00298             addUnitTerm(term);
00299         }
00300         return this;
00301     }
00302 
00303 }

Generated on Tue Apr 21 15:54:55 2009 for HepData common classes by  doxygen 1.5.5