#!/usr/bin/perl -w
######################################################################
##  This program is copyright (c) 2001 Bruce Ravel
##  <ravel@phys.washington.edu>
##  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.
## -------------------------------------------------------------------
######################################################################

use Xray::Absorption;
Xray::Absorption -> load("elam");
use Chemistry::Formula qw(parse_formula formula_data);
use strict;

(@ARGV) or &usage;
($ARGV[0] =~ /-{1,2}h(elp)?/i) and &usage;

use Getopt::Std;
use vars qw(%opt);
$opt{o} = "";
getopts('ld:e:f:', \%opt);

my (%count, $string);
my $energy  = $opt{e} || 0;
my $density = $opt{d} || 0;
if ($opt{f}||$opt{l}) {
  my (%formula, %density);
  &formula_data(\%formula, \%density);
  if ($opt{l}) {
    print "Known formulas:\n\n";
    printf " %-15s %-30s %-s\n", 'name', 'formula', 'density';
    print '-' x 70, $/;
    foreach my $f (sort (keys %formula)) {
      printf " %-15s %-30s %-s\n", $f, $formula{$f}, $density{$f};
    };
    exit;
  };
  ($formula{$opt{f}}) or die "\"$opt{f}\" is not a known material\n";
  $string  = $formula{$opt{f}};
  $density = $density{$opt{f}};
} else {
  $string = $ARGV[0];
};
($energy > 0) or $density = 0;
my $ok = parse_formula($string, \%count);
my $dens = ($density =~ /^(\d+\.?\d*|\.\d+)$/) ? $density : 0;

($ok) or do {
  print "Input error:\n\t$count{error}";
  die "\n";
};

print <<EOH;

Input string: "$string"

  element     number
 ---------   --------
EOH
my ($weight, $xsec) = (0,0);
my ($barns_per_formula_unit, $amu_per_formula_unit) = (0,0);
foreach my $k (sort (keys(%count))) {
  $barns_per_formula_unit += Xray::Absorption -> cross_section($k, $energy) * $count{$k};
  $amu_per_formula_unit += Xray::Absorption -> get_atomic_weight($k) * $count{$k};
  if ($count{$k} > 0.001) {
    printf("    %-2s        %.3f\n", $k, $count{$k});
  } else {
    printf("    %-2s        %g\n", $k, $count{$k});
  };
};
## 1 amu = 1.6607143 x 10^-24 gm
$xsec = $barns_per_formula_unit / $amu_per_formula_unit / 1.6607143;
printf "\nThis weighs %.3f amu.\n", $amu_per_formula_unit;
if ($xsec == 0) {
  print "(Energy too low or not provided.  Absorption calculation skipped.)\n";
} else {
  $xsec *= $dens;
  if ($xsec > 0) {
    if (10000/$xsec > 500) {
      printf("Absorbtion length = %.3f cm at %.2f eV.\n", 1/$xsec, $energy);
    } else {
      printf("Absorbtion length = %.1f microns at %.2f eV.\n", 10000/$xsec, $energy);
    };
  } else {
    print "(The absorption length calculation requires a value for density.)";
  };
};

sub usage {
  print <<EOH;
 Enumerate chemical formulas and compute absorption length

 usage:
   formula -e # -d # <string> // formula, energy, and density supplied
   formula -e # -f <string>   // use a known formula
   formula -l                 // list of known materials
   formula -h                 // this message

EOH
  exit;
};
