1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
package Demeter::Plugins::X15B; # -*- cperl -*-
use File::Basename;
use Moose;
extends 'Demeter::Plugins::FileType';
has '+is_binary' => (default => 1);
has '+description' => (default => "NSLS beamline X15B");
has '+version' => (default => 0.1);
has '+metadata_ini' => (default => File::Spec->catfile(File::Basename::dirname($INC{'Demeter.pm'}), 'Demeter', 'share', 'xdi', 'x15b.ini'));
use Const::Fast;
const my $INIFILE => 'x15b.demeter_conf';
has '+conffile' => (default => File::Spec->catfile(dirname($INC{'Demeter.pm'}), 'Demeter', 'Plugins', $INIFILE));
Demeter -> co -> read_config(File::Spec->catfile(dirname($INC{'Demeter.pm'}), 'Demeter', 'Plugins', $INIFILE));
#const my $ENERGY => 0; # columns containing the
#const my $I0 => 6; # relevant scalars
#const my $NARROW => 8;
#const my $WIDE => 9;
#const my $TRANS => 10;
sub is {
my ($self) = @_;
my $Ocircumflex = chr(212);
my $nulls = chr(0).chr(0).chr(0);
open D, $self->file or $self->Croak("could not open " . $self->file . " as data (X15B)\n");
binmode D;
my $first = <D>;
close D;
return 1 if ($first =~ /^$Ocircumflex$nulls/);
return 0;
};
sub fix {
my ($self) = @_;
my $new = File::Spec->catfile($self->stash_folder, $self->filename);
($new = File::Spec->catfile($self->stash_folder, "toss")) if (length($new) > 127);
my @columns = (Demeter->co->default("x15b", "energy") - 1,
Demeter->co->default("x15b", "i0") - 1,
Demeter->co->default("x15b", "narrow") - 1,
Demeter->co->default("x15b", "wide") - 1,
Demeter->co->default("x15b", "trans") - 1);
my @blob = ();
my $file = $self->file;
## slurp the entire binary file into an array of 4-byte floats
do {
local $/ = undef;
open D, $file or die "could not read $file as data (fix in X15B)\n";
@blob = unpack("f*", <D>);
close D
};
open N, ">".$new or die "could not write to $new (fix in X15B)\n";
## the header is mysterious, but the project name from scanedit is
## in there, so pull that out as text (pack and unpack process this
## mysterious header as text)
my @header = ();
foreach (1..53) {
push @header, shift @blob;
};
my $string = pack("f*", @header);
my $project = "??";
foreach (unpack("A*", $string)) {
$project = "$1 $2" if (/(\w+)\s+(\d+\/\d+\/\d+)/);
};
print N <<EOH
# X15B project: $project
# original file: $file
# unpacked from original data as a sequence of 4-byte floats
# --------------------------------------------------------------------
# energy I0 narrow wide trans
EOH
;
## just pull out the relevant columns. we are only reading the
## energy, i0, the narrow and wide windows from the Ge detector, and
## the transmission ion chmaber. All other scalars are presumed
## uninteresting. The indeces of these scalars in the line are
## defined as constants (see above).
while (@blob) {
shift @blob;
my @line = ();
foreach (1..15) {
push @line, shift(@blob);
};
## just write out the relevant lines
printf N " %12.4f %12.4f %12.4f %12.4f %12.4f\n",
@line[@columns];
#@line[$ENERGY, $I0, $NARROW, $WIDE, $TRANS];
}; # loop over rows of data
close N;
$self->fixed($new);
return $new;
}
sub suggest {
my ($self, $which) = @_;
$which ||= 'fluorescence';
if ($which eq 'transmission') {
return (energy => '$1',
numerator => '$2',
denominator => '$5',
ln => 1,);
} else {
return (energy => '$1',
numerator => '$3',
denominator => '$2',
ln => 0,);
};
};
__PACKAGE__->meta->make_immutable;
1;
__END__
=head1 NAME
Demeter::Plugin::X15B - NSLS X15B filetype plugin
=head1 VERSION
This documentation refers to Demeter version 0.9.26.
=head1 SYNOPSIS
This plugin directly reads the binary files written by NSLS beamline
X15B.
=head1 X15B files
At X15b there is a program called x15totxt, written in Turbo Pascal by
some dude named Tim Darling. He kindly left behind a short
explanation the format of the X15b binary data file. It seems that
the header is 53 4-byte numbers. Each line of data contains 16 4 byte
numbers. Thus this file is easily unpacked and processed in four byte
bites.
The X15B file is recognized by a a four character sequence at the
beginning of the file which consists of character 212 (capital
O-circumflex in ISO 8859) followed by three nulls (character 0).
The resulting file is a well-labeled, well-formatted column data file
in a form that will work well with Athena or virtually any other
analysis or plotting program. The columns are: energy, the I0 ion
chamber, the narrow and wide windows on the germanium detector, and
the transmission ion chamber.
=head1 CONFIGURATION
Only the relevant columns from the original data file are passed along
to the output ascii file. These column numbers can be configured in
the F<x15b.demeter_conf> file or via Athena's project registry
configuration interface.
=head1 AUTHOR
Bruce Ravel, L<http://bruceravel.github.io/home>
http://bruceravel.github.io/demeter
=cut
|