""" open/dulcinea/lib/test/utest_unit.py """ from sancho.utest import UTest, raises from dulcinea.physical_unit import PhysicalUnit, UnitCollection, UnitError from qp.lib.spec import get_spec_problems class PhysicalUnitTest (UTest): def _pre(self): self.units = UnitCollection() def _post(self): del self.units def get_units(self, *names): return [self.units[name] for name in names] def check_basics(self): "basic unit finding and conversion" units = self.units # Assume these units already exist. kilogram = units['kg'] gram = units['g'] metre = units['m'] inch = units['inch'] assert kilogram.name == "kg" assert kilogram.get_name() == "kg" assert kilogram.get_name(html=1) == "kg" assert kilogram.factor == 1.0 assert kilogram.offset == 0.0 assert not kilogram.artificial assert kilogram.convert_value(1.5, gram) == 1500.0 assert round(metre.get_conversion_factor(inch), 2) == 39.37 get_unit = units.get_unit assert get_unit('kg') == kilogram assert (kilogram*metre).artificial assert get_unit('kg*m').artificial raises(TypeError, get_unit, 66) assert kilogram.is_dimension('mass') assert metre.is_dimension('length') assert units['Torr'].is_dimension('pressure') assert get_spec_problems(units) == [], get_spec_problems(units) assert get_spec_problems(kilogram) == [] def check_temperature(self): units = self.units degF = units.get_unit('degF') degC = units.get_unit('degC') kelvin = units.get_unit('K') warm_day = 80 # in fahrenheit cold_day = 0 # in fahrenheit fpw = 0 # "freezing point of water" in celsius htsc = 70 # "high temperature" superconductivity # (at a brisk 70 K) abs_zero = 0 # in kelvin assert round(degF.convert_value(warm_day, degC),2) == 26.67 assert round(degF.convert_value(warm_day, kelvin),2) == 299.82 assert round(degF.convert_value(cold_day, degC),2) == -17.78 assert round(degF.convert_value(cold_day, kelvin),2) == 255.37 assert degC.convert_value(fpw, degC) == fpw assert round(degC.convert_value(fpw, degF),2) == 32.00 assert round(degC.convert_value(fpw, kelvin),2) == 273.15 assert round(kelvin.convert_value(htsc, degC),2) == -203.15 assert round(kelvin.convert_value(htsc, degF),2) == -333.67 assert round(kelvin.convert_value(abs_zero, kelvin),2) == 0 assert round(kelvin.convert_value(abs_zero, degC),2) == -273.15 assert round(kelvin.convert_value(abs_zero, degF),2) == -459.67 assert degC.is_dimension('temperature') assert degF.is_dimension('temperature') assert kelvin.is_dimension('temperature') assert not kelvin.is_dimension('mass') def check_conversion(self): "conversion functions on unit collection" units = self.units inch = units.get_unit('inch') mm = units.get_unit('mm') degC = units.get_unit('degC') degF = units.get_unit('degF') K = units.get_unit('K') assert round(units.convert_value(6, inch, mm), 2) == 152.4 assert round(units.convert_value(0, degC, degC), 2) == 0.0 assert round(units.convert_value(0, degC, degF), 2) == 32.00 assert round(units.convert_value(0, degC, K), 2) == 273.15 def check_add_units(self): "define alternate units and convert to/from them" units = self.units units.add_unit('ft', units['inch'], 12) units.add_unit('yard', units['ft'], 3) yard = units.get_unit('yard') assert round(yard.get_conversion_factor(), 4) == .9144 inch = units.get_unit('inch') assert inch.powers == (1, 0, 0, 0, 0, 0, 0) assert round(inch.factor, 5) == 0.0254 unit = units['ft'] / units['min'] assert unit.powers == (1, 0, -1, 0, 0, 0, 0) assert round(unit.factor, 5) == 0.00508 assert round(units.convert_value(3, units['yard'], units['m']), 4) == 2.7432 assert round(units.convert_value(500, units['s'], units['hour']), 4) == .1389 def check_implicit(self): "implicit unit definition" units = self.units units.add_unit('ft', units['inch'], 12) units.add_unit('mile', units['ft'], 5280) mph = units['mile'] / units['hour'] assert units['mile/hour'] is mph mps = units.get_unit('m/s', 1) ipm = units['inch'] / units['min'] assert round(ipm.convert_value(1.5, mps), 7) == 6.35e-4 assert round(ipm.convert_value(1.5, mph), 6) == 1.42e-3 def check_compare(self): units = self.units units.get_unit("cm") (metre, centimetre, inch, sec, hertz) = \ self.get_units('m', 'cm', 'inch', 's', 'Hz') assert metre == metre assert not metre == centimetre assert metre.is_compatible(centimetre) assert metre.is_compatible(inch) assert not metre.is_compatible(None) assert not sec.is_compatible(hertz) assert sec.is_dimension('time') assert sec.is_inverse_compatible(hertz) assert hertz.is_dimension('frequency') metre2 = PhysicalUnit("m", metre.powers, units) metre3 = PhysicalUnit("foo", metre.powers, units) assert metre == metre2 assert metre == metre3 # This depends on the list of temperature units defined in # UnitCollection. There aren't that many temperature units in # the world, though, so it's unlikely that we'd add more and # break this test. temp_units = units.get_compatible_units('degC') temp_units = sorted([(u.factor, u.name) for u in temp_units]) assert temp_units == [(5./9, 'degF'), (1, 'K'), (1, 'degC')] time_units = sorted([(u.factor, u.name) for u in units.get_compatible_units('s')]) expect = [(1, 's'), (60, 'min'), (60*60, 'hour'), (60*60*24, 'day'), (60*60*24*7, 'week')] assert time_units == expect # Test that implicit addition affects get_compatible_units() units.get_unit("us") units.get_unit("ms") time_units = sorted([(u.factor, u.name) for u in units.get_compatible_units('s')]) expect = [(1e-6, "us"), (1e-3, "ms")] + expect assert time_units == expect def check_arith1(self): self.units.get_unit("cm") (metre, centimetre, inch) = \ self.get_units('m', 'cm', 'inch') scaled_cm = centimetre*100.0 assert scaled_cm.powers == metre.powers assert scaled_cm.factor == metre.factor assert metre is scaled_cm assert str(scaled_cm) == "m" alt_cm = centimetre*1 assert centimetre is alt_cm assert alt_cm*100 is metre assert str(alt_cm) == "cm" scaled_cm = centimetre * inch.get_conversion_factor(centimetre) assert scaled_cm.powers == inch.powers assert scaled_cm.factor == inch.factor assert inch is scaled_cm assert str(scaled_cm) == "inch" def check_arith2(self): "arithmetic on physical units with other physical units" self.units.get_unit("um") (inch, um, sec, metre,) = \ self.get_units('inch', 'um', 's', 'm') ips = inch/sec mps = metre/sec assert ips.get_name() == "inch/s" assert mps.get_name() == "m/s" assert ips.get_powers() == (1, 0, -1, 0, 0, 0, 0) assert mps.get_powers() == (1, 0, -1, 0, 0, 0, 0) assert ips.is_compatible(mps) assert round(ips.convert_value(10.0, mps),3) == 0.254 minv = metre.inv() assert minv.get_name() == "1/m" assert minv.get_powers() == (-1, 0, 0, 0, 0, 0, 0) assert minv.get_conversion_factor() == 1.0 assert (ips*metre).get_name() == "(inch/s)*m" assert (minv/ips).get_name() == "(1/m)/(inch/s)" assert (minv/4).get_name() == "1/m/4" umps = um/sec assert (umps*metre).get_name() == "(um/s)*m" assert (minv/umps).get_name() == "(1/m)/(um/s)" assert (minv/4).get_name(html=1) == "1/m/4" assert (minv/(1/3.0)).get_name(html=1) == "1/m/0.333333" msq = metre*metre assert msq.is_compatible(self.units['m^2']) assert msq.get_name() == "m*m" assert msq.get_powers() == (2, 0, 0, 0, 0, 0, 0) assert not msq.is_compatible(metre) raises(UnitError, msq.convert_value, 1, mps) def check_delete(self): # Can't delete standard SI units raises(TypeError, self.units.delete_unit, 'm') raises(AssertionError, self.units.delete_unit, self.units['g']) raises(AssertionError, self.units.delete_unit, self.units['Wb']) # Some deletions that should work cmps = self.units.get_unit('cm/s') assert self.units['cm/s'] == cmps self.units.delete_unit(cmps) raises(ValueError, self.units.get_unit, 'cm/s', create=False) # get_unit() can bring it back (but as a different object) assert self.units.get_unit('cm/s') == cmps assert self.units.get_unit('cm/s') is not cmps # This one can't be brought back mil = self.units['mil'] self.units.delete_unit(mil) try: self.units['mil'] assert 0 except KeyError: pass raises(ValueError, self.units.get_unit, 'mil') def check_massquery(self): # Don't make any assumptions about which units are "natural" or # "artificial" -- it's non-obvious and a bit surprising in a # newly-created UnitCollection. Doesn't really matter in real # life, though, since the 'artificial' flag was added well after # all the important units already existed in our live database. all_units = list(self.units.units.values()) nat_units = self.units.get_natural_units() art_units = [u for u in self.units.units.values() if u.get_artificial()] assert set(all_units) == set(nat_units) | set(art_units) if __name__ == "__main__": PhysicalUnitTest()