.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Chemistry::Formula 3pm" .TH Chemistry::Formula 3pm "2021-01-07" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Chemistry::Formula \- Enumerate elements in a chemical formula .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use Chemistry::Formula qw(parse_formula); \& parse_formula(\*(AqPb (H (TiO3)2 )2 U [(H2O)3]2\*(Aq, \e%count); .Ve .PP That is obviously not a real compound, but it demonstrates the capabilities of the routine. This returns .PP .Vb 7 \& %count = ( \& \*(AqO\*(Aq => 18, \& \*(AqH\*(Aq => 14, \& \*(AqTi\*(Aq => 4, \& \*(AqU\*(Aq => 1, \& \*(AqPb\*(Aq => 1 \& ); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This module provides a function which parses a string containing a chemical formula and returns the number of each element in the string. It can handle nested parentheses and square brackets and correctly computes stoichiometry given numbers outside the (possibly nested) parentheses. .PP No effort is made to evaluate the chemical plausibility of the formula. The example above parses just fine using this module, even though it is clearly not a viable compound. Charge balancing, bond valence, and so on is beyond the scope of this module. .PP Only one function is exported, \f(CW\*(C`parse_formula\*(C'\fR. This takes a string and a hash reference as its arguments and returns 0 or 1. .PP .Vb 1 \& $ok = parse_formula(\*(AqPbTiO3\*(Aq, \e%count); .Ve .PP If the formula was parsed without trouble, \f(CW\*(C`parse_formula\*(C'\fR returns 1. If there was any problem, it returns 0 and \f(CW$count\fR{error} is filled with a string describing the problem. It throws an error afer the \&\fBfirst\fR error encountered without testing the rest of the string. .PP If the formula was parsed correctly, the \f(CW%count\fR hash contains element symbols as its keys and the number of each element as its values. .PP Here is an example of a program that reads a string from the command line and, for the formula unit described in the string, writes the weight and absorption in barns. .PP .Vb 3 \& use Data::Dumper; \& use Xray::Absorption; \& use Chemistry::Formula qw(parse_formula); \& \& parse_formula($ARGV[0], \e%count); \& \& print Data::Dumper\->Dump([\e%count], [qw(*count)]); \& my ($weight, $barns) = (0,0); \& foreach my $k (keys(%$count)) { \& $weight += \& Xray::Absorption \-> get_atomic_weight($k) * $count{$k}; \& $barns += \& Xray::Absorption \-> cross_section($k, 9000) * $count{$k}; \& }; \& printf "This weighs %.3f amu and absorbs %.3f barns at 9 keV.\en", \& $weight, $barns; .Ve .PP Pretty simple. .PP The parser is not brilliant. Here are the ground rules: .IP "1." 4 Element symbols must be first letter capitalized. .IP "2." 4 Whitespace is unimportant \*(-- it will be removed from the string. So will dollar signs, underscores, and curly braces (in an attempt to handle TeX). Also a sequence like this: '/sub 3/' will be converted to '3' (in an attempt to handle \s-1INSPEC\s0). .IP "3." 4 Numbers can be integers or floating point numbers. Things like 5, 0.5, 12.87, and .5 are all acceptible, as is exponential notation like 1e\-2. Note that exponential notation must use a leading number to avoid confusion with element symbols. That is, 1e\-2 is ok, but e\-2 is not. .IP "4." 4 Uncapitalized symbols or unrecognized symbols will flag an error. .IP "5." 4 An error will be flagged if the number of open parens is different from the number of close parens. .IP "6." 4 An error will be flagged if any unusual symbols are found in the string. .SH "ACKNOWLEDGMENTS" .IX Header "ACKNOWLEDGMENTS" This was written at the suggestion of Matt Newville, who tested early versions. .PP The routine \f(CW\*(C`matchingbrace\*(C'\fR was swiped from the C::Scan module, which can be found on \s-1CPAN.\s0 C::Scan is maintained by Hugo van der Sanden. .SH "AUTHOR" .IX Header "AUTHOR" Bruce Ravel .PP http://cars9.uchicago.edu/~ravel/software/ .PP \&\s-1SVN\s0 repository: http://cars9.uchicago.edu/svn/libperlxray/