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