comparison lib/PeriodicTable.pm @ 0:4816e4a8ae95 draft default tip

Uploaded
author deepakjadmin
date Wed, 20 Jan 2016 09:23:18 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4816e4a8ae95
1 package PeriodicTable;
2 #
3 # $RCSfile: PeriodicTable.pm,v $
4 # $Date: 2015/02/28 20:47:18 $
5 # $Revision: 1.37 $
6 #
7 # Author: Manish Sud <msud@san.rr.com>
8 #
9 # Copyright (C) 2015 Manish Sud. All rights reserved.
10 #
11 # This file is part of MayaChemTools.
12 #
13 # MayaChemTools is free software; you can redistribute it and/or modify it under
14 # the terms of the GNU Lesser General Public License as published by the Free
15 # Software Foundation; either version 3 of the License, or (at your option) any
16 # later version.
17 #
18 # MayaChemTools is distributed in the hope that it will be useful, but without
19 # any warranty; without even the implied warranty of merchantability of fitness
20 # for a particular purpose. See the GNU Lesser General Public License for more
21 # details.
22 #
23 # You should have received a copy of the GNU Lesser General Public License
24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
26 # Boston, MA, 02111-1307, USA.
27 #
28
29 use strict;
30 use Carp;
31 use Text::ParseWords;
32 use TextUtil;
33 use FileUtil;
34
35 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
36
37 @ISA = qw(Exporter);
38 @EXPORT = qw();
39 @EXPORT_OK = qw(GetElements GetElementsByGroupName GetElementsByGroupNumber GetElementsByAmericanStyleGroupLabel GetElementsByEuropeanStyleGroupLabel GetElementsByPeriodNumber GetElementMostAbundantNaturalIsotopeData GetElementNaturalIsotopeCount GetElementNaturalIsotopesData GetElementNaturalIsotopeAbundance GetElementMostAbundantNaturalIsotopeMass GetElementMostAbundantNaturalIsotopeMassNumber GetElementNaturalIsotopeMass GetElementPropertiesData GetElementPropertiesNames GetElementPropertiesNamesAndUnits GetElementPropertyUnits GetIUPACGroupNumberFromAmericanStyleGroupLabel GetIUPACGroupNumberFromEuropeanStyleGroupLabel IsElement IsElementNaturalIsotopeMassNumber IsElementProperty);
40
41 %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]);
42
43 #
44 # Load atomic properties and isotope data for elements...
45 #
46 my(%ElementDataMap, %ElementIsotopeDataMap, %ElementSymbolMap, @ElementPropertyNames, %ElementPropertyNamesMap, %ElementIsotopeDerivedDataMap);
47 _LoadPeriodicTableElementData();
48
49 #
50 # Get a list of all known element symbols...
51 #
52 sub GetElements {
53 my($AtomicNumber, @ElementSymbols);
54
55 @ElementSymbols = ();
56 for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) {
57 push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol};
58 }
59 return (wantarray ? @ElementSymbols : \@ElementSymbols);
60 }
61
62 #
63 # Get element symbols of elements with a specific group name. Valid group
64 # names are: Alkali metals, Alkaline earth metals, Coinage metals, Pnictogens,
65 # Chalcogens, Halogens, Noble gases; Additionally, usage of Lanthanides (Lanthanoids)
66 # and Actinides (Actinoids) is also supported.
67 #
68 sub GetElementsByGroupName {
69 my($SpecifiedGroupName) = @_;
70 my($AtomicNumber, @ElementSymbols, $GroupName);
71
72 if (IsEmpty($SpecifiedGroupName)) {
73 return (wantarray ? () : undef);
74 }
75 if ($SpecifiedGroupName =~ /Lanthanide/i) {
76 $SpecifiedGroupName = 'Lanthanoids';
77 }
78 elsif ($SpecifiedGroupName =~ /Actinide/i) {
79 $SpecifiedGroupName = 'Actinoids';
80 }
81 @ElementSymbols = ();
82 for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) {
83 $GroupName = $ElementDataMap{$AtomicNumber}{GroupName};
84 if ($SpecifiedGroupName =~ /$GroupName/i ) {
85 push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol};
86 }
87 }
88 return (wantarray ? @ElementSymbols : \@ElementSymbols);
89 }
90
91 #
92 # Get element symbols of elements in a specific IUPAC group number.
93 # A reference to an array containing element symbols is returned.
94 #
95 sub GetElementsByGroupNumber {
96 my($GroupNumber) = @_;
97 my($AtomicNumber, @ElementSymbols);
98
99 if (!IsInteger($GroupNumber)) {
100 return (wantarray ? () : undef);
101 }
102
103 @ElementSymbols = ();
104 for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) {
105 if ($GroupNumber eq $ElementDataMap{$AtomicNumber}{GroupNumber}) {
106 push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol};
107 }
108 }
109 return (wantarray ? @ElementSymbols : \@ElementSymbols);
110 }
111
112 #
113 # Get element symbols of elements in a specific American style group label.
114 # A reference to an array containing element symbols is returned.
115 #
116 sub GetElementsByAmericanStyleGroupLabel {
117 my($GroupLabel) = @_;
118
119 return _GetElementsByGroupLabel($GroupLabel, 'AmericanStyle');
120 }
121
122 #
123 # Get element symbols of elements in a specific European style group label.
124 # A reference to an array containing element symbols is returned.
125 #
126 sub GetElementsByEuropeanStyleGroupLabel {
127 my($GroupLabel) = @_;
128
129 return _GetElementsByGroupLabel($GroupLabel, 'EuropeanStyle');
130 }
131
132 #
133 # Get IUPAC group number from American style group label. A comma delimited
134 # string is returned for group VIII or VIIIB.
135 #
136 sub GetIUPACGroupNumberFromAmericanStyleGroupLabel {
137 my($GroupLabel) = @_;
138 my($GroupNumber);
139
140 if (IsEmpty($GroupLabel)) {
141 return undef;
142 }
143 $GroupNumber = "";
144 SWITCH: {
145 if ($GroupLabel =~ /^IA$/) { $GroupNumber = 1; last SWITCH;}
146 if ($GroupLabel =~ /^IIA$/) { $GroupNumber = 2; last SWITCH;}
147 if ($GroupLabel =~ /^IIIB$/) { $GroupNumber = 3; last SWITCH;}
148 if ($GroupLabel =~ /^IVB$/) { $GroupNumber = 4; last SWITCH;}
149 if ($GroupLabel =~ /^VB$/) { $GroupNumber = 5; last SWITCH;}
150 if ($GroupLabel =~ /^VIB$/) { $GroupNumber = 6; last SWITCH;}
151 if ($GroupLabel =~ /^VIIB$/) { $GroupNumber = 7; last SWITCH;}
152 if ($GroupLabel =~ /^(VIII|VIIIB)$/) { $GroupNumber = '8,9,10'; last SWITCH;}
153 if ($GroupLabel =~ /^IB$/) { $GroupNumber = 11; last SWITCH;}
154 if ($GroupLabel =~ /^IIB$/) { $GroupNumber = 12; last SWITCH;}
155 if ($GroupLabel =~ /^IIIA$/) { $GroupNumber = 13; last SWITCH;}
156 if ($GroupLabel =~ /^IVA$/) { $GroupNumber = 14; last SWITCH;}
157 if ($GroupLabel =~ /^VA$/) { $GroupNumber = 15; last SWITCH;}
158 if ($GroupLabel =~ /^VIA$/) { $GroupNumber = 16; last SWITCH;}
159 if ($GroupLabel =~ /^VIIA$/) { $GroupNumber = 17; last SWITCH;}
160 if ($GroupLabel =~ /^VIIIA$/) { $GroupNumber = 18; last SWITCH;}
161 $GroupNumber = "";
162 }
163 if (!$GroupNumber) {
164 return undef;
165 }
166 return $GroupNumber;
167 }
168
169 #
170 # Get IUPAC group number from European style group label. A comma delimited
171 # string is returned for group VIII or VIIIA
172 #
173 sub GetIUPACGroupNumberFromEuropeanStyleGroupLabel {
174 my($GroupLabel) = @_;
175 my($GroupNumber);
176
177 if (IsEmpty($GroupLabel)) {
178 return undef;
179 }
180 $GroupNumber = "";
181 SWITCH: {
182 if ($GroupLabel =~ /^IA$/) { $GroupNumber = 1; last SWITCH;}
183 if ($GroupLabel =~ /^IIA$/) { $GroupNumber = 2; last SWITCH;}
184 if ($GroupLabel =~ /^IIIA$/) { $GroupNumber = 3; last SWITCH;}
185 if ($GroupLabel =~ /^IVA$/) { $GroupNumber = 4; last SWITCH;}
186 if ($GroupLabel =~ /^VA$/) { $GroupNumber = 5; last SWITCH;}
187 if ($GroupLabel =~ /^VIA$/) { $GroupNumber = 6; last SWITCH;}
188 if ($GroupLabel =~ /^VIIA$/) { $GroupNumber = 7; last SWITCH;}
189 if ($GroupLabel =~ /^(VIII|VIIIA)$/) { $GroupNumber = '8,9,10'; last SWITCH;}
190 if ($GroupLabel =~ /^IB$/) { $GroupNumber = 11; last SWITCH;}
191 if ($GroupLabel =~ /^IIB$/) { $GroupNumber = 12; last SWITCH;}
192 if ($GroupLabel =~ /^IIIB$/) { $GroupNumber = 13; last SWITCH;}
193 if ($GroupLabel =~ /^IVB$/) { $GroupNumber = 14; last SWITCH;}
194 if ($GroupLabel =~ /^VB$/) { $GroupNumber = 15; last SWITCH;}
195 if ($GroupLabel =~ /^VIB$/) { $GroupNumber = 16; last SWITCH;}
196 if ($GroupLabel =~ /^VIIB$/) { $GroupNumber = 17; last SWITCH;}
197 if ($GroupLabel =~ /^VIIIB$/) { $GroupNumber = 18; last SWITCH;}
198 $GroupNumber = "";
199 }
200 if (!$GroupNumber) {
201 return undef;
202 }
203 return $GroupNumber;
204 }
205
206 #
207 # Get element symbols of elements in a specific period number.
208 # A reference to an array containing element symbols is returned.
209 #
210 sub GetElementsByPeriodNumber {
211 my($SpecifiedPeriodNumber) = @_;
212 my($AtomicNumber, $PeriodNumber, @ElementSymbols);
213
214 if (!IsInteger($SpecifiedPeriodNumber)) {
215 return (wantarray ? () : undef);
216 }
217
218 @ElementSymbols = ();
219 for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) {
220 $PeriodNumber = $ElementDataMap{$AtomicNumber}{PeriodNumber};
221 if ($PeriodNumber =~ /\(/) {
222 # Lanthanides and Actinides...
223 ($PeriodNumber) = split /\(/, $PeriodNumber;
224 }
225 if ($PeriodNumber == $SpecifiedPeriodNumber) {
226 push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol};
227 }
228 }
229 return (wantarray ? @ElementSymbols : \@ElementSymbols);
230 }
231
232 #
233 # Get data for most abundant isotope of an element using element symbol or atomic number.
234 #
235 sub GetElementMostAbundantNaturalIsotopeData {
236 my($ElementID) = @_;
237 my($AtomicNumber);
238
239 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
240 return (wantarray ? () : undef);
241 }
242
243 my(@IsotopeData, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance);
244 $MassNumber = $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber};
245 $IsotopeSymbol = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{IsotopeSymbol};
246 $RelativeAtomicMass = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass};
247 $NaturalAbundance = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance};
248 @IsotopeData = ();
249 @IsotopeData = ($AtomicNumber, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance);
250
251 return (wantarray ? @IsotopeData : \@IsotopeData);
252
253 }
254 #
255 # Get natural isotope count for an element...
256 #
257 sub GetElementNaturalIsotopeCount {
258 my($ElementID) = @_;
259 my($AtomicNumber);
260
261 if ($AtomicNumber = _ValidateElementID($ElementID)) {
262 return $ElementIsotopeDerivedDataMap{$AtomicNumber}{IsotopeCount};
263 }
264 else {
265 return undef;
266 }
267 }
268
269 #
270 # Get all available isotope data for an element using element symbol or atomic number or
271 # data for a specific mass number using one of these two invocation methods:
272 #
273 # $HashRef = GetElementNaturalIsotopesData($ElementID);
274 #
275 # $HashRef = GetElementNaturalIsotopesData($ElementID, $MassNumber);
276 #
277 # In the first mode, a reference to a two-dimensional hash array is return where first
278 # and second dimension keys correspond to mass number and isotope data labels.
279 #
280 # And in the second mode, a refernce to one-dimensional hash array is returned with
281 # keys and values corresponding to isotope data label and values.
282 #
283 sub GetElementNaturalIsotopesData {
284 my($ElementID, $MassNumber, $InvocationMode, $AtomicNumber);
285
286 if (@_ == 2) {
287 ($ElementID, $MassNumber) = @_;
288 $InvocationMode = 2;
289 }
290 else {
291 ($ElementID) = @_;
292 $InvocationMode = 1;
293 }
294 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
295 return undef;
296 }
297 if ($InvocationMode == 1) {
298 return \%{$ElementIsotopeDataMap{$AtomicNumber}};
299 }
300 elsif ($InvocationMode == 2) {
301 if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) {
302 return \%{$ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}};
303 }
304 else {
305 return undef;
306 }
307 }
308 else {
309 return undef;
310 }
311 }
312
313 #
314 # Get relative atomic mass for an element with specfic mass number.
315 #
316 sub GetElementNaturalIsotopeMass {
317 my($ElementID, $MassNumber) = @_;
318 my($AtomicNumber);
319
320 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
321 return undef;
322 }
323 if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) {
324 return $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass};
325 }
326 else {
327 return undef;
328 }
329 }
330
331 #
332 # Get relative atomic mass of most abundant isotope for an element...
333 #
334 sub GetElementMostAbundantNaturalIsotopeMass {
335 my($ElementID) = @_;
336 my($AtomicNumber);
337
338 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
339 return undef;
340 }
341 my($MassNumber, $RelativeAtomicMass);
342
343 $MassNumber = $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber};
344 $RelativeAtomicMass = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass};
345
346 return $RelativeAtomicMass;
347 }
348
349 #
350 # Get mass number of most abundant isotope for an element...
351 #
352 sub GetElementMostAbundantNaturalIsotopeMassNumber {
353 my($ElementID) = @_;
354 my($AtomicNumber);
355
356 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
357 return undef;
358 }
359 my($MassNumber);
360
361 $MassNumber = $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber};
362
363 return $MassNumber;
364 }
365 #
366 # Get % natural abundance of natural isotope for an element with specfic mass number.
367 #
368 sub GetElementNaturalIsotopeAbundance {
369 my($ElementID, $MassNumber) = @_;
370 my($AtomicNumber);
371
372 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
373 return undef;
374 }
375 if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) {
376 return $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance};
377 }
378 else {
379 return undef;
380 }
381 }
382
383 #
384 # Get all available properties data for an element using element symbol or atomic number.
385 # A reference to a hash array is returned with keys and values representing property
386 # name and its values respectively.
387 #
388 sub GetElementPropertiesData {
389 my($ElementID) = @_;
390 my($AtomicNumber);
391
392 if ($AtomicNumber = _ValidateElementID($ElementID)) {
393 return \%{$ElementDataMap{$AtomicNumber}};
394 }
395 else {
396 return undef;
397 }
398 }
399
400 #
401 # Get names of all available element properties. A reference to an array containing
402 # names of all available properties is returned.
403 #
404 sub GetElementPropertiesNames {
405 my($Mode);
406 my($PropertyName, @PropertyNames);
407
408 $Mode = 'ByGroup';
409 if (@_ == 1) {
410 ($Mode) = @_;
411 }
412
413 @PropertyNames = ();
414 if ($Mode =~ /^Alphabetical$/i) {
415 # AtomicNumber, ElementSymbol and ElementName are always listed first...
416 push @PropertyNames, qw(AtomicNumber ElementSymbol ElementName);
417 for $PropertyName (sort keys %ElementPropertyNamesMap) {
418 if ($PropertyName !~ /^(AtomicNumber|ElementSymbol|ElementName)$/i) {
419 push @PropertyNames, $PropertyName;
420 }
421 }
422 }
423 else {
424 push @PropertyNames, @ElementPropertyNames;
425 }
426 return (wantarray ? @PropertyNames : \@PropertyNames);
427 }
428
429 #
430 # Get names and units of all available element properties...
431 # A reference to a hash array is returned with keys and values representing property
432 # name and its units respectively. Names with no units contains empty strings as hash
433 # values.
434 #
435 sub GetElementPropertiesNamesAndUnits {
436
437 return \%ElementPropertyNamesMap;
438 }
439
440 #
441 # Get units for a specific element property. An empty string is returned for a property
442 # with no units.
443 #
444 sub GetElementPropertyUnits {
445 my($PropertyName) = @_;
446 my($PropertyUnits);
447
448 $PropertyUnits = (exists($ElementPropertyNamesMap{$PropertyName})) ? $ElementPropertyNamesMap{$PropertyName} : undef;
449
450 return $PropertyUnits;
451 }
452
453 #
454 # Is it a known element? Input is either an element symol or a atomic number.
455 #
456 sub IsElement {
457 my($ElementID) = @_;
458 my($Status);
459
460 $Status = (_ValidateElementID($ElementID)) ? 1 : 0;
461
462 return $Status;
463 }
464
465 #
466 # Is it a valid mass number for an element? Element ID is either an element symol or a atomic number.
467 #
468 sub IsElementNaturalIsotopeMassNumber {
469 my($ElementID, $MassNumber) = @_;
470 my($AtomicNumber, $Status);
471
472 $Status = 0;
473 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
474 return $Status;
475 }
476 if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) {
477 $Status = 1;
478 }
479
480 return $Status;
481 }
482
483 #
484 # Is it an available element property?
485 #
486 sub IsElementProperty {
487 my($PropertyName) = @_;
488 my($Status);
489
490 $Status = (exists($ElementPropertyNamesMap{$PropertyName})) ? 1 : 0;
491
492 return $Status;
493 }
494
495 #
496 # Implents GetElement<PropertyName> for a valid proprty name.
497 #
498 sub AUTOLOAD {
499 my($ElementID) = @_;
500 my($FunctionName, $PropertyName, $PropertyValue, $AtomicNumber);
501
502 $PropertyValue = undef;
503
504 use vars qw($AUTOLOAD);
505 $FunctionName = $AUTOLOAD;
506 $FunctionName =~ s/.*:://;
507
508 # Only Get<PropertyName> functions are supported...
509 if ($FunctionName !~ /^GetElement/) {
510 croak "Error: Function, PeriodicTable::$FunctionName, is not supported by AUTOLOAD in PeriodicTable module: Only GetElement<PropertyName> functions are implemented...";
511 }
512
513 $PropertyName = $FunctionName;
514 $PropertyName =~ s/^GetElement//;
515 if (!exists $ElementPropertyNamesMap{$PropertyName}) {
516 croak "Error: Function, PeriodicTable::$FunctionName, is not supported by AUTOLOAD in PeriodicTable module: Unknown element property name, $PropertyName, specified...";
517 }
518
519 if (!($AtomicNumber = _ValidateElementID($ElementID))) {
520 return undef;
521 }
522 $PropertyValue = $ElementDataMap{$AtomicNumber}{$PropertyName};
523 return $PropertyValue;
524 }
525
526 #
527 # Get elements labels for group name specified using American or European style...
528 #
529 sub _GetElementsByGroupLabel {
530 my($GroupLabel, $LabelStyle) = @_;
531 my($GroupNumber);
532
533 if ($LabelStyle =~ /^AmericanStyle$/i) {
534 $GroupNumber = GetIUPACGroupNumberFromAmericanStyleGroupLabel($GroupLabel);
535 }
536 elsif ($LabelStyle =~ /^EuropeanStyle$/i) {
537 $GroupNumber = GetIUPACGroupNumberFromEuropeanStyleGroupLabel($GroupLabel);
538 }
539
540 if (IsEmpty($GroupNumber)) {
541 return (wantarray ? () : undef);
542 }
543
544 my($AtomicNumber, @GroupElements, @ElementSymbols);
545 @ElementSymbols = ();
546 if ($GroupNumber =~ /\,/) {
547 my(@GroupNumbers);
548
549 @GroupNumbers = split /\,/, $GroupNumber;
550 for $GroupNumber (@GroupNumbers) {
551 @GroupElements = GetElementsByGroupNumber($GroupNumber);
552 push @ElementSymbols, @GroupElements;
553 }
554 }
555 else {
556 @GroupElements = GetElementsByGroupNumber($GroupNumber);
557 push @ElementSymbols, @GroupElements;
558 }
559 return (wantarray ? @ElementSymbols : \@ElementSymbols);
560 }
561
562 #
563 # Load PeriodicTableElementData.csv and PeriodicTableIsotopeData.csv files from
564 # <MayaChemTools>/lib directory...
565 #
566 sub _LoadPeriodicTableElementData {
567 my($ElementDataFile, $ElementIsotopeDataFile, $MayaChemToolsLibDir);
568
569 $MayaChemToolsLibDir = GetMayaChemToolsLibDirName();
570
571 $ElementDataFile = "$MayaChemToolsLibDir" . "/data/PeriodicTableElementData.csv";
572 $ElementIsotopeDataFile = "$MayaChemToolsLibDir" . "/data/PeriodicTableIsotopeData.csv";
573
574 if (! -e "$ElementDataFile") {
575 croak "Error: MayaChemTools package file, $ElementDataFile, is missing: Possible installation problems...";
576 }
577 if (! -e "$ElementIsotopeDataFile") {
578 croak "Error: MayaChemTools package file, $ElementIsotopeDataFile, is missing: Possible installation problems...";
579 }
580
581 _LoadElementData($ElementDataFile);
582 _LoadElementIsotopeData($ElementIsotopeDataFile);
583 }
584
585 #
586 # Load PeriodicTableElementData.csv file from <MayaChemTools>/lib directory...
587 #
588 sub _LoadElementData {
589 my($ElementDataFile) = @_;
590
591 %ElementDataMap = ();
592 @ElementPropertyNames = ();
593 %ElementPropertyNamesMap = ();
594 %ElementSymbolMap = ();
595
596 # Load atomic properties data for all elements...
597 #
598 # File Format:
599 #"AtomicNumber","ElementSymbol","ElementName","AtomicWeight","GroupNumber","GroupName","PeriodNumber","Block","GroundStateConfiguration","ValenceElectrons","GroundStateLevel","StandardState","CommonValences","LowestCommonValence","HighestCommonValence","CommonOxidationNumbers","LowestCommonOxidationNumber","HighestCommonOxidationNumber","BondLength(pm)","AtomicRadiusEmpirical(pm)","AtomicRadiusCalculated(pm)","CovalentRadiusEmpirical(pm)","VanderWaalsRadius(pm)","ElectronAffinity(kJ mol-1)","FirstIonizationEnergy(kJ mol-1)","PaulingElectronegativity(Pauling units)","SandersonElectronegativity(Pauling units)","AllredRochowElectronegativity(Pauling units)","MullikenJaffeElectronegativity(Pauling units)","AllenElectronegativity(Pauling units)","DensityOfSolid(kg m-3)","MolarVolume(cm3)","VelocityOfSound(m s-1)","YoungsModulus(GPa)","RigidityModulus(GPa)","BulkModulus(GPa)","PoissonsRatio(No units)","MineralHardness(No units)","BrinellHardness(MN m-2)","VickersHardness(MN m-2)","ElectricalResistivity(10-8 omega m)","Reflectivity(%)","RefractiveIndex(No units)","MeltingPoint(Celsius)","BoilingPoint(Celsius)","CriticalTemperature(Celsius)","SuperconductionTemperature(Celsius)","ThermalConductivity(W m-1 K-1)","CoefficientOfLinearExpansion(K-1 x 10^6)","EnthalpyOfFusion(kJ mol-1)","EnthalpyOfVaporization(kJ mol-1)","EnthalpyOfAtmization(kJ mol-1)","Color","Classification","DiscoveredBy","DiscoveredAt","DiscoveredWhen","OriginOfName"
600 #
601 #
602 my($AtomicNumber, $ElementSymbol, $Line, $NumOfCols, $InDelim, $Index, $Name, $Value, $Units, @LineWords, @ColLabels);
603
604 $InDelim = "\,";
605 open ELEMENTDATAFILE, "$ElementDataFile" or croak "Couldn't open $ElementDataFile: $! ...";
606
607 # Skip lines up to column labels...
608 LINE: while ($Line = GetTextLine(\*ELEMENTDATAFILE)) {
609 if ($Line !~ /^#/) {
610 last LINE;
611 }
612 }
613 @ColLabels= quotewords($InDelim, 0, $Line);
614 $NumOfCols = @ColLabels;
615
616 # Extract property names from column labels - and unit names where appropriate...
617 @ElementPropertyNames = ();
618 for $Index (0 .. $#ColLabels) {
619 $Name = $ColLabels[$Index];
620 $Units = "";
621 if ($Name =~ /\(/) {
622 ($Name, $Units) = split /\(/, $Name;
623 $Units =~ s/\)//g;
624 }
625 push @ElementPropertyNames, $Name;
626
627 # Store element names and units...
628 $ElementPropertyNamesMap{$Name} = $Units;
629 }
630
631 # Process element data...
632 LINE: while ($Line = GetTextLine(\*ELEMENTDATAFILE)) {
633 if ($Line =~ /^#/) {
634 next LINE;
635 }
636 @LineWords = ();
637 @LineWords = quotewords($InDelim, 0, $Line);
638 if (@LineWords != $NumOfCols) {
639 croak "Error: The number of data fields, @LineWords, in $ElementDataFile must be $NumOfCols.\nLine: $Line...";
640 }
641 $AtomicNumber = $LineWords[0]; $ElementSymbol = $LineWords[1];
642 if (exists $ElementDataMap{$AtomicNumber}) {
643 carp "Warning: Ignoring data for element $ElementSymbol: It has already been loaded.\nLine: $Line....";
644 next LINE;
645 }
646
647 # Store all the values...
648 %{$ElementDataMap{$AtomicNumber}} = ();
649 for $Index (0 .. $#LineWords) {
650 $Name = $ElementPropertyNames[$Index];
651 $Value = $LineWords[$Index];
652 $ElementDataMap{$AtomicNumber}{$Name} = $Value;
653 }
654 }
655 close ELEMENTDATAFILE;
656
657 # Setup the element symbol map as well...
658 _SetupElementSymbolMap();
659 }
660
661 #
662 # Load PeriodicTableIsotopeData.csv files from <MayaChemTools>/lib directory...
663 #
664 sub _LoadElementIsotopeData {
665 my($ElementIsotopeDataFile) = @_;
666
667 %ElementIsotopeDataMap = ();
668 %ElementIsotopeDerivedDataMap = ();
669
670 # Load isotope data for all elements...
671 #
672 # File format:
673 # "Atomic Number","Isotope Symbol","Mass Number","Relative Atomic Mass","% Natural Abundnace"
674 #
675 # Empty values for "Relative Atomic Mass" and "% Natural Abundnace" imply absence of any
676 # naturally occuring isotopes for the element.
677 #
678 my($InDelim, $Line, $NumOfCols, @ColLabels, @LineWords);
679
680 $InDelim = "\,";
681 open ISOTOPEDATAFILE, "$ElementIsotopeDataFile" or croak "Couldn't open $ElementIsotopeDataFile: $! ...";
682
683 # Skip lines up to column labels...
684 LINE: while ($Line = GetTextLine(\*ISOTOPEDATAFILE)) {
685 if ($Line !~ /^#/) {
686 last LINE;
687 }
688 }
689 @ColLabels= quotewords($InDelim, 0, $Line);
690 $NumOfCols = @ColLabels;
691
692 my($AtomicNumber, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance, %ZeroNaturalAbundanceMap);
693 %ZeroNaturalAbundanceMap = ();
694
695 # Process element data...
696 LINE: while ($Line = GetTextLine(\*ISOTOPEDATAFILE)) {
697 if ($Line =~ /^#/) {
698 next LINE;
699 }
700 @LineWords = ();
701 @LineWords = quotewords($InDelim, 0, $Line);
702 if (@LineWords != $NumOfCols) {
703 croak "Error: The number of data fields, @LineWords, in $ElementIsotopeDataFile must be $NumOfCols.\nLine: $Line...";
704 }
705 ($AtomicNumber, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance) = @LineWords;
706 if (exists $ZeroNaturalAbundanceMap{$AtomicNumber}) {
707 # Only one isotope data line allowed for elements with no natural isotopes...
708 carp "Warning: Ignoring isotope data for element with atomic number $AtomicNumber: Only one data line allowed for an element with no natural isotopes.\nLine: $Line...";
709 next LINE;
710 }
711 if (IsEmpty($NaturalAbundance)) {
712 $RelativeAtomicMass = 0;
713 $NaturalAbundance = 0;
714 $ZeroNaturalAbundanceMap{$AtomicNumber} = 1;
715 }
716 if (exists $ElementIsotopeDataMap{$AtomicNumber}) {
717 # Additional data for an existing element...
718 if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) {
719 carp "Warning: Ignoring isotope data for element with atomic number $AtomicNumber: It has already been loaded.\nLine: $Line...";
720 next LINE;
721 }
722 }
723 else {
724 # Data for a new element...
725 %{$ElementIsotopeDataMap{$AtomicNumber}} = ();
726 }
727 %{$ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}} = ();
728 $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{IsotopeSymbol} = $IsotopeSymbol;
729 $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass} = $RelativeAtomicMass;
730 $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance} = $NaturalAbundance;
731 }
732 close ISOTOPEDATAFILE;
733
734 _SetupElementIsotopeDerivedDataMap();
735 }
736
737 #
738 # Map mass number of most abundant isotope for each element; additionally,
739 # count number of isotopes as well.
740 #
741 sub _SetupElementIsotopeDerivedDataMap {
742 my($AtomicNumber, $MassNumber, $NaturalAbundance, $MostNaturalAbundance, $MostAbundantMassNumber, $IsotopeCount);
743
744 %ElementIsotopeDerivedDataMap = ();
745
746 for $AtomicNumber (sort {$a <=> $b} keys %ElementIsotopeDataMap) {
747 $IsotopeCount = 0;
748 $MostAbundantMassNumber = 0;
749 $MostNaturalAbundance = 0;
750 MASSNUMBER: for $MassNumber (sort {$a <=> $b} keys %{$ElementIsotopeDataMap{$AtomicNumber}}) {
751 $NaturalAbundance = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance};
752 if (IsEmpty($NaturalAbundance)) {
753 # No natural isotopes available...
754 $MostAbundantMassNumber = $MassNumber;
755 last MASSNUMBER;
756 }
757 if ($NaturalAbundance == 0) {
758 # Not a natural isotope; Listed in periodic table data file to support non-natural
759 # elements such as T. It's not included in natural isotope count...
760 next MASSNUMBER;
761 }
762 $IsotopeCount++;
763 if ($NaturalAbundance > $MostNaturalAbundance) {
764 $MostAbundantMassNumber = $MassNumber;
765 $MostNaturalAbundance = $NaturalAbundance;
766 }
767 }
768 %{$ElementIsotopeDerivedDataMap{$AtomicNumber}} = ();
769 $ElementIsotopeDerivedDataMap{$AtomicNumber}{IsotopeCount} = $IsotopeCount;
770 $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber} = $MostAbundantMassNumber;
771 }
772 }
773
774 #
775 # Setup element symbol map...
776 #
777 sub _SetupElementSymbolMap {
778 my($AtomicNumber, $ElementSymbol);
779
780 %ElementSymbolMap = ();
781
782 for $AtomicNumber (keys %ElementDataMap) {
783 $ElementSymbol = $ElementDataMap{$AtomicNumber}{ElementSymbol};
784 $ElementSymbolMap{$ElementSymbol} = $AtomicNumber;
785 }
786 }
787
788 # Validate element ID...
789 sub _ValidateElementID {
790 my($ElementID) = @_;
791 my($ElementSymbol, $AtomicNumber);
792
793 if ($ElementID =~ /[^0-9]/) {
794 # Assume atomic symbol...
795 $ElementSymbol = $ElementID;
796 if (exists $ElementSymbolMap{$ElementSymbol}) {
797 $AtomicNumber = $ElementSymbolMap{$ElementSymbol};
798 }
799 else {
800 return undef;
801 }
802 }
803 else {
804 # Assume atomic number...
805 $AtomicNumber = $ElementID;
806 if (!exists $ElementDataMap{$AtomicNumber}) {
807 return undef;
808 }
809 }
810 return $AtomicNumber;
811 }
812
813 1;
814
815 __END__
816
817 =head1 NAME
818
819 PeriodicTable
820
821 =head1 SYNOPSIS
822
823 use PeriodicTable;
824
825 use PeriodicTable qw(:all);
826
827 =head1 DESCRIPTION
828
829 B<PeriodicTable> module provides the following functions:
830
831 GetElementMostAbundantNaturalIsotopeData,
832 GetElementMostAbundantNaturalIsotopeMass,
833 GetElementMostAbundantNaturalIsotopeMassNumber, GetElementNaturalIsotopeAbundance,
834 GetElementNaturalIsotopeCount, GetElementNaturalIsotopeMass,
835 GetElementNaturalIsotopesData, GetElementPropertiesData,
836 GetElementPropertiesNames, GetElementPropertiesNamesAndUnits,
837 GetElementPropertyUnits, GetElements, GetElementsByAmericanStyleGroupLabel,
838 GetElementsByEuropeanStyleGroupLabel, GetElementsByGroupName,
839 GetElementsByGroupNumber, GetElementsByPeriodNumber,
840 GetIUPACGroupNumberFromAmericanStyleGroupLabel,
841 GetIUPACGroupNumberFromEuropeanStyleGroupLabel, IsElement,
842 IsElementNaturalIsotopeMassNumber, IsElementProperty
843
844 =head1 METHODS
845
846 =over 4
847
848 =item B<GetElements>
849
850 @ElementSymbols = GetElements();
851 $ElementSymbolsRef = GetElements();
852
853 Returns an array or a reference to an array of known element symbols
854
855 =item B<GetElementsByGroupName>
856
857 @ElementSymbols = GetElementsByGroupName($GroupName);
858 $ElementSymbolsRef = GetElementsByGroupName($GroupName);
859
860 Returns an array or a reference to an array of element symbols for a specified I<GroupName>.
861 Supported I<GroupName> values are: I<Alkali metals, Alkaline earth metals, Coinage metals, Pnictogens,
862 Chalcogens, Halogens, Noble gases>; Additionally, usage of I<Lanthanides> (Lanthanoids)
863 and I<Actinides> (Actinoids) is also supported.
864
865 =item B<GetElementsByGroupNumber>
866
867 @ElementSymbols = GetElementsByGroupNumber($GroupNumber);
868 $ElementSymbolsRef = GetElementsByGroupNumber($GroupNumber);
869
870 Returns an array or a reference to an array of element symbols for a specified I<GroupNumber>
871
872 =item B<GetElementsByAmericanStyleGroupLabel>
873
874 @ElementSymbols = GetElementsByAmericanStyleGroupLabel($GroupLabel);
875 $ElementSymbolsRef = GetElementsByAmericanStyleGroupLabel($GroupLabel);
876
877 Returns an array or a reference to an array of element symbols for a specified American
878 style I<GroupLabel>. Valid values for Amercian style group labels: I<IA to VIIIA, IB to VIIIB, VIII>.
879
880 =item B<GetElementsByEuropeanStyleGroupLabel>
881
882 @ElementSymbols = GetElementsByEuropeanStyleGroupLabel($GroupLabel);
883 $ElementSymbolsRef = GetElementsByEuropeanStyleGroupLabel($GroupLabel);
884
885 Returns an array or a reference to an array of element symbols for a specified European
886 style I<GroupLabel>. Valid values for European style group labels: I<IA to VIIIA, IB to VIIIB, VIII>.
887
888 =item B<GetElementsByPeriodNumber>
889
890 @ElementSymbols = GetElementsByPeriodNumber($PeriodNumber);
891 $ElementSymbolsRef = GetElementsByPeriodNumber($PeriodNumber);
892
893 Returns an array or a reference to an array of element symbols for a specified I<PeriodNumber>.
894
895 =item B<GetElementMostAbundantNaturalIsotopeData>
896
897 @IsotopeData = GetElementMostAbundantNaturalIsotopeData(
898 $ElementID);
899 $IsotopeDataRef = GetElementMostAbundantNaturalIsotopeData(
900 $ElementID);
901
902 Returns an array or reference to an array containing data for most abundant isotope of
903 an element specfied by element symbol or atomic number. Isotope data arrays contain these
904 values: I<AtomicNumber, IsotopeSymbol, MassNumber, RelativeAtomicMass, and NaturalAbundance>.
905
906 =item B<GetElementMostAbundantNaturalIsotopeMassNumber>
907
908 $MassNumber = GetElementMostAbundantNaturalIsotopeMassNumber($ElementID);
909
910 Returns mass number of most abundant natural isotope of an element specfied by element
911 symbol or atomic number
912
913 =item B<GetElementNaturalIsotopeCount>
914
915 $IsotopeCount = GetElementNaturalIsotopeCount($ElementID);
916
917 Returns natural isotope count for an element specfied by element symbol or
918 atomic number
919
920 =item B<GetElementNaturalIsotopesData>
921
922 $DataHashRef = GetElementNaturalIsotopesData($ElementID,
923 [$MassNumber]);
924
925 Reurns a reference to a hash containingall available isotope data for an element specified
926 using element symbol or aromic number; an optional mass number indicates retrieve data
927 for a specific isotope
928
929 =item B<GetElementNaturalIsotopeAbundance>
930
931 $Abundance = GetElementNaturalIsotopeAbundance($ElementID,
932 $MassNumber);
933
934 Returns percent abundance of natural isotope for an element with specfic mass
935 number.
936
937 =item B<GetElementMostAbundantNaturalIsotopeMass>
938
939 $RelativeAtomicMass = GetElementMostAbundantNaturalIsotopeMass(
940 $ElementID);
941
942 Returns relative atomic mass of most abundant isotope for an element specified using
943 element symbol or aromic number.
944
945 =item B<GetElementNaturalIsotopeMass>
946
947 $RelativeAtomicMass = GetElementNaturalIsotopeMass($ElementID,
948 $MassNumber);
949
950 Returns relative atomic mass of an element with specfic mass number.
951
952 =item B<GetElementPropertiesData>
953
954 $PropertyDataHashRef = GetElementPropertiesData($ElementID);
955
956 Returns a reference to a hash containing all available properties data for an element
957 specified using element symbol or atomic number.
958
959 =item B<GetElementPropertyName>
960
961 $PropertyValue = GetElement<PropertyName>($ElementID);
962
963 Returns value of an element for a element specified using element symbol or atomic number.
964
965 These functions are not defined in this modules; these are implemented on-the-fly using
966 Perl's AUTOLOAD funcionality.
967
968 Here is the list of known element I<property names>: AllenElectronegativity,
969 AllredRochowElectronegativity, AtomicNumber, AtomicRadiusCalculated,
970 AtomicRadiusEmpirical, AtomicWeight, Block, BoilingPoint, BondLength,
971 BrinellHardness, BulkModulus, Classification, CoefficientOfLinearExpansion, Color,
972 CommonValences, LowestCommonValence, HighestCommonValence,
973 CommonOxidationNumbers, LowestCommonOxidationNumber, HighestCommonOxidationNumber,
974 CovalentRadiusEmpirical, CriticalTemperature, DensityOfSolid, DiscoveredAt, DiscoveredBy,
975 DiscoveredWhen, ElectricalResistivity, ElectronAffinity, ElementName, ElementSymbol, EnthalpyOfAtmization,
976 EnthalpyOfFusion, EnthalpyOfVaporization, FirstIonizationEnergy, GroundStateConfiguration, GroundStateLevel,
977 GroupName, GroupNumber, NaturalIsotopeData, MeltingPoint, MineralHardness, MolarVolume,
978 MullikenJaffeElectronegativity, OriginOfName, PaulingElectronegativity, PeriodNumber, PoissonsRatio,
979 Reflectivity, RefractiveIndex, RigidityModulus, SandersonElectronegativity, StandardState,
980 SuperconductionTemperature, ThermalConductivity, VanderWaalsRadius, VelocityOfSound, VickersHardness,
981 YoungsModulus.
982
983 =item B<GetElementPropertiesNames>
984
985 @PropertyNames = GetElementPropertiesNames([$Mode]);
986 $PropertyNamesRef = GetElementPropertiesNames([$Mode]);
987
988 Returns names of all available element properties. Optional mode parameter controls
989 grouping of property names; Possible values: I<ByGroup or Alphabetical>. Default:
990 I<ByGroup>.
991
992 =item B<GetElementPropertiesNamesAndUnits>
993
994 $NameUnitsHashRef = GetElementPropertiesNamesAndUnits();
995
996 Returns a reference to a hash of property names and units of all available element
997 properties. Names with no units contains empty strings.
998
999 =item B<GetElementPropertyUnits>
1000
1001 $Units = GetElementPropertyUnits($PropertyName);
1002
1003 Returns units for a specific element property name. An empty string is returned for
1004 a property with no units.
1005
1006 =item B<GetIUPACGroupNumberFromAmericanStyleGroupLabel>
1007
1008 $GroupNumber = GetIUPACGroupNumberFromAmericanStyleGroupLabel(
1009 $GroupLabel);
1010
1011 Returns IUPAC group numbers of a specific American style group label. A comma delimited
1012 string is returned for group VIII or VIIIB.
1013
1014 =item B<GetIUPACGroupNumberFromEuropeanStyleGroupLabel>
1015
1016 $GroupNumber = GetIUPACGroupNumberFromEuropeanStyleGroupLabel(
1017 $GroupLabel);
1018
1019 Returns IUPAC group numbers of a specific European style group label. A comma delimited
1020 string is returned for group VIII or VIIIA.
1021
1022 =item B<IsElement>
1023
1024 $Status = IsElement($ElementID);
1025
1026 Returns 1 or 0 based on whether it's a known element symbol or atomic number.
1027
1028 =item B<IsElementNaturalIsotopeMassNumber>
1029
1030 $Status = IsElementNaturalIsotopeMassNumber($ElementID, $MassNumber);
1031
1032 Returns 1 or 0 based on whether it's a valid mass number for an element symbol
1033 or atomic number.
1034
1035 =item B<IsElementProperty>
1036
1037 $Status = IsElementProperty($PropertyName);
1038
1039 Returns 1 or 0 based on whether it's a valid property name.
1040
1041 =back
1042
1043 =head1 AUTHOR
1044
1045 Manish Sud <msud@san.rr.com>
1046
1047 =head1 SEE ALSO
1048
1049 AminoAcids.pm, NucleicAcids.pm
1050
1051 =head1 COPYRIGHT
1052
1053 Copyright (C) 2015 Manish Sud. All rights reserved.
1054
1055 This file is part of MayaChemTools.
1056
1057 MayaChemTools is free software; you can redistribute it and/or modify it under
1058 the terms of the GNU Lesser General Public License as published by the Free
1059 Software Foundation; either version 3 of the License, or (at your option)
1060 any later version.
1061
1062 =cut