#!/usr/bin/perl -w
################################################################################
# merge.pl
# Richard Corke (richard.corke@thep.lu.se)
#
# Changed structure to not read entire files into memory
#
# Based on merge.pl v1.2 by Michel Herquet (UCL-CP3)
# DESCRIPTION : script to merge to LHE events files
# USAGE :
# ./merge.pl eventfile1.lhe.gz eventfile2.lhe.gz ... result.lhe.gz banner.txt
# Note that result can be eventfile1, eventfile2, ...
# OUTPUT : merged file, banner
################################################################################
use Compress::Zlib;
use List::Util qw[min max];
###########################################################################
# Initialisation
###########################################################################
# Set tag names for later
my $begin_header = '';
my $begin_event = '';
my $end_event = '';
my $begin_init = '';
my $end_init = '';
# Parse the command line arguments
if ( $#ARGV < 2 ) {
die "This script must be called with at least three filenames as arguments!\n";
}
my $bannerfile = pop(@ARGV);
my $outfile = pop(@ARGV);
###########################################################################
# First pass - extract number of events and cross-sections
###########################################################################
foreach $infile (@ARGV) {
$gzin = gzopen($infile, "r") || die ("Couldn't open file $infile\n");
# No. events and cross-section from current file
$noevents = $xsec = -1;
# Storage for current file's init block
@gzinit = ();
# Keep track if we are in the init block or not
$initblock = 0;
# LHE version extracted from current file ; 1 by default
$lhe_version = 1.0;
while (1) {
$gzbytes = $gzin->gzreadline($gzline);
if ($gzbytes == -1) { die("Error reading from file $infile\n"); }
if ($gzbytes == 0) { last; }
# Extract information and lhe_version
if ($initblock == 0) {
if ($gzline =~ s/# Number of Events\s*:\s*(.*)\n/$1/) { $noevents = $gzline; }
if ($gzline =~ s/# Integrated weight \(pb\)\s*:\s*(.*)\n/$1/) { $xsec = $gzline; }
#if ($gzline =~ s/\s*(.*)\s*=\s*lhe_version.*\n/$1/) { $lhe_version = $gzline; }
if ($gzline =~ s//$1/) { $lhe_version = $gzline; }
# Check if we enter block
if ($gzline =~ m/$begin_init/) { $initblock++; next; }
# Extract information
} else {
# Check for end of block
if ($gzline =~ m/$end_init/) { last; }
# Remove leading whitespace and split
$gzline =~ s/^\s+//;
@gzparam = split(/\s+/, $gzline);
# Skip the block introduced in LHE version 3
if ($lhe_version >= 3 && $gzline =~ m/ block line has right no. of entries
if ($initblock == 1) {
if ($#gzparam != 9) { die "Not right number of params in init"; }
} else {
if ($#gzparam != 3) { die "Not right number of params in init"; }
}
push(@gzinit, [ @gzparam ]);
$initblock++;
}
}
$gzin->gzclose();
# Check the file contained all the information we need
if ($noevents == -1 || $xsec == -1) {
die("Couldn't extract No. Events / Cross-section from $infile")
}
# Store information for later
push(@infiles, [ $infile, $noevents, $xsec, [ @gzinit ], $lhe_version ]);
}
###########################################################################
# Check/compute cross-sections, totals and unit weight
###########################################################################
$oldxsec = $infiles[0][2];
@oldinit = ($infiles[0][3][0]);
$oldlhe_version = $infiles[0][4];
# Form a composite init block by including any subprocess that
# is present for any of the files. Take the first occurance
# of the subprocess from all the files.
my %uniqentries;
my $genblock;
foreach $infile (@infiles) {
for($i=1; $i < scalar(@{$infile->[3]}); $i++) {
if ($infile->[3][$i] =~ /^[3][$i];
next;
}
# Important to take first entry, as this is treated
# differently in the next loop
elsif (!exists $uniqentries{$infile->[3][$i][3]}) {
$uniqentries{$infile->[3][$i][3]} = $infile->[3][$i];
}
}
}
# Maintain MadGraph's convention of reverse sorting by LPRUP
my @initentry = reverse sort { $a->[3] <=> $b->[3] } values %uniqentries;
push(@oldinit, @initentry);
push(@oldinit, $genblock);
$totevents = 0; $totxsec = 0.0;
foreach $infile (@infiles) {
print "Input file: $infile->[0]\n";
print " No. Events = $infile->[1], Cross-section = $infile->[2], LHE version = $infile->[4]\n";
# Check that cross sections do not differ too much
$newxsec = $infile->[2];
if (abs(($newxsec - $oldxsec) / $newxsec) > 0.05 ) {
print " WARNING Cross sections do not agree with a 5\% precision!\n";
}
$oldxsec = $newxsec;
$curlhe_version = $infile->[4];
if (abs($curlhe_version - $oldlhe_version) > 0.001) {
die("LHE version does not match");
}
@currinit = @{$infile->[3]};
# Same number of entries on first line of block?
if ($#{$oldinit[0]} != $#{$currinit[0]}) { die("Init blocks do not match"); }
# Create new init block (overwrite first file's init block data)
for ($i = 1; $i <= $#oldinit; $i++) {
# Match entry in init block based on LPRUP
my @matchingsubprocess = ();
if ($oldinit[$i] =~ /^[1];
$oldinit[$i][1] *= $oldinit[$i][1] * $infile->[1]**2;
} else {
$oldinit[$i][0] += ($matchingsubprocess[0] * $infile->[1]);
$oldinit[$i][1] += $matchingsubprocess[1]**2 * $infile->[1]**2;
}
# XMAXUP = max(xmaxup)
$oldinit[$i][2] = max($oldinit[$i][2], $matchingsubprocess[2]);
}
# Total number of events and total cross-section
$totevents += $infile->[1];
$totxsec += ($infile->[1] * $infile->[2]);
print "\n";
}
print "\n";
# Finish calculation of XSECUP and XERRUP
for ($i = 1; $i <= $#oldinit; $i++) {
if ($oldinit[$i] =~ /^$bannerfile") || die ("Couldn't open file $outfile\n");
$stage = 0;
$eventcount = 0;
foreach $infile (@infiles) {
$gzin = gzopen($infile->[0], "r") || die ("Couldn't open file $infile\n");
while (1) {
$gzbytes = $gzin->gzreadline($gzline);
if ($gzbytes == -1) { die("Error reading from file $infile\n"); }
if ($gzbytes == 0) { last; }
# Pre-header
if ($stage == 0) {
if ($gzline =~ m/$begin_header/) { $stage++; }
# Header (and output to banner)
} elsif ($stage == 1) {
$gzline =~ s/# Integrated weight \(pb\)\s*:(.*)\n/# Integrated weight (pb) : $dispxsec\n/;
$gzline =~ s/# Number of Events\s*:(.*)\n/# Number of Events : $totevents\n/;
$gzline =~ s/# Unit wgt\s*:(.*)\n/# Unit wgt : $uwgt\n/;
if ($gzline =~ m/$end_header/) { $stage++; }
else { print BANNER $gzline; }
# Init block
} elsif ($stage == 2) {
if ($gzline =~ m/$end_init/) {
$gzline = "\n";
for ($i = 0; $i <= $#oldinit; $i++) {
if ($oldinit[$i] =~ /^gzwrite($gzline);
}
}
# Write out closing tag and close
$gzout->gzwrite("\n");
$gzout->gzclose();
print "Wrote $eventcount events\n";
exit(0);