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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9