Mercurial > repos > deepakjadmin > mayatool3_test2
diff lib/PeriodicTable.pm @ 0:4816e4a8ae95 draft default tip
Uploaded
author | deepakjadmin |
---|---|
date | Wed, 20 Jan 2016 09:23:18 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/PeriodicTable.pm Wed Jan 20 09:23:18 2016 -0500 @@ -0,0 +1,1062 @@ +package PeriodicTable; +# +# $RCSfile: PeriodicTable.pm,v $ +# $Date: 2015/02/28 20:47:18 $ +# $Revision: 1.37 $ +# +# Author: Manish Sud <msud@san.rr.com> +# +# Copyright (C) 2015 Manish Sud. All rights reserved. +# +# This file is part of MayaChemTools. +# +# MayaChemTools is free software; you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 3 of the License, or (at your option) any +# later version. +# +# MayaChemTools is distributed in the hope that it will be useful, but without +# any warranty; without even the implied warranty of merchantability of fitness +# for a particular purpose. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or +# write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, +# Boston, MA, 02111-1307, USA. +# + +use strict; +use Carp; +use Text::ParseWords; +use TextUtil; +use FileUtil; + +use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +@ISA = qw(Exporter); +@EXPORT = qw(); +@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); + +%EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]); + +# +# Load atomic properties and isotope data for elements... +# +my(%ElementDataMap, %ElementIsotopeDataMap, %ElementSymbolMap, @ElementPropertyNames, %ElementPropertyNamesMap, %ElementIsotopeDerivedDataMap); +_LoadPeriodicTableElementData(); + +# +# Get a list of all known element symbols... +# +sub GetElements { + my($AtomicNumber, @ElementSymbols); + + @ElementSymbols = (); + for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) { + push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol}; + } + return (wantarray ? @ElementSymbols : \@ElementSymbols); +} + +# +# Get element symbols of elements with a specific group name. Valid group +# names are: Alkali metals, Alkaline earth metals, Coinage metals, Pnictogens, +# Chalcogens, Halogens, Noble gases; Additionally, usage of Lanthanides (Lanthanoids) +# and Actinides (Actinoids) is also supported. +# +sub GetElementsByGroupName { + my($SpecifiedGroupName) = @_; + my($AtomicNumber, @ElementSymbols, $GroupName); + + if (IsEmpty($SpecifiedGroupName)) { + return (wantarray ? () : undef); + } + if ($SpecifiedGroupName =~ /Lanthanide/i) { + $SpecifiedGroupName = 'Lanthanoids'; + } + elsif ($SpecifiedGroupName =~ /Actinide/i) { + $SpecifiedGroupName = 'Actinoids'; + } + @ElementSymbols = (); + for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) { + $GroupName = $ElementDataMap{$AtomicNumber}{GroupName}; + if ($SpecifiedGroupName =~ /$GroupName/i ) { + push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol}; + } + } + return (wantarray ? @ElementSymbols : \@ElementSymbols); +} + +# +# Get element symbols of elements in a specific IUPAC group number. +# A reference to an array containing element symbols is returned. +# +sub GetElementsByGroupNumber { + my($GroupNumber) = @_; + my($AtomicNumber, @ElementSymbols); + + if (!IsInteger($GroupNumber)) { + return (wantarray ? () : undef); + } + + @ElementSymbols = (); + for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) { + if ($GroupNumber eq $ElementDataMap{$AtomicNumber}{GroupNumber}) { + push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol}; + } + } + return (wantarray ? @ElementSymbols : \@ElementSymbols); +} + +# +# Get element symbols of elements in a specific American style group label. +# A reference to an array containing element symbols is returned. +# +sub GetElementsByAmericanStyleGroupLabel { + my($GroupLabel) = @_; + + return _GetElementsByGroupLabel($GroupLabel, 'AmericanStyle'); +} + +# +# Get element symbols of elements in a specific European style group label. +# A reference to an array containing element symbols is returned. +# +sub GetElementsByEuropeanStyleGroupLabel { + my($GroupLabel) = @_; + + return _GetElementsByGroupLabel($GroupLabel, 'EuropeanStyle'); +} + +# +# Get IUPAC group number from American style group label. A comma delimited +# string is returned for group VIII or VIIIB. +# +sub GetIUPACGroupNumberFromAmericanStyleGroupLabel { + my($GroupLabel) = @_; + my($GroupNumber); + + if (IsEmpty($GroupLabel)) { + return undef; + } + $GroupNumber = ""; + SWITCH: { + if ($GroupLabel =~ /^IA$/) { $GroupNumber = 1; last SWITCH;} + if ($GroupLabel =~ /^IIA$/) { $GroupNumber = 2; last SWITCH;} + if ($GroupLabel =~ /^IIIB$/) { $GroupNumber = 3; last SWITCH;} + if ($GroupLabel =~ /^IVB$/) { $GroupNumber = 4; last SWITCH;} + if ($GroupLabel =~ /^VB$/) { $GroupNumber = 5; last SWITCH;} + if ($GroupLabel =~ /^VIB$/) { $GroupNumber = 6; last SWITCH;} + if ($GroupLabel =~ /^VIIB$/) { $GroupNumber = 7; last SWITCH;} + if ($GroupLabel =~ /^(VIII|VIIIB)$/) { $GroupNumber = '8,9,10'; last SWITCH;} + if ($GroupLabel =~ /^IB$/) { $GroupNumber = 11; last SWITCH;} + if ($GroupLabel =~ /^IIB$/) { $GroupNumber = 12; last SWITCH;} + if ($GroupLabel =~ /^IIIA$/) { $GroupNumber = 13; last SWITCH;} + if ($GroupLabel =~ /^IVA$/) { $GroupNumber = 14; last SWITCH;} + if ($GroupLabel =~ /^VA$/) { $GroupNumber = 15; last SWITCH;} + if ($GroupLabel =~ /^VIA$/) { $GroupNumber = 16; last SWITCH;} + if ($GroupLabel =~ /^VIIA$/) { $GroupNumber = 17; last SWITCH;} + if ($GroupLabel =~ /^VIIIA$/) { $GroupNumber = 18; last SWITCH;} + $GroupNumber = ""; + } + if (!$GroupNumber) { + return undef; + } + return $GroupNumber; +} + +# +# Get IUPAC group number from European style group label. A comma delimited +# string is returned for group VIII or VIIIA +# +sub GetIUPACGroupNumberFromEuropeanStyleGroupLabel { + my($GroupLabel) = @_; + my($GroupNumber); + + if (IsEmpty($GroupLabel)) { + return undef; + } + $GroupNumber = ""; + SWITCH: { + if ($GroupLabel =~ /^IA$/) { $GroupNumber = 1; last SWITCH;} + if ($GroupLabel =~ /^IIA$/) { $GroupNumber = 2; last SWITCH;} + if ($GroupLabel =~ /^IIIA$/) { $GroupNumber = 3; last SWITCH;} + if ($GroupLabel =~ /^IVA$/) { $GroupNumber = 4; last SWITCH;} + if ($GroupLabel =~ /^VA$/) { $GroupNumber = 5; last SWITCH;} + if ($GroupLabel =~ /^VIA$/) { $GroupNumber = 6; last SWITCH;} + if ($GroupLabel =~ /^VIIA$/) { $GroupNumber = 7; last SWITCH;} + if ($GroupLabel =~ /^(VIII|VIIIA)$/) { $GroupNumber = '8,9,10'; last SWITCH;} + if ($GroupLabel =~ /^IB$/) { $GroupNumber = 11; last SWITCH;} + if ($GroupLabel =~ /^IIB$/) { $GroupNumber = 12; last SWITCH;} + if ($GroupLabel =~ /^IIIB$/) { $GroupNumber = 13; last SWITCH;} + if ($GroupLabel =~ /^IVB$/) { $GroupNumber = 14; last SWITCH;} + if ($GroupLabel =~ /^VB$/) { $GroupNumber = 15; last SWITCH;} + if ($GroupLabel =~ /^VIB$/) { $GroupNumber = 16; last SWITCH;} + if ($GroupLabel =~ /^VIIB$/) { $GroupNumber = 17; last SWITCH;} + if ($GroupLabel =~ /^VIIIB$/) { $GroupNumber = 18; last SWITCH;} + $GroupNumber = ""; + } + if (!$GroupNumber) { + return undef; + } + return $GroupNumber; +} + +# +# Get element symbols of elements in a specific period number. +# A reference to an array containing element symbols is returned. +# +sub GetElementsByPeriodNumber { + my($SpecifiedPeriodNumber) = @_; + my($AtomicNumber, $PeriodNumber, @ElementSymbols); + + if (!IsInteger($SpecifiedPeriodNumber)) { + return (wantarray ? () : undef); + } + + @ElementSymbols = (); + for $AtomicNumber (sort {$a <=> $b} keys %ElementDataMap) { + $PeriodNumber = $ElementDataMap{$AtomicNumber}{PeriodNumber}; + if ($PeriodNumber =~ /\(/) { + # Lanthanides and Actinides... + ($PeriodNumber) = split /\(/, $PeriodNumber; + } + if ($PeriodNumber == $SpecifiedPeriodNumber) { + push @ElementSymbols, $ElementDataMap{$AtomicNumber}{ElementSymbol}; + } + } + return (wantarray ? @ElementSymbols : \@ElementSymbols); +} + +# +# Get data for most abundant isotope of an element using element symbol or atomic number. +# +sub GetElementMostAbundantNaturalIsotopeData { + my($ElementID) = @_; + my($AtomicNumber); + + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return (wantarray ? () : undef); + } + + my(@IsotopeData, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance); + $MassNumber = $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber}; + $IsotopeSymbol = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{IsotopeSymbol}; + $RelativeAtomicMass = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass}; + $NaturalAbundance = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance}; + @IsotopeData = (); + @IsotopeData = ($AtomicNumber, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance); + + return (wantarray ? @IsotopeData : \@IsotopeData); + +} +# +# Get natural isotope count for an element... +# +sub GetElementNaturalIsotopeCount { + my($ElementID) = @_; + my($AtomicNumber); + + if ($AtomicNumber = _ValidateElementID($ElementID)) { + return $ElementIsotopeDerivedDataMap{$AtomicNumber}{IsotopeCount}; + } + else { + return undef; + } +} + +# +# Get all available isotope data for an element using element symbol or atomic number or +# data for a specific mass number using one of these two invocation methods: +# +# $HashRef = GetElementNaturalIsotopesData($ElementID); +# +# $HashRef = GetElementNaturalIsotopesData($ElementID, $MassNumber); +# +# In the first mode, a reference to a two-dimensional hash array is return where first +# and second dimension keys correspond to mass number and isotope data labels. +# +# And in the second mode, a refernce to one-dimensional hash array is returned with +# keys and values corresponding to isotope data label and values. +# +sub GetElementNaturalIsotopesData { + my($ElementID, $MassNumber, $InvocationMode, $AtomicNumber); + + if (@_ == 2) { + ($ElementID, $MassNumber) = @_; + $InvocationMode = 2; + } + else { + ($ElementID) = @_; + $InvocationMode = 1; + } + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return undef; + } + if ($InvocationMode == 1) { + return \%{$ElementIsotopeDataMap{$AtomicNumber}}; + } + elsif ($InvocationMode == 2) { + if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) { + return \%{$ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}}; + } + else { + return undef; + } + } + else { + return undef; + } +} + +# +# Get relative atomic mass for an element with specfic mass number. +# +sub GetElementNaturalIsotopeMass { + my($ElementID, $MassNumber) = @_; + my($AtomicNumber); + + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return undef; + } + if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) { + return $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass}; + } + else { + return undef; + } +} + +# +# Get relative atomic mass of most abundant isotope for an element... +# +sub GetElementMostAbundantNaturalIsotopeMass { + my($ElementID) = @_; + my($AtomicNumber); + + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return undef; + } + my($MassNumber, $RelativeAtomicMass); + + $MassNumber = $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber}; + $RelativeAtomicMass = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass}; + + return $RelativeAtomicMass; +} + +# +# Get mass number of most abundant isotope for an element... +# +sub GetElementMostAbundantNaturalIsotopeMassNumber { + my($ElementID) = @_; + my($AtomicNumber); + + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return undef; + } + my($MassNumber); + + $MassNumber = $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber}; + + return $MassNumber; +} +# +# Get % natural abundance of natural isotope for an element with specfic mass number. +# +sub GetElementNaturalIsotopeAbundance { + my($ElementID, $MassNumber) = @_; + my($AtomicNumber); + + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return undef; + } + if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) { + return $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance}; + } + else { + return undef; + } +} + +# +# Get all available properties data for an element using element symbol or atomic number. +# A reference to a hash array is returned with keys and values representing property +# name and its values respectively. +# +sub GetElementPropertiesData { + my($ElementID) = @_; + my($AtomicNumber); + + if ($AtomicNumber = _ValidateElementID($ElementID)) { + return \%{$ElementDataMap{$AtomicNumber}}; + } + else { + return undef; + } +} + +# +# Get names of all available element properties. A reference to an array containing +# names of all available properties is returned. +# +sub GetElementPropertiesNames { + my($Mode); + my($PropertyName, @PropertyNames); + + $Mode = 'ByGroup'; + if (@_ == 1) { + ($Mode) = @_; + } + + @PropertyNames = (); + if ($Mode =~ /^Alphabetical$/i) { + # AtomicNumber, ElementSymbol and ElementName are always listed first... + push @PropertyNames, qw(AtomicNumber ElementSymbol ElementName); + for $PropertyName (sort keys %ElementPropertyNamesMap) { + if ($PropertyName !~ /^(AtomicNumber|ElementSymbol|ElementName)$/i) { + push @PropertyNames, $PropertyName; + } + } + } + else { + push @PropertyNames, @ElementPropertyNames; + } + return (wantarray ? @PropertyNames : \@PropertyNames); +} + +# +# Get names and units of all available element properties... +# A reference to a hash array is returned with keys and values representing property +# name and its units respectively. Names with no units contains empty strings as hash +# values. +# +sub GetElementPropertiesNamesAndUnits { + + return \%ElementPropertyNamesMap; +} + +# +# Get units for a specific element property. An empty string is returned for a property +# with no units. +# +sub GetElementPropertyUnits { + my($PropertyName) = @_; + my($PropertyUnits); + + $PropertyUnits = (exists($ElementPropertyNamesMap{$PropertyName})) ? $ElementPropertyNamesMap{$PropertyName} : undef; + + return $PropertyUnits; +} + +# +# Is it a known element? Input is either an element symol or a atomic number. +# +sub IsElement { + my($ElementID) = @_; + my($Status); + + $Status = (_ValidateElementID($ElementID)) ? 1 : 0; + + return $Status; +} + +# +# Is it a valid mass number for an element? Element ID is either an element symol or a atomic number. +# +sub IsElementNaturalIsotopeMassNumber { + my($ElementID, $MassNumber) = @_; + my($AtomicNumber, $Status); + + $Status = 0; + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return $Status; + } + if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) { + $Status = 1; + } + + return $Status; +} + +# +# Is it an available element property? +# +sub IsElementProperty { + my($PropertyName) = @_; + my($Status); + + $Status = (exists($ElementPropertyNamesMap{$PropertyName})) ? 1 : 0; + + return $Status; +} + +# +# Implents GetElement<PropertyName> for a valid proprty name. +# +sub AUTOLOAD { + my($ElementID) = @_; + my($FunctionName, $PropertyName, $PropertyValue, $AtomicNumber); + + $PropertyValue = undef; + + use vars qw($AUTOLOAD); + $FunctionName = $AUTOLOAD; + $FunctionName =~ s/.*:://; + + # Only Get<PropertyName> functions are supported... + if ($FunctionName !~ /^GetElement/) { + croak "Error: Function, PeriodicTable::$FunctionName, is not supported by AUTOLOAD in PeriodicTable module: Only GetElement<PropertyName> functions are implemented..."; + } + + $PropertyName = $FunctionName; + $PropertyName =~ s/^GetElement//; + if (!exists $ElementPropertyNamesMap{$PropertyName}) { + croak "Error: Function, PeriodicTable::$FunctionName, is not supported by AUTOLOAD in PeriodicTable module: Unknown element property name, $PropertyName, specified..."; + } + + if (!($AtomicNumber = _ValidateElementID($ElementID))) { + return undef; + } + $PropertyValue = $ElementDataMap{$AtomicNumber}{$PropertyName}; + return $PropertyValue; +} + +# +# Get elements labels for group name specified using American or European style... +# +sub _GetElementsByGroupLabel { + my($GroupLabel, $LabelStyle) = @_; + my($GroupNumber); + + if ($LabelStyle =~ /^AmericanStyle$/i) { + $GroupNumber = GetIUPACGroupNumberFromAmericanStyleGroupLabel($GroupLabel); + } + elsif ($LabelStyle =~ /^EuropeanStyle$/i) { + $GroupNumber = GetIUPACGroupNumberFromEuropeanStyleGroupLabel($GroupLabel); + } + + if (IsEmpty($GroupNumber)) { + return (wantarray ? () : undef); + } + + my($AtomicNumber, @GroupElements, @ElementSymbols); + @ElementSymbols = (); + if ($GroupNumber =~ /\,/) { + my(@GroupNumbers); + + @GroupNumbers = split /\,/, $GroupNumber; + for $GroupNumber (@GroupNumbers) { + @GroupElements = GetElementsByGroupNumber($GroupNumber); + push @ElementSymbols, @GroupElements; + } + } + else { + @GroupElements = GetElementsByGroupNumber($GroupNumber); + push @ElementSymbols, @GroupElements; + } + return (wantarray ? @ElementSymbols : \@ElementSymbols); +} + +# +# Load PeriodicTableElementData.csv and PeriodicTableIsotopeData.csv files from +# <MayaChemTools>/lib directory... +# +sub _LoadPeriodicTableElementData { + my($ElementDataFile, $ElementIsotopeDataFile, $MayaChemToolsLibDir); + + $MayaChemToolsLibDir = GetMayaChemToolsLibDirName(); + + $ElementDataFile = "$MayaChemToolsLibDir" . "/data/PeriodicTableElementData.csv"; + $ElementIsotopeDataFile = "$MayaChemToolsLibDir" . "/data/PeriodicTableIsotopeData.csv"; + + if (! -e "$ElementDataFile") { + croak "Error: MayaChemTools package file, $ElementDataFile, is missing: Possible installation problems..."; + } + if (! -e "$ElementIsotopeDataFile") { + croak "Error: MayaChemTools package file, $ElementIsotopeDataFile, is missing: Possible installation problems..."; + } + + _LoadElementData($ElementDataFile); + _LoadElementIsotopeData($ElementIsotopeDataFile); +} + +# +# Load PeriodicTableElementData.csv file from <MayaChemTools>/lib directory... +# +sub _LoadElementData { + my($ElementDataFile) = @_; + + %ElementDataMap = (); + @ElementPropertyNames = (); + %ElementPropertyNamesMap = (); + %ElementSymbolMap = (); + + # Load atomic properties data for all elements... + # + # File Format: + #"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" + # + # + my($AtomicNumber, $ElementSymbol, $Line, $NumOfCols, $InDelim, $Index, $Name, $Value, $Units, @LineWords, @ColLabels); + + $InDelim = "\,"; + open ELEMENTDATAFILE, "$ElementDataFile" or croak "Couldn't open $ElementDataFile: $! ..."; + + # Skip lines up to column labels... + LINE: while ($Line = GetTextLine(\*ELEMENTDATAFILE)) { + if ($Line !~ /^#/) { + last LINE; + } + } + @ColLabels= quotewords($InDelim, 0, $Line); + $NumOfCols = @ColLabels; + + # Extract property names from column labels - and unit names where appropriate... + @ElementPropertyNames = (); + for $Index (0 .. $#ColLabels) { + $Name = $ColLabels[$Index]; + $Units = ""; + if ($Name =~ /\(/) { + ($Name, $Units) = split /\(/, $Name; + $Units =~ s/\)//g; + } + push @ElementPropertyNames, $Name; + + # Store element names and units... + $ElementPropertyNamesMap{$Name} = $Units; + } + + # Process element data... + LINE: while ($Line = GetTextLine(\*ELEMENTDATAFILE)) { + if ($Line =~ /^#/) { + next LINE; + } + @LineWords = (); + @LineWords = quotewords($InDelim, 0, $Line); + if (@LineWords != $NumOfCols) { + croak "Error: The number of data fields, @LineWords, in $ElementDataFile must be $NumOfCols.\nLine: $Line..."; + } + $AtomicNumber = $LineWords[0]; $ElementSymbol = $LineWords[1]; + if (exists $ElementDataMap{$AtomicNumber}) { + carp "Warning: Ignoring data for element $ElementSymbol: It has already been loaded.\nLine: $Line...."; + next LINE; + } + + # Store all the values... + %{$ElementDataMap{$AtomicNumber}} = (); + for $Index (0 .. $#LineWords) { + $Name = $ElementPropertyNames[$Index]; + $Value = $LineWords[$Index]; + $ElementDataMap{$AtomicNumber}{$Name} = $Value; + } + } + close ELEMENTDATAFILE; + + # Setup the element symbol map as well... + _SetupElementSymbolMap(); +} + +# +# Load PeriodicTableIsotopeData.csv files from <MayaChemTools>/lib directory... +# +sub _LoadElementIsotopeData { + my($ElementIsotopeDataFile) = @_; + + %ElementIsotopeDataMap = (); + %ElementIsotopeDerivedDataMap = (); + + # Load isotope data for all elements... + # + # File format: + # "Atomic Number","Isotope Symbol","Mass Number","Relative Atomic Mass","% Natural Abundnace" + # + # Empty values for "Relative Atomic Mass" and "% Natural Abundnace" imply absence of any + # naturally occuring isotopes for the element. + # + my($InDelim, $Line, $NumOfCols, @ColLabels, @LineWords); + + $InDelim = "\,"; + open ISOTOPEDATAFILE, "$ElementIsotopeDataFile" or croak "Couldn't open $ElementIsotopeDataFile: $! ..."; + + # Skip lines up to column labels... + LINE: while ($Line = GetTextLine(\*ISOTOPEDATAFILE)) { + if ($Line !~ /^#/) { + last LINE; + } + } + @ColLabels= quotewords($InDelim, 0, $Line); + $NumOfCols = @ColLabels; + + my($AtomicNumber, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance, %ZeroNaturalAbundanceMap); + %ZeroNaturalAbundanceMap = (); + + # Process element data... + LINE: while ($Line = GetTextLine(\*ISOTOPEDATAFILE)) { + if ($Line =~ /^#/) { + next LINE; + } + @LineWords = (); + @LineWords = quotewords($InDelim, 0, $Line); + if (@LineWords != $NumOfCols) { + croak "Error: The number of data fields, @LineWords, in $ElementIsotopeDataFile must be $NumOfCols.\nLine: $Line..."; + } + ($AtomicNumber, $IsotopeSymbol, $MassNumber, $RelativeAtomicMass, $NaturalAbundance) = @LineWords; + if (exists $ZeroNaturalAbundanceMap{$AtomicNumber}) { + # Only one isotope data line allowed for elements with no natural isotopes... + 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..."; + next LINE; + } + if (IsEmpty($NaturalAbundance)) { + $RelativeAtomicMass = 0; + $NaturalAbundance = 0; + $ZeroNaturalAbundanceMap{$AtomicNumber} = 1; + } + if (exists $ElementIsotopeDataMap{$AtomicNumber}) { + # Additional data for an existing element... + if (exists $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}) { + carp "Warning: Ignoring isotope data for element with atomic number $AtomicNumber: It has already been loaded.\nLine: $Line..."; + next LINE; + } + } + else { + # Data for a new element... + %{$ElementIsotopeDataMap{$AtomicNumber}} = (); + } + %{$ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}} = (); + $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{IsotopeSymbol} = $IsotopeSymbol; + $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{RelativeAtomicMass} = $RelativeAtomicMass; + $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance} = $NaturalAbundance; + } + close ISOTOPEDATAFILE; + + _SetupElementIsotopeDerivedDataMap(); +} + +# +# Map mass number of most abundant isotope for each element; additionally, +# count number of isotopes as well. +# +sub _SetupElementIsotopeDerivedDataMap { + my($AtomicNumber, $MassNumber, $NaturalAbundance, $MostNaturalAbundance, $MostAbundantMassNumber, $IsotopeCount); + + %ElementIsotopeDerivedDataMap = (); + + for $AtomicNumber (sort {$a <=> $b} keys %ElementIsotopeDataMap) { + $IsotopeCount = 0; + $MostAbundantMassNumber = 0; + $MostNaturalAbundance = 0; + MASSNUMBER: for $MassNumber (sort {$a <=> $b} keys %{$ElementIsotopeDataMap{$AtomicNumber}}) { + $NaturalAbundance = $ElementIsotopeDataMap{$AtomicNumber}{$MassNumber}{NaturalAbundance}; + if (IsEmpty($NaturalAbundance)) { + # No natural isotopes available... + $MostAbundantMassNumber = $MassNumber; + last MASSNUMBER; + } + if ($NaturalAbundance == 0) { + # Not a natural isotope; Listed in periodic table data file to support non-natural + # elements such as T. It's not included in natural isotope count... + next MASSNUMBER; + } + $IsotopeCount++; + if ($NaturalAbundance > $MostNaturalAbundance) { + $MostAbundantMassNumber = $MassNumber; + $MostNaturalAbundance = $NaturalAbundance; + } + } + %{$ElementIsotopeDerivedDataMap{$AtomicNumber}} = (); + $ElementIsotopeDerivedDataMap{$AtomicNumber}{IsotopeCount} = $IsotopeCount; + $ElementIsotopeDerivedDataMap{$AtomicNumber}{MostAbundantMassNumber} = $MostAbundantMassNumber; + } +} + +# +# Setup element symbol map... +# +sub _SetupElementSymbolMap { + my($AtomicNumber, $ElementSymbol); + + %ElementSymbolMap = (); + + for $AtomicNumber (keys %ElementDataMap) { + $ElementSymbol = $ElementDataMap{$AtomicNumber}{ElementSymbol}; + $ElementSymbolMap{$ElementSymbol} = $AtomicNumber; + } +} + +# Validate element ID... +sub _ValidateElementID { + my($ElementID) = @_; + my($ElementSymbol, $AtomicNumber); + + if ($ElementID =~ /[^0-9]/) { + # Assume atomic symbol... + $ElementSymbol = $ElementID; + if (exists $ElementSymbolMap{$ElementSymbol}) { + $AtomicNumber = $ElementSymbolMap{$ElementSymbol}; + } + else { + return undef; + } + } + else { + # Assume atomic number... + $AtomicNumber = $ElementID; + if (!exists $ElementDataMap{$AtomicNumber}) { + return undef; + } + } + return $AtomicNumber; +} + +1; + +__END__ + +=head1 NAME + +PeriodicTable + +=head1 SYNOPSIS + +use PeriodicTable; + +use PeriodicTable qw(:all); + +=head1 DESCRIPTION + +B<PeriodicTable> module provides the following functions: + +GetElementMostAbundantNaturalIsotopeData, +GetElementMostAbundantNaturalIsotopeMass, +GetElementMostAbundantNaturalIsotopeMassNumber, GetElementNaturalIsotopeAbundance, +GetElementNaturalIsotopeCount, GetElementNaturalIsotopeMass, +GetElementNaturalIsotopesData, GetElementPropertiesData, +GetElementPropertiesNames, GetElementPropertiesNamesAndUnits, +GetElementPropertyUnits, GetElements, GetElementsByAmericanStyleGroupLabel, +GetElementsByEuropeanStyleGroupLabel, GetElementsByGroupName, +GetElementsByGroupNumber, GetElementsByPeriodNumber, +GetIUPACGroupNumberFromAmericanStyleGroupLabel, +GetIUPACGroupNumberFromEuropeanStyleGroupLabel, IsElement, +IsElementNaturalIsotopeMassNumber, IsElementProperty + +=head1 METHODS + +=over 4 + +=item B<GetElements> + + @ElementSymbols = GetElements(); + $ElementSymbolsRef = GetElements(); + +Returns an array or a reference to an array of known element symbols + +=item B<GetElementsByGroupName> + + @ElementSymbols = GetElementsByGroupName($GroupName); + $ElementSymbolsRef = GetElementsByGroupName($GroupName); + +Returns an array or a reference to an array of element symbols for a specified I<GroupName>. +Supported I<GroupName> values are: I<Alkali metals, Alkaline earth metals, Coinage metals, Pnictogens, +Chalcogens, Halogens, Noble gases>; Additionally, usage of I<Lanthanides> (Lanthanoids) +and I<Actinides> (Actinoids) is also supported. + +=item B<GetElementsByGroupNumber> + + @ElementSymbols = GetElementsByGroupNumber($GroupNumber); + $ElementSymbolsRef = GetElementsByGroupNumber($GroupNumber); + +Returns an array or a reference to an array of element symbols for a specified I<GroupNumber> + +=item B<GetElementsByAmericanStyleGroupLabel> + + @ElementSymbols = GetElementsByAmericanStyleGroupLabel($GroupLabel); + $ElementSymbolsRef = GetElementsByAmericanStyleGroupLabel($GroupLabel); + +Returns an array or a reference to an array of element symbols for a specified American +style I<GroupLabel>. Valid values for Amercian style group labels: I<IA to VIIIA, IB to VIIIB, VIII>. + +=item B<GetElementsByEuropeanStyleGroupLabel> + + @ElementSymbols = GetElementsByEuropeanStyleGroupLabel($GroupLabel); + $ElementSymbolsRef = GetElementsByEuropeanStyleGroupLabel($GroupLabel); + +Returns an array or a reference to an array of element symbols for a specified European +style I<GroupLabel>. Valid values for European style group labels: I<IA to VIIIA, IB to VIIIB, VIII>. + +=item B<GetElementsByPeriodNumber> + + @ElementSymbols = GetElementsByPeriodNumber($PeriodNumber); + $ElementSymbolsRef = GetElementsByPeriodNumber($PeriodNumber); + +Returns an array or a reference to an array of element symbols for a specified I<PeriodNumber>. + +=item B<GetElementMostAbundantNaturalIsotopeData> + + @IsotopeData = GetElementMostAbundantNaturalIsotopeData( + $ElementID); + $IsotopeDataRef = GetElementMostAbundantNaturalIsotopeData( + $ElementID); + +Returns an array or reference to an array containing data for most abundant isotope of +an element specfied by element symbol or atomic number. Isotope data arrays contain these +values: I<AtomicNumber, IsotopeSymbol, MassNumber, RelativeAtomicMass, and NaturalAbundance>. + +=item B<GetElementMostAbundantNaturalIsotopeMassNumber> + + $MassNumber = GetElementMostAbundantNaturalIsotopeMassNumber($ElementID); + +Returns mass number of most abundant natural isotope of an element specfied by element +symbol or atomic number + +=item B<GetElementNaturalIsotopeCount> + + $IsotopeCount = GetElementNaturalIsotopeCount($ElementID); + +Returns natural isotope count for an element specfied by element symbol or +atomic number + +=item B<GetElementNaturalIsotopesData> + + $DataHashRef = GetElementNaturalIsotopesData($ElementID, + [$MassNumber]); + +Reurns a reference to a hash containingall available isotope data for an element specified +using element symbol or aromic number; an optional mass number indicates retrieve data +for a specific isotope + +=item B<GetElementNaturalIsotopeAbundance> + + $Abundance = GetElementNaturalIsotopeAbundance($ElementID, + $MassNumber); + +Returns percent abundance of natural isotope for an element with specfic mass +number. + +=item B<GetElementMostAbundantNaturalIsotopeMass> + + $RelativeAtomicMass = GetElementMostAbundantNaturalIsotopeMass( + $ElementID); + +Returns relative atomic mass of most abundant isotope for an element specified using +element symbol or aromic number. + +=item B<GetElementNaturalIsotopeMass> + + $RelativeAtomicMass = GetElementNaturalIsotopeMass($ElementID, + $MassNumber); + +Returns relative atomic mass of an element with specfic mass number. + +=item B<GetElementPropertiesData> + + $PropertyDataHashRef = GetElementPropertiesData($ElementID); + +Returns a reference to a hash containing all available properties data for an element +specified using element symbol or atomic number. + +=item B<GetElementPropertyName> + + $PropertyValue = GetElement<PropertyName>($ElementID); + +Returns value of an element for a element specified using element symbol or atomic number. + +These functions are not defined in this modules; these are implemented on-the-fly using +Perl's AUTOLOAD funcionality. + +Here is the list of known element I<property names>: AllenElectronegativity, +AllredRochowElectronegativity, AtomicNumber, AtomicRadiusCalculated, +AtomicRadiusEmpirical, AtomicWeight, Block, BoilingPoint, BondLength, +BrinellHardness, BulkModulus, Classification, CoefficientOfLinearExpansion, Color, +CommonValences, LowestCommonValence, HighestCommonValence, +CommonOxidationNumbers, LowestCommonOxidationNumber, HighestCommonOxidationNumber, +CovalentRadiusEmpirical, CriticalTemperature, DensityOfSolid, DiscoveredAt, DiscoveredBy, +DiscoveredWhen, ElectricalResistivity, ElectronAffinity, ElementName, ElementSymbol, EnthalpyOfAtmization, +EnthalpyOfFusion, EnthalpyOfVaporization, FirstIonizationEnergy, GroundStateConfiguration, GroundStateLevel, +GroupName, GroupNumber, NaturalIsotopeData, MeltingPoint, MineralHardness, MolarVolume, +MullikenJaffeElectronegativity, OriginOfName, PaulingElectronegativity, PeriodNumber, PoissonsRatio, +Reflectivity, RefractiveIndex, RigidityModulus, SandersonElectronegativity, StandardState, +SuperconductionTemperature, ThermalConductivity, VanderWaalsRadius, VelocityOfSound, VickersHardness, +YoungsModulus. + +=item B<GetElementPropertiesNames> + + @PropertyNames = GetElementPropertiesNames([$Mode]); + $PropertyNamesRef = GetElementPropertiesNames([$Mode]); + +Returns names of all available element properties. Optional mode parameter controls +grouping of property names; Possible values: I<ByGroup or Alphabetical>. Default: +I<ByGroup>. + +=item B<GetElementPropertiesNamesAndUnits> + + $NameUnitsHashRef = GetElementPropertiesNamesAndUnits(); + +Returns a reference to a hash of property names and units of all available element +properties. Names with no units contains empty strings. + +=item B<GetElementPropertyUnits> + + $Units = GetElementPropertyUnits($PropertyName); + +Returns units for a specific element property name. An empty string is returned for +a property with no units. + +=item B<GetIUPACGroupNumberFromAmericanStyleGroupLabel> + + $GroupNumber = GetIUPACGroupNumberFromAmericanStyleGroupLabel( + $GroupLabel); + +Returns IUPAC group numbers of a specific American style group label. A comma delimited +string is returned for group VIII or VIIIB. + +=item B<GetIUPACGroupNumberFromEuropeanStyleGroupLabel> + + $GroupNumber = GetIUPACGroupNumberFromEuropeanStyleGroupLabel( + $GroupLabel); + +Returns IUPAC group numbers of a specific European style group label. A comma delimited +string is returned for group VIII or VIIIA. + +=item B<IsElement> + + $Status = IsElement($ElementID); + +Returns 1 or 0 based on whether it's a known element symbol or atomic number. + +=item B<IsElementNaturalIsotopeMassNumber> + + $Status = IsElementNaturalIsotopeMassNumber($ElementID, $MassNumber); + +Returns 1 or 0 based on whether it's a valid mass number for an element symbol +or atomic number. + +=item B<IsElementProperty> + + $Status = IsElementProperty($PropertyName); + +Returns 1 or 0 based on whether it's a valid property name. + +=back + +=head1 AUTHOR + +Manish Sud <msud@san.rr.com> + +=head1 SEE ALSO + +AminoAcids.pm, NucleicAcids.pm + +=head1 COPYRIGHT + +Copyright (C) 2015 Manish Sud. All rights reserved. + +This file is part of MayaChemTools. + +MayaChemTools is free software; you can redistribute it and/or modify it under +the terms of the GNU Lesser General Public License as published by the Free +Software Foundation; either version 3 of the License, or (at your option) +any later version. + +=cut