Formula/0000755000175000017500000000000011615063333011460 5ustar segresegreFormula/t/0000755000175000017500000000000011615063333011723 5ustar segresegreFormula/t/stub.t0000644000175000017500000000022511043203346013057 0ustar segresegre#! /usr/bin/perl -w BEGIN { $| = 1; print "1..1$/"; } END {print "not ok 1$/" unless $loaded;} use Chemistry::Formula; $loaded = 1; print "ok 1$/"; Formula/lib/0000755000175000017500000000000011153431232012220 5ustar segresegreFormula/lib/Chemistry/0000755000175000017500000000000011615063333014175 5ustar segresegreFormula/lib/Chemistry/Formula.pm0000644000175000017500000003130211370625157016145 0ustar segresegre###################################################################### ## This module is copyright (c) 2001-2010 Bruce Ravel ## ## http://cars9.uchicago.edu/~ravel/software ## http://cars9.uchicago.edu/svn/libperlxray ## ## ------------------------------------------------------------------- ## All rights reserved. This program is free software; you can ## redistribute it and/or modify it under the same terms as Perl ## itself. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## Artistic License for more details. ## ------------------------------------------------------------------- ###################################################################### ## Code: package Chemistry::Formula; require Exporter; @ISA = qw(Exporter); @EXPORT = qw(parse_formula); @EXPORT_OK = qw(formula_data); use strict; use warnings; use version; use Regexp::Common; use Readonly; use File::Spec; #use Ifeffit::FindFile; use vars qw(@ISA $VERSION $install_dir); $VERSION = version->new("3.0.1"); $install_dir = &identify_self; Readonly my $NUMBER => $RE{num}{real}; my $is_windows = (($^O eq 'MSWin32') or ($^O eq 'cygwin')); my $elem_match = '([BCFHIKNOPSUVWY]|A[cglrstu]|B[aeir]|C[adelorsu]|Dy|E[ru]|F[er]|G[ade]|H[efgo]|I[nr]|Kr|L[aiu]|M[gno]|N[abdeip]|Os|P[abdmortu]|R[abehnu]|S[bceimnr]|T[abcehilm]|Xe|Yb|Z[nr])'; #my $num_match = '\d+\.?\d*|\.\d+'; my $debug = 0; my ($ok, $count); =for Explanation: (parse_formula) input: string and reference to a hash return: 1 if string was parsed, 0 if an error was encountered this throws an error after the *first* error encountered . To pre-process the string: (1) remove spaces and underscores -- also remove $ and curly braces in an attempt to deal with TeX, (2) translate square braces to parens, (3) remove /sub #/ in an attempt to deal with INSPEC (4) count number of open and close parens =cut sub parse_formula { my $in = $_[0]; $count = $_[1]; $ok = 1; ## string preprocessing: $in =~ s{[ \t_\$\{\}]+}{}g; # (1) $in =~ tr{[]}{()}; # (2) $in =~ s{/sub(\d+)/}{$1}g; # (3), note that spaces have already # been removed my @chars = split(//, $in); # my $open = grep /\(/g, @chars; # (4) my $close = grep /\)/g, @chars; # if ($open != $close) { $$count{error} = "$open opening and $close closing parentheses.\n"; return 0; } else { &parse_segment($in, 1); # this fills the %count hash ## &normalize_count; return $ok; }; }; =for Explanation: (parse_segment) This works by recursion. Pluck off the first segment of the string, interpret that segment, and pass the rest of the string to this routine for further processing. . So, for Pb(TiO3)2, interpret Pb and recurse (TiO3)2. Then recurse TiO3 with a multiplier of 2. =cut sub parse_segment { my ($in, $mult) = @_; return unless $ok; return if ($in =~ /^\s*$/); printf(":parse_segment: \"%s\" with multiplier %d\n", $in, $mult) if ($debug); my ($end, $scale) = (0, 1); $end = ($in =~ /\(/g) ? pos($in) : length($in)+1; # look for next open paren if ($end > 1) { unit(substr($in, 0, $end-1), $mult); --$end; } else { matchingbrace($in); $end = pos($in); if (substr($in, $end) =~ /^($NUMBER)/o) { # handle number outside parens $scale = $1; $end += length($1); pos($in) = $end; parse_segment(substr($in, 1, $end-2-length($1)), $mult*$scale); } else { parse_segment(substr($in, 1, $end-2), $mult*$scale); }; }; return unless $ok; # parse remaining bit after last paren ($end < length($in)) and parse_segment(substr($in, $end), $mult); }; ## interpret an unparenthesized segment sub unit { my ($string, $multiplier) = @_; while ($string) { print ":unit: ", $string, $/ if ($debug); if ($string =~ /^([A-Z][a-z]?)/) { my $el = $1; unless ($el =~ /^($elem_match)$/o) { $$count{error} = "\"$el\" is not a valid element symbol\n"; print ":unit: ", $$count{error}, $/ if ($debug); $ok = 0; return; }; $string = substr($string, length($el)); if ($string =~ /^($NUMBER)/o) { $$count{$el} += $1*$multiplier; $string = substr($string, length($1)); } else { $$count{$el} += $multiplier; }; } else { $$count{error} = "\"$string\" begins with something that is not an element symbol\n"; $$count{error} .= "\telements must be first letter capitalized\n"; print ":unit: ", $$count{error}, $/ if ($debug); $ok = 0; return; }; }; }; ## Swiped from C::Scan, found on CPAN, and written (I think) by ## Hugo van der Sanden (hv@crypt0.demon.co.uk) sub matchingbrace { # pos($_[0]) is after the opening brace now my $n = 0; while ($_[0] =~ /([\{\[\(])|([\]\)\}])/g) { $1 ? $n++ : $n-- ; return 1 if $n < 0; } # pos($_[0]) is after the closing brace now return; # false } ## ## sub normalize_count { ## my $sum = 0; ## map { $sum += $$count{$_} } (keys %$count); ## map { $$count{$_} /= $sum } (keys %$count); ## }; sub identify_self { my @caller = caller; use File::Basename qw(dirname); return dirname($caller[1]); }; sub formula_data { my ($formula, $density) = @_; #my $datafile = ($is_windows) ? # Ifeffit::FindFile->find("other", "formula_dat") : # File::Spec -> catfile($install_dir, "Formula", "formula.dat"); #open FORMULA, $datafile or die "could not open $datafile for reading: $!\n"; while () { next if (/^\s*$/); next if (/^\s*\#/); chomp; my @list = (split(/\|/, $_)); foreach (0..2) { $list[$_] =~ s/^\s+//; $list[$_] =~ s/\s+$//; }; $$formula{$list[0]} = $list[1]; $$density{$list[0]} = $list[2]; }; #close FORMULA; }; =head1 NAME Chemistry::Formula - Enumerate elements in a chemical formula =head1 SYNOPSIS use Chemistry::Formula qw(parse_formula); parse_formula('Pb (H (TiO3)2 )2 U [(H2O)3]2', \%count); That is obviously not a real compound, but it demonstrates the capabilities of the routine. This returns %count = ( 'O' => 18, 'H' => 14, 'Ti' => 4, 'U' => 1, 'Pb' => 1 ); =head1 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. 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. Only one function is exported, C. This takes a string and a hash reference as its arguments and returns 0 or 1. $ok = parse_formula('PbTiO3', \%count); If the formula was parsed without trouble, C returns 1. If there was any problem, it returns 0 and $count{error} is filled with a string describing the problem. It throws an error afer the B error encountered without testing the rest of the string. If the formula was parsed correctly, the %count hash contains element symbols as its keys and the number of each element as its values. 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. use Data::Dumper; use Xray::Absorption; use Chemistry::Formula qw(parse_formula); parse_formula($ARGV[0], \%count); print Data::Dumper->Dump([\%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.\n", $weight, $barns; Pretty simple. The parser is not brilliant. Here are the ground rules: =over 4 =item 1. Element symbols must be first letter capitalized. =item 2. 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 INSPEC). =item 3. 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. =item 4. Uncapitalized symbols or unrecognized symbols will flag an error. =item 5. An error will be flagged if the number of open parens is different from the number of close parens. =item 6. An error will be flagged if any unusual symbols are found in the string. =back =head1 ACKNOWLEDGMENTS This was written at the suggestion of Matt Newville, who tested early versions. The routine C was swiped from the C::Scan module, which can be found on CPAN. C::Scan is maintained by Hugo van der Sanden. =head1 AUTHOR Bruce Ravel http://cars9.uchicago.edu/~ravel/software/ SVN repository: http://cars9.uchicago.edu/svn/libperlxray/ =cut 1; __DATA__ ###################################################################### ## ## This file contains formula and density data used by ## Chemistry::Formula. Please feel free to add to this file and to ## contribute your additions back to the author: ## Bruce Ravel ## ## http://feff.phys.washington.edu/~ravel/atoms/ ## ###################################################################### ## ## This file is a very simple database. (1) Blank lines or lines ## beginning with a hash (#) are ignored. (2) Entries contain three ## fields, separated by a vertical bar (|). The first field is the ## common name of the material. The second field is the chemical ## formula, written according to the rules of Chemistry::Formula. The ## third field is the density of the material. ## ## The materials chosen in this file are materials of interest to the ## synchrotron scientist. ## ## Many of these materials were swiped from a list provided by Erik ## Gullikson at Berkeley's center for X-Ray Optics. ## # Name | Formula | Density (g/cm^3) Water | H2O | 1 Lead | Pb | 11.34 Aluminum | Al | 2.72 Kapton | C22 H10 O4 N2 | 1.42 Lead Titanate | PbTiO3 | 8.06 Nitrogen | N | 0.00125 Argon | Ar | 0.001784 Helium | He | 0.00009 Neon | Ne | 0.000905 Krypton | Kr | 0.00374 Xenon | Xe | 0.00588 Air | (N2)0.78 (O2)0.21 (CO2)0.03 Ar0.01 Kr0.000001 Xe0.0000009 | 0.0013 Carbon (Diamond) | C | 3.51 Carbon (Graphite) | C | 2.25 Boron Nitride | BN | 2.29 YAG | Y3 Al5 O12 | 4.56 ## swiped from Gullikson Sapphire | Al2O3 | 3.97 Polymide | C22 H10 N2 O5 | 1.43 Polypropylene | C3H6 | 0.90 PMMA | C5 H8 O2 | 1.19 Polycarbonate | C16 H14 O3 | 1.2 Kimol | C16 H14 O3 | 1.2 Mylar | C10 H8 O4 | 1.4 Teflon | C2F4 | 2.2 Parylene-C | C8 H7 Cl | 1.29 Parylene-N | C8H8 | 1.11 Fluorite | CaF2 | 3.18 Mica | K Al3 Si3 O12 H2 | 2.83 Salt | NaCl | 2.165 SiO2 (Silica) | SiO2 | 2.2 SiO2 (Quartz) | SiO2 | 2.65 Rutile | TiO2 | 4.26 ULE | Si0.925 Ti0.075 O2 | 2.205 Zerodur | Si0.56 Al0.5 P0.16 Li0.04 Ti0.02 Zr0.02 Zn0.03 O2.46 | 2.53 ## metals Beryllium | Be | 1.85 Copper | Cu | 8.94 Molybdenum | Mo | 10.22 Iron | Fe | 7.86 Zinc | Zn | 7.14 Silicon | Si | 2.33 Gold | Au | 19.37 Silver | Ag | 10.5 Platinum | Pt | 21.37 Tungsten | W | 19.3 Tantalum | Ta | 16.6 ## solvents Alcohol (Ethyl) | C2H5OH | 0.789 Acetone | C3H6O | 0.790 Alcohol (Methyl) | CH3OH | 0.792 Alcohol (Propyl) | C3H8O | 0.804 Toluene | C7H8 | 0.867 Xylene | C6H4(CH3)2 | 0.844 Formula/data/0000755000175000017500000000000011615063333012371 5ustar segresegreFormula/data/formula.dat0000644000175000017500000000647611300143016014531 0ustar segresegre###################################################################### ## ## This file contains formula and density data used by ## Chemistry::Formula. Please feel free to add to this file and to ## contribute your additions back to the author: ## Bruce Ravel ## ## http://feff.phys.washington.edu/~ravel/atoms/ ## ###################################################################### ## ## This file is a very simple database. (1) Blank lines or lines ## beginning with a hash (#) are ignored. (2) Entries contain three ## fields, separated by a vertical bar (|). The first field is the ## common name of the material. The second field is the chemical ## formula, written according to the rules of Chemistry::Formula. The ## third field is the density of the material. ## ## The materials chosen in this file are materials of interest to the ## synchrotron scientist. ## ## Many of these materials were swiped from a list provided by Erik ## Gullikson at Berkeley's center for X-Ray Optics. ## # Name | Formula | Density (g/cm^3) Water | H2O | 1 Lead | Pb | 11.34 Aluminum | Al | 2.72 Kapton | C22 H10 O4 N2 | 1.42 Lead Titanate | PbTiO3 | 8.06 Nitrogen | N | 0.00125 Argon | Ar | 0.001784 Helium | He | 0.00009 Neon | Ne | 0.000905 Krypton | Kr | 0.00374 Xenon | Xe | 0.00588 Air | (N2)0.78 (O2)0.21 (CO2)0.03 Ar0.01 Kr0.000001 Xe0.0000009 | 0.0013 Carbon (Diamond) | C | 3.51 Carbon (Graphite) | C | 2.25 Boron Nitride | BN | 2.29 YAG | Y3 Al5 O12 | 4.56 ## swiped from Gullikson Sapphire | Al2O3 | 3.97 Polymide | C22 H10 N2 O5 | 1.43 Polypropylene | C3H6 | 0.90 PMMA | C5 H8 O2 | 1.19 Polycarbonate | C16 H14 O3 | 1.2 Kimol | C16 H14 O3 | 1.2 Mylar | C10 H8 O4 | 1.4 Teflon | C2F4 | 2.2 Parylene-C | C8 H7 Cl | 1.29 Parylene-N | C8H8 | 1.11 Fluorite | CaF2 | 3.18 Mica | K Al3 Si3 O12 H2 | 2.83 Salt | NaCl | 2.165 SiO2 (Silica) | SiO2 | 2.2 SiO2 (Quartz) | SiO2 | 2.65 Rutile | TiO2 | 4.26 ULE | Si0.925 Ti0.075 O2 | 2.205 Zerodur | Si0.56 Al0.5 P0.16 Li0.04 Ti0.02 Zr0.02 Zn0.03 O2.46 | 2.53 ## metals Beryllium | Be | 1.85 Copper | Cu | 8.94 Molybdenum | Mo | 10.22 Iron | Fe | 7.86 Zinc | Zn | 7.14 Silicon | Si | 2.33 Gold | Au | 19.37 Silver | Ag | 10.5 Platinum | Pt | 21.37 Tungsten | W | 19.3 Tantalum | Ta | 16.6 ## solvents Alcohol (Ethyl) | C2O5OH | 0.789 Acetone | C3H6O | 0.790 Alcohol (Methyl) | CH3OH | 0.792 Alcohol (Propyl) | C3H8O | 0.804 Toluene | C7H8 | 0.867 Xylene | C6H4(CH3)2 | 0.844 Formula/INSTALL0000644000175000017500000000117510734535007012520 0ustar segresegreQuick installation instructions for Chemistry::Formula Do these three steps at the command line: perl Build.PL ./Build sudo ./Build install If you are on a system that uses root, you should become root before doing the last step, then simply type ./Build install The first step will warn you if you have any missing dependencies. If you obtained this from the SVN repository, then you will find a script called "install_prereqs" in the directory above this one. Running it will install all the missing pre-requisites, including the Module::Build, which is used to build and install this module. BR (26 December, 2007)Formula/MANIFEST0000644000175000017500000000022511370625157012616 0ustar segresegreBuild.PL data/formula.dat examples/formula.cgi examples/formula_noabs INSTALL lib/Chemistry/Formula.pm MANIFEST This list of files README META.yml Formula/examples/0000755000175000017500000000000011615063333013276 5ustar segresegreFormula/examples/formula_noabs0000755000175000017500000000342110730036577016062 0ustar segresegre#!/usr/bin/perl -w ###################################################################### ## This program is copyright (c) 2002 Bruce Ravel ## ## http://feff.phys.washington.edu/~ravel/ ## ## ------------------------------------------------------------------- ## All rights reserved. This program is free software; you can ## redistribute it and/or modify it under the same terms as Perl ## itself. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## Artistic License for more details. ## ------------------------------------------------------------------- ###################################################################### ## Code: ## Very simple interface to Chemistry::Formula use Chemistry::Formula qw(parse_formula); use strict; (@ARGV) or &usage; ($ARGV[0] =~ /-{1,2}h(elp)?/i) and &usage; my (%count, $string); $string = $ARGV[0]; my $ok = parse_formula($string, \%count); ($ok) or do { print "Input error:\n\t$count{error}"; die "\n"; }; print < 0.001) { printf(" %-2s %.3f\n", $k, $count{$k}); } else { printf(" %-2s %g\n", $k, $count{$k}); }; }; sub usage { print < can be any reasonable chemical formula as expressed in ASCII, in latex, or by INSPEC. Thus parens and square brackets can be used for groupings. All element symbols must be capitalized (i.e. first letter capital and second letter lower case). EOH exit; }; Formula/examples/formula.cgi0000755000175000017500000001743010730036577015446 0ustar segresegre#!/usr/bin/perl ###################################################################### ## Time-stamp: my $cvs_info = '$Id:$ '; ###################################################################### ## This program is copyright (c) 2001 Bruce Ravel ## ## http://feff.phys.washington.edu/~ravel/ ## ## ------------------------------------------------------------------- ## All rights reserved. This program is free software; you can ## redistribute it and/or modify it under the same terms as Perl ## itself. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## Artistic License for more details. ## ------------------------------------------------------------------- ###################################################################### BEGIN { my $extra_INC = # Set this if you have Atoms installed "/home/bruce/perl"; # outside of Perl's normal search path ($extra_INC) and unshift @INC, $extra_INC; } use strict; use constant PI => 4 * atan2 1, 1; use constant HBARC => 1973.27053324; use Chemistry::Formula qw(parse_formula formula_data); use Xray::Absorption; Xray::Absorption -> load("Elam"); use CGI; # load CGI routines use CGI::Carp 'fatalsToBrowser'; $CGI::POST_MAX=1024 * 1000; # max 1M posts my $q = new CGI; # create new CGI object my $version = (split(' ', $cvs_info))[2] || "0.04"; my $date = (split(' ', $cvs_info))[3] || "14 May 2002"; my $bruce_home = "http://feff.phys.washington.edu/~ravel/"; my $formula_url = $bruce_home . "software/Formula/"; my $absorption_url = $bruce_home . "software/Absorption/"; my (%formula, %density); &formula_data(\%formula, \%density); my @formulas = sort (keys %formula); unshift @formulas, ""; my $answer = ""; my $run = 1; my $table_row = {qw(align CENTER valign CENTER)}; my $table_params = {qw(border 1 cellspacing 0 cellpadding 5 align CENTER width 85% bgcolor white)}; my $table_top = {qw(align center bgcolor #000077)}; my $table_top_span = {qw(align center bgcolor #000077 colspan 3)}; my $params; if ($q->param('debug')) { foreach my $key ($q->param) { $params .= $q->b("$key -> ") . $q->param($key) . $q->br; }; }; if ($q->param('special')) { $q->param(formula=>$formula{$q->param('special')}); $q->param(density=>$density{$q->param('special')}); #$q->param(special=>""); }; ($q->param('formula')) and &parse_it; #($q->param('formula'), \%count); print $q->header, # create the HTTP header $q->start_html(-title=>'Absorption of X-rays by Materials', -bgcolor=>'white', -meta=>{'copyright'=>'copyright 2001-2002 Bruce Ravel'} ), $q->h1({align=>'CENTER'}, 'Absorption of X-rays by Materials'); print $q->p({align=>"center"}, "This page will compute the absorption length. i.e. the thickness which will attenuate the x-ray beam e-fold, of a material at a given energy given the chemical formula and density of that material."), $q->p({align=>"center"}, "Specify a chemical formula and supply the density" . $q->br . "OR" . $q->br . "Select a material from the list of materials commonly found at a synchrotron") , $q->startform(), ## data entry table $q->table($table_params, $q->Tr($table_row, $q->td($table_top_span, $q->font({-color=>"white"}, $q->strong($q->font({size=>'+1'}, "Data entry"))), )), $q->Tr($table_row, $q->td( $q->strong("Formula: ") . $q->textfield(-name=>'formula', -size=>50, -default=>"") . $q->p . $q->strong("Density: ") . $q->textfield(-name=>'density', -size=>10, -default=>"")), $q->td($q->strong($q->font({color=>"#990099", size=>'+2'},"OR"))), $q->td( $q->strong("Known Compounds: ") . $q -> br . $q->popup_menu(-name=>'special', -default=>"", -values=>[@formulas]))), $q->Tr($table_row, $q->td({colspan=>3}, $q->strong("Photon Energy: ") . $q->textfield(-name=>'energy', -size=>6, -default=>9000) . ' ' . $q->popup_menu(-name=>'units', -default=>"eV", -values=>[qw(eV keV Angstrom)]) . '     ' . $q->submit(-name=>'Compute', -value=>'Compute') . '     ' . $q->defaults(-name=>'Reset', -value=>'Reset') ), ), ), $q->p(); ($answer) and print ## results of calculation $q->table($table_params, $q->Tr($table_row, $q->td($table_top, $q->font({-color=>"white"}, $q->strong($q->font({size=>'+1'},"Results"))), )), (($params) ? $q->Tr($table_row, $q->td([$params])) : ()), $q->Tr($table_row, $q->td([$answer])), ); print $q->endform, ## bottom of page $q->hr(), $q->p("This web page isn't the most brilliant bit of programming. If you want to specify your own compound and density, you need to select the blank item from the list of known compounds."), $q->hr(), $q->p({-align=>'right'}, $q->small("formula.cgi version $version ($date), copyright © 2001-2002 Bruce Ravel")), $q->p({-align=>'right'}, $q->small("This cgi script uses the " . $q->a({href=>$formula_url}, "Chemistry::Formula") . " and " . $q->a({href=>$absorption_url}, "Xray::Absorption") . " perl modules.")), $q->p({-align=>'right'}, $q->small($q->a({href=>$bruce_home}, "Bruce's homepage"))), $q->end_html, $/; # end the HTML ## parse formula and compute absorption. Load results into $answer. sub parse_it { my %count; unless ($q->param('formula')) { $answer = $q->pre("No formula given.\n"); return; }; my $ok = parse_formula($q->param('formula'), \%count); my $energy = $q->param('energy'); ($q->param("units") eq "keV") and ($energy *= 1000); ($q->param("units") eq "Angstrom") and ($energy = 2*PI*HBARC / $energy); if ($ok) { #my ($weight, $xsec) = (0,0); my $dens = ($q->param('density') =~ /^(\d+\.?\d*|\.\d+)$/) ? $q->param('density') : 0; my @list; my ($barns_per_formula_unit, $amu_per_formula_unit) = (0,0); foreach my $k (sort (keys(%count))) { if ($count{$k} > 0.001) { push @list, $q->td({-align=>'center'}, [$k, sprintf("%6.3f", $count{$k})]); } else { push @list, $q->td({-align=>'center'}, [$k, sprintf("%6g", $count{$k})]); }; ## $weight += Xray::Absorption -> get_atomic_weight($k) * $count{$k}; $barns_per_formula_unit += Xray::Absorption -> cross_section($k, $energy) * $count{$k}; $amu_per_formula_unit += Xray::Absorption -> get_atomic_weight($k) * $count{$k}; ## my $scale = ($q->param('density')) ## ? Xray::Absorption -> get_conversion($k) : 1; ## $xsec += ## Xray::Absorption -> ## cross_section($k, $energy) * $count{$k} / $scale; }; ## 1 amu = 1.6607143 x 10^-24 gm $xsec = $barns_per_formula_unit / $amu_per_formula_unit / 1.6607143; if ($xsec == 0) { $answer .= $q->p("The energy is too low or was not provided. The absorption calculation was skipped."); } else { $xsec *= $dens; if ($xsec > 0) { my $length = (10000/$xsec > 500) ? sprintf("%.3f cm", 1/$xsec) : sprintf("%.1f micron", 10000/$xsec); $answer .= $q->p("One absorbtion length is approximately " . $q->strong($q->font({color=>"red"}, $length)) . " at " . sprintf("%.2f eV", $energy)); } else { $answer .= $q->p("The absorption length calculation\nrequires a value for density."); }; }; $answer .= $q->table($q->th(["element", "number"]), $q->Tr(\@list) ); ## $answer .= $q->p(sprintf("This weighs %.3f amu per formula ## unit.", $weight)); } else { $answer = "\Input error: ".$count{error}; }; }; Formula/Build.PL0000644000175000017500000000221511300251542012744 0ustar segresegreuse strict; use warnings; use Module::Build; # my $class = Module::Build->subclass( # class => "My::Builder", # code => q{ # sub ACTION_ppd { # my $self = shift; # $self->SUPER::ACTION_ppd; # open O, '>__temp__'; # open I, 'Chemistry-Formula.ppd'; # while () { # $_ =~ s{File-Spec}{PathTools}; # print O $_; # }; # close I; # close O; # rename '__temp__', 'Chemistry-Formula.ppd'; # }; # }, # ); my $build = Module::Build -> new( create_readme => 1, ##create_makefile_pl => 'traditional', license => 'perl', module_name => 'Chemistry::Formula', dist_author => 'Bruce Ravel', requires => { 'Chemistry::Elements' => 0, 'File::Spec' => 0, #'Test::More' => 0, 'Regexp::Common' => 0, Readonly => 0, version => 0, }, #dat_files => { # 'data/formula.dat' => 'lib/Chemistry/Formula/formula.dat', # }, recommends => {}, sign => 0, ); #$build->add_build_element('dat'); $build->create_build_script; Formula/MANIFEST.SKIP0000644000175000017500000000112211370625157013360 0ustar segresegre# Avoid version control files. \bRCS\b \bCVS\b ,v$ \B\.svn\b \B\.cvsignore$ # Avoid Makemaker generated and utility files. \bMakefile$ \bblib \bMakeMaker-\d \bpm_to_blib$ \bblibdirs$ ^MANIFEST\.SKIP$ # Avoid Module::Build generated and utility files. \bBuild$ \bBuild.bat$ \b_build # Avoid Devel::Cover generated files \bcover_db # Avoid temp and backup files. ~$ \.tmp$ \.old$ \.bak$ \#$ \.# \.rej$ # Avoid OS-specific files/dirs # Mac OSX metadata \B\.DS_Store # Mac OSX SMB mount metadata files \B\._ # Avoid archives of this distribution \bChemistry-Formula-[\d\.\_]+ ^MYMETA.yml$ Formula/private-install0000755000175000017500000000335511370623061014530 0ustar segresegre#!/bin/sh -x ###################################################################### ## This simple shell script is a replacement for the `make install' ## stage of the standard perl module installation sequence. If you ## are installing as a private user, you do not have write access to ## the system level directories where perl wants to install modules. ## It is possible to override these locations from the command line, ## but that requires a large number of awkward command line ## arguments. In this script, I have attempted to make good guesses ## for where things should be installed. These guesses are: ## ## modules: install to the location in the PERL5LIB or PERLLIB ## environment variable ## scripts: $HOME/bin -- a reasonable guess for where a normal user ## might keep personal programs and scripts ## man pages: into this directory -- this is roughly equivalent to ## not installing the man pages. most normal users do ## not keep personal man pages ## architecture dependent files: ## the auto/ directory under PERL5LIB or PERLLIB ## ## If this doesn't work for you, just edit this file as appropriate. ###################################################################### if [ $PERL5LIB ] then PLIB=`echo $PERL5LIB | sed ' s/\([^:]*\):.*/\1/'` elif [ $PERLLIB ] then PLIB=`echo $PERLLIB | sed ' s/\([^:]*\):.*/\1/'` else echo "Neither PERL5LIB nor PERLLIB are set. Private installation halting." exit fi ./Build --install_path lib=$PLIB \ --install_path arch=$PLIB \ --install_path bin=$HOME/bin \ --install_path script=$HOME/bin \ --install_path bindoc=`pwd`/man/ \ --install_path libdoc=`pwd`/man/ \ install