[system] / trunk / pg / lib / Units.pm Repository:
ViewVC logotype

Annotation of /trunk/pg/lib/Units.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3655 - (view) (download) (as text)

1 : sh002i 1050
2 :    
3 :     # This is the "exported" subroutine. Use this to evaluate the units given in an answer.
4 :    
5 :     sub evaluate_units {
6 :     &Units::evaluate_units;
7 :     }
8 :    
9 :     # Methods for evaluating units in answers
10 :     package Units;
11 :    
12 :     #require Exporter;
13 :     #@ISA = qw(Exporter);
14 :     #@EXPORT = qw(evaluate_units);
15 :    
16 :    
17 :     # compound units are entered such as m/sec^2 or kg*m/sec^2
18 :     # the format is unit[^power]*unit^[*power].../ unit^power*unit^power....
19 :     # there can be only one / in a unit.
20 :     # powers can be negative integers as well as positive integers.
21 :    
22 :     # These subroutines return a unit hash.
23 :     # A unit hash has the entries
24 :     # factor => number number can be any real number
25 :     # m => power power is a signed integer
26 :     # kg => power
27 :     # s => power
28 :     # rad => power
29 :     # degC => power
30 :     # degF => power
31 :     # degK => power
32 :     # perhaps other fundamental units will added later as well.
33 :    
34 :    
35 :     my %fundamental_units = ('factor' => 1,
36 :     'm' => 0,
37 :     'kg' => 0,
38 :     's' => 0,
39 :     'rad' => 0,
40 :     'degC' => 0,
41 :     'degF' => 0,
42 :     'degK' => 0,
43 :     'mol' => 0, # moles, treated as a fundamental unit?
44 : glarose 3576 'amp' => 0,
45 : sh002i 1050 );
46 :    
47 :     # This hash contains all of the units which will be accepted. These must
48 :     #be defined in terms of the
49 :     # fundamental units given above. If the power of the fundamental unit is
50 :     #not included it is assumed to
51 :     # be zero.
52 :    
53 :     my $PI = 4*atan2(1,1);
54 : gage 3655 # 9.80665 m/s^2 -- standard accelearationof gravity
55 : sh002i 1050
56 :     my %known_units = ('m' => {
57 :     'factor' => 1,
58 :     'm' => 1
59 :     },
60 :     'kg' => {
61 :     'factor' => 1,
62 :     'kg' => 1
63 :     },
64 :     's' => {
65 :     'factor' => 1,
66 :     's' => 1
67 :     },
68 :     'rad' => {
69 :     'factor' => 1,
70 :     'rad' => 1
71 :     },
72 :     'degC' => {
73 :     'factor' => 1,
74 :     'degC' => 1
75 :     },
76 :     'degF' => {
77 :     'factor' => 1,
78 :     'degF' => 1
79 :     },
80 :     'degK' => {
81 :     'factor' => 1,
82 :     'degK' => 1
83 :     },
84 :     'mol' => {
85 : glarose 3576 'factor' =>1,
86 :     'mol' =>1
87 :     },
88 :     'amp' => {
89 :     'factor' => 1,
90 :     'amp' => 1,
91 :     },
92 : sh002i 1050 # ANGLES
93 :     # deg -- degrees
94 :     #
95 :     'deg' => {
96 :     'factor' => 0.0174532925,
97 :     'rad' => 1
98 :     },
99 :     # TIME
100 :     # s -- seconds
101 :     # ms -- miliseconds
102 :     # min -- minutes
103 :     # hr -- hours
104 :     # day -- days
105 :     # yr -- years -- 365 days in a year
106 :     #
107 :     'ms' => {
108 :     'factor' => 0.001,
109 :     's' => 1
110 :     },
111 :     'min' => {
112 :     'factor' => 60,
113 :     's' => 1
114 :     },
115 :     'hr' => {
116 :     'factor' => 3600,
117 :     's' => 1
118 :     },
119 :     'day' => {
120 :     'factor' => 86400,
121 :     's' => 1
122 :     },
123 :     'yr' => {
124 :     'factor' => 31557600,
125 :     's' => 1
126 :     },
127 :    
128 :     # LENGTHS
129 :     # m -- meters
130 :     # cm -- centimeters
131 :     # km -- kilometers
132 :     # mm -- millimeters
133 :     # micron -- micrometer
134 :     # um -- micrometer
135 :     # nm -- nanometer
136 :     # A -- Angstrom
137 :     #
138 :     'km' => {
139 :     'factor' => 1000,
140 :     'm' => 1
141 :     },
142 :     'cm' => {
143 :     'factor' => 0.01,
144 :     'm' => 1
145 :     },
146 :     'mm' => {
147 :     'factor' => 0.001,
148 :     'm' => 1
149 :     },
150 :     'micron' => {
151 :     'factor' => 10**(-6),
152 :     'm' => 1
153 :     },
154 :     'um' => {
155 :     'factor' => 10**(-6),
156 :     'm' => 1
157 :     },
158 :     'nm' => {
159 :     'factor' => 10**(-9),
160 :     'm' => 1
161 :     },
162 :     'A' => {
163 :     'factor' => 10**(-10),
164 :     'm' => 1
165 :     },
166 :     # ENGLISH LENGTHS
167 :     # in -- inch
168 :     # ft -- feet
169 :     # mi -- mile
170 :     # light-year
171 :     #
172 :     'in' => {
173 :     'factor' => 0.0254,
174 :     'm' => 1
175 :     },
176 :     'ft' => {
177 :     'factor' => 0.3048,
178 :     'm' => 1
179 :     },
180 :     'mi' => {
181 :     'factor' => 1609.344,
182 :     'm' => 1
183 :     },
184 :     'light-year' => {
185 :     'factor' => 9.46E15,
186 :     'm' => 1
187 :     },
188 :     # VOLUME
189 :     # L -- liter
190 :     # ml -- milliliters
191 :     # cc -- cubic centermeters
192 :     #
193 :     'L' => {
194 :     'factor' => 0.001,
195 :     'm' => 3
196 :     },
197 :     'cc' => {
198 :     'factor' => 10**(-6),
199 :     'm' => 3,
200 :     },
201 :     'ml' => {
202 :     'factor' => 10**(-6),
203 :     'm' => 3,
204 :     },
205 :     # VELOCITY
206 :     # knots -- nautical miles per hour
207 :     #
208 :     'knots' => {
209 :     'factor' => 0.5144444444,
210 :     'm' => 1,
211 :     's' => -1
212 :     },
213 :     # MASS
214 :     # g -- grams
215 :     # kg -- kilograms
216 :     #
217 :     'g' => {
218 :     'factor' => 0.001,
219 :     'kg' => 1
220 :     },
221 :     # ENGLISH MASS
222 :     # slug -- slug
223 :     #
224 :     'slug' => {
225 :     'factor' => 14.6,
226 :     'kg' => 1
227 :     },
228 :     # FREQUENCY
229 :     # Hz -- Hertz
230 :     # kHz -- kilo Hertz
231 :     # MHz -- mega Herta
232 :     #
233 :     'Hz' => {
234 :     'factor' => 2*$PI, #2pi
235 :     's' => -1,
236 :     'rad' => 1
237 :     },
238 :     'kHz' => {
239 :     'factor' => 1000*2*$PI, #1000*2pi,
240 :     's' => -1,
241 :     'rad' => 1
242 :     },
243 :     'MHz' => {
244 :     'factor' => (10**6)*2*$PI, #10^6 * 2pi,
245 :     's' => -1,
246 :     'rad' => 1
247 :     },
248 :     'rev' => {
249 : apizer 1079 'factor' => 2*$PI,
250 : sh002i 1050 'rad' => 1
251 :     },
252 :     'cycles' => {
253 : apizer 1079 'factor' => 2*$PI,
254 : sh002i 1050 'rad' => 1
255 : apizer 1079 },
256 : sh002i 1050
257 :     # COMPOUND UNITS
258 :     #
259 :     # FORCE
260 :     # N -- Newton
261 :     # microN -- micro Newton
262 :     # uN -- micro Newton
263 :     # dyne -- dyne
264 :     # lb -- pound
265 :     # ton -- ton
266 :     #
267 :     'N' => {
268 :     'factor' => 1,
269 :     'm' => 1,
270 :     'kg' => 1,
271 :     's' => -2
272 :     },
273 :     'microN' => {
274 :     'factor' => 10**(-6),
275 :     'm' => 1,
276 :     'kg' => 1,
277 :     's' => -2
278 :     },
279 :     'uN' => {
280 :     'factor' => 10**(-6),
281 :     'm' => 1,
282 :     'kg' => 1,
283 :     's' => -2
284 :     },
285 :     'dyne' => {
286 :     'factor' => 10**(-5),
287 :     'm' => 1,
288 :     'kg' => 1,
289 :     's' => -2
290 :     },
291 :     'lb' => {
292 : gage 3655 'factor' => 4.4482216152605,
293 : sh002i 1050 'm' => 1,
294 :     'kg' => 1,
295 :     's' => -2
296 :     },
297 :     'ton' => {
298 :     'factor' => 8900,
299 :     'm' => 1,
300 :     'kg' => 1,
301 :     's' => -2
302 :     },
303 :     # ENERGY
304 :     # J -- Joule
305 :     # kJ -- kilo Joule
306 :     # erg -- erg
307 :     # lbf -- foot pound
308 :     # cal -- calorie
309 :     # kcal -- kilocalorie
310 :     # eV -- electron volt
311 :     # kWh -- kilo Watt hour
312 :     #
313 :     'J' => {
314 :     'factor' => 1,
315 :     'm' => 2,
316 :     'kg' => 1,
317 :     's' => -2
318 :     },
319 :     'kJ' => {
320 :     'factor' => 1000,
321 :     'm' => 2,
322 :     'kg' => 1,
323 :     's' => -2
324 :     },
325 :     'erg' => {
326 :     'factor' => 10**(-7),
327 :     'm' => 2,
328 :     'kg' => 1,
329 :     's' => -2
330 :     },
331 :     'lbf' => {
332 : gage 3655 'factor' => 1.35582,
333 : sh002i 1050 'm' => 2,
334 :     'kg' => 1,
335 :     's' => -2
336 :     },
337 :     'cal' => {
338 :     'factor' => 4.19,
339 :     'm' => 2,
340 :     'kg' => 1,
341 :     's' => -2
342 :     },
343 :     'kcal' => {
344 :     'factor' => 4190,
345 :     'm' => 2,
346 :     'kg' => 1,
347 :     's' => -2
348 :     },
349 :     'eV' => {
350 :     'factor' => 1.60E-9,
351 :     'm' => 2,
352 :     'kg' => 1,
353 :     's' => -2
354 :     },
355 :     'kWh' => {
356 :     'factor' => 3.6E6,
357 :     'm' => 2,
358 :     'kg' => 1,
359 :     's' => -2
360 :     },
361 :     # POWER
362 :     # W -- Watt
363 :     # kW -- kilo Watt
364 :     # hp -- horse power 746 W
365 :     #
366 :     'W' => {
367 :     'factor' => 1,
368 :     'm' => 2,
369 :     'kg' => 1,
370 :     's' => -3
371 :     },
372 :     'kW' => {
373 :     'factor' => 1000,
374 :     'm' => 2,
375 :     'kg' => 1,
376 :     's' => -3
377 :     },
378 :     'hp' => {
379 :     'factor' => 746,
380 :     'm' => 2,
381 :     'kg' => 1,
382 :     's' => -3
383 :     },
384 :     # PRESSURE
385 :     # Pa -- Pascal
386 :     # kPa -- kilo Pascal
387 :     # atm -- atmosphere
388 :     'Pa' => {
389 :     'factor' => 1,
390 :     'm' => -1,
391 :     'kg' => 1,
392 :     's' => -2
393 :     },
394 :     'kPa' => {
395 :     'factor' => 1000,
396 :     'm' => -1,
397 :     'kg' => 1,
398 :     's' => -2
399 :     },
400 :     'atm' => {
401 :     'factor' => 1.01E5,
402 :     'm' => -1,
403 :     'kg' => 1,
404 :     's' => -2
405 :     },
406 : glarose 3576 # ELECTRICAL UNITS (incomplete)
407 :     # C -- Coulomb
408 :     # V -- volt
409 :     # mV -- milivolt
410 :     # kV -- kilovolt
411 :     # MV -- megavolt
412 :     # F -- Farad
413 :     # mF -- miliFarad
414 :     # uF -- microFarad
415 :     # ohm -- ohm
416 :     # kohm -- kilo-ohm
417 :     'C' => {
418 :     'factor' => 1,
419 :     'amp' => 1,
420 :     's' => 1,
421 :     },
422 :     'V' => {
423 :     'factor' => 1,
424 :     'J' => 1,
425 :     'C' => -1,
426 :     },
427 :     'mV' => {
428 :     'factor' => 0.001,
429 :     'V' => 1,
430 :     },
431 :     'kV' => {
432 :     'factor' => 1000,
433 :     'V' => 1,
434 :     },
435 :     'MV' => {
436 :     'factor' => 10**(6),
437 :     'V' => 1,
438 :     },
439 :     'F' => {
440 :     'factor' => 1,
441 :     'C' => 1,
442 :     'V' => -1,
443 :     },
444 :     'mF' => {
445 :     'factor' => 0.001,
446 :     'F' => 1,
447 :     },
448 :     'uF' => {
449 :     'factor' => 10**(-6),
450 :     'F' => 1,
451 :     },
452 :     'ohm' => {
453 :     'factor' => 1,
454 :     'V' => 1,
455 :     'amp' => -1,
456 :     },
457 :     'kohm' => {
458 :     'factor' => 1000,
459 :     'ohm' => 1,
460 :     },
461 : sh002i 1050 );
462 :    
463 :    
464 :    
465 :     sub process_unit {
466 : apizer 1079
467 :     my $string = shift;
468 :     die ("UNIT ERROR: No units were defined.") unless defined($string); #
469 : sh002i 1050 #split the string into numerator and denominator --- the separator is /
470 :     my ($numerator,$denominator) = split( m{/}, $string );
471 :    
472 : apizer 1079
473 :    
474 : sh002i 1050 $denominator = "" unless defined($denominator);
475 :     my %numerator_hash = process_term($numerator);
476 :     my %denominator_hash = process_term($denominator);
477 :    
478 :    
479 :     my %unit_hash = %fundamental_units;
480 :     my $u;
481 :     foreach $u (keys %unit_hash) {
482 :     if ( $u eq 'factor' ) {
483 :     $unit_hash{$u} = $numerator_hash{$u}/$denominator_hash{$u}; # calculate the correction factor for the unit
484 :     } else {
485 : apizer 1079
486 : sh002i 1050 $unit_hash{$u} = $numerator_hash{$u} - $denominator_hash{$u}; # calculate the power of the fundamental unit in the unit
487 :     }
488 : apizer 1079 }
489 :     # return a unit hash.
490 : sh002i 1050 return(%unit_hash);
491 :     }
492 :    
493 :     sub process_term {
494 : apizer 1079 my $string = shift;
495 : sh002i 1050 my %unit_hash = %fundamental_units;
496 :     if ($string) {
497 : apizer 1079
498 : sh002i 1050 #split the numerator or denominator into factors -- the separators are *
499 : apizer 1079
500 : sh002i 1050 my @factors = split(/\*/, $string);
501 : apizer 1079
502 : sh002i 1050 my $f;
503 :     foreach $f (@factors) {
504 :     my %factor_hash = process_factor($f);
505 : apizer 1079
506 : sh002i 1050 my $u;
507 :     foreach $u (keys %unit_hash) {
508 :     if ( $u eq 'factor' ) {
509 :     $unit_hash{$u} = $unit_hash{$u} * $factor_hash{$u}; # calculate the correction factor for the unit
510 :     } else {
511 : apizer 1079
512 : sh002i 1050 $unit_hash{$u} = $unit_hash{$u} + $factor_hash{$u}; # calculate the power of the fundamental unit in the unit
513 :     }
514 :     }
515 :     }
516 :     }
517 :     #returns a unit hash.
518 :     #print "process_term returns", %unit_hash, "\n";
519 :     return(%unit_hash);
520 : apizer 1079 }
521 : sh002i 1050
522 : apizer 1079
523 : sh002i 1050 sub process_factor {
524 : apizer 1079 my $string = shift;
525 : sh002i 1050 #split the factor into unit and powers
526 : apizer 1079
527 : sh002i 1050 my ($unit_name,$power) = split(/\^/, $string);
528 :     $power = 1 unless defined($power);
529 :     my %unit_hash = %fundamental_units;
530 : apizer 1079
531 : sh002i 1050 if ( defined( $known_units{$unit_name} ) ) {
532 :     my %unit_name_hash = %{$known_units{$unit_name}}; # $reference_units contains all of the known units.
533 :     my $u;
534 :     foreach $u (keys %unit_hash) {
535 :     if ( $u eq 'factor' ) {
536 :     $unit_hash{$u} = $unit_name_hash{$u}**$power; # calculate the correction factor for the unit
537 :     } else {
538 :     my $fundamental_unit = $unit_name_hash{$u};
539 :     $fundamental_unit = 0 unless defined($fundamental_unit); # a fundamental unit which doesn't appear in the unit need not be defined explicitly
540 :     $unit_hash{$u} = $fundamental_unit*$power; # calculate the power of the fundamental unit in the unit
541 :     }
542 :     }
543 :     } else {
544 :     die "UNIT ERROR Unrecognizable unit: |$unit_name|";
545 :     }
546 :     %unit_hash;
547 :     }
548 :    
549 :     # This is the "exported" subroutine. Use this to evaluate the units given in an answer.
550 :     sub evaluate_units {
551 :     my $unit = shift;
552 :     my %output = eval(q{process_unit( $unit)});
553 :     %output = %fundamental_units if $@; # this is what you get if there is an error.
554 :     $output{'ERROR'}=$@ if $@;
555 :     %output;
556 :     }
557 :     #################

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9