| 0 | 1 <html> | 
|  | 2 <head> | 
|  | 3 <title>MayaChemTools:Code:MolecularFormula.pm</title> | 
|  | 4 <meta http-equiv="content-type" content="text/html;charset=utf-8"> | 
|  | 5 <link rel="stylesheet" type="text/css" href="../../../css/MayaChemToolsCode.css"> | 
|  | 6 </head> | 
|  | 7 <body leftmargin="20" rightmargin="20" topmargin="10" bottommargin="10"> | 
|  | 8 <br/> | 
|  | 9 <center> | 
|  | 10 <a href="http://www.mayachemtools.org" title="MayaChemTools Home"><img src="../../../images/MayaChemToolsLogo.gif" border="0" alt="MayaChemTools"></a> | 
|  | 11 </center> | 
|  | 12 <br/> | 
|  | 13 <pre> | 
|  | 14 <a name="package-MolecularFormula-"></a>   1 <span class="k">package </span><span class="i">MolecularFormula</span><span class="sc">;</span> | 
|  | 15    2 <span class="c">#</span> | 
|  | 16    3 <span class="c"># $RCSfile: MolecularFormula.pm,v $</span> | 
|  | 17    4 <span class="c"># $Date: 2015/02/28 20:47:18 $</span> | 
|  | 18    5 <span class="c"># $Revision: 1.25 $</span> | 
|  | 19    6 <span class="c">#</span> | 
|  | 20    7 <span class="c"># Author: Manish Sud <msud@san.rr.com></span> | 
|  | 21    8 <span class="c">#</span> | 
|  | 22    9 <span class="c"># Copyright (C) 2015 Manish Sud. All rights reserved.</span> | 
|  | 23   10 <span class="c">#</span> | 
|  | 24   11 <span class="c"># This file is part of MayaChemTools.</span> | 
|  | 25   12 <span class="c">#</span> | 
|  | 26   13 <span class="c"># MayaChemTools is free software; you can redistribute it and/or modify it under</span> | 
|  | 27   14 <span class="c"># the terms of the GNU Lesser General Public License as published by the Free</span> | 
|  | 28   15 <span class="c"># Software Foundation; either version 3 of the License, or (at your option) any</span> | 
|  | 29   16 <span class="c"># later version.</span> | 
|  | 30   17 <span class="c">#</span> | 
|  | 31   18 <span class="c"># MayaChemTools is distributed in the hope that it will be useful, but without</span> | 
|  | 32   19 <span class="c"># any warranty; without even the implied warranty of merchantability of fitness</span> | 
|  | 33   20 <span class="c"># for a particular purpose.  See the GNU Lesser General Public License for more</span> | 
|  | 34   21 <span class="c"># details.</span> | 
|  | 35   22 <span class="c">#</span> | 
|  | 36   23 <span class="c"># You should have received a copy of the GNU Lesser General Public License</span> | 
|  | 37   24 <span class="c"># along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or</span> | 
|  | 38   25 <span class="c"># write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,</span> | 
|  | 39   26 <span class="c"># Boston, MA, 02111-1307, USA.</span> | 
|  | 40   27 <span class="c">#</span> | 
|  | 41   28 | 
|  | 42   29 <span class="k">use</span> <span class="w">strict</span><span class="sc">;</span> | 
|  | 43   30 <span class="k">use</span> <span class="w">Carp</span><span class="sc">;</span> | 
|  | 44   31 <span class="k">use</span> <span class="w">Text::ParseWords</span><span class="sc">;</span> | 
|  | 45   32 <span class="k">use</span> <span class="w">TextUtil</span><span class="sc">;</span> | 
|  | 46   33 <span class="k">use</span> <span class="w">PeriodicTable</span><span class="sc">;</span> | 
|  | 47   34 | 
|  | 48   35 <span class="k">use</span> <span class="w">vars</span> <span class="q">qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS)</span><span class="sc">;</span> | 
|  | 49   36 | 
|  | 50   37 <span class="i">@ISA</span> = <span class="q">qw(Exporter)</span><span class="sc">;</span> | 
|  | 51   38 <span class="i">@EXPORT</span> = <span class="q">qw()</span><span class="sc">;</span> | 
|  | 52   39 <span class="i">@EXPORT_OK</span> = <span class="q">qw(CalculateMolecularWeight CalculateExactMass CalculateElementalComposition FormatCompositionInfomation GetElementsAndCount IsMolecularFormula)</span><span class="sc">;</span> | 
|  | 53   40 | 
|  | 54   41 <span class="i">%EXPORT_TAGS</span> = <span class="s">(</span><span class="w">all</span>  <span class="cm">=></span> <span class="s">[</span><span class="i">@EXPORT</span><span class="cm">,</span> <span class="i">@EXPORT_OK</span><span class="s">]</span><span class="s">)</span><span class="sc">;</span> | 
|  | 55   42 | 
|  | 56   43 <span class="c">#</span> | 
|  | 57   44 <span class="c"># Calculate molecular weight assuming its a valid molecular formula...</span> | 
|  | 58   45 <span class="c">#</span> | 
|  | 59 <a name="CalculateMolecularWeight-"></a>  46 <span class="k">sub </span><span class="m">CalculateMolecularWeight</span> <span class="s">{</span> | 
|  | 60   47   <span class="k">my</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 61   48   <span class="k">my</span><span class="s">(</span><span class="i">$Index</span><span class="cm">,</span> <span class="i">$MolecularWeight</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="cm">,</span> <span class="i">$AtomicWeight</span><span class="cm">,</span> <span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="s">)</span><span class="sc">;</span> | 
|  | 62   49 | 
|  | 63   50   <span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="s">)</span> = <span class="i">_ProcessMolecularFormula</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span><span class="sc">;</span> | 
|  | 64   51   <span class="k">if</span> <span class="s">(</span>!<span class="s">(</span><span class="k">defined</span><span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="s">)</span> && <span class="k">defined</span><span class="s">(</span><span class="i">$FormulaElementCountRef</span><span class="s">)</span><span class="s">)</span><span class="s">)</span> <span class="s">{</span> | 
|  | 65   52     <span class="k">return</span> <span class="k">undef</span><span class="sc">;</span> | 
|  | 66   53   <span class="s">}</span> | 
|  | 67   54 | 
|  | 68   55   <span class="i">$MolecularWeight</span> = <span class="n">0</span><span class="sc">;</span> | 
|  | 69   56 | 
|  | 70   57   <span class="k">for</span> <span class="i">$Index</span> <span class="s">(</span><span class="n">0</span> .. <span class="i">$#</span>{<span class="i">$FormulaElementsRef</span>}<span class="s">)</span> <span class="s">{</span> | 
|  | 71   58     <span class="i">$ElementSymbol</span> = <span class="i">$FormulaElementsRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 72   59     <span class="i">$ElementCount</span> = <span class="i">$FormulaElementCountRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 73   60     <span class="i">$AtomicWeight</span> = <span class="i">PeriodicTable::GetElementAtomicWeight</span><span class="s">(</span><span class="i">$ElementSymbol</span><span class="s">)</span><span class="sc">;</span> | 
|  | 74   61     <span class="i">$MolecularWeight</span> += <span class="i">$AtomicWeight</span> * <span class="i">$ElementCount</span><span class="sc">;</span> | 
|  | 75   62   <span class="s">}</span> | 
|  | 76   63   <span class="k">return</span> <span class="i">$MolecularWeight</span><span class="sc">;</span> | 
|  | 77   64 <span class="s">}</span> | 
|  | 78   65 | 
|  | 79   66 <span class="c">#</span> | 
|  | 80   67 <span class="c"># Calculate exact mass assuming it's a valid formula...</span> | 
|  | 81   68 <span class="c">#</span> | 
|  | 82 <a name="CalculateExactMass-"></a>  69 <span class="k">sub </span><span class="m">CalculateExactMass</span> <span class="s">{</span> | 
|  | 83   70   <span class="k">my</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 84   71   <span class="k">my</span><span class="s">(</span><span class="i">$Index</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="cm">,</span> <span class="i">$ExactMass</span><span class="cm">,</span> <span class="i">$RelativeAtomicMass</span><span class="cm">,</span> <span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="s">)</span><span class="sc">;</span> | 
|  | 85   72 | 
|  | 86   73   <span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="s">)</span> = <span class="i">_ProcessMolecularFormula</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span><span class="sc">;</span> | 
|  | 87   74   <span class="k">if</span> <span class="s">(</span>!<span class="s">(</span><span class="k">defined</span><span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="s">)</span> && <span class="k">defined</span><span class="s">(</span><span class="i">$FormulaElementCountRef</span><span class="s">)</span><span class="s">)</span><span class="s">)</span> <span class="s">{</span> | 
|  | 88   75     <span class="k">return</span> <span class="k">undef</span><span class="sc">;</span> | 
|  | 89   76   <span class="s">}</span> | 
|  | 90   77   <span class="i">$ExactMass</span> = <span class="n">0</span><span class="sc">;</span> | 
|  | 91   78 | 
|  | 92   79   <span class="k">for</span> <span class="i">$Index</span> <span class="s">(</span><span class="n">0</span> .. <span class="i">$#</span>{<span class="i">$FormulaElementsRef</span>}<span class="s">)</span> <span class="s">{</span> | 
|  | 93   80     <span class="i">$ElementSymbol</span> = <span class="i">$FormulaElementsRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 94   81     <span class="i">$ElementCount</span> = <span class="i">$FormulaElementCountRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 95   82     <span class="i">$RelativeAtomicMass</span> = <span class="i">PeriodicTable::GetElementMostAbundantNaturalIsotopeMass</span><span class="s">(</span><span class="i">$ElementSymbol</span><span class="s">)</span><span class="sc">;</span> | 
|  | 96   83     <span class="k">if</span> <span class="s">(</span>!<span class="k">defined</span><span class="s">(</span><span class="i">$RelativeAtomicMass</span><span class="s">)</span><span class="s">)</span> <span class="s">{</span> | 
|  | 97   84       <span class="k">next</span> <span class="j">ELEMENT</span><span class="sc">;</span> | 
|  | 98   85     <span class="s">}</span> | 
|  | 99   86     <span class="i">$ExactMass</span> += <span class="i">$RelativeAtomicMass</span> * <span class="i">$ElementCount</span><span class="sc">;</span> | 
|  | 100   87   <span class="s">}</span> | 
|  | 101   88   <span class="k">return</span> <span class="i">$ExactMass</span><span class="sc">;</span> | 
|  | 102   89 <span class="s">}</span> | 
|  | 103   90 | 
|  | 104   91 | 
|  | 105   92 <span class="c">#</span> | 
|  | 106   93 <span class="c"># Calculate elemental composition and return reference to arrays</span> | 
|  | 107   94 <span class="c"># containing elements and their percent composition...</span> | 
|  | 108   95 <span class="c">#</span> | 
|  | 109 <a name="CalculateElementalComposition-"></a>  96 <span class="k">sub </span><span class="m">CalculateElementalComposition</span> <span class="s">{</span> | 
|  | 110   97   <span class="k">my</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 111   98   <span class="k">my</span><span class="s">(</span><span class="i">$Index</span><span class="cm">,</span> <span class="i">$MolecularWeight</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="cm">,</span> <span class="i">$AtomicWeight</span><span class="cm">,</span> <span class="i">$Composition</span><span class="cm">,</span> <span class="i">$CompositionMultiplier</span><span class="cm">,</span> <span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="cm">,</span> <span class="i">@FormulaElements</span><span class="cm">,</span> <span class="i">@FormulaElementComposition</span><span class="s">)</span><span class="sc">;</span> | 
|  | 112   99 | 
|  | 113  100   <span class="i">$MolecularWeight</span> = <span class="i">CalculateMolecularWeight</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span><span class="sc">;</span> | 
|  | 114  101   <span class="k">if</span> <span class="s">(</span>! <span class="k">defined</span> <span class="i">$MolecularWeight</span><span class="s">)</span> <span class="s">{</span> | 
|  | 115  102     <span class="k">return</span> <span class="s">(</span><span class="k">undef</span><span class="cm">,</span> <span class="k">undef</span><span class="s">)</span><span class="sc">;</span> | 
|  | 116  103   <span class="s">}</span> | 
|  | 117  104   <span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="s">)</span> = <span class="i">_ProcessMolecularFormula</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span><span class="sc">;</span> | 
|  | 118  105 | 
|  | 119  106   <span class="i">@FormulaElements</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 120  107   <span class="i">@FormulaElementComposition</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 121  108 | 
|  | 122  109   <span class="k">if</span> <span class="s">(</span>!<span class="i">$MolecularWeight</span><span class="s">)</span> <span class="s">{</span> | 
|  | 123  110     <span class="k">return</span> <span class="s">(</span> \<span class="i">@FormulaElements</span><span class="cm">,</span> \<span class="i">@FormulaElementComposition</span><span class="s">)</span><span class="sc">;</span> | 
|  | 124  111   <span class="s">}</span> | 
|  | 125  112 | 
|  | 126  113   <span class="i">$CompositionMultiplier</span> = <span class="n">100</span> / <span class="i">$MolecularWeight</span><span class="sc">;</span> | 
|  | 127  114 | 
|  | 128  115   <span class="k">for</span> <span class="i">$Index</span> <span class="s">(</span><span class="n">0</span> .. <span class="i">$#</span>{<span class="i">$FormulaElementsRef</span>}<span class="s">)</span> <span class="s">{</span> | 
|  | 129  116     <span class="i">$ElementSymbol</span> = <span class="i">$FormulaElementsRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 130  117     <span class="i">$ElementCount</span> = <span class="i">$FormulaElementCountRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 131  118     <span class="i">$AtomicWeight</span> = <span class="i">PeriodicTable::GetElementAtomicWeight</span><span class="s">(</span><span class="i">$ElementSymbol</span><span class="s">)</span><span class="sc">;</span> | 
|  | 132  119     <span class="i">$Composition</span> = <span class="s">(</span><span class="i">$AtomicWeight</span> * <span class="i">$ElementCount</span><span class="s">)</span> * <span class="i">$CompositionMultiplier</span><span class="sc">;</span> | 
|  | 133  120 | 
|  | 134  121     <span class="k">push</span> <span class="i">@FormulaElements</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="sc">;</span> | 
|  | 135  122     <span class="k">push</span> <span class="i">@FormulaElementComposition</span><span class="cm">,</span> <span class="i">$Composition</span><span class="sc">;</span> | 
|  | 136  123   <span class="s">}</span> | 
|  | 137  124 | 
|  | 138  125   <span class="k">return</span> <span class="s">(</span> \<span class="i">@FormulaElements</span><span class="cm">,</span> \<span class="i">@FormulaElementComposition</span><span class="s">)</span><span class="sc">;</span> | 
|  | 139  126 <span class="s">}</span> | 
|  | 140  127 | 
|  | 141  128 <span class="c"># Using refernece to element and its composition arrays, format composition information</span> | 
|  | 142  129 <span class="c"># as: Element: Composition;...</span> | 
|  | 143  130 <span class="c">#</span> | 
|  | 144 <a name="FormatCompositionInfomation-"></a> 131 <span class="k">sub </span><span class="m">FormatCompositionInfomation</span> <span class="s">{</span> | 
|  | 145  132   <span class="k">my</span><span class="s">(</span><span class="i">$Index</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementComposition</span><span class="cm">,</span> <span class="i">$ElementsRef</span><span class="cm">,</span> <span class="i">$ElementCompositionRef</span><span class="cm">,</span> <span class="i">$Precision</span><span class="cm">,</span> <span class="i">$Composition</span><span class="s">)</span><span class="sc">;</span> | 
|  | 146  133 | 
|  | 147  134   <span class="i">$Precision</span> = <span class="n">2</span><span class="sc">;</span> | 
|  | 148  135   <span class="k">if</span> <span class="s">(</span><span class="i">@_</span> == <span class="n">3</span><span class="s">)</span> <span class="s">{</span> | 
|  | 149  136     <span class="s">(</span><span class="i">$ElementsRef</span><span class="cm">,</span> <span class="i">$ElementCompositionRef</span><span class="cm">,</span> <span class="i">$Precision</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 150  137   <span class="s">}</span> | 
|  | 151  138   <span class="k">else</span> <span class="s">{</span> | 
|  | 152  139     <span class="s">(</span><span class="i">$ElementsRef</span><span class="cm">,</span> <span class="i">$ElementCompositionRef</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 153  140   <span class="s">}</span> | 
|  | 154  141 | 
|  | 155  142   <span class="i">$Composition</span> = <span class="q">''</span><span class="sc">;</span> | 
|  | 156  143   <span class="k">for</span> <span class="i">$Index</span> <span class="s">(</span><span class="n">0</span> .. <span class="i">$#</span>{<span class="i">$ElementsRef</span>}<span class="s">)</span> <span class="s">{</span> | 
|  | 157  144     <span class="i">$ElementSymbol</span> = <span class="i">$ElementsRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 158  145     <span class="i">$ElementComposition</span> = <span class="i">$ElementCompositionRef</span>->[<span class="i">$Index</span>]<span class="sc">;</span> | 
|  | 159  146     <span class="i">$ElementComposition</span> = <span class="k">sprintf</span><span class="s">(</span><span class="q">"%.${Precision}f"</span><span class="cm">,</span> <span class="i">$ElementComposition</span><span class="s">)</span><span class="sc">;</span> | 
|  | 160  147 | 
|  | 161  148     <span class="i">$Composition</span> .= <span class="s">(</span><span class="i">$Composition</span><span class="s">)</span> ? <span class="q">'; '</span> <span class="co">:</span> <span class="q">''</span><span class="sc">;</span> | 
|  | 162  149     <span class="i">$Composition</span> .=  <span class="q">"${ElementSymbol}: ${ElementComposition}%"</span><span class="sc">;</span> | 
|  | 163  150   <span class="s">}</span> | 
|  | 164  151 | 
|  | 165  152   <span class="k">return</span> <span class="i">$Composition</span><span class="sc">;</span> | 
|  | 166  153 <span class="s">}</span> | 
|  | 167  154 | 
|  | 168  155 <span class="c">#</span> | 
|  | 169  156 <span class="c"># Get elements and their count...</span> | 
|  | 170  157 <span class="c">#</span> | 
|  | 171 <a name="GetElementsAndCount-"></a> 158 <span class="k">sub </span><span class="m">GetElementsAndCount</span> <span class="s">{</span> | 
|  | 172  159   <span class="k">my</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 173  160   <span class="k">my</span><span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span><span class="sc">;</span> | 
|  | 174  161 | 
|  | 175  162   <span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span> = <span class="i">_ProcessMolecularFormula</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span><span class="sc">;</span> | 
|  | 176  163 | 
|  | 177  164   <span class="k">return</span> <span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="s">)</span><span class="sc">;</span> | 
|  | 178  165 <span class="s">}</span> | 
|  | 179  166 | 
|  | 180  167 <span class="c">#</span> | 
|  | 181  168 <span class="c"># Is it a valid molecular formula?</span> | 
|  | 182  169 <span class="c">#</span> | 
|  | 183 <a name="IsMolecularFormula-"></a> 170 <span class="k">sub </span><span class="m">IsMolecularFormula</span> <span class="s">{</span> | 
|  | 184  171   <span class="k">my</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="cm">,</span> <span class="i">$PrintErrorMsg</span><span class="cm">,</span> <span class="i">$Status</span><span class="cm">,</span> <span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span><span class="sc">;</span> | 
|  | 185  172 | 
|  | 186  173   <span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 187  174 | 
|  | 188  175   <span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="cm">,</span> <span class="i">$FormulaElementCountRef</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span> = <span class="i">_ProcessMolecularFormula</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span><span class="sc">;</span> | 
|  | 189  176   <span class="i">$Status</span> = <span class="s">(</span><span class="k">defined</span><span class="s">(</span><span class="i">$FormulaElementsRef</span><span class="s">)</span> && <span class="k">defined</span><span class="s">(</span><span class="i">$FormulaElementCountRef</span><span class="s">)</span><span class="s">)</span> ? <span class="n">1</span> <span class="co">:</span> <span class="n">0</span><span class="sc">;</span> | 
|  | 190  177 | 
|  | 191  178   <span class="k">return</span> <span class="s">(</span><span class="k">wantarray</span> ? <span class="s">(</span><span class="i">$Status</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span> <span class="co">:</span> <span class="i">$Status</span><span class="s">)</span><span class="sc">;</span> | 
|  | 192  179 <span class="s">}</span> | 
|  | 193  180 | 
|  | 194  181 <span class="c">#</span> | 
|  | 195  182 <span class="c"># Process molecular formula. For a valid formula, return references to arrays conatining elements</span> | 
|  | 196  183 <span class="c"># and element count; otherwsie, return undef.</span> | 
|  | 197  184 <span class="c">#</span> | 
|  | 198 <a name="_ProcessMolecularFormula-"></a> 185 <span class="k">sub </span><span class="m">_ProcessMolecularFormula</span> <span class="s">{</span> | 
|  | 199  186   <span class="k">my</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 200  187   <span class="k">my</span><span class="s">(</span><span class="i">$ErrorMsg</span><span class="s">)</span> = <span class="q">''</span><span class="sc">;</span> | 
|  | 201  188 | 
|  | 202  189   <span class="i">$MolecularFormula</span> = <span class="i">_CleanUpFormula</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span><span class="sc">;</span> | 
|  | 203  190 | 
|  | 204  191   <span class="c"># Make sure it only contains numbers and letters...</span> | 
|  | 205  192   <span class="k">if</span> <span class="s">(</span><span class="i">$MolecularFormula</span> =~ <span class="q">/[^a-zA-Z0-9\(\)\[\]]/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 206  193     <span class="i">$ErrorMsg</span> = <span class="q">'Molecular formula contains characters other than a-zA-Z0-9'</span><span class="sc">;</span> | 
|  | 207  194     <span class="k">return</span> <span class="s">(</span><span class="k">undef</span><span class="cm">,</span> <span class="k">undef</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span><span class="sc">;</span> | 
|  | 208  195   <span class="s">}</span> | 
|  | 209  196 | 
|  | 210  197   <span class="c"># Parse the formula...</span> | 
|  | 211  198   <span class="k">my</span><span class="s">(</span><span class="i">$ElementSpec</span><span class="cm">,</span> <span class="i">$FormulaElementSpec</span><span class="cm">,</span> <span class="i">$Spec</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="cm">,</span>  <span class="i">@FormulaElements</span><span class="cm">,</span> <span class="i">@ElementCount</span><span class="cm">,</span> <span class="i">%FormulaElementsToCountMap</span><span class="cm">,</span> <span class="i">@SubFormulaElements</span><span class="cm">,</span> <span class="i">%SubFormulaElementsToCountMap</span><span class="s">)</span><span class="sc">;</span> | 
|  | 212  199 | 
|  | 213  200   <span class="i">@FormulaElements</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> <span class="i">@ElementCount</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 214  201   <span class="i">%FormulaElementsToCountMap</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 215  202 | 
|  | 216  203 <span class="c"># Setup element symbol and count regular expression...</span> | 
|  | 217  204 <span class="c"># IUPAC: http://www.iupac.org/reports/provisional/abstract04/RB-prs310804/Chap4-3.04.pdf</span> | 
|  | 218  205 <span class="c">#</span> | 
|  | 219  206 | 
|  | 220  207   <span class="i">$FormulaElementSpec</span> = <span class="q">qr/</span> | 
|  | 221  208                    <span class="q">                   \G(                         # $1</span> | 
|  | 222  209                          <span class="q">                         (?:</span> | 
|  | 223  210                            <span class="q">                           ([A-Z][a-z]?)   # Two or one letter element symbol; $2</span> | 
|  | 224  211                            <span class="q">                           ([0-9]*)          # Optionally followed by element count; $3</span> | 
|  | 225  212                          <span class="q">                         )</span> | 
|  | 226  213                          <span class="q">                         | \( | \[</span> | 
|  | 227  214                          <span class="q">                         | \)[0-9]* | \][0-9]*</span> | 
|  | 228  215                          <span class="q">                         | .</span> | 
|  | 229  216                       <span class="q">                      )</span> | 
|  | 230  217                    <span class="q">                   /x</span><span class="sc">;</span> | 
|  | 231  218 | 
|  | 232  219   <span class="k">my</span><span class="s">(</span><span class="i">$ProcessingParenthesis</span><span class="s">)</span><span class="sc">;</span> | 
|  | 233  220   <span class="i">$ProcessingParenthesis</span> = <span class="n">0</span><span class="sc">;</span> | 
|  | 234  221   <span class="c"># Go over the formula...</span> | 
|  | 235  222   <span class="j">FORMULA:</span> <span class="k">while</span> <span class="s">(</span><span class="i">$MolecularFormula</span> =~ <span class="q">/$FormulaElementSpec/gx</span><span class="s">)</span> <span class="s">{</span> | 
|  | 236  223     <span class="s">(</span><span class="i">$Spec</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="s">)</span> = <span class="s">(</span><span class="i">$1</span><span class="cm">,</span> <span class="i">$2</span><span class="cm">,</span> <span class="i">$3</span><span class="s">)</span><span class="sc">;</span> | 
|  | 237  224 | 
|  | 238  225     <span class="c"># Handle parenthesis in formula to indicate repeating units...</span> | 
|  | 239  226     <span class="k">if</span> <span class="s">(</span><span class="i">$Spec</span> =~ <span class="q">/^(\(|\[)/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 240  227       <span class="k">if</span> <span class="s">(</span><span class="i">$ProcessingParenthesis</span><span class="s">)</span> <span class="s">{</span> | 
|  | 241  228         <span class="i">$ErrorMsg</span> = <span class="q">"Molecular formula contains multiple level of () or []"</span><span class="sc">;</span> | 
|  | 242  229         <span class="k">return</span> <span class="s">(</span><span class="k">undef</span><span class="cm">,</span> <span class="k">undef</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span><span class="sc">;</span> | 
|  | 243  230       <span class="s">}</span> | 
|  | 244  231       <span class="i">$ProcessingParenthesis</span> = <span class="n">1</span><span class="sc">;</span> | 
|  | 245  232       <span class="i">@SubFormulaElements</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 246  233       <span class="i">%SubFormulaElementsToCountMap</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 247  234       <span class="k">next</span> <span class="j">FORMULA</span><span class="sc">;</span> | 
|  | 248  235     <span class="s">}</span> | 
|  | 249  236     <span class="k">elsif</span> <span class="s">(</span><span class="i">$Spec</span> =~ <span class="q">/^(\)|\])/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 250  237       <span class="i">$ProcessingParenthesis</span> = <span class="n">0</span><span class="sc">;</span> | 
|  | 251  238 | 
|  | 252  239       <span class="c"># Retrieve repeat count and move data to @FormulaElements and %FormulaElementsToCountMap;</span> | 
|  | 253  240       <span class="k">my</span><span class="s">(</span><span class="i">$RepeatCount</span><span class="cm">,</span> <span class="i">$Symbol</span><span class="cm">,</span> <span class="i">$Count</span><span class="s">)</span><span class="sc">;</span> | 
|  | 254  241       <span class="i">$RepeatCount</span> = <span class="i">$Spec</span><span class="sc">;</span> | 
|  | 255  242       <span class="i">$RepeatCount</span> =~  <span class="q">s/(\)|\])//g</span><span class="sc">;</span> | 
|  | 256  243       <span class="k">if</span> <span class="s">(</span>!<span class="i">$RepeatCount</span><span class="s">)</span> <span class="s">{</span> | 
|  | 257  244         <span class="i">$RepeatCount</span> = <span class="n">1</span><span class="sc">;</span> | 
|  | 258  245       <span class="s">}</span> | 
|  | 259  246       <span class="c"># Copy data...</span> | 
|  | 260  247       <span class="k">for</span> <span class="i">$Symbol</span> <span class="s">(</span><span class="i">@SubFormulaElements</span><span class="s">)</span> <span class="s">{</span> | 
|  | 261  248         <span class="i">$Count</span> = <span class="i">$SubFormulaElementsToCountMap</span>{<span class="i">$Symbol</span>} * <span class="i">$RepeatCount</span><span class="sc">;</span> | 
|  | 262  249         <span class="i">_SetupFormulaElementData</span><span class="s">(</span>\<span class="i">@FormulaElements</span><span class="cm">,</span> \<span class="i">%FormulaElementsToCountMap</span><span class="cm">,</span> <span class="i">$Symbol</span><span class="cm">,</span> <span class="i">$Count</span><span class="s">)</span><span class="sc">;</span> | 
|  | 263  250       <span class="s">}</span> | 
|  | 264  251 | 
|  | 265  252       <span class="c"># Get ready again...</span> | 
|  | 266  253       <span class="i">@SubFormulaElements</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 267  254       <span class="i">%SubFormulaElementsToCountMap</span> = <span class="s">(</span><span class="s">)</span><span class="sc">;</span> | 
|  | 268  255 | 
|  | 269  256       <span class="k">next</span> <span class="j">FORMULA</span><span class="sc">;</span> | 
|  | 270  257     <span class="s">}</span> | 
|  | 271  258 | 
|  | 272  259     <span class="c"># Retrieve element symbol and count...</span> | 
|  | 273  260     <span class="i">$ElementSymbol</span> = <span class="s">(</span><span class="i">$Spec</span> && !<span class="i">$ElementSymbol</span><span class="s">)</span> ? <span class="i">$Spec</span> <span class="co">:</span> <span class="s">(</span><span class="i">$ElementSymbol</span> ? <span class="i">$ElementSymbol</span> <span class="co">:</span> <span class="q">''</span><span class="s">)</span><span class="sc">;</span> | 
|  | 274  261     <span class="i">$ElementCount</span> = <span class="i">$ElementCount</span> ? <span class="i">$ElementCount</span> <span class="co">:</span> <span class="n">1</span><span class="sc">;</span> | 
|  | 275  262     <span class="k">if</span> <span class="s">(</span>!<span class="i">PeriodicTable::IsElement</span><span class="s">(</span><span class="i">$ElementSymbol</span><span class="s">)</span><span class="s">)</span> <span class="s">{</span> | 
|  | 276  263       <span class="i">$ErrorMsg</span> = <span class="q">"Molecular formula contains unknown elemental symbol $ElementSymbol"</span><span class="sc">;</span> | 
|  | 277  264       <span class="k">return</span> <span class="s">(</span><span class="k">undef</span><span class="cm">,</span> <span class="k">undef</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span><span class="sc">;</span> | 
|  | 278  265     <span class="s">}</span> | 
|  | 279  266 | 
|  | 280  267     <span class="k">if</span> <span class="s">(</span><span class="i">$ProcessingParenthesis</span><span class="s">)</span> <span class="s">{</span> | 
|  | 281  268       <span class="i">_SetupFormulaElementData</span><span class="s">(</span>\<span class="i">@SubFormulaElements</span><span class="cm">,</span> \<span class="i">%SubFormulaElementsToCountMap</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="s">)</span><span class="sc">;</span> | 
|  | 282  269     <span class="s">}</span> | 
|  | 283  270     <span class="k">else</span> <span class="s">{</span> | 
|  | 284  271       <span class="i">_SetupFormulaElementData</span><span class="s">(</span>\<span class="i">@FormulaElements</span><span class="cm">,</span> \<span class="i">%FormulaElementsToCountMap</span><span class="cm">,</span> <span class="i">$ElementSymbol</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="s">)</span><span class="sc">;</span> | 
|  | 285  272     <span class="s">}</span> | 
|  | 286  273   <span class="s">}</span> | 
|  | 287  274 | 
|  | 288  275   <span class="c"># Setup element count array...</span> | 
|  | 289  276   <span class="k">for</span> <span class="i">$ElementSymbol</span> <span class="s">(</span><span class="i">@FormulaElements</span><span class="s">)</span> <span class="s">{</span> | 
|  | 290  277     <span class="i">$ElementCount</span> = <span class="i">$FormulaElementsToCountMap</span>{<span class="i">$ElementSymbol</span>}<span class="sc">;</span> | 
|  | 291  278     <span class="k">push</span> <span class="i">@ElementCount</span><span class="cm">,</span> <span class="i">$ElementCount</span><span class="sc">;</span> | 
|  | 292  279   <span class="s">}</span> | 
|  | 293  280 | 
|  | 294  281   <span class="c"># Make sure it all adds up to 100%; otherwise, adjust the last value..</span> | 
|  | 295  282 | 
|  | 296  283   <span class="k">return</span> <span class="s">(</span>\<span class="i">@FormulaElements</span><span class="cm">,</span> \<span class="i">@ElementCount</span><span class="cm">,</span> <span class="i">$ErrorMsg</span><span class="s">)</span><span class="sc">;</span> | 
|  | 297  284 <span class="s">}</span> | 
|  | 298  285 | 
|  | 299  286 <span class="c"># Clean it up...</span> | 
|  | 300 <a name="_CleanUpFormula-"></a> 287 <span class="k">sub </span><span class="m">_CleanUpFormula</span> <span class="s">{</span> | 
|  | 301  288   <span class="k">my</span><span class="s">(</span><span class="i">$MolecularFormula</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 302  289   <span class="c">#Take out any spaces...</span> | 
|  | 303  290   <span class="i">$MolecularFormula</span> =~ <span class="q">s/ //g</span><span class="sc">;</span> | 
|  | 304  291 | 
|  | 305  292   <span class="c"># Eliminate any charge specifications: +, - or [1-9]+[+-]</span> | 
|  | 306  293   <span class="c"># e.g NO+ [Al(H2O)6]3+ [H2NO3]+</span> | 
|  | 307  294   <span class="k">if</span> <span class="s">(</span><span class="i">$MolecularFormula</span> =~ <span class="q">/[\+\-]/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 308  295     <span class="k">if</span> <span class="s">(</span><span class="i">$MolecularFormula</span> =~ <span class="q">/\][0-9]+[\+\-]/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 309  296       <span class="c"># Bracket followed optionally by number and then, +/- ...</span> | 
|  | 310  297       <span class="c"># [Al(H2O)6]3+ ...</span> | 
|  | 311  298       <span class="i">$MolecularFormula</span> =~ <span class="q">s/\][0-9]+[\+\-]/\]/g</span><span class="sc">;</span> | 
|  | 312  299     <span class="s">}</span> | 
|  | 313  300     <span class="k">elsif</span> <span class="s">(</span><span class="i">$MolecularFormula</span> =~ <span class="q">/[\+\-][0-9]*/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 314  301       <span class="c"># +/- followed optionally by a number...</span> | 
|  | 315  302       <span class="c"># C37H42N2O6+2, Cu+</span> | 
|  | 316  303       <span class="i">$MolecularFormula</span> =~ <span class="q">s/[\+\-][0-9]*//g</span><span class="sc">;</span> | 
|  | 317  304     <span class="s">}</span> | 
|  | 318  305   <span class="s">}</span> | 
|  | 319  306 | 
|  | 320  307   <span class="c"># Eliminate any brackets - ] or ) - not followed by numbers:</span> | 
|  | 321  308   <span class="c"># e.g. Li[H2PO4]</span> | 
|  | 322  309   <span class="k">if</span> <span class="s">(</span><span class="i">$MolecularFormula</span> !~ <span class="q">/\][0-9]+/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 323  310     <span class="i">$MolecularFormula</span> =~ <span class="q">s/[\[\]]//g</span><span class="sc">;</span> | 
|  | 324  311   <span class="s">}</span> | 
|  | 325  312   <span class="k">if</span> <span class="s">(</span><span class="i">$MolecularFormula</span> !~ <span class="q">/\)[0-9]+/</span><span class="s">)</span> <span class="s">{</span> | 
|  | 326  313     <span class="i">$MolecularFormula</span> =~ <span class="q">s/[\(\)]//g</span><span class="sc">;</span> | 
|  | 327  314   <span class="s">}</span> | 
|  | 328  315   <span class="c"># Change adducts to parenthesis format...</span> | 
|  | 329  316   <span class="c"># Na2CO3.10H2O -> Na2CO3(H2O)10</span> | 
|  | 330  317   <span class="c"># 3CdSO4.8H2O -> (CdSO4)3(H2O)8</span> | 
|  | 331  318   <span class="k">if</span> <span class="s">(</span><span class="i">$MolecularFormula</span> =~ <span class="q">/\./</span><span class="s">)</span> <span class="s">{</span> | 
|  | 332  319     <span class="k">my</span><span class="s">(</span><span class="i">$SubFormula</span><span class="cm">,</span> <span class="i">$Count</span><span class="cm">,</span> <span class="i">$Spec</span><span class="s">)</span><span class="sc">;</span> | 
|  | 333  320     <span class="k">my</span><span class="s">(</span><span class="i">@MolecularFormulaSplits</span><span class="s">)</span> = <span class="k">split</span> <span class="q">/\./</span><span class="cm">,</span> <span class="i">$MolecularFormula</span><span class="sc">;</span> | 
|  | 334  321     <span class="i">$MolecularFormula</span> = <span class="q">''</span><span class="sc">;</span> | 
|  | 335  322     <span class="k">for</span> <span class="i">$SubFormula</span> <span class="s">(</span><span class="i">@MolecularFormulaSplits</span><span class="s">)</span> <span class="s">{</span> | 
|  | 336  323       <span class="s">(</span><span class="i">$Count</span><span class="cm">,</span> <span class="i">$Spec</span><span class="s">)</span> = <span class="i">$SubFormula</span> =~ <span class="q">/^([0-9]*)(.*?)$/</span><span class="sc">;</span> | 
|  | 337  324       <span class="k">if</span> <span class="s">(</span><span class="i">$Count</span><span class="s">)</span> <span class="s">{</span> | 
|  | 338  325         <span class="i">$MolecularFormula</span> .= <span class="q">"(${Spec})${Count}"</span><span class="sc">;</span> | 
|  | 339  326       <span class="s">}</span> | 
|  | 340  327       <span class="k">else</span> <span class="s">{</span> | 
|  | 341  328         <span class="i">$MolecularFormula</span> .= <span class="i">$Spec</span><span class="sc">;</span> | 
|  | 342  329       <span class="s">}</span> | 
|  | 343  330     <span class="s">}</span> | 
|  | 344  331   <span class="s">}</span> | 
|  | 345  332 | 
|  | 346  333   <span class="k">return</span> <span class="i">$MolecularFormula</span><span class="sc">;</span> | 
|  | 347  334 <span class="s">}</span> | 
|  | 348  335 | 
|  | 349  336 <span class="c"># Store the element and count...</span> | 
|  | 350 <a name="_SetupFormulaElementData-"></a> 337 <span class="k">sub </span><span class="m">_SetupFormulaElementData</span> <span class="s">{</span> | 
|  | 351  338   <span class="k">my</span><span class="s">(</span><span class="i">$ElementsRef</span><span class="cm">,</span> <span class="i">$ElementsToCountMapRef</span><span class="cm">,</span> <span class="i">$Element</span><span class="cm">,</span> <span class="i">$Count</span><span class="s">)</span> = <span class="i">@_</span><span class="sc">;</span> | 
|  | 352  339 | 
|  | 353  340   <span class="k">if</span> <span class="s">(</span><span class="k">exists</span> <span class="i">$ElementsToCountMapRef</span>->{<span class="i">$Element</span>}<span class="s">)</span> <span class="s">{</span> | 
|  | 354  341     <span class="i">$ElementsToCountMapRef</span>->{<span class="i">$Element</span>} += <span class="i">$Count</span><span class="sc">;</span> | 
|  | 355  342   <span class="s">}</span> | 
|  | 356  343   <span class="k">else</span> <span class="s">{</span> | 
|  | 357  344     <span class="k">push</span> <span class="i">@</span>{<span class="i">$ElementsRef</span>}<span class="cm">,</span> <span class="i">$Element</span><span class="sc">;</span> | 
|  | 358  345     <span class="i">$ElementsToCountMapRef</span>->{<span class="i">$Element</span>} = <span class="i">$Count</span><span class="sc">;</span> | 
|  | 359  346   <span class="s">}</span> | 
|  | 360  347 <span class="s">}</span> | 
|  | 361  348 | 
|  | 362 <a name="EOF-"></a></pre> | 
|  | 363 <p> </p> | 
|  | 364 <br /> | 
|  | 365 <center> | 
|  | 366 <img src="../../../images/h2o2.png"> | 
|  | 367 </center> | 
|  | 368 </body> | 
|  | 369 </html> |