1package Physics::Unit; 2 3use strict; 4use warnings; 5use Carp; 6use base qw(Exporter); 7use vars qw( 8 $VERSION 9 @EXPORT_OK 10 %EXPORT_TAGS 11 $debug 12 $number_re 13); 14 15$VERSION = '0.54'; 16$VERSION = eval $VERSION; 17 18@EXPORT_OK = qw( 19 $number_re 20 GetTypeUnit 21 GetUnit 22 InitBaseUnit 23 InitPrefix 24 InitTypes 25 InitUnit 26 ListTypes 27 ListUnits 28 NumBases 29 DeleteNames 30); 31 32%EXPORT_TAGS = ('ALL' => \@EXPORT_OK); 33 34# This is the regular expression used to parse out a number. It 35# is here so that other modules can use it for convenience. 36 37$number_re = '([-+]?((\d+\.?\d*)|(\.\d+))([eE][-+]?((\d+\.?\d*)|(\.\d+)))?)'; 38 39# The value of this hash is a string representing the token returned 40# when this word is seen 41 42my %reserved_word = ( 43 per => 'divide', 44 square => 'square', 45 sq => 'square', 46 cubic => 'cubic', 47 squared => 'squared', 48 cubed => 'cubed', 49); 50 51# Pre-defined units 52my %unit_by_name; 53 54# Values are references to units representing the prefix 55my %prefix; 56 57# Known quantity types. The values of this hash are references to 58# unit objects that exemplify these types 59my %prototype; 60 61# The number of base units 62my $NumBases = 0; 63 64# The names of the base units 65my @BaseName; 66 67InitBaseUnit ( 68 'Distance' => ['meter', 'm', 'meters', 'metre', 'metres'], 69 'Mass' => ['gram', 'gm', 'grams'], 70 'Time' => ['second', 's', 'sec', 'secs', 'seconds'], 71 'Temperature' => ['kelvin', 'k', 'kelvins', 72 'degree-kelvin', 'degrees-kelvin', 'degree-kelvins'], 73 'Current' => ['ampere', 'amp', 'amps', 'amperes'], 74 'Substance' => ['mole', 'mol', 'moles'], 75 'Luminosity' => ['candela', 'cd', 'candelas', 'candle', 'candles'], 76 'Money' => ['us-dollar', 'dollar', 'dollars', 'us-dollars', '$'], 77 'Data' => ['bit', 'bits'], 78); 79 80InitPrefix ( 81 'deka', 1e1, 82 'deca', 1e1, 83 'hecto', 1e2, 84 'kilo', 1e3, 85 'mega', 1e6, 86 'giga', 1e9, 87 'tera', 1e12, 88 'peta', 1e15, 89 'exa', 1e18, 90 'zetta', 1e21, 91 'yotta', 1e24, 92 'deci', 1e-1, 93 'centi', 1e-2, 94 'milli', 1e-3, 95 'micro', 1e-6, 96 'nano', 1e-9, 97 'pico', 1e-12, 98 'femto', 1e-15, 99 'atto', 1e-18, 100 'zepto', 1e-21, 101 'yocto', 1e-24, 102 103 # binary prefixes 104 'kibi', 2**10, 105 'mebi', 2**20, 106 'gibi', 2**30, 107 'tebi', 2**40, 108 'pebi', 2**50, 109 'exbi', 2**60, 110 111 # others 112 'semi', 0.5, 113 'demi', 0.5, 114); 115 116 117InitUnit ( 118 # Dimensionless 119 ['pi',], '3.1415926535897932385', 120 ['e',], '2.7182818284590452354', 121 122 ['unity', 'one', 'ones',], '1', 123 ['two', 'twos',], '2', 124 ['three', 'threes',], '3', 125 ['four', 'fours',], '4', 126 ['five', 'fives',], '5', 127 ['six', 'sixes',], '6', 128 ['seven', 'sevens',], '7', 129 ['eight', 'eights',], '8', 130 ['nine', 'nines'], '9', 131 ['ten', 'tens',], '10', 132 ['eleven', 'elevens',], '11', 133 ['twelve', 'twelves',], '12', 134 ['thirteen', 'thirteens',], '13', 135 ['fourteen', 'fourteens',], '14', 136 ['fifteen', 'fifteens',], '15', 137 ['sixteen', 'sixteens',], '16', 138 ['seventeen', 'seventeens',], '17', 139 ['eighteen', 'eighteens',], '18', 140 ['nineteen', 'nineteens',], '19', 141 ['twenty', 'twenties',], '20', 142 ['thirty', 'thirties',], '30', 143 ['forty', 'forties',], '40', 144 ['fifty', 'fifties',], '50', 145 ['sixty', 'sixties',], '60', 146 ['seventy', 'seventies',], '70', 147 ['eighty', 'eighties',], '80', 148 ['ninety', 'nineties',], '90', 149 ['hundred', 'hundreds'], '100', 150 ['thousand', 'thousands'], '1000', 151 ['million', 'millions',], '1e6', 152 ['billion', 'billions',], '1e9', 153 ['trillion', 'trillions',], '1e12', 154 ['quadrillion', 'quadrillions',], '1e15', 155 ['quintillion', 'quintillions',], '1e18', 156 157 ['half', 'halves',], '0.5', 158 ['third', 'thirds',], '1/3', 159 ['fourth', 'fourths',], '0.25', 160 ['tenth',], '0.1', 161 ['hundredth',], '0.01', 162 ['thousandth',], '0.001', 163 ['millionth',], '1e-6', 164 ['billionth',], '1e-9', 165 ['trillionth',], '1e-12', 166 ['quadrillionth',], '1e-15', 167 ['quintillionth',], '1e-18', 168 169 ['percent', '%',], '0.01', 170 ['dozen', 'doz',], '12', 171 ['gross',], '144', 172 173 # Angular 174 ['radian', 'radians',], '1', 175 ['steradian', 'sr', 'steradians',], '1', 176 ['degree', 'deg', 'degrees',], 'pi radians / 180', 177 ['arcminute', 'arcmin', 'arcminutes',], 'deg / 60', 178 ['arcsecond', 'arcsec', 'arcseconds',], 'arcmin / 60', 179 180 # Distance 181 ['foot', 'ft', 'feet',], '.3048 m', # exact 182 ['inch', 'in', 'inches',], 'ft/12', # exact 183 ['mil', 'mils',], 'in/1000', # exact 184 ['yard', 'yards',], '3 ft', # exact 185 ['fathom', 'fathoms',], '2 yards', # exact 186 ['rod', 'rods',], '5.5 yards', # exact 187 ['pole', 'poles',], '1 rod', # exact 188 ['perch', 'perches',], '1 rod', # exact 189 ['furlong', 'furlongs',], '40 rods', # exact 190 ['mile', 'mi', 'miles',], '5280 ft', # exact 191 192 ['micron', 'microns', 'um',], '1e-6 m', # exact 193 ['angstrom', 'a', 'angstroms',], '1e-10 m', # exact 194 ['cm',], 'centimeter', # exact 195 ['km',], 'kilometer', # exact 196 ['nm',], 'nanometer', # exact 197 ['mm',], 'millimeter', # exact 198 199 ['pica',], 'in/6', # exact, but see below 200 ['point',], 'pica/12', # exact 201 202 ['nautical-mile', 'nmi', 'nauticalmiles', 203 'nauticalmile', 'nautical-miles',], '1852 m', # exact 204 ['astronomical-unit', 'au',], '1.49598e11 m', 205 ['light-year', 'ly', 'light-years', 206 'lightyear', 'lightyears'], '9.46e15 m', 207 ['parsec', 'parsecs',], '3.083e16 m', 208 209 # equatorial radius of the reference geoid: 210 ['re'], '6378388 m', # exact 211 # polar radius of the reference geoid: 212 ['rp'], '6356912 m', # exact 213 214 # Acceleration 215 ['g0', 'earth-gravity'], '9.80665 m/s^2', # exact 216 217 # Mass 218 ['kg',], 'kilogram', # exact 219 ['metric-ton', 'metric-tons', 'tonne', 220 'tonnes'], '1000 kg', # exact 221 222 ['grain', 'grains'], '.0648 gm', 223 224 ['pound-mass', 'lbm', 'lbms', 225 'pounds-mass'], '0.45359237 kg', # exact 226 ['ounce', 'oz', 'ounces'], 'lbm/16', # exact 227 ['stone', 'stones'], '14 lbm', # exact 228 ['hundredweight', 'hundredweights'], '100 lbms', # exact 229 ['ton', 'tons', 'short-ton', 'short-tons'], '2000 lbms', # exact 230 ['long-ton', 'long-tons'], '2240 lbms', # exact 231 232 ['slug', 'slugs'], 'lbm g0 s^2/ft', # exact 233 ['mg',], 'milligram', # exact 234 ['ug',], 'microgram', # exact 235 236 ['dram', 'drams'], 'ounce / 16', # exact 237 238 ['troy-pound', 'troy-pounds'], '0.373 kg', 239 ['troy-ounce', 'troy-ounces', 240 'ounce-troy', 'ounces-troy'], '31.103 gm', 241 ['pennyweight', 'pennyweights'], '1.555 gm', 242 ['scruple', 'scruples'], '1.296 gm', 243 244 ['hg',], 'hectogram', # exact 245 ['dag',], 'decagram', # exact 246 ['dg',], 'decigram', # exact 247 ['cg',], 'centigram', # exact 248 ['carat', 'carats', 'karat', 'karats',], '200 milligrams', # exact 249 ['j-point',], '2 carats', # exact 250 251 ['atomic-mass-unit', 'amu', 'u', 252 'atomic-mass-units'], '1.6605402e-27 kg', 253 254 255 # Time 256 ['minute', 'min', 'mins', 'minutes'], '60 s', 257 ['hour', 'hr', 'hrs', 'hours'], '60 min', 258 ['day', 'days'], '24 hr', 259 ['week', 'wk', 'weeks'], '7 days', 260 ['fortnight', 'fortnights'], '2 week', 261 ['year', 'yr', 'yrs', 'years'], '365.25 days', 262 ['month', 'mon', 'mons', 'months'], 'year / 12', # an average month 263 ['score', 'scores'], '20 yr', 264 ['century', 'centuries'], '100 yr', 265 ['millenium', 'millenia',], '1000 yr', 266 267 ['ms', 'msec', 'msecs'], 'millisecond', 268 ['us', 'usec', 'usecs'], 'microsecond', 269 ['ns', 'nsec', 'nsecs'], 'nanosecond', 270 ['ps', 'psec', 'psecs'], 'picosecond', 271 272 # Data 273 ['byte', 'bytes'], '8 bits', 274 275 # Frequency 276 ['hertz', 'hz'], '1/sec', 277 ['becquerel', 'bq'], '1 hz', 278 ['revolution', 'revolutions',], '1', 279 ['rpm',], 'revolutions per minute', 280 ['cycle', 'cycles',], '1', 281 282 # Current 283 ['abampere', 'abamp', 'abamps', 'abamperes'], '10 amps', 284 ['statampere', 'statamp', 'statamps', 'statamperes'], '3.336e-10 amps', 285 286 ['ma',], 'milliamp', 287 ['ua',], 'microamp', 288 289 # Electric_potential 290 ['volt', 'v', 'volts'], 'kg m^2 / amp s^3', 291 ['mv',], 'millivolt', 292 ['uv',], 'microvolt', 293 ['abvolt', 'abvolts'], '1e-8 volt', 294 ['statvolt', 'statvolts'], '299.8 volt', 295 296 # Resistance 297 ['ohm', 'ohms'], 'kg m^2 / amp^2 s^3', 298 ['abohm', 'abohms'], 'nano ohm', 299 ['statohm', 'statohms'], '8.987e11 ohm', 300 ['kilohm', 'kilohms',], 'kilo ohm', 301 ['megohm', 'megohms'], 'mega ohm', 302 303 # Conductance 304 ['siemens',], 'amp^2 s^3 / kg m^2', 305 ['mho', 'mhos'], '1/ohm', 306 307 # Capacitance 308 ['farad', 'f', 'farads'], 'amp^2 s^4 / kg m^2', 309 ['abfarad', 'abfarads'], 'giga farad', 310 ['statfarad', 'statfarads'], '1.113e-12 farad', 311 312 ['uf',], 'microfarad', 313 ['pf',], 'picofarads', 314 315 # Inductance 316 ['henry', 'henrys'], 'kg m^2 / amp^2 s^2', 317 ['abhenry', 'abhenrys'], 'nano henry', 318 ['stathenry', 'stathenrys'], '8.987e11 henry', 319 320 ['uh',], 'microhenry', 321 ['mh',], 'millihenry', 322 323 # Magnetic_flux 324 ['weber', 'wb', 'webers'], 'kg m^2 / amp s^2', 325 ['maxwell', 'maxwells'], '1e-8 weber', 326 327 # Magnetic_field 328 ['tesla', 'teslas'], 'kg / amp sec^2', 329 ['gauss',], '1e-4 tesla', 330 331 # Temperature 332 ['degree-rankine', 'degrees-rankine'], '5/9 * kelvin', # exact 333 334 # Force 335 ['pound', 'lb', 'lbs', 'pounds', 336 'pound-force', 'lbf', 337 'pounds-force', 'pound-weight'], 'slug foot / s^2', # exact 338 ['ounce-force', 'ozf'], 'pound-force / 16', # exact 339 ['newton', 'nt', 'newtons'], 'kg m / s^2', # exact 340 ['dyne', 'dynes'], 'gm cm / s^2', # exact 341 ['gram-weight', 'gram-force'], 'gm g0', # exact 342 ['kgf',], 'kilo gram-force', # exact 343 344 # Area 345 ['are', 'ares'], '100 square meters', 346 ['hectare', 'hectares',], '100 ares', 347 ['acre', 'acres'], '43560 square feet', 348 ['barn', 'barns'], '1e-28 square meters', 349 350 # Volume 351 ['liter', 'l', 'liters'], 'm^3/1000', # exact 352 ['cl',], 'centiliter', # exact 353 ['dl',], 'deciliter', # exact 354 ['cc', 'ml',], 'cubic centimeter', # exact 355 356 ['gallon', 'gal', 'gallons'], '3.785411784 liter', 357 ['quart', 'qt', 'quarts'], 'gallon/4', 358 ['peck', 'pecks'], '8 quarts', 359 ['bushel', 'bushels'], '4 pecks', 360 ['fifth', 'fifths'], 'gallon/5', 361 ['pint', 'pt', 'pints'], 'quart/2', 362 ['cup', 'cups'], 'pint/2', 363 ['fluid-ounce', 'floz', 'fluidounce', 364 'fluidounces', 'fluid-ounces'], 'cup/8', 365 ['gill', 'gills'], '4 fluid-ounces', 366 ['fluidram', 'fluidrams'], '3.5516 cc', 367 ['minim', 'minims'], '0.059194 cc', 368 ['tablespoon', 'tbsp', 'tablespoons'], 'fluid-ounce / 2', 369 ['teaspoon', 'tsp', 'teaspoons'], 'tablespoon / 3', 370 371 # Power 372 ['watt', 'w', 'watts'], 'kg m^2 / s^3', 373 ['horsepower', 'hp'], '550 foot pound-force / s', 374 375 # Energy 376 ['joule', 'j', 'joules'], 'kg m^2 / s^2', # exact 377 ['electron-volt', 'ev', 'electronvolt', 378 'electronvolts', 'electron-volts'], '1.60217733e-19 joule', 379 380 ['mev',], 'mega electron-volt', 381 ['gev',], 'giga electron-volt', 382 ['tev',], 'tera electron-volt', 383 384 ['calorie', 'cal', 'calories'], '4.184 joules', # exact 385 ['kcal',], 'kilocalorie', # exact 386 ['british-thermal-unit', 'btu', 'btus', 387 'britishthermalunit', 'britishthermalunits', 388 'british-thermal-units'], '1055.056 joule', 389 ['erg', 'ergs'], '1.0e-7 joule', # exact 390 ['kwh',], 'kilowatt hour', # exact 391 392 # Torque 393 ['foot-pound', 'ftlb', 'ft-lb', 394 'footpound', 'footpounds', 'foot-pounds'], 'foot pound-force', 395 396 # Charge 397 ['coulomb', 'coul', 'coulombs'], 'ampere second', 398 ['abcoulomb', 'abcoul', 'abcoulombs'], '10 coulomb', 399 ['statcoulomb', 'statcoul', 'statcoulombs'], '3.336e-10 coulomb', 400 ['elementary-charge', 'eq'], '1.6021892e-19 coulomb', 401 402 # Pressure 403 ['pascal', 'pa'], 'newton / m^2', 404 ['bar', 'bars'], '1e5 pascal', 405 ['torr',], '(101325 / 760) pascal', 406 ['psi',], 'pounds per inch^2', 407 ['atmosphere', 'atm'], '101325 pascal', # exact 408 409 # Speed 410 ['mph',], 'mi/hr', 411 ['kph',], 'km/hr', 412 ['kps',], 'km/s', 413 ['fps',], 'ft/s', 414 ['knot', 'knots'], 'nm/hr', 415 ['mps',], 'meter/s', 416 ['speed-of-light', 'c'], '2.99792458e8 m/sec', 417 418 # Dose of radiation 419 ['gray', 'gy'], 'joule / kg', 420 ['sievert', 'sv'], 'joule / kg', 421 ['rad',], 'gray / 100', 422 ['rem',], 'sievert / 100', 423 424 # Other 425 ['gravitational-constant', 'g'], '6.6720e-11 m^3 / kg s^2', 426 # Planck constant: 427 ['h'], '6.626196e-34 J/s', 428 # Avogadro constant: 429 ['na'], '6.022169/mol', 430); 431 432 433InitTypes ( 434 'Dimensionless' => 'unity', 435 'Frequency' => 'hertz', 436 'Electric_potential' => 'volt', 437 'Resistance' => 'ohm', 438 'Conductance' => 'siemens', 439 'Capacitance' => 'farad', 440 'Inductance' => 'henry', 441 'Magnetic_flux' => 'weber', 442 'Magnetic_field' => 'tesla', 443 'Momentum' => 'kg m/s', 444 'Force' => 'newton', 445 'Area' => 'are', 446 'Volume' => 'liter', 447 'Power' => 'watt', 448 'Energy' => 'joule', 449 'Torque' => 'kg m^2/s^2', 450 'Charge' => 'coulomb', 451 'Pressure' => 'pascal', 452 'Speed' => 'mps', 453 'Dose' => 'gray', # of radiation 454 'Acceleration' => 'm/s^2', 455); 456 457 458GetUnit('joule')->type('Energy'); 459GetUnit('ev')->type('Energy'); 460GetUnit('mev')->type('Energy'); 461GetUnit('gev')->type('Energy'); 462GetUnit('tev')->type('Energy'); 463GetUnit('cal')->type('Energy'); 464GetUnit('kcal')->type('Energy'); 465GetUnit('btu')->type('Energy'); 466GetUnit('erg')->type('Energy'); 467GetUnit('kwh')->type('Energy'); 468GetUnit('ftlb')->type('Torque'); 469 470 471sub InitBaseUnit { 472 while (@_) { 473 my ($t, $names) = (shift, shift); 474 croak 'Invalid arguments to InitBaseUnit' 475 if ref $t || (ref $names ne "ARRAY"); 476 477 print "Initializing Base Unit $$names[0]\n" if $debug; 478 479 my $unit = NewOne(); 480 $unit->AddNames(@$names); 481 $unit->{def} = $unit->name(); # def same as name 482 483 # The dimension vector for this Unit has zeros in every place 484 # except the last 485 $unit->{dim}->[$NumBases] = 1; 486 $BaseName[$NumBases] = $unit->abbr(); 487 $NumBases++; 488 489 $unit->NewType($t); 490 } 491} 492 493sub InitPrefix { 494 while (@_) { 495 my ($name, $factor) = (shift, shift); 496 croak 'Invalid arguments to InitPrefix' 497 if !$name || !$factor || ref $name || ref $factor; 498 499 print "Initializing Prefix $name\n" if $debug; 500 501 my $u = NewOne(); 502 $u->AddNames($name); 503 $u->{factor} = $factor; 504 $u->{type} = 'prefix'; 505 $prefix{$name} = $u; 506 507 $u->{def} = $factor; 508 } 509} 510 511sub InitUnit { 512 while (@_) { 513 my ($names, $def) = (shift, shift); 514 515 if (ref $names ne "ARRAY" || !$def) { 516 print "InitUnit, second argument is '$def'\n"; 517 croak 'Invalid arguments to InitUnit'; 518 } 519 520 print "Initializing Unit $$names[0]\n" if $debug; 521 my $u = CreateUnit($def); 522 $u->AddNames(@$names); 523 } 524} 525 526sub InitTypes { 527 while (@_) { 528 my ($t, $u) = (shift, shift); 529 croak 'Invalid arguments to InitTypes' 530 if !$t || ref $t || !$u; 531 532 my $unit = GetUnit($u); 533 $unit->NewType($t); 534 } 535} 536 537sub GetUnit { 538 my $u = shift; 539 croak 'GetUnit: expected an argument' unless $u; 540 return $u if ref $u; 541 542 if ($unit_by_name{$u}) { 543 #print "GetUnit, $u yields ", $unit_by_name{$u}->name, "\n"; 544 return $unit_by_name{$u}; 545 } 546 547 # Try it as an expression 548 return CreateUnit($u); 549} 550 551sub ListUnits { 552 return sort keys %unit_by_name; 553} 554 555sub ListTypes { 556 return sort keys %prototype; 557} 558 559sub NumBases { 560 return $NumBases; 561} 562 563sub GetTypeUnit { 564 my $t = shift; 565 return $prototype{$t}; 566} 567 568# DeleteNames - argument can be either an array ref, a list of name strings, or 569# a unit object 570sub DeleteNames { 571 my $arg0 = $_[0]; 572 my $argIsUnit = ref $arg0 && ref $arg0 ne 'ARRAY'; 573 # Get the list of names to delete 574 my $names = 575 !ref $arg0 576 ? \@_ # list of names 577 : ref $arg0 eq 'ARRAY' 578 ? $arg0 # array ref 579 : $arg0->{names}; # unit object 580 581 my $u; 582 if ($argIsUnit) { $u = $arg0; } 583 for my $n (@$names) { 584 if (LookName($n) != 2) { 585 croak "'$n' is not a unit name."; 586 } 587 print "deleting '$n'\n" if $debug; 588 delete $prefix{$n}; 589 if (!$argIsUnit) { $u = $unit_by_name{$n}; } 590 delete $unit_by_name{$n}; 591 # Delete the array element matching $n from @{$u->{names}} 592 if (!$argIsUnit) { 593 $u->{names} = [ grep { $_ ne $n } @{$u->{names}} ]; 594 } 595 } 596 if ($argIsUnit) { $u->{names} = []; } 597} 598 599 600sub new { 601 my $proto = shift; 602 my $class; 603 604 my $self; 605 if (ref $proto) { # object method 606 $self = $proto->copy; 607 } 608 else { # class method 609 my $r = shift; 610 $self = CreateUnit($r); 611 } 612 613 $self->AddNames(@_); 614 return $self; 615} 616 617sub type { 618 my $self = shift; 619 620 # See if the user is setting the type 621 my $t; 622 if ($t = shift) { 623 # XXX Maybe we should check that $t is a valid type name, and 624 # XXX that it's type really does match. 625 return $self->{type} = $t; 626 } 627 628 # If the type is known already, return it 629 return $self->{type} if $self->{type}; 630 631 # See if it is a prefix 632 my $name = $self->name(); 633 634 return $self->{type} = 'prefix' 635 if defined $name && defined $prefix{$name}; 636 637 # Collect all matching types 638 my @t; 639 for (keys %prototype) { 640 push @t, $_ 641 unless CompareDim($self, $prototype{$_}); 642 } 643 644 # Return value depends on whether we got zero, one, or multiple types 645 return undef unless @t; 646 return $self->{type} = $t[0] if @t == 1; 647 return \@t; 648} 649 650sub name { 651 my $self = shift; 652 my $n = $self->{names}; 653 return $$n[0]; 654} 655 656sub abbr { 657 my $self = shift; 658 my $n = ${$self->{names}}[0]; 659 return undef unless defined $n; 660 661 for ($self->names()) { 662 $n = $_ if length $_ < length $n; 663 } 664 return $n; 665} 666 667sub names { 668 my $self = shift; 669 return @{$self->{names}}; 670} 671 672sub def { 673 my $self = shift; 674 return $self->{def}; 675} 676 677sub expanded { 678 my $self = shift; 679 my $s = $self->{factor}; 680 $s = '' if $s == 1; 681 682 my $i = 0; 683 for my $d (@{$self->{dim}}) { 684 if ($d) { 685 #print "Dimension index $i is $d\n"; 686 if ($s) { $s .= " "; } 687 $s .= $BaseName[$i]; 688 $s .= "^$d" unless $d == 1; 689 } 690 $i++; 691 } 692 693 $s = 1 if $s eq ''; 694 return $s; 695} 696 697sub ToString { 698 my $self = shift; 699 return $self->name || $self->def || $self->expanded; 700} 701 702sub factor { 703 my $self = shift; 704 if (@_) { 705 $self->CheckChange; 706 $self->{factor} = shift; 707 } 708 return $self->{factor}; 709} 710 711sub convert { 712 my ($self, $other) = @_; 713 my $u = GetUnit($other); 714 carp "Can't convert ". $self->name() .' to '. $u->name() 715 if CompareDim($self, $u); 716 return $self->{factor} / $u->{factor}; 717} 718 719sub times { 720 my $self = shift; 721 $self->CheckChange; 722 my $u = GetUnit(shift); 723 $self->{factor} *= $u->{factor}; 724 725 for (0 .. $NumBases) { 726 my $u_val = defined $u->{dim}[$_] ? $u->{dim}[$_] : 0; 727 if (defined $self->{dim}[$_]) { 728 $self->{dim}[$_] += $u_val; 729 } 730 else { 731 $self->{dim}[$_] = $u_val; 732 } 733 } 734 735 $self->{type} = ''; 736 return $self; 737} 738 739sub recip { 740 my $self = shift; 741 $self->CheckChange; 742 $self->{factor} = 1 / $self->{factor}; 743 744 for (0 .. $NumBases) { 745 if (defined $self->{dim}[$_]) { 746 $self->{dim}->[$_] = -$self->{dim}->[$_]; 747 } 748 else { 749 $self->{dim}[$_] = 0; 750 } 751 } 752 753 return $self; 754} 755 756sub divide { 757 my ($self, $other) = @_; 758 my $u = GetUnit($other)->copy; 759 $self->times($u->recip); 760} 761 762sub power { 763 my $self = shift; 764 $self->CheckChange; 765 my $p = shift; 766 die 'Exponentiation to integer values only, please' 767 unless $p == int $p; 768 $self->{factor} **= $p; 769 770 for (0 .. $NumBases) { 771 $self->{dim}[$_] = 0 unless defined $self->{dim}[$_]; 772 $self->{dim}[$_] *= $p; 773 } 774 775 $self->{type} = ''; 776 return $self; 777} 778 779sub add { 780 my $self = shift; 781 $self->CheckChange; 782 783 my $other = shift; 784 my $u = GetUnit($other); 785 786 croak "Can't add ". $u->type .' to a '. $self->type 787 if CompareDim($self, $u); 788 $self->{factor} += $u->{factor}; 789 return $self; 790} 791 792sub neg { 793 my $self = shift; 794 $self->CheckChange; 795 $self->{factor} = -$self->{factor}; 796 return $self; 797} 798 799sub subtract { 800 my ($self, $other) = @_; 801 my $u = GetUnit($other)->copy; 802 $self->add( $u->neg ); 803} 804 805sub copy { 806 my $self = shift; 807 my $n = { 808 'factor' => $self->{factor}, 809 'dim' => [@{$self->{dim}}], 810 'type' => $self->{type}, 811 'names' => [], 812 'def' => $self->{def}, 813 }; 814 815 bless $n, 'Physics::Unit'; 816 return $n; 817} 818 819sub equal { 820 my $obj1 = shift; 821 822 # If it was called as a class method, throw away the first 823 # argument (the class name) 824 $obj1 = shift unless ref $obj1; 825 $obj1 = GetUnit($obj1); 826 my $obj2 = GetUnit(shift); 827 828 return 0 if CompareDim($obj1, $obj2); 829 return 0 unless $obj1->{factor} == $obj2->{factor}; 830 return 1; 831} 832 833sub NewOne { 834 my $u = { 835 'factor' => 1, 836 'dim' => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 837 'type' => undef, 838 'names' => [], 839 'def' => undef, 840 }; 841 bless $u, 'Physics::Unit'; 842} 843 844sub AddNames { 845 my $self = shift; 846 my $n; 847 while ($n = shift) { 848 croak "Can't use a reference as a name!" if ref $n; 849 carp "Name $n is already defined" if LookName($n); 850 push @{$self->{names}}, "\L$n"; 851 $unit_by_name{$n} = $self; 852 } 853} 854 855sub NewType { 856 my ($self, $t) = @_; 857# my $oldtype = $self->type; 858# croak "NewType: the type $t is already defined as $oldtype" 859# if $oldtype ne 'unknown'; 860 $self->{type} = $t; 861 $prototype{$t} = $self; 862} 863 864sub CreateUnit { 865 my $def = shift; 866 # argument was a Unit object 867 return $def->new() if ref $def; 868 # argument was either a simple name or an expression - doesn't matter 869 $def = lc $def; 870 871 my $u = expr($def); 872 $u->{def} = $def; 873 return $u; 874} 875 876sub CompareDim { 877 my ($u1, $u2) = @_; 878 my $d1 = $u1->{dim}; 879 my $d2 = $u2->{dim}; 880 881 for (0 .. $NumBases) { 882 $$d1[$_] = 0 unless defined $$d1[$_]; 883 $$d2[$_] = 0 unless defined $$d2[$_]; 884 my $c = ($$d1[$_] <=> $$d2[$_]); 885 return $c if $c; 886 } 887 return 0; 888} 889 890sub LookName { 891 my $name = shift; 892 return 3 if defined $prototype{$name}; 893 return 2 if defined $unit_by_name{$name}; 894 return 1 if defined $reserved_word{$name}; 895 return 0; 896} 897 898sub DebugString { 899 my $self = shift; 900 my $s = $self->{factor}; 901 $s .= '['. join (', ', @{$self->{dim}}) .']'; 902 return $s; 903} 904 905sub CheckChange { 906 my $self = shift; 907 carp "You're not allowed to change named units!" if $self->{names}[0]; 908 $self->{names} = []; 909 $self->{type} = $self->{def} = undef; 910} 911 912# global variables used for parsing. 913my $def; # string being parsed 914my $tok; # the token type 915my $numval; # the value when the token is a number 916my $tokname; # when it is a name 917my $indent; # used to indent debug messages 918 919# parser 920sub expr { 921 if (@_) { 922 $def = shift; 923 get_token(); 924 } 925 926 print ' ' x $indent, "inside expr\n" if $debug; 927 $indent++; 928 my $u = term(); 929 930 for (;;) { 931 if ($tok eq 'times') { 932 get_token(); 933 $u->times(term()); 934 } 935 elsif ($tok eq 'divide') { 936 get_token(); 937 $u->divide(term()); 938 } 939 else { 940 print ' ' x $indent, "expr: returning ", $u->DebugString, "\n" 941 if $debug; 942 $indent--; 943 return $u; 944 } 945 } 946} 947 948sub term { 949 print ' ' x $indent, "inside term\n" if $debug; 950 $indent++; 951 my $u = Factor(); 952 953 for (;;) { 954 print ' ' x $indent, "inside term loop\n" if $debug; 955 if ($tok eq 'number' || 956 $tok eq 'name' || 957 $tok eq 'prefix' || 958 $tok eq 'square' || 959 $tok eq 'cubic') 960 { 961 $u->times(Factor()); 962 } 963 else { 964 print ' ' x $indent, "term: returning ", $u->DebugString, "\n" 965 if $debug; 966 $indent--; 967 return $u; 968 } 969 } 970} 971 972sub Factor { 973 print ' ' x $indent, "inside factor\n" if $debug; 974 $indent++; 975 976 my $u = prim(); 977 978 for (;;) { 979 print ' ' x $indent, "inside factor loop\n" if $debug; 980 if ($tok eq 'exponent') { 981 get_token(); 982 die 'Exponent must be an integer' 983 unless $tok eq 'number'; 984 $u->power($numval); 985 get_token(); 986 } 987 else { 988 print ' ' x $indent, "factor: returning ", 989 $u->DebugString, "\n" if $debug; 990 $indent--; 991 return $u; 992 } 993 } 994} 995 996sub prim { 997 print ' ' x $indent, "inside prim\n" if $debug; 998 $indent++; 999 1000 my $u; 1001 1002 if ($tok eq 'number') { 1003 print ' ' x $indent, "got number $numval\n" if $debug; 1004 # Create a new Unit object to represent this number 1005 $u = NewOne(); 1006 $u->{factor} = $numval; 1007 get_token(); 1008 } 1009 elsif ($tok eq 'prefix') { 1010 print ' ' x $indent, "got a prefix: ", "$tokname\n" if $debug; 1011 $u = GetUnit($tokname)->copy(); 1012 get_token(); 1013 $u->times(prim()); 1014 } 1015 elsif ($tok eq 'name') { 1016 print ' ' x $indent, "got a name: ", "$tokname\n" if $debug; 1017 $u = GetUnit($tokname)->copy(); 1018 get_token(); 1019 } 1020 elsif ($tok eq 'lparen') { 1021 print ' ' x $indent, "got a left paren\n" if $debug; 1022 get_token(); 1023 $u = expr(); 1024 die 'Missing right parenthesis' 1025 unless $tok eq 'rparen'; 1026 get_token(); 1027 } 1028 elsif ($tok eq 'end') { 1029 print ' ' x $indent, "got end\n" if $debug; 1030 $u = NewOne(); 1031 } 1032 elsif ($tok eq 'square') { 1033 get_token(); 1034 $u = prim()->power(2); 1035 } 1036 elsif ($tok eq 'cubic') { 1037 get_token(); 1038 $u = prim()->power(3); 1039 } 1040 else { 1041 die 'Primary expected'; 1042 } 1043 1044 print ' ' x $indent, "prim: returning ", $u->DebugString, "\n" 1045 if $debug; 1046 $indent--; 1047 1048 # Before returning, see if the *next* token is 'squared' or 'cubed' 1049 for(;;) { 1050 if ($tok eq 'squared') { 1051 get_token(); 1052 $u->power(2); 1053 } 1054 elsif ($tok eq 'cubed') { 1055 get_token(); 1056 $u->power(3); 1057 } 1058 else { 1059 last; 1060 } 1061 } 1062 1063 return $u; 1064} 1065 1066sub get_token { 1067 print ' ' x $indent, "get_token, looking at '$def'\n" if $debug; 1068 1069 # First remove whitespace at the begining 1070 $def =~ s/^\s+//; 1071 1072 if ($def eq '') { 1073 $tok = 'end'; 1074 return; 1075 } 1076 1077 if ($def =~ s/^\(//) { 1078 $tok = 'lparen'; 1079 } 1080 elsif ($def =~ s/^\)//) { 1081 $tok = 'rparen'; 1082 } 1083 elsif ($def =~ s/^\*\*// || $def =~ s/^\^//) { 1084 $tok = 'exponent'; 1085 } 1086 elsif ($def =~ s/^\*//) { 1087 $tok = 'times'; 1088 } 1089 elsif ($def =~ s/^\///) { 1090 $tok = 'divide'; 1091 } 1092 elsif ($def =~ s/^$number_re//io) { 1093 $numval = $1 + 0; # convert to a number 1094 $tok = 'number'; 1095 } 1096 elsif ($def =~ /^([^\ \n\r\t\f\(\)\/\^\*]+)/) { 1097 my $t = $1; 1098 my $l = LookName($t); 1099 1100 if ($l == 1) { 1101 $tok = $reserved_word{$t}; 1102 $tokname = $t; 1103 $def = substr $def, length($t); 1104 return; 1105 } 1106 elsif ($l == 2) { 1107 $tok = 'name'; 1108 $tokname = $t; 1109 $def = substr $def, length($t); 1110 return; 1111 } 1112 1113 # Couldn't find the name on the first try, look for prefix 1114 for my $p (keys %prefix) { 1115 if ($t =~ /^$p/i) { 1116 $tok = 'prefix'; 1117 $tokname = $p; 1118 $def = substr $def, length($p); 1119 return; 1120 } 1121 } 1122 die "Unknown unit: $t\n"; 1123 } 1124 else { 1125 die "Illegal token in $def"; 1126 } 1127} 1128 11291; 1130__END__ 1131 1132=begin comment 1133 1134Style conventions for this module's POD: 1135 - Names of other classes should be in and 1136 L<> for a link: L<Physics::Unit::Scalar|Physics::Unit::Scalar>. 1137 - Unit names by themselves in the text: B<sec> 1138 - Inline unit expressions: no quotes, B<cubic meters> 1139 - But if it's a code snippet, then C<$u = "cubic meters"> 1140 - "Unit" in caps, when it refers to an object. 1141 - "unit library", "unit expression" (lowercase) 1142 1143=end comment 1144 1145=head1 NAME 1146 1147Physics::Unit - Manipulate physics units and dimensions. 1148 1149=head1 SYNOPSIS 1150 1151 use Physics::Unit ':ALL'; # exports all util. function names 1152 1153 # Define your own unit named "ff" 1154 $ff = new Physics::Unit('furlong / fortnight', 'ff'); 1155 print $ff->type, "\n"; # prints: Speed 1156 1157 # Convert to mph; this prints: One ff is 0.0003720... miles per hour 1158 print "One ", $ff->name, " is ", $ff->convert('mph'), " miles per hour\n"; 1159 1160 # Get canonical string representation 1161 print $ff->expanded, "\n"; # prints: 0.0001663... m s^-1 1162 1163 # More intricate unit expression (using the newly defined unit 'ff'): 1164 $gonzo = new Physics::Unit "13 square millimeters per ff"; 1165 print $gonzo->expanded, "\n"; # prints: 0.07816... m s 1166 1167 # Doing arithmetic maintains the types of units 1168 $m = $ff->copy->times("5 kg"); 1169 print "This ", $m->type, " unit is ", $m->ToString, "\n"; 1170 # prints: This Momentum unit is 0.8315... m gm s^-1 1171 1172See also the L<Synopsis|Physics::Unit::Scalar/Synopsis> section of 1173L<Physics::Unit::Scalar|Physics::Unit::Scalar> for more examples. 1174 1175=head1 DESCRIPTION 1176 1177These modules provide classes for the representation of physical units and 1178quantities, as well as a large library of predefined Physics::Unit objects. 1179New units and quantities can be created with simple human-readable expressions 1180(for example, C<cubic meters per second>). The resultant objects can then be 1181manipulated arithmetically, with the dimensionality correctly maintained. 1182 1183Physics::Unit objects generally represent standard, named units, 1184like B<meter> or B<electronvolt>. 1185L<Physics::Unit::Scalar|Physics::Unit::Scalar> and related classes, on the 1186other hand, are used to represent various quantities that might occur as the 1187result of a measurement or a specification, like "5.7 meters" or "7.4 1188teraelectronvolts". 1189 1190A Physics::Unit object has a list of names, a dimensionality, and a magnitude. 1191For example, the SI unit of force is the B<newton>. In this module, it can be 1192referred to with any of the names B<newton>, B<nt>, or B<newtons>. It's dimensionality 1193is that of a force: mass X distance / time^2. It's magnitude is 1000, which 1194expresses how large it is in terms of the unprefixed base units B<gram>, B<meter>, and B<second>. 1195 1196Units are created through the use of unit expressions, which allow 1197you to combine previously defined named units in new and interesting 1198ways. In the synopsis above, C<furlong / fortnight> is a unit 1199expression. 1200 1201Units that have the same dimensionality (for example, B<acres> and B<square kilometers>) 1202can be compared, and converted from one to the other. 1203 1204=head1 GUIDE TO DOCUMENTATION 1205 1206=over 1207 1208=item Physics::Unit 1209 1210This page. 1211 1212=item L<Physics::Unit::Scalar|Physics::Unit::Scalar> 1213 1214Describes the Scalar class and all of the type-specific classes 1215that derive from Scalar. 1216 1217=item L<physics-unit> 1218 1219Describes the command-line utility that is included with this module. 1220 1221=item L<Physics::Unit::UnitsByName|Physics::Unit::UnitsByName> 1222 1223Table of all of the units predefined in the unit library, alphabetically 1224by name. 1225 1226=item L<Physics::Unit::UnitsByType|Physics::Unit::UnitsByType> 1227 1228Tables listing all the units in the unit library, grouped by type. 1229 1230=item L<Physics::Unit::Implementation|Physics::Unit::Implementation> 1231 1232Describes some implementation details for the Unit module. 1233 1234=item L<Physics::Unit::Scalar::Implementation|Physics::Unit::Scalar::Implementation> 1235 1236Implementation details for the Scalar module. 1237 1238=back 1239 1240=head1 TYPES OF UNITS 1241 1242A Unit can have one or more names associated with it, or it can be 1243unnamed (anonymous). Named units are immutable. This ensures that 1244expressions used to derive other Units will remain consistent. 1245The values of anonymous Unit objects, however, can change. 1246 1247Among named Units, there are three types: prefixes (for example, 1248"kilo", "mega", etc.), base units, and derived units. 1249 1250A prefix Unit is a special-case dimensionless Unit object that 1251can be used in expressions attached to other Unit names with no 1252intervening whitespace. For example, "kilogram" is a unit expression that uses the 1253prefix B<kilo>. For more details about the use of prefixes, see 1254L</"Unit Expressions">, below. 1255 1256A base unit is one that defines a new base dimension. For example, 1257the Unit B<meter> is a base unit; it defines the dimension for B<Distance>. 1258The predefined unit library defines nine base units, for each of nine 1259fundamental quantities. See L</InitBaseUnit()> below for a list. 1260 1261A derived Unit is one that is built up from other named Units, using a 1262unit expression. Most Units are derived Units. 1263 1264The terms base dimension and derived dimension (or derived type) are 1265sometimes used. B<Distance> is an example of a base dimension. It is not 1266derived from any other set of dimensional quantities. B<Speed>, however, 1267is a derived dimension (or derived type), corresponding to 1268B<Distance> / B<Time>. 1269 1270=head1 UNIT NAMES 1271 1272Unit names are not allowed to contain whitespace, or any of the 1273characters ^, *, /, (, or ). Case is not significant. Also, they may not 1274begin with any sequence of characters that could be interpreted as a 1275decimal number. Furthermore, the following reserved words are not allowed as 1276unit names: B<per>, B<square>, B<sq>, B<cubic>, B<squared>, or B<cubed>. Other than 1277that, pretty much anything goes. 1278 1279=head1 UNIT EXPRESSIONS 1280 1281Unit expressions allow you to create new Unit objects from the set of 1282existing named Units. Some examples of unit expressions are: 1283 1284 megaparsec / femtosecond 1285 kg / feet^2 sec 1286 square millimeter 1287 kilogram meters per second squared 1288 1289The operators allowed in unit expressions are, in order from high to 1290low precedence: 1291 1292=over 4 1293 1294=item prefix 1295 1296Any prefix that is attached to a Unit name is applied to that Unit 1297immediately (highest precedence). Note that if there is whitespace 1298between the prefix and the Unit name, this would be the space 1299operator, which is not the same (see below). 1300 1301The unit library comes with a rather complete set of predefined SI prefixes; 1302see the L<UnitsByType|Physics::Unit::UnitsByType> page. 1303 1304The prefixes are allowed before units, or by themselves. Thus, these 1305are equivalent: 1306 1307 (megameter) 1308 (mega meter) 1309 1310But note that when used in expressions, there can be subtle differences, because 1311the precedence of the prefix operation is higher than the space operator. So 1312C<square megameter> is a unit of area, but C<square mega meter> is a unit of 1313distance (equal to B<10^12 meters>). 1314 1315=item square, sq, or cubic 1316 1317Square or cube the next thing on the line 1318 1319=item squared or cubed 1320 1321Square or cube the previous thing on the line. 1322 1323=item C<< ^ >> or C<< ** >> 1324 1325Exponentiation (must be to an integral power) 1326 1327=item I<whitespace> 1328 1329Any amount of whitespace between units is considered a multiplication 1330 1331=item E<42>, /, or per 1332 1333Multiplication or division 1334 1335=item I<parentheses> 1336 1337Can be used to override the precedence of any of the operators. 1338 1339=back 1340 1341For the most part, this precedence order lets you write unit expressions 1342in a natural way. For example, note that the space operator has higher precedence 1343than '*', '/', or 'per'. Thus "C<meters/sec sec>" is a unit of acceleration, 1344but "C<meters/sec*sec>" is not. The latter is equivalent to just 'meters'. 1345 1346=head2 Expression Grammar 1347 1348This is the approximate grammar used by the parser. 1349 1350 expr : term 1351 | term '/' expr 1352 | term '*' expr 1353 | term 'per' expr 1354 1355 term : factor 1356 | term <whitespace> factor 1357 1358 factor : primary 1359 | primary '**' integer 1360 1361 primary : number 1362 | word 1363 | '(' expr ')' 1364 | 'square' primary 1365 | 'sq' primary 1366 | 'cubic' primary 1367 | primary 'squared' 1368 | primary 'cubed' 1369 1370=head1 PREDEFINED UNIT LIBRARY 1371 1372A rather complete set of units is pre-defined in the unit library, so it 1373will probably be rare that you'll need to define your own. See the 1374L<UnitsByName|Physics::Unit::UnitsByName> or 1375L<UnitsByType|Physics::Unit::UnitsByType> page for a complete list. 1376 1377A B<pound> is a unit of force. I was very much tempted to make it a unit 1378of mass, since that is the way it is used in everyday speech, but I just 1379couldn't do it. The everyday pound, then, is named B<pound-mass>, 1380B<lbm>, B<lbms>, or B<pounds-mass>. 1381 1382However, I couldn't bring myself to do the same thing to all the 1383other American units derived from a B<pound>. Therefore, B<ounce>, B<ton>, 1384B<long-ton>, and B<hundredweight> are all units of mass. 1385 1386=head2 Physical Constants 1387 1388A few physical constants were defined as Unit objects. This list is 1389very restricted, however. I limited them to physical constants which 1390really qualify as universal, according to (as much as I know of) the 1391laws of physics, and a few constants which have been defined by 1392international agreement. Thus, they are: 1393 1394=over 1395 1396=item * c - the speed of light 1397 1398=item * G - the universal gravitational constant 1399 1400=item * eq - elementary charge 1401 1402=item * em - electron mass 1403 1404=item * u - atomic mass unit 1405 1406=item * g0 - standard gravity 1407 1408=item * atm - standard atmosphere 1409 1410=item * re - equatorial radius of the reference geoid 1411 1412=item * rp - polar radius of the reference geoid 1413 1414=item * h - Planck constant 1415 1416=item * Na - Avogadro constant 1417 1418=back 1419 1420=head2 Name Conflicts and Resolutions 1421 1422A few unit names and abbreviations had to be changed in order to avoid name 1423conflicts. These are: 1424 1425=over 1426 1427=item * Elementary charge - abbreviated B<eq> instead of B<e> 1428 1429=item * Earth gravity - abbreviated B<g0> instead of B<g> 1430 1431=item * B<point> - there are several definitions for this term. In our library, 1432we define it to be exactly 1/72 of an inch. 1433 1434=item * B<minute> is defined as a unit of time. For the unit of arc, use 1435B<arcminute>. Same for B<second> and B<arcsecond>. 1436 1437=item * B<pound> - As described above, this is defined as a unit of force, with 1438synonyms B<pound-force>, B<pounds-force>, B<pound-weight>, and B<lbf>. 1439For the unit of mass, use B<pound-mass>, B<pounds-mass>, or B<lbm>. 1440 1441=item * B<ounce> - As a unit of mass, use B<ounce>, B<ounce-force>, or B<ozf>. 1442For the unit of volume, use B<fluid-ounce>, B<floz>, or B<fluidounce>. 1443 1444=back 1445 1446=head1 EXPORT OPTIONS 1447 1448By default, this module exports nothing. You can request all of the 1449L<functions|/FUNCTIONS> to be exported as follows: 1450 1451 use Physics::Unit ':ALL'; 1452 1453Or, you can just get specific ones. For example: 1454 1455 use Physics::Unit qw( GetUnit ListUnits ); 1456 1457=head1 FUNCTIONS 1458 1459=over 1460 1461=item InitBaseUnit(I<$type1>, I<$nameList1>, I<$type2>, I<$nameList2>, ...) 1462 1463This function is used to define any number of new, fundamental, 1464independent dimensional quantities. Each such quantity is represented 1465by a Unit object, which must have at least one name. From these base 1466units, all the units in the system are derived. 1467 1468The library is initialized to know about nine base quantities. These 1469quantities, and the base units which represent them, are: 1470 1471=over 1472 1473=item 1. Distance - meter 1474 1475=item 2. Mass - gram 1476 1477=item 3. Time - second 1478 1479=item 4. Temperature - kelvin 1480 1481=item 5. Current - ampere 1482 1483=item 6. Substance - mole 1484 1485=item 7. Luminosity - candela 1486 1487=item 8. Money - us-dollar 1488 1489=item 9. Data - bit 1490 1491=back 1492 1493More base quantities can be added at run-time, by calling this 1494function. The arguments to this function are in pairs. Each pair 1495consists of a type name followed by a reference to an array. The 1496array consists of a list of names which can be used to reference the 1497unit. For example: 1498 1499 InitBaseUnit('Beauty' => ['sonja', 'sonjas', 'yh']); 1500 1501This defines a new basic physical type, called B<Beauty>. This also 1502causes the creation of a single new Unit object, which has three 1503names: B<sonja>, B<sonjas>, and B<yh>. The type B<Beauty> is refered to as a 1504base type. The Unit B<sonja> is refered to as the base unit 1505corresponding to the type B<Beauty>. 1506 1507After defining a new base Unit and type, you can then create other 1508Units derived from this Unit, and other types derived from this type. 1509 1510=item InitPrefix(I<$name1>, I<$number1>, I<$name2>, I<$number2>, ...) 1511 1512This function defines new prefixes. For example: 1513 1514 InitPrefix('gonzo' => 1e100, 'piccolo' => 1e-100); 1515 1516From then on, you can use those prefixes to define new units, as in: 1517 1518 $beautification_rate = new Physics::Unit('5 piccolosonjas / hour'); 1519 1520=item InitUnit(I<$nameList1>, I<$unitDef1>, I<$nameList2>, I<$unitDef2>, ...) 1521 1522This function creates one or more new named Units. This is called at 1523compile time to initialize the module with all the predefined units. 1524It may also be 1525called by users at runtime, to expand the unit system. For example: 1526 1527 InitUnit( ['chris', 'cfm'] => '3 piccolosonjas' ); 1528 1529creates another Unit of type B<Beauty> equal to B<3e-100 sonjas>. 1530 1531Both this utility function and the C<new> class method can be used to 1532create new, named Unit objects. Units created with 1533C<InitUnit> must have a name, however, whereas C<new> can be used to create anonymous 1534Unit objects. 1535 1536In this function and in others, an argument that specifies a Unit (a "unitDef") 1537can be given 1538either as Unit object, a single Unit name, or a unit expression. 1539So, for example, these are the same: 1540 1541 InitUnit( ['mycron'], '3600 sec' ); 1542 InitUnit( ['mycron'], 'hour' ); 1543 InitUnit( ['mycron'], GetUnit('hour') ); 1544 1545No forward references are allowed. 1546 1547=item InitTypes(I<$typeName1>, I<$unit1>, I<$typeName2>, I<$unit2>, ...) 1548 1549Use this function to define derived types. For example: 1550 1551 InitTypes( 'Blooming' => 'sonja / year' ); 1552 1553defines a new type that for a rate of change of B<Beauty> with time. 1554 1555This function associates a type name with a specific dimensionality. 1556The magnitude of the Unit is not used. 1557 1558=item GetUnit(I<$unitDef>) 1559 1560Returns a Unit object associated with the the argument passed in. The 1561argument can either be a Unit object (in which case it is simply returned), 1562a unit name (in which case the name is looked up and a reference to the 1563corresponding Unit is returns), or a unit expression (in which case a new 1564Unit object is created and a reference to it is returned). 1565 1566=item ListUnits() 1567 1568Returns a list of all Unit names known, sorted alphabetically. 1569 1570=item ListTypes() 1571 1572Returns a list of all the quantity types known to the library, sorted 1573alphabetically. 1574 1575=item NumBases() 1576 1577Returns the number of base dimension units. 1578 1579=item GetTypeUnit(I<$type>) 1580 1581Returns the Unit object corresponding to a given type name, or B<undef> if 1582the type is not recognized. 1583 1584=item DeleteNames(I<@names>) 1585 1586=item DeleteNames(I<$unit>) 1587 1588Deletes the names indicated by the argument, which can either be a list 1589of names, a reference to array of names, or a Unit object. If the argument 1590is a Unit object, then all the names of that Unit are deleted. 1591 1592This provides a mechanism to override specific definitions in the default 1593unit library. Use with this with caution. If existing Unit objects 1594had been constructed using these names, the C<def> value of those 1595Units would be rendered invalid when these names are removed. 1596 1597=back 1598 1599=head1 METHODS 1600 1601=over 1602 1603=item new Physics::Unit( I<$unit> [, I<$name1>, I<$name2>, ... ] ) 1604 1605=item I<$u>->new( [I<$name1>, I<$name2>, ... ] ) 1606 1607This method creates a new Unit object. The names are optional. 1608If more than one name is given, the first is the "primary name", 1609which means it is the one returned by the C<name()> method. 1610 1611Unit names must be unique. See the L<UnitsByName|Physics::Unit::UnitsByName> 1612page to see an alphabetical list of all the pre-defined unit names. 1613 1614If no names are given, then an anonymous Unit is created. Note that 1615another way of creating new anonymous Units is with the C<GetUnit()> 1616function. Unlike GetUnit(), however, the new method always creates 1617a new object. 1618 1619Examples: 1620 1621 # Create a new, named unit: 1622 $u = new Physics::Unit ('3 pi furlongs', 'gorkon'); 1623 1624=item I<$u>->type([I<$typeName>]) 1625 1626Get or set this Unit's type. 1627 1628For example: 1629 1630 print GetUnit('rod')->type, "\n"; # 'Distance' 1631 1632Usually it will not be necessary to set a Unit's type. The type 1633is normally determined uniquely from the dimensionality. 1634However, occasionally, more than one type can match a given Unit's 1635dimensionality. 1636 1637For example, B<Torque> and B<Energy> have the same 1638dimensionality. In that case, all of the predefined, named Units are explicitly 1639designated to be one type or the other. For example, the Unit B<newton> 1640is defined to have the type B<Energy>. See the 1641L<UnitsByType|Physics::Unit::UnitsByType> page to 1642see which Units are defined as B<Energy> and which as B<Torque>. 1643 1644If you create a new Unit object that has this dimensionality, then it will 1645be necessary to explicitly specify which type that Unit object is. 1646 1647When this method is called to set the Unit's type, only one type 1648string argument is allowed, and it must be a predefined type name 1649(see C<InitTypes> above). 1650 1651This method returns one of: 1652 1653=over 1654 1655=item C<undef> 1656 1657no type was found to match the unit's dimensionality 1658 1659=item 'prefix' 1660 1661in the special case where the unit is a named prefix 1662 1663=item a type name 1664 1665the prototype unit for this type name matches the unit's dimensionality 1666 1667=item an array of type names 1668 1669more than one type was found to match the unit's dimensionality 1670 1671=back 1672 1673Some examples: 1674 1675 $u1 = new Physics::Unit('kg m^2/s^2'); 1676 $t = $u1->type; # ['Energy', 'Torque'] 1677 1678 $u1->type('Energy'); # This establishes the type once and for all 1679 $t = $u1->type; # 'Energy' 1680 1681 # Create a new copy of a predefined, typed unit: 1682 $u3 = GetUnit('joule')->new; 1683 $t = $u3->type; # 'Energy' 1684 1685=item I<$u>->name() 1686 1687Returns the primary name of the Unit. If this Unit has no names, then 1688C<undef>. 1689 1690=item I<$u>->abbr() 1691 1692Returns the shortest name of the Unit. If this Unit has no names, 1693C<undef>. 1694 1695=item I<$u>->names() 1696 1697Returns a list of names that can be used to reference the Unit. 1698Returns the empty list if the Unit is unnamed. 1699 1700=item I<$u>->def() 1701 1702Returns the string that was used to define this Unit. Note that if 1703the Unit has been manipulated with any of the arithmetic methods, 1704then the C<def> method will return C<undef>, since the definition string is 1705no longer a valid definition of the Unit. 1706 1707=item I<$u>->expanded() 1708 1709Produces a string representation of the Unit, in terms of the base 1710Units. For example: 1711 1712 print GetUnit('calorie')->expanded, "\n"; # "4184 m^2 gm s^-2" 1713 1714=item I<$u>->ToString() 1715 1716There are several ways to serialize a Unit object to a string. 1717This method is designed to give you what you usually want, and to always 1718give something meaningful. 1719 1720If the object is named, this does the same as the C<name()> method above. 1721Otherwise, if the object's definition string is still valid, this 1722does the same as the C<def()> method above. Otherwise, this does the same 1723thing as the C<expanded()> method. 1724 1725=item I<$u>->factor([I<$newValue>]) 1726 1727Get or set the Unit's conversion factor (magnitude). If this is used to set a 1728Unit's factor, then the Unit object must be anonymous. 1729 1730=item I<$u>->convert(I<$unitDef>) 1731 1732Returns the number which converts this Unit to another. The types of 1733the Units must match. For example: 1734 1735 print GetUnit('mile')->convert('foot'), "\n"; # 5280 1736 1737=item I<$u>->times(I<$unitDef>) 1738 1739Multiply this object by the given Unit. This will, in general, change a 1740Unit's dimensionality, and hence its type. 1741 1742=item I<$u>->recip() 1743 1744Replaced a Unit with its reciprocal. This will, in general, change a 1745Unit's dimensionality, and hence its type. 1746 1747=item I<$u>->divide(I<$unitDef>) 1748 1749Divide this object by the given Unit. This will, in general, change a 1750Unit's dimensionality, and hence its type. 1751 1752For example: 1753 1754 $u = new Physics::Unit('36 m^2'); 1755 $u->divide('3 meters'); # now '12 m' 1756 $u->divide(3); # now '4 m' 1757 $u->divide('.5 sec'); # now '8 m/s' 1758 1759=item I<$u>->power(I<$i>) 1760 1761Raises a Unit to an integral power. This will, in general, change its 1762dimensionality, and hence its type. 1763 1764=item I<$u>->add(I<$unitDef>) 1765 1766Add a Unit, which must be of the same type. 1767 1768=item I<$u>->neg() 1769 1770Replace a Unit with its arithmetic negative. 1771 1772=item I<$u>->subtract(I<$unitDef>) 1773 1774Subtract a Unit, which must be of the same type. 1775 1776=item I<$u>->copy() 1777 1778This creates a copy of an existing Unit, without copying the names. 1779So you are free to modify the copy (while modification of 1780named Units is verboten). If the type of the existing Unit is 1781well-defined, then it, also, is copied. 1782 1783This is the same as the new method, when new is called as an object 1784method with no names. 1785 1786=item I<$u>->equal(I<$unit>) 1787 1788=item Physics::Unit->equal(I<$unit1>, I<$unit2>); 1789 1790This returns 1 if the two Unit objects have the same type and the 1791same magnitude. 1792 1793=back 1794 1795=head1 SEE ALSO 1796 1797Here are some other modules that might fit your needs better than this one: 1798 1799=over 1800 1801=item * L<MooseX::Types::NumUnit> 1802 1803=item * L<Math::Units> 1804 1805=item * L<Math::Units::PhysicalValue> 1806 1807=item * L<Petrophysics::Unit> 1808 1809=item * L<Physics::Udunits2> 1810 1811=back 1812 1813=head1 AUTHOR 1814 1815Written by Chris Maloney <voldrani@gmail.com> 1816 1817Special thanks for major contributions and encouragement from Joel Berger. 1818Thanks also to Ben Bullock, and initial help in formatting for distribution 1819from Gene Boggs <cpan@ology.net>. 1820 1821=head1 COPYRIGHT AND LICENSE 1822 1823Copyright 2002-2003 by Chris Maloney 1824 1825This library is free software; you can redistribute it and/or modify 1826it under the same terms as Perl itself. 1827 1828