#!/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 $end_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);