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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9