package Util::Xspec;
##############################################################################
#
# DESCRIPTION: This Xanadu subclass adds functionality specific to xspec
# DESCRIPTION: specifically a method to extract the results of model fits.
#
# HISTORY
# HISTORY: $Log: Xspec.pm,v $
# HISTORY: Revision 1.3 2014/02/27 07:01:07 apsop
# HISTORY: VERSION header now shows CVS Revision
# HISTORY:
# HISTORY: Revision 1.2 2006/08/01 20:35:34 apsop
# HISTORY: Add in CVS history indicator.
# HISTORY:
# HISTORY: 1.0 -> 1.1 2002-04-01
# HISTORY: Now allows an Xserver display to be specified when initializing
# HISTORY:
# HISTORY: 1.1 -> 1.2 2003-05-16
# HISTORY: Added more methods for parsing chi-squared and flux from stdout.
#
# VERSION: $Revision: 1.3 $
#
##############################################################################
use Util::Xanadu;
@ISA=("Util::Xanadu");
use strict;
sub new {
my $self=shift;
return $self->SUPER::new("xspec");
}
##############################################################################
# parse the results of a model fit.
# returns a list of hash references. There is one hash per model parameter.
# The keys to the hash are as follows:
# FIT - the number of the model fit - more than one "fit" command can be given
# in a single xspec session.
# COMPONENT - the model component number as assigned by xspec
# MODEL - the name of the xspec model for which this is a component.
# PARAM - the name of the parameter within the model
# VALUE - the best fit value
# ERROR - an estimate for the error in the best fit value. Note that
# these values are estimated from the second derivative of
# chi-squared at the minimum and are not as reliable as errors
# derived from an exploration of chi-squared space around the
# minimum.
#
##############################################################################
sub fit_results {
my $self = shift;
############################
# get the stdout text
############################
my $text = $self->stdout();
###############################################
# split by commands and their following text
###############################################
my @commands = split /^[\s!]*XSPEC>\s*/m, $text;
#############################
# loop over all fit commands
#############################
my @results=();
my $fit_number=0;
my $fit;
foreach $fit (grep /^fit/, @commands) {
#############################################################
# pull out the fit results these are offset by dashed lines
#############################################################
my ($result) = $fit =~ /^\s*-+\s*^\s*-+\s*^(.*)^\s*-+\s*^\s*-+\s*$/sm;
#########################################################
# split the results into lines and select the numbered
# lines since these are the parameters
#########################################################
my @lines = split /\n/, $result;
@lines = grep /^\s*[1-9]/, @lines;
###################################
# loop over lines parsing each one
###################################
foreach (@lines) {
my @fields = split;
my $record = {};
$record->{FIT} = $fit_number;
$record->{COMPONENT} = $fields[2];
$record->{MODEL} = $fields[3];
$record->{PARAM} = $fields[4];
$record->{VALUE} = $fields[@fields-3];
$record->{ERROR} = $fields[@fields-1];
push @results, ($record);
} # end of loop over parameters
$fit_number++;
} # end of loop over fits
return @results;
} # end of fit_results method
##############################################################################
#
##############################################################################
sub chi_squared {
my $self = shift;
############################
# get the stdout text
############################
my $text = $self->stdout();
###############################################
# split by commands and their following text
###############################################
my @commands = split /^[\s!]*XSPEC>\s*/m, $text;
#############################
# loop over all fit commands
#############################
my @results=();
my $fit_number=0;
my $fit;
foreach $fit (grep /^fit/, @commands) {
my $record={};
$record->{FIT} = $fit_number++;
my ($chi2) = $fit =~ /Chi-Squared =\s+([^\s]+)/;
my ($reduced) = $fit =~ /Reduced chi-squared =\s+([^\s]+)/;
my ($prob) = $fit =~ /Null hypothesis probability =\s+([^\s]+)/;
my ($dof) = $fit =~ /(\d+) degrees of freedom/;
$record->{CHI2} = $chi2;
$record->{REDUCED_CHI2}= $reduced;
$record->{PROBABILITY} = $prob;
$record->{FREEDOM} = $dof;
#print "chi2=$chi2 reduced=$reduced dof=$dof prob=$prob\n";
push @results, ($record);
} # end of loop over fit commands
return @results;
} # end of chi_squared method
##############################################################################
#
##############################################################################
sub flux {
my $self = shift;
############################
# get the stdout text
############################
my $text = $self->stdout();
###############################################
# split by commands and their following text
###############################################
my @commands = split /^[\s!]*XSPEC>\s*/m, $text;
#############################
# loop over all fit commands
#############################
my @results=();
my $fit_number=0;
foreach my $fit (grep /^flux/, @commands) {
my $record={};
my ($photons) = $fit =~ /([^\s]+)\s+photons/;
my ($ergs) = $fit =~ /([^\s]+)\s+ergs/;
my @errors = $fit =~
/Error range\s+([^\s]+)\s+-\s+([^\s]+)\s+\(\s*([^\s]+)\s+-\s+([^\s]+)\s*\)/;
$record->{FIT} = $fit_number++;
$record->{PHOTONS} = $photons;
$record->{ERGS} = $ergs;
$record->{PHOTONS_LO} = shift @errors;
$record->{PHOTONS_HI} = shift @errors;
$record->{ERGS_LO} = shift @errors;
$record->{ERGS_HI} = shift @errors;
push @results, ($record);
}
return @results;
} # end of flux command
sub DESTROY {
my $self = shift;
# check for an overridden destructor...
$self->SUPER::DESTROY if $self->can("SUPER::DESTROY");
}
1;