File: convertcore.py

package info (click to toggle)
limnoria 2026.1.16-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,584 kB
  • sloc: python: 50,436; makefile: 49; sh: 14
file content (1285 lines) | stat: -rw-r--r-- 46,382 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
#****************************************************************************
# This file has been modified from its original version. It has been
# formatted to fit your irc bot.
#
# The original version is a nifty PyQt application written by Douglas Bell,
# available at  http://convertall.bellz.org/
#
# Below is the original copyright. Doug Bell rocks.
# The hijacker is Keith Jones, and he has no bomb in his shoe.
#
#****************************************************************************

import re
import copy

unitData = \
"""
#*****************************************************************************
#units.dat, the units data file, version 0.6.2
#
# ConvertAll, a units conversion program
# Copyright (C) 2016, Douglas W. Bell
#
# This is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License, Version 2.  This program is
# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
#*****************************************************************************
#
# Units are defined by an optional quantity and an equivalent unit or unit
# combination.  A Python expression may be used for the quantity, but is
# restricted to using only the following operators: *, /, +, -.
# Beware of integer division truncation: be sure to use a float for at least
# one of the values.
#
# The unit type must be placed in square brackets before a set of units.  The
# first comment after the equivalent unit will be put in parenthesis after the
# unit name (usually used to give the full name of an abbreviated unit).  The
# next comment will be used in the program list's comment column; later
# comments and full line comments are ignored.
#
# Non-linear units are indicated with an equivalent unit in square brackets,
# followed by either equations or equivalency lists for the definition.  For
# equations, two are given, separated by a ';'.  Both are functions of "x", the
# first going from the unit to the equivalent unit and the second one in
# reverse.  Any valid Python expression returning a float (including the
# functions in the math module) should work.  The equivalency list is a Python
# list of tuples giving points for linear interpolation.
#
# All units must reduce to primitive units, which are indicated by an
# equivalent unit starting with '!'.  A special "unitless" primitve unit
# (usualty called "unit") has '!!' for an equivalent unit.  Circular references
# must also be avoided.
#
# Primitive units:  kg, m, s, K, A, mol, cd, rad, sr, bit, unit
#
##############################################################################

#
# mass units
#
[mass]
kg                  = !                  # kilogram
kilogram            = kg
key                 = kg                 # # drug slang
hectogram           = 100 gram
dekagram            = 10 gram
gram                = 0.001 kg
g                   = gram               # gram
decigram            = 0.1 gram
centigram           = 0.01 gram
milligram           = 0.001 gram
mg                  = milligram          # milligram
microgram           = 0.001 mg
tonne               = 1000 kg            # # metric
metric ton          = tonne
megagram            = tonne
kilotonne           = 1000 tonne         # # metric
gigagram            = 1e9 gram
teragram            = 1e12 gram
carat               = 0.2 gram
ct                  = carat              # carat
amu                 = 1.66053873e-27 kg  # atomic mass
atomic mass unit    = amu
pound               = 0.45359237 kg      #        # avoirdupois
lb                  = pound              # pound  # avoirdupois
lbm                 = pound              # pound  # avoirdupois
ounce               = 1/16.0 pound       #        # avoirdupois
oz                  = ounce              # ounce  # avoirdupois
lid                 = ounce              #        # drug slang
dram                = 1/16.0 ounce       #        # avoirdupois
pound troy          = 5760 grain
lb troy             = pound troy         # pound troy
ounce troy          = 1/12.0 lb troy
oz troy             = ounce troy         # ounce troy
ton                 = 2000 lb            # # non-metric
kiloton             = 1000 ton           # # non-metric
long ton            = 2240 lb            # # Imperial
ton imperial        = long ton
slug                = lbf*s^2/ft
stone               = 14 lb
grain               = 1/7000.0 lb
pennyweight         = 24 grain
hundredweight long  = 112 lb             # # Imperial
hundredweight short = 100 lb             # # US & Canada
solar mass          = 1.9891e30 kg


#
# length / distance units
#
[length]
m                        = !              # meter
meter                    = m
metre                    = m
dm                       = 0.1 m          # decimeter
decimeter                = dm
cm                       = 0.01 m         # centimeter
centimeter               = cm
mm                       = 0.001 m        # millimeter
millimeter               = mm
micrometer               = 1e-6 m
micron                   = micrometer
nanometer                = 1e-9 m
nm                       = nanometer      # nanometer
dekameter                = 10 m
hectometer               = 100 m
km                       = 1000 m         # kilometer
kilometer                = km
megameter                = 1000 km
angstrom                 = 1e-10 m
fermi                    = 1e-15 m        # # nuclear sizes
inch                     = 2.54 cm
in                       = inch           # inch
inches                   = inch
mil                      = 0.001 inch
microinch                = 1e-6 inch
microinches              = microinch
foot                     = 12 inch
ft                       = foot           # foot
feet                     = foot
foot US survey           = 1200/3937.0 m
Cape foot                = 1.033 foot
yard                     = 3 ft
yd                       = yard           # yard
mile                     = 5280 ft        # # statute mile
mi                       = mile           # mile # statute mile
nautical mile            = 1852 m
nmi                      = nautical mile  # nautical mile
mile US survey           = 5280 foot US survey
league                   = 3 mile
chain                    = 66 ft
chain US survey          = 66 foot US survey
link                     = 0.01 chain
fathom                   = 6 ft
cable                    = 0.1 nautical mile
rod                      = 5.5 yard
furlong                  = 40 rod
hand                     = 4 inch
cubit                    = 21.8 inch      # # biblical unit
point                    = 1/72.0 inch    # # desktop publishing point
pica                     = 12 point
caliber                  = 1.0 inch       # # bullet sizes
rack unit                = 1.75 in        # # computing
smoot                    = 67 inch
football field           = 100 yd
marathon                 = 46145 yd
mil Swedish              = 10 km
versta                   = 3500 ft        # # Russian unit
au                       = 1.49597870691e11 m   # astronomical unit
astronomical unit        = au
LD                       = 384400 km      # lunar distance # astronomical
lunar distance           = LD             # # astronomical distance
light year               = 365.25 light speed * day
light minute             = light speed * min
light second             = light speed * s
parsec                   = 3.0856775813e16 m
kiloparsec               = 1000 parsec
megaparsec               = 1000 kiloparsec
screw size               = [in] 0.013*x + 0.06 ; (x - 0.06) / 0.013 \
                           # # Unified diameters, non-linear
AWG Dia                  = [in] pow(92.0,(36-x)/39.0)/200.0 ; \
                           36 - 39.0*log(200.0*x)/log(92.0) \
                           # American Wire Gauge \
                           # use -1, -2 for 00, 000; non-linear
American Wire Gauge Dia  = [in] pow(92.0,(36-x)/39.0)/200.0 ; \
                           36 - 39.0*log(200.0*x)/log(92.0) \
                           #  # use -1, -2 for 00, 000; non-linear
British Std Wire Gauge   = [in] [(-6, .500), (-5, .464), (-3, .400), \
                           (-2, .372), (3, .252), (6, .192), (10, .128), \
                           (14, .080), (19, .040), (23, .024), (26, .018), \
                           (28, .0148), (30, .0124), (39, .0052), \
                           (49, .0012), (50, .001)] \
                           #  # use -1, -2 for 2/0, 3/0; non-linear
standard gauge           = [in] [(-5, .448350), (1, .269010), (14, .0747250), \
                           (16, .0597800), (17, .0538020), (20, .0358680), \
                           (26, .0179340), (31, .0104615), (36, .00672525), \
                           (38, .00597800)] # steel \
                           # Manufacturers Std. Gauge, non-linear
zinc gauge               = [in] [(1, .002), (10, .02), (15, .04), (19, .06), \
                           (23, .1), (24, .125), (27, .5), (28, 1)]  \
                           # # sheet metal thickness, non-linear
ring size                = [in] 0.1018*x + 1.4216 ; (x - 1.4216) / 0.1018  \
                           # # US size, circum., non-linear
shoe size mens           = [in] x/3.0 + 7 + 1/3.0 ; (x - 7 - 1/3.0) * 3 \
                           # # US sizes, non-linear
shoe size womens         = [in] x/3.0 + 6 + 5/6.0 ; (x - 6 - 5/6.0) * 3 \
                           # # US sizes, non-linear


#
# time units
#
[time]
s             = !                 # second
sec           = s                 # second
second        = s
ms            = 0.001 s           # millisecond
millisecond   = ms
microsecond   = 1e-6 s
ns            = 1e-9 s            # nanosecond
nanosecond    = ns
minute        = 60 s
min           = minute            # minute
hour          = 60 min
hr            = hour              # hour
bell          = 30 min            #  # naval definition
watch         = 4 hour
watches       = watch
day           = 24 hr
week          = 7 day
wk            = week              # week
fortnight     = 14 day
month         = 1/12.0 year
year          = 365.242198781 day
yr            = year              # year
calendar year = 365 day
decade        = 10 year
century       = 100 year
centuries     = century
millennium    = 1000 year
millennia     = millennium
[scheduling]
man hour      = 168/40.0 hour
man week      = 40 man hour
man month     = 1/12.0 man year
man year      = 52 man week


#
# temperature
#
[temperature]
K                 = !     # Kelvin
Kelvin            = K
deg K             = K     # Kelvin
degree Kelvin     = K

C                 = [K] x + 273.15 ; x - 273.15  # Celsius  # non-linear
Celsius           = [K] x + 273.15 ; x - 273.15  #          # non-linear
deg C             = [K] x + 273.15 ; x - 273.15  # Celsius  # non-linear
degree Celsius    = [K] x + 273.15 ; x - 273.15  #          # non-linear

R                 = 5/9.0 K     # Rankine
Rankine           = R
deg R             = R           # Rankine
F                 = [R] x + 459.67 ; x - 459.67  # Fahrenheit  # non-linear
Fahrenheit        = [R] x + 459.67 ; x - 459.67  #             # non-linear
deg F             = [R] x + 459.67 ; x - 459.67  # Fahrenheit  # non-linear
degree Fahrenheit = [R] x + 459.67 ; x - 459.67  #             # non-linear

[temp. diff.]
C deg             = K        # Celsius degree
Celsius degree    = C deg
F deg             = R        # Fahrenheit deg.
Fahrenheit degree = F deg


#
# electrical units
#
[current]
A              = !              # ampere
ampere         = A
amp            = A
milliampere    = 0.001 A
milliamp       = milliampere
mA             = milliampere    # milliampere
microampere    = 0.001 mA
kiloampere     = 1000 A
kA             = kiloampere     # kiloampere
[charge]
coulomb        = A*s
amp hour       = A*hr
mAh            = 0.001 amp hour # milliamp hour
milliamp hour  = mAh
[potential]
volt           = W/A
V              = volt           # volt
millivolt      = 0.001 volt
mV             = millivolt      # millivolt
kilovolt       = 1000 volt
kV             = kilovolt       # kilovolt
[resistance]
ohm            = V/A
milliohm       = 0.001 ohm
microhm        = 0.001 milliohm
kilohm         = 1000 ohm
[conductance]
siemens        = A/V
[capacitance]
farad          = coulomb/V
millifarad     = 0.001 farad
microfarad     = 0.001 millifarad
nanofarad      = 1e-9 farad
picofarad      = 1e-12 farad
[magn. flux]
weber          = V*s
Wb             = weber          # weber
maxwell        = 1e-8 Wb
[inductance]
henry          = Wb/A
H              = henry          # henry
millihenry     = 0.001 henry
mH             = millihenry     # millihenry
microhenry     = 0.001 mH
[flux density]
tesla          = Wb/m^2
T              = tesla          # tesla
gauss          = maxwell/cm^2


#
# molecular units
#
[molecular qty]
mol          = !           # mole       # gram mole
mole         = mol         #            # gram mole
gram mole    = mol
kilomole     = 1000 mol
kmol         = kilomole    # kilomole
pound mole   = mol*lbm/gram
lbmol        = pound mole  # pound mole
[size of a mol]
avogadro     = gram/(amu*mol)


#
# Illumination units
#
[lum. intens.]
cd          = !          # candela
candela     = cd

[luminous flux]
lumen        = cd * sr
lm           = lumen     # lumen

[illuminance]
lux          = lumen/m^2
footcandle   = lumen/ft^2
metercandle  = lumen/m^2

[luminance]
lambert      = cd/(pi*cm^2)
millilambert = 0.001 lambert
footlambert  = cd/(pi*ft^2)


#
# angular units
#
[angle]
radian      = !
rad         = radian         # radian
circle      = 2 pi*radian
turn        = circle
revolution  = circle
rev         = revolution     # revolution
degree      = 1/360.0 circle
deg         = degree         # degree
arc min     = 1/60.0 degree  # minute
arc minute  = arc min
min arc     = arc min        # minute
minute arc  = arc min
arc sec     = 1/60.0 arc min # second
arc second  = arc sec
sec arc     = arc sec        # second
second arc  = arc sec
quadrant    = 1/4.0 circle
right angle = quadrant
gradian     = 0.01 quadrant


#
# solid angle units
#
[solid angle]
sr         = !      # steradian
steradian  = sr
sphere     = 4 pi*sr
hemisphere = 1/2.0 sphere


#
# information units
#
[data]
bit              = !
kilobit          = 1000 bit          #                  # based on power of 10
megabit          = 1000 kilobit      #                  # based on power of 10
byte             = 8 bit
B                = byte              # byte
kilobyte         = 1024 byte         #                  # based on power of 2
kB               = kilobyte          # kilobyte         # based on power of 2
megabyte         = 1024 kB           #                  # based on power of 2
MB               = megabyte          # megabyte         # based on power of 2
gigabyte         = 1024 MB           #                  # based on power of 2
GB               = gigabyte          # gigabyte         # based on power of 2
terabyte         = 1024 GB           #                  # based on power of 2
TB               = terabyte          # terabyte         # based on power of 2
petabyte         = 1024 TB           #                  # based on power of 2
PB               = petabyte          # petabyte         # based on power of 2

kilobyte IEC std = 1000 byte         #                  # based on power of 10
kB IEC std       = kilobyte IEC std  # kilobyte         # based on power of 10
megabyte IEC std = 1000 kB IEC std   #                  # based on power of 10
MB IEC std       = megabyte IEC std  # megabyte         # based on power of 10
gigabyte IEC std = 1000 MB IEC std   #                  # based on power of 10
GB IEC std       = gigabyte IEC std  # gigabyte         # based on power of 10
terabyte IEC std = 1000 GB IEC std   #                  # based on power of 10
TB IEC std       = terabyte IEC std  # terabyte         # based on power of 10
petabyte IEC std = 1000 TB IEC std   #                  # based on power of 10
PB IEC std       = petabyte IEC std  # petabyte         # based on power of 10

kibibyte         = 1024 byte
KiB              = kibibyte          # kibibyte
mebibyte         = 1024 KiB
MiB              = mebibyte          # mebibyte
gibibyte         = 1024 MiB
GiB              = gibibyte          # gibibyte
tebibyte         = 1024 GiB
TiB              = tebibyte          # tebibyte
pebibyte         = 1024 TiB
PiB              = pebibyte          # pebibyte

[data transfer]
bps              = bit/sec           # bits / second
kbps             = 1000 bps          # kilobits / sec.  # based on power of 10


#
# Unitless numbers
#
[quantity]
unit               = !!
1                  = unit            # unit
pi                 = 3.14159265358979323846 unit
pair               = 2 unit
hat trick          = 3 unit          # # sports
dozen              = 12 unit
doz                = dozen           # dozen
bakers dozen       = 13 unit
score              = 20 unit
gross              = 144 unit
great gross        = 12 gross
ream               = 500 unit
percent            = 0.01 unit
%                  = percent
mill               = 0.001 unit
[interest rate]
APR                = [unit] log(1 + x/100) ;  (exp(x) - 1)*100 \
                     # annual % rate # based on continuous compounding
[concentration]
proof              = 1/200.0 unit    # # alcohol content
ppm                = 1e-6 unit       # parts per million
parts per million  = ppm
ppb                = 1e-9 unit       # parts per billion
parts per billion  = ppb
ppt                = 1e-12 unit      # parts per trillion
parts per trillion = ppt
karat              = 1/24.0 unit     # # gold purity
carat gold         = karat           # # gold purity


#
# force units
#
[force]
newton         = kg*m/s^2
N              = newton           # newton
dekanewton     = 10 newton
kilonewton     = 1000 N
kN             = kilonewton       # kilonewton
meganewton     = 1000 kN
millinewton    = 0.001 N
dyne           = cm*g/s^2
kg force       = kg * gravity     # kilogram f
kgf            = kg force         # kilogram force
kilogram force = kg force
kp             = kg force         # kilopond
kilopond       = kg force
gram force     = g * gravity
pound force    = lbm * gravity    #              # avoirdupois
lbf            = pound force      # pound force  # avoirdupois
ton force      = ton * gravity
ounce force    = ounce * gravity
ozf            = ounce force      # ounce force
tonne force    = tonne * gravity  # # metric
pdl            = lbm * ft / sec^2 # poundal # Imperial force
poundal        = pdl              # # Imperial force


#
# area units
#
[area]
barn                     = 1e-28 m^2       # # particle physics
are                      = 100 m^2
decare                   = 10 are
dekare                   = 10 are
hectare                  = 100 are
stremma                  = 1000 m^2
acre                     = 10 chain^2
section                  = mile^2
township                 = 36 section
homestead                = 160 acre
square perch             = 30.25 yd^2
rood                     = 0.25 acre
rai                      = 1600 m^2        # # Thai
ngaan                    = 400 m^2         # # Thai
circular inch            = 1/4.0 pi*in^2   # # area of 1 inch circle
circular mil             = 1/4.0 pi*mil^2  # # area of 1 mil circle
AWG Area                 = [in^2] pi/4*pow(pow(92.0,(36-x)/39.0)/200.0,2) ; \
                           36 - 39.0*log(200.0*sqrt(x*4.0/pi))/log(92.0) \
                           # American Wire Gauge \
                           # use -1, -2 for 00, 000; non-linear
American Wire Gauge Area = [in^2] pi/4*pow(pow(92.0,(36-x)/39.0)/200.0,2) ; \
                           36 - 39.0*log(200.0*sqrt(x*4.0/pi))/log(92.0) \
                           #  # use -1, -2 for 00, 000; non-linear


#
# volume units
#
[volume]
cc                   = cm^3                 # cubic centimeter
cubic centimeter     = cc
liter                = 1000 cc
l                    = liter                # liter
litre                = liter
deciliter            = 0.1 liter
centiliter           = 0.01 liter
milliliter           = cc
ml                   = milliliter           # milliliter
microliter           = 1e-6 liter
dekaliter            = 10 liter
hectoliter           = 100 liter
kiloliter            = 1000 liter
kl                   = kiloliter            # kiloliter
megaliter            = 1000 kiloliter
gallon               = 231 in^3             #             # US liquid
gal                  = gallon               # gallon      # US liquid
quart                = 1/4.0 gallon         #             # US liquid
qt                   = quart                # quart       # US liquid
pint                 = 1/2.0 quart          #             # US liquid
pt                   = pint                 # pint        # US liquid
fluid ounce          = 1/16.0 pint          #             # US
fl oz                = fluid ounce          # fluid ounce # US
ounce fluid          = fluid ounce          #             # US
fluid dram           = 1/8.0 fluid ounce    #             # US
minim                = 1/480.0 fluid ounce  #             # US
imperial gallon      = 4.54609 liter
imp gal              = imperial gallon      # imperial gallon
gallon imperial      = imperial gallon
imperial quart       = 1/4.0 imp gal
imp qt               = imperial quart       # imperial quart
quart imperial       = imperial quart
imperial pint        = 1/8.0 imp gal
imp pt               = imperial pint        # imperial pint
pint imperial        = imperial pint
imperial fluid ounce = 1/160.0 imp gal
imp fl oz            = imperial fluid ounce # imperial fluid ounce
imperial fluid dram  = 1/8.0 imp fl oz
imperial minim       = 1/480.0 imp fl oz
cup                  = 8 fl oz
tablespoon           = 1/16.0 cup
tbsp                 = tablespoon           # tablespoon
teaspoon             = 1/3.0 tbsp
tsp                  = teaspoon             # teaspoon
barrel               = 42 gallon
bbl                  = barrel               # barrel
shot                 = 1.5 fl oz
fifth                = 1/5.0 gallon         #             # alcohol
wine bottle          = 750 ml
magnum               = 1.5 liter            #             # alcohol
keg                  = 15.5 gallon          #             # beer
hogshead wine        = 63 gal
hogshead beer        = 54 gal
bushel               = 2150.42 in^3
peck                 = 1/4.0 bushel
cord                 = 128 ft^3
board foot           = ft^2*in
board feet           = board foot


#
# velocity units
#
[velocity]
knot        = nmi/hr
kt          = knot             # knot
light speed = 2.99792458e8 m/s
mph         = mi/hr            # miles/hour
kph         = km/hr            # kilometers/hour
mach        = 340.29 m/s       # # speed sound at STP
[rot. velocity]
rpm         = rev/min          # rev/min
rps         = rev/sec          # rev/sec


#
# flow rate units
#
[fluid flow]
gph         = gal/hr           # gallons/hour
gpm         = gal/min          # gallons/minute
cfs         = ft^3/sec         # cu ft/second
cfm         = ft^3/min         # cu ft/minute
lpm         = l/min            # liter/min
[gas flow]
sccm        = atm*cc/min       # std cc/min      # pressure * flow
sccs        = atm*cc/sec       # std cc/sec      # pressure * flow
slpm        = atm*l/min        # std liter/min   # pressure * flow
slph        = atm*l/hr         # std liter/hour  # pressure * flow
scfh        = atm*ft^3/hour    # std cu ft/hour  # pressure * flow
scfm        = atm*ft^3/min     # std cu ft/min   # pressure * flow


#
# pressure units
#
[pressure]
Pa                    = N/m^2                    # pascal
pascal                = Pa
hPa                   = 100 Pa                   # hectopascal
hectopascal           = hPa
kPa                   = 1000 Pa                  # kilopascal
kilopascal            = kPa
MPa                   = 1000 kPa                 # megapascal
megapascal            = MPa
GPa                   = 1000 MPa                 # gigapascal
gigapascal            = GPa
atm                   = 101325 Pa                # atmosphere
atmosphere            = atm
bar                   = 1e5 Pa
mbar                  = 0.001 bar                # millibar
millibar              = mbar
microbar              = 0.001 mbar
decibar               = 0.1 bar
kilobar               = 1000 bar
megabar               = 1000 kilobar
mm Hg                 = mm*density Hg*gravity
millimeter of Hg      = mm Hg
torr                  = mm Hg
micron of Hg          = micron*density Hg*gravity
in Hg                 = in*density Hg*gravity    # inch of Hg
inch of Hg            = in Hg
m water               = m*density water*gravity  # meter of H2O # fresh water
m H2O                 = m water                  # meter of H2O # fresh water
meter of water        = m water                  #              # fresh water
in water              = in*density water*gravity # inch of H2O  # fresh water
in H2O                = in water                 # inch of H2O  # fresh water
inch of water         = in water                 #              # fresh water
ft water              = ft*density water*gravity # feet of H2O  # fresh water
ft H2O                = ft water                 # feet of H20  # fresh water
feet of water         = ft water                 #              # fresh water
foot of head          = ft water                 #              # fresh water
ft hd                 = ft water                 # foot of head # fresh water
psi                   = lbf/in^2                 # pound / sq inch
pound per sq inch     = psi
ksi                   = 1000 psi                 # 1000 lb / sq inch


#
# density units
#
[density]
density water         = gram/cm^3
density sea water     = 1.025 gram/cm^3
density Hg            = 13.5950981 gram/cm^3
density air           = 1.293 kg/m^3          # # at STP
density steel         = 0.283 lb/in^3         # # carbon steel
density aluminum      = 0.098 lb/in^3
density zinc          = 0.230 lb/in^3
density brass         = 0.310 lb/in^3         # # 80Cu-20Zn
density copper        = 0.295 lb/in^3
density iron          = 0.260 lb/in^3         # # cast iron
density nickel        = 0.308 lb/in^3
density tin           = 0.275 lb/in^3
density titanium      = 0.170 lb/in^3
density silver        = 0.379 lb/in^3
density nylon         = 0.045 lb/in^3
density polycarbonate = 0.045 lb/in^3


#
# energy units
#
[energy]
joule                 = N*m
J                     = joule             # joule
kilojoule             = 1000 joule
kJ                    = kilojoule         # kilojoule
megajoule             = 1000 kilojoule
gigajoule             = 1000 megajoule
millijoule            = 0.001 joule
mJ                    = millijoule        # millijoule
calorie               = 4.1868 J
cal                   = calorie           # calorie
kilocalorie           = 1000 cal
kcal                  = kilocalorie       # kilocalorie
calorie food          = kilocalorie
thermie               = 1000 kcal
Btu                   = cal*lb*R/(g*K)    # British thermal unit
British thermal unit  = Btu
therm                 = 100000 Btu
erg                   = cm*dyne
electronvolt          = 1.602176462e-19 J
eV                    = electronvolt      # electronvolt
kWh                   = kW*hour           # kilowatt-hour
kilowatt hour         = kWh
ton TNT               = 4.184e9 J
tonne oil equivalent  = 41.868 gigajoule
tonne coal equivalent = 7000000 kcal


#
# power units
#
[power]
watt              = J/s
W                 = watt            # watt
kilowatt          = 1000 W
kW                = kilowatt        # kilowatt
megawatt          = 1000 kW
MW                = megawatt        # megawatt
gigawatt          = 1000 MW
GW                = gigawatt        # gigawatt
milliwatt         = 0.001 W
horsepower        = 550 ft*lbf/sec
hp                = horsepower      # horsepower
metric horsepower = 75 kgf*m/s
ton refrigeration = 12000 Btu/hr
MBH               = 1000 Btu/hr     # 1000 Btu/hr


#
# frequency
#
[frequency]
hertz       = unit/sec
Hz          = hertz      # hertz
millihertz  = 0.001 Hz
kilohertz   = 1000 Hz
kHz         = kilohertz  # kilohertz
megahertz   = 1000 kHz
MHz         = megahertz  # megahertz
gigahertz   = 1000 MHz
GHz         = gigahertz  # gigahertz


#
# radioactivity
#
[radioactivity]
becquerel       = unit/sec
Bq              = becquerel     # becquerel
curie           = 3.7e10 Bq
millicurie      = 0.001 curie
roentgen        = 2.58e-4 coulomb/kg
[radiation dose]
gray            = J/kg
Gy              = gray          # gray
centigray       = 0.01 Gy
rad. abs. dose  = 0.01 Gy       # # commonly rad
sievert         = J/kg          # # equiv. dose
millisievert    = 0.001 sievert # # equiv. dose
Sv              = sievert       # sievert # equiv. dose
rem             = 0.01 Sv       # # roentgen equiv mammal
millirem        = 0.001 rem     # # roentgen equiv mammal


#
# viscosity
#
[dyn viscosity]
poise        = g/(cm*s)
P            = poise       # poise
centipoise   = 0.01 poise
cP           = centipoise  # centipoise

[kin viscosity]
stokes       = cm^2/s
St           = stokes      # stokes
centistokes  = 0.01 stokes
cSt          = centistokes # centistokes


#
# misc. units
#
[acceleration]
gravity                = 9.80665 m/s^2
galileo                = cm/s^2
[constant]
gravity constant       = 6.673e-11 N*m^2/kg^2
gas constant           = 8.314472 J/(mol*K)   # R
[fuel consumpt.]
mpg                    = mi/gal               # miles/gallon
mpg imp                = mi/gallon imperial   # miles/gallon imp
liter per 100 km       = [mpg] 3.785411784 / (x * 0.01609344) ; \
                         3.785411784 / (x * 0.01609344) # # non-linear
[permeability]
darcy                  = 1 cm^2*centipoise/atm/s
millidarcy             = 0.001 darcy

"""


class UnitGroup:
    "Stores, updates and converts a group of units"
    maxDecPlcs = 8
    def __init__(self, unitData, option):
        self.unitData = unitData
        self.option = option
        self.unitList = []
        self.currentNum = 0
        self.factor = 1.0
        self.reducedList = []
        self.linear = 1

    def update(self, text, cursorPos=None):
        "Decode user entered text into units"
        self.unitList = self.parseGroup(text)
        if cursorPos != None:
            self.updateCurrentUnit(text, cursorPos)
        else:
            self.currentNum = len(self.unitList) - 1

    def updateCurrentUnit(self, text, cursorPos):
        "Set current unit number"
        self.currentNum = len(re.findall(r'[\*/]', text[:cursorPos]))

    def currentUnit(self):
        "Return current unit if its a full match, o/w None"
        if self.unitList and self.unitList[self.currentNum].equiv:
            return self.unitList[self.currentNum]
        return None

    def currentPartialUnit(self):
        "Return unit with at least a partial match, o/w None"
        if not self.unitList:
            return None
        return self.unitData.findPartialMatch(self.unitList[self.currentNum]\
                                              .name)

    def currentSortPos(self):
        "Return unit near current unit for sorting"
        if not self.unitList:
            return self.unitData[self.unitData.sortedKeys[0]]
        return self.unitData.findSortPos(self.unitList[self.currentNum]\
                                         .name)

    def replaceCurrent(self, unit):
        "Replace the current unit with unit"
        if self.unitList:
            exp = self.unitList[self.currentNum].exp
            self.unitList[self.currentNum] = copy.copy(unit)
            self.unitList[self.currentNum].exp = exp
        else:
            self.unitList.append(copy.copy(unit))

    def completePartial(self):
        "Replace a partial unit with a full one"
        if self.unitList and not self.unitList[self.currentNum].equiv:
            text = self.unitList[self.currentNum].name
            unit = self.unitData.findPartialMatch(text)
            if unit:
                exp = self.unitList[self.currentNum].exp
                self.unitList[self.currentNum] = copy.copy(unit)
                self.unitList[self.currentNum].exp = exp

    def moveToNext(self, upward):
        "Replace unit with adjacent one based on match or sort position"
        unit = self.currentSortPos()
        num = self.unitData.sortedKeys.index(unit.name.\
                                             replace(' ', '')) \
                                             + (upward and -1 or 1)
        if 0 <= num < len(self.unitData.sortedKeys):
            self.replaceCurrent(self.unitData[self.unitData.sortedKeys[num]])

    def addOper(self, mult):
        "Add new operator & blank unit after current, * if mult is true"
        if self.unitList:
            self.completePartial()
            prevExp = self.unitList[self.currentNum].exp
            self.currentNum += 1
            self.unitList.insert(self.currentNum, Unit(''))
            if (not mult and prevExp > 0) or (mult and prevExp < 0):
                self.unitList[self.currentNum].exp = -1

    def changeExp(self, newExp):
        "Change the current unit's exponent"
        if self.unitList:
            self.completePartial()
            if self.unitList[self.currentNum].exp > 0:
                self.unitList[self.currentNum].exp = newExp
            else:
                self.unitList[self.currentNum].exp = -newExp

    def clearUnit(self):
        "Remove units"
        self.unitList = []

    def parseGroup(self, text):
        "Return list of units from text string"
        unitList = []
        parts = [part.strip() for part in re.split(r'([\*/])', text)]
        numerator = 1
        while parts:
            unit = self.parseUnit(parts.pop(0))
            if not numerator:
                unit.exp = -unit.exp
            if parts and parts.pop(0) == '/':
                numerator = not numerator
            unitList.append(unit)
        return unitList

    def parseUnit(self, text):
        "Return a valid or invalid unit with exponent from a text string"
        parts = text.split('^', 1)
        exp = 1
        if len(parts) > 1:   # has exponent
            try:
                exp = int(parts[1])
            except ValueError:
                if parts[1].lstrip().startswith('-'):
                    exp = -Unit.partialExp  # tmp invalid exp
                else:
                    exp = Unit.partialExp
        unitText = parts[0].strip().replace(' ', '')
        unit = copy.copy(self.unitData.get(unitText, None))
        if not unit and unitText and unitText[-1] == 's' and not \
           self.unitData.findPartialMatch(unitText):   # check for plural
            unit = copy.copy(self.unitData.get(unitText[:-1], None))
        if not unit:
            #unit = Unit(parts[0].strip())   # tmp invalid unit
            raise UnitDataError('%s is not a valid unit.' % (unitText))
        unit.exp = exp
        return unit

    def unitString(self, unitList=None):
        "Return the full string for this group or a given group"
        if unitList == None:
            unitList = self.unitList[:]
        fullText = ''
        if unitList:
            fullText = unitList[0].unitText(0)
            numerator = 1
            for unit in unitList[1:]:
                if (numerator and unit.exp > 0) \
                   or (not numerator and unit.exp < 0):
                    fullText = '%s * %s' % (fullText, unit.unitText(1))
                else:
                    fullText = '%s / %s' % (fullText, unit.unitText(1))
                    numerator = not numerator
        return fullText

    def groupValid(self):
        "Return 1 if all unitself.reducedLists are valid"
        if not self.unitList:
            return 0
        for unit in self.unitList:
            if not unit.unitValid():
                return 0
        return 1

    def reduceGroup(self):
        "Update reduced list of units and factor"
        self.linear = 1
        self.reducedList = []
        self.factor = 1.0
        if not self.groupValid():
            return
        count = 0
        tmpList = self.unitList[:]
        while tmpList:
            count += 1
            if count > 5000:
                raise UnitDataError('Circular unit definition')
            unit = tmpList.pop(0)
            if unit.equiv in ('!', '!!'):
                self.reducedList.append(copy.copy(unit))
            elif not unit.equiv:
                raise UnitDataError('Invalid conversion for "%s"' % unit.name)
            else:
                if unit.fromEqn:
                    self.linear = 0
                newList = self.parseGroup(unit.equiv)
                for newUnit in newList:
                    newUnit.exp *= unit.exp
                tmpList.extend(newList)
                self.factor *= unit.factor**unit.exp
        self.reducedList.sort()
        tmpList = self.reducedList[:]
        self.reducedList = []
        for unit in tmpList:
            if self.reducedList and unit == self.reducedList[-1]:
                self.reducedList[-1].exp += unit.exp
            else:
                self.reducedList.append(unit)
        self.reducedList = [unit for unit in self.reducedList if \
                            unit.name != 'unit' and unit.exp != 0]

    def categoryMatch(self, otherGroup):
        "Return 1 if unit types are equivalent"
        if not self.checkLinear() or not otherGroup.checkLinear():
            return 0
        return self.reducedList == otherGroup.reducedList and \
               [unit.exp for unit in self.reducedList] \
               == [unit.exp for unit in otherGroup.reducedList]

    def checkLinear(self):
        "Return 1 if linear or acceptable non-linear"
        if not self.linear:
            if len(self.unitList) > 1 or self.unitList[0].exp != 1:
                return 0
        return 1

    def compatStr(self):
        "Return string with reduced unit or linear compatability problem"
        if self.checkLinear():
            return self.unitString(self.reducedList)
        return 'Cannot combine non-linear units'

    def convert(self, num, toGroup):

        "Return num of this group converted to toGroup"
        if self.linear:
            num *= self.factor
        else:
            num = self.nonLinearCalc(num, 1) * self.factor


        n2 = -1
        if toGroup.linear:
            n2 =  num / toGroup.factor
        else:
            n2 = toGroup.nonLinearCalc(num / toGroup.factor, 0)
        return n2

    def nonLinearCalc(self, num, isFrom):
        "Return result of non-linear calculation"

        x = num
        try:
            if self.unitList[0].toEqn:      # regular equations
                if isFrom:
                    temp =  float(eval(self.unitList[0].fromEqn))
                    return temp
                temp = float(eval(self.unitList[0].toEqn))
                return temp
            data = list(eval(self.unitList[0].fromEqn))  # extrapolation list
            if isFrom:
                data = [(float(group[0]), float(group[1])) for group in data]
            else:
                data = [(float(group[1]), float(group[0])) for group in data]
            data.sort()
            pos = len(data) - 1
            for i in range(len(data)):
                if num <= data[i][0]:
                    pos = i
                    break
            if pos == 0:
                pos = 1
            y = (num-data[pos-1][0]) / float(data[pos][0]-data[pos-1][0]) \
                   * (data[pos][1]-data[pos-1][1]) + data[pos-1][1]
            return y
        except OverflowError:
            return 1e9999
        except:
            raise UnitDataError('Bad equation for %s' % self.unitList[0].name)

    def convertStr(self, num, toGroup):
        "Return formatted string of converted number"
        return self.formatNumStr(self.convert(num, toGroup))

    def formatNumStr(self, num):
        "Return num string formatted per options"
        decPlcs = self.option.intData('DecimalPlaces', 0, UnitGroup.maxDecPlcs)
        if self.option.boolData('SciNotation'):
            return ('%%0.%dE' % decPlcs) % num
        if self.option.boolData('FixedDecimals'):
            return ('%%0.%df' % decPlcs) % num
        return ('%%0.%dG' % decPlcs) % num


class UnitDataError(Exception):
    pass


class UnitData(dict):
    def __init__(self):
        dict.__init__(self)
        self.sortedKeys = []

    def readData(self):
        "Read all unit data from file"
        types = []
        typeUnits = {}
        lines = unitData.splitlines()
        for i in range(len(lines)):     # join continuation lines
            delta = 1
            while lines[i].rstrip().endswith('\\'):
                lines[i] = ''.join([lines[i].rstrip()[:-1], lines[i+delta]])
                lines[i+delta] = ''
                delta += 1
        units = [Unit(line) for line in lines if \
                 line.split('#', 1)[0].strip()]   # remove comment lines
        typeText = ''
        for unit in units:               # find & set headings
            if unit.name.startswith('['):
                typeText = unit.name[1:-1].strip()
                types.append(typeText)
                typeUnits[typeText] = []
            unit.typeName = typeText
        units = [unit for unit in units if unit.equiv]  # keep valid units
        for unit in units:
            self[unit.name.replace(' ', '')] = unit
            typeUnits[unit.typeName].append(unit.name)
        self.sortedKeys = list(self.keys())
        self.sortedKeys.sort()

        if len(self.sortedKeys) < len(units):
            raise UnitDataError('Duplicate unit names found')

        return (types, typeUnits)

    def findPartialMatch(self, text):
        "Return first partially matching unit or None"
        text = text.replace(' ', '')
        if not text:
            return None
        for name in self.sortedKeys:
            if name.startswith(text):
                return self[name]
        return None

    def findSortPos(self, text):
        "Return unit whose abbrev comes immediately after text"
        text = text.replace(' ', '')
        for name in self.sortedKeys:
            if text <= name:
                return self[name]
        return self[self.sortedKeys[-1]]


class Unit:
    "Reads and stores a single unit conversion"
    partialExp = 1000
    def __init__(self, dataStr):
        dataList = dataStr.split('#')
        unitList = dataList.pop(0).split('=', 1)
        self.name = unitList.pop(0).strip()
        self.equiv = ''
        self.factor = 1.0
        self.fromEqn = ''   # used only for non-linear units
        self.toEqn = ''     # used only for non-linear units
        if unitList:
            self.equiv = unitList[0].strip()
            if self.equiv[0] == '[':   # used only for non-linear units
                try:
                    self.equiv, self.fromEqn = re.match(r'\[(.*?)\](.*)', \
                                                        self.equiv).groups()
                    if ';' in self.fromEqn:
                        self.fromEqn, self.toEqn = self.fromEqn.split(';', 1)
                        self.toEqn = self.toEqn.strip()
                    self.fromEqn = self.fromEqn.strip()
                except AttributeError:
                    raise UnitDataError('Bad equation for "%s"' % self.name)
            else:                # split factor and equiv unit for linear
                parts = self.equiv.split(None, 1)
                if len(parts) > 1 and re.search(r'[^\d\.eE\+\-\*/]', parts[0]) \
                   == None:       # only allowed digits and operators
                    try:
                        self.factor = float(eval(parts[0]))
                        self.equiv = parts[1]
                    except:
                        pass
        self.comments = [comm.strip() for comm in dataList]
        self.comments.extend([''] * (2 - len(self.comments)))
        self.exp = 1
        self.viewLink = [None, None]
        self.typeName = ''

    def description(self):
        "Return name and 1st comment (usu. full name) if applicable"
        if self.comments[0]:
            return '%s  (%s)' % (self.name, self.comments[0])
        return self.name

    def unitValid(self):
        "Return 1 if unit and exponent are valid"
        if self.equiv and -Unit.partialExp < self.exp < Unit.partialExp:
            return 1
        return 0

    def unitText(self, absExp=0):
        "Return text for unit name with exponent or absolute value of exp"
        exp = self.exp
        if absExp:
            exp = abs(self.exp)
        if exp == 1:
            return self.name
        if -Unit.partialExp < exp < Unit.partialExp:
            return '%s^%d' % (self.name, exp)
        if exp > 1:
            return '%s^' % self.name
        else:
            return '%s^-' % self.name

    def __cmp__(self, other):
        return cmp(self.name, other.name)

    def __lt__(self, other):
        return self.name < other.name

    def __eq__(self, other):
        return self.name == other.name

############################################################################
# Wrapper functionality
#
############################################################################


# Parse the data file, and set everything up for conversion
data = UnitData()
(types, unitsByType) = data.readData()

# At the moment, we're not handling options
option = None

# set up the objects for unit conversion
fromUnit = UnitGroup(data, option)
toUnit = UnitGroup(data, option)

def convert(num, unit1, unit2):
    """ Convert from one unit to another

    num is the factor for the first unit. Raises UnitDataError for
    various errors.
    """
    fromUnit.update(unit1)
    toUnit.update(unit2)

    fromUnit.reduceGroup()
    toUnit.reduceGroup()

    # Match up unit categories
    if not fromUnit.categoryMatch(toUnit):
        raise UnitDataError('unit categories did not match')

    return fromUnit.convert(num, toUnit)



def units(type):
    """ Return comma separated string list of units of given type, or
        a list of types if the argument is not valid.
    """
    if type in types:
        return '%s units: %s' % (type, ', '.join(unitsByType[type]))
    else:
        return 'valid types: ' + ', '.join(types)