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
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
00165
00166 if ( myCU.equals(otherCU) ) return true;
00167
00168
00169
00170
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
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
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
00200
00201
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
00224
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
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
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 }