Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Saving generator protons from pile-up for standard mixing and premixing #20172

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Configuration/StandardSequences/python/Digi_cff.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@
# add updating the GEN information by default
from Configuration.StandardSequences.Generator_cff import *
from GeneratorInterface.Core.generatorSmeared_cfi import *
from PhysicsTools.HepMCCandAlgos.genPUProtons_cfi import *

doAllDigi = cms.Sequence(generatorSmeared*calDigi+muonDigi)
pdigi = cms.Sequence(generatorSmeared*fixGenInfo*cms.SequencePlaceholder("randomEngineStateProducer")*cms.SequencePlaceholder("mix")*doAllDigi*addPileupInfo)
pdigi = cms.Sequence(generatorSmeared*fixGenInfo*cms.SequencePlaceholder("randomEngineStateProducer")*cms.SequencePlaceholder("mix")*doAllDigi*addPileupInfo*genPUProtons)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the new producer is needed here (which it is..) - it should be moved out of PhysicsTools. I would suggest that SimGeneral/PileupInformation is a good place for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rationale for the new plugin was that it needed to convert from HepMC particles to GenParticles, as other modules in PhysicsTools/HepMCCandAlgos.
Should both plugin and configuration fragment be moved to SimGeneral/PileupInformation or just the configuration?
Many thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its both the plugin and the config that should move - Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

pdigi_valid = cms.Sequence(pdigi)
pdigi_nogen=cms.Sequence(generatorSmeared*cms.SequencePlaceholder("randomEngineStateProducer")*cms.SequencePlaceholder("mix")*doAllDigi*addPileupInfo)
pdigi_nogen=cms.Sequence(generatorSmeared*cms.SequencePlaceholder("randomEngineStateProducer")*cms.SequencePlaceholder("mix")*doAllDigi*addPileupInfo*genPUProtons)
pdigi_valid_nogen=cms.Sequence(pdigi_nogen)

from GeneratorInterface.HiGenCommon.HeavyIon_cff import *
Expand Down
249 changes: 249 additions & 0 deletions PhysicsTools/HepMCCandAlgos/plugins/GenPUProtonProducer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
/* \class GenPUProtonProducer
*
* Modification of GenParticleProducer.
* Saves final state protons from HepMC events in Crossing Frame, in the generator-particle format.
*
* Note: Use the option USER_CXXFLAGS=-DEDM_ML_DEBUG with SCRAM in order to enable the debug messages
*
* March 9, 2017 : Initial version.
* March 14, 2017 : Updated debug messages.
* July 27, 2017 : Removed extra loop initially inherited from GenParticleProducer.
*
*/

#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
#include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h"
#include "DataFormats/HepMCCandidate/interface/GenParticle.h"
#include "FWCore/Utilities/interface/EDMException.h"

#include <vector>
#include <string>
#include <map>
#include <set>

namespace GenPUProtonProducer_utilities {

class ConvertParticle {
public:
static const int PDGCacheMax = 32768;
static constexpr double mmToCm = 0.1;

ConvertParticle() :
abortOnUnknownPDGCode_( true ),
initialized_( false ),
chargeP_( PDGCacheMax, 0 ), chargeM_( PDGCacheMax, 0 ) {};

ConvertParticle(bool abortOnUnknownPDGCode) :
abortOnUnknownPDGCode_( abortOnUnknownPDGCode ),
initialized_( false ),
chargeP_( PDGCacheMax, 0 ), chargeM_( PDGCacheMax, 0 ) {};

~ConvertParticle() {};

bool initialized() const { return initialized_; }

void init(HepPDT::ParticleDataTable const& pdt) {
if( !initialized_ ) {
for( HepPDT::ParticleDataTable::const_iterator p = pdt.begin(); p != pdt.end(); ++p ) {
HepPDT::ParticleID const& id = p->first;
int pdgId = id.pid(), apdgId = std::abs( pdgId );
int q3 = id.threeCharge();
if ( apdgId < PDGCacheMax && pdgId > 0 ) {
chargeP_[ apdgId ] = q3;
chargeM_[ apdgId ] = -q3;
} else if ( apdgId < PDGCacheMax ) {
chargeP_[ apdgId ] = -q3;
chargeM_[ apdgId ] = q3;
} else {
chargeMap_[ pdgId ] = q3;
chargeMap_[ -pdgId ] = -q3;
}
}
initialized_ = true;
}
}

bool operator() (reco::GenParticle& cand, HepMC::GenParticle const* part) {
reco::Candidate::LorentzVector p4( part->momentum() );
int pdgId = part->pdg_id();
cand.setThreeCharge( chargeTimesThree( pdgId ) );
cand.setPdgId( pdgId );
cand.setStatus( part->status() );
cand.setP4( p4 );
cand.setCollisionId(0);
HepMC::GenVertex const* v = part->production_vertex();
if ( v != 0 ) {
HepMC::ThreeVector vtx = v->point3d();
reco::Candidate::Point vertex( vtx.x() * mmToCm, vtx.y() * mmToCm, vtx.z() * mmToCm );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hi @antoniovilela - i'm (naively) surprised by the need for this unit conversion.. It does match a few other codes I find - but what is the source of these non-cmd-standard units

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the HepMC internal unit is mm, which is converted to cm for the GenParticle format. We see later that the vertex position distribution is consistent.

cand.setVertex( vertex );
} else {
cand.setVertex( reco::Candidate::Point( 0, 0, 0 ) );
}
return true;
}

private:
bool abortOnUnknownPDGCode_;
bool initialized_;
std::vector<int> chargeP_, chargeM_;
std::map<int, int> chargeMap_;

int chargeTimesThree( int id ) const {
if( std::abs( id ) < PDGCacheMax )
return id > 0 ? chargeP_[ id ] : chargeM_[ - id ];

std::map<int, int>::const_iterator f = chargeMap_.find( id );
if ( f == chargeMap_.end() ) {
if ( abortOnUnknownPDGCode_ )
throw edm::Exception( edm::errors::LogicError ) << "invalid PDG id: " << id << std::endl;
else
return HepPDT::ParticleID(id).threeCharge();
}
return f->second;
}

};

class SelectProton {
public:
bool operator() ( HepMC::GenParticle const* part, double minPz ) const {
bool selection = ( ( !part->end_vertex() && part->status() == 1 ) &&
( part->pdg_id() == 2212 ) && ( TMath::Abs( part->momentum().pz() ) >= minPz ) );
return selection;
}
};

}

#include "FWCore/Framework/interface/EDProducer.h"
#include "FWCore/Utilities/interface/InputTag.h"
#include "DataFormats/Candidate/interface/CandidateFwd.h"
#include "DataFormats/HepMCCandidate/interface/GenParticleFwd.h"

#include "SimDataFormats/CrossingFrame/interface/CrossingFrame.h"
#include "SimDataFormats/GeneratorProducts/interface/HepMCProduct.h"
#include "PhysicsTools/HepMCCandAlgos/interface/MCTruthHelper.h"
#include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h"
#include "DataFormats/HepMCCandidate/interface/GenParticle.h"

namespace edm { class ParameterSet; }

class GenPUProtonProducer : public edm::EDProducer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new legacy modules are no longer allowed.
please change to edm::stream or edm::global

public:
GenPUProtonProducer( const edm::ParameterSet & );
~GenPUProtonProducer();

virtual void produce( edm::Event& e, const edm::EventSetup&) override;
reco::GenParticleRefProd ref_;

private:
edm::EDGetTokenT<CrossingFrame<edm::HepMCProduct> > mixToken_;

bool abortOnUnknownPDGCode_;
std::vector<int> bunchList_;
double minPz_;
GenPUProtonProducer_utilities::ConvertParticle convertParticle_;
GenPUProtonProducer_utilities::SelectProton select_;

};

#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "DataFormats/Common/interface/Handle.h"
#include "FWCore/Framework/interface/ESHandle.h"
#include "FWCore/Framework/interface/Event.h"
#include "FWCore/Framework/interface/EventSetup.h"
#include "FWCore/Utilities/interface/EDMException.h"

#include "DataFormats/HepMCCandidate/interface/GenParticle.h"
#include "SimDataFormats/CrossingFrame/interface/MixCollection.h"
#include "SimGeneral/HepPDTRecord/interface/ParticleDataTable.h"

#include <algorithm>

using namespace edm;
using namespace reco;
using namespace std;
using namespace HepMC;

GenPUProtonProducer::GenPUProtonProducer( const ParameterSet & cfg ) :
abortOnUnknownPDGCode_( cfg.getUntrackedParameter<bool>( "abortOnUnknownPDGCode", true ) ),
bunchList_( cfg.getParameter<vector<int> >( "bunchCrossingList" ) ),
minPz_( cfg.getParameter<double>( "minPz" ) )
{
produces<GenParticleCollection>();
mixToken_ = consumes<CrossingFrame<HepMCProduct> >( InputTag(cfg.getParameter<std::string>( "mix" ),"generatorSmeared") );
}

GenPUProtonProducer::~GenPUProtonProducer() { }

void GenPUProtonProducer::produce( Event& evt, const EventSetup& es ) {

if ( !convertParticle_.initialized() ) {
ESHandle<HepPDT::ParticleDataTable> pdt_handle;
es.getData( pdt_handle );
HepPDT::ParticleDataTable const& pdt = *pdt_handle.product();
convertParticle_.init( pdt );
}

unsigned int totalSize = 0;
unsigned int npiles = 1;

Handle<CrossingFrame<HepMCProduct> > cf;
evt.getByToken(mixToken_,cf);
std::auto_ptr<MixCollection<HepMCProduct> > cfhepmcprod( new MixCollection<HepMCProduct>( cf.product() ) );
npiles = cfhepmcprod->size();

LogDebug("GenPUProtonProducer") << " Number of pile-up events : " << npiles << endl;

for(unsigned int icf = 0; icf < npiles; ++icf){
LogDebug("GenPUProtonProducer") << "CF " << icf << " size : " << cfhepmcprod->getObject(icf).GetEvent()->particles_size() << endl;
totalSize += cfhepmcprod->getObject(icf).GetEvent()->particles_size();
}
LogDebug("GenPUProtonProducer") << "Total size : " << totalSize << endl;

// Initialise containers
auto candsPtr = std::make_unique<GenParticleCollection>();
GenParticleCollection& cands = *candsPtr;

// Loop over pile-up events
MixCollection<HepMCProduct>::MixItr mixHepMC_itr;
unsigned int total_number_of_protons = 0;
size_t idx_mix = 0;
// Fill collection
for( mixHepMC_itr = cfhepmcprod->begin() ; mixHepMC_itr != cfhepmcprod->end() ; ++mixHepMC_itr, ++idx_mix ){
int bunch = mixHepMC_itr.bunch();

if( find( bunchList_.begin(), bunchList_.end(), bunch ) != bunchList_.end() ){

auto event = (*mixHepMC_itr).GetEvent();

size_t num_particles = event->particles_size();

// Fill output collection
unsigned int number_of_protons = 0;
for( auto p = event->particles_begin() ; p != event->particles_end() ; ++p ) {
HepMC::GenParticle const* part = *p;
if( select_(part, minPz_) ) {
reco::GenParticle cand;
convertParticle_( cand, part);
++number_of_protons;
cands.push_back( cand );
}
}
LogDebug("GenPUProtonProducer") << "Idx : " << idx_mix << " Bunch : " << bunch
<< " Number of particles : " << num_particles
<< " Number of protons : " << number_of_protons << endl;

total_number_of_protons += number_of_protons;
}
}
LogDebug("GenPUProtonProducer") << "Total number of protons : " << total_number_of_protons << endl;
LogDebug("GenPUProtonProducer") << "Output collection size : " << cands.size() << endl;

evt.put( std::move(candsPtr) );
}

#include "FWCore/Framework/interface/MakerMacros.h"

DEFINE_FWK_MODULE( GenPUProtonProducer );

7 changes: 7 additions & 0 deletions PhysicsTools/HepMCCandAlgos/python/genPUProtons_cfi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import FWCore.ParameterSet.Config as cms

genPUProtons = cms.EDProducer("GenPUProtonProducer",
mix = cms.string("mix"),
bunchCrossingList = cms.vint32(0),
minPz = cms.double( 4800. )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should these also cover

  • pA runs
  • lower energy pp runs
    • recall that the default config is still for run1 which appears to be not covered by this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right and I can change the value of "minPz" so that it is relevant for lower-energy simulated events.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the value should be changed so that either one value fits all [reasonable] data taking that we had or modified by era

)
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@
'keep GenLumiInfoHeader_generator_*_*',
'keep GenLumiInfoProduct_*_*_*',
'keep GenEventInfoProduct_generator_*_*',
'keep recoGenParticles_genPUProtons_*_*',
'keep recoGenParticles_*_genPUProtons_*',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why there are two collections?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gpetruc, @slava77
There will be only one collection saved, but there are two possible workflows:
i) Standard mixing, where the collection is saved from the 'genPUProtons' module in the DIGI sequence:
Type Module Label Process
vectorreco::GenParticle "genPUProtons" "" "HLT"

ii) Pre-mixing, where the collection is saved in the premixed sample and later copied by the DataMixingModule ('mixData'), with label 'genPUProtons':
Type Module Label Process
vectorreco::GenParticle "mixData" "genPUProtons" "DIGI2RAW"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these can/should be changed to be an EDAlias so that the only saved branches are recoGenParticles_genPUProtons

See examples in SimGeneral/MixingModule/python/aliases_PreMix_cfi.py
it will be something like this (perhaps for both mix and mixData)

genPUProtons = cms.EDAlias(
    mixData = cms.VPSet(cms.PSet(
        type = cms.string('recoGenParticles')
    ))
)

I tried this in 250202.17 (premix) and it worked:

  • default: recoGenParticles_mixData_genPUProtons_HLT.
  • with the modification (and keep of only recoGenParticles_genPUProtons__*) : recoGenParticles_genPUProtons_genPUProtons_HLT

# RUN
'keep LHERunInfoProduct_*_*_*',
'keep GenRunInfoProduct_*_*_*',
Expand Down
12 changes: 9 additions & 3 deletions SimGeneral/Configuration/python/SimGeneral_EventContent_cff.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,23 @@
outputCommands = cms.untracked.vstring('keep CrossingFramePlaybackInfoNew_*_*_*',
'keep PileupSummaryInfos_*_*_*',
'keep int6stdbitsetstdpairs_*_AffectedAPVList_*',
'keep int_*_bunchSpacing_*')
'keep int_*_bunchSpacing_*',
'keep *_genPUProtons*_*_*',
'keep *_*_genPUProtons*_*')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these *_*_genPUProtons can be removed after EDAlias is in place

)
#RECO content
SimGeneralRECO = cms.PSet(
outputCommands = cms.untracked.vstring('keep PileupSummaryInfos_*_*_*',
'keep int_*_bunchSpacing_*')
'keep int_*_bunchSpacing_*',
'keep *_genPUProtons*_*_*',
'keep *_*_genPUProtons*_*')
)
#AOD content
SimGeneralAOD = cms.PSet(
outputCommands = cms.untracked.vstring('keep PileupSummaryInfos_*_*_*',
'keep int_*_bunchSpacing_*')
'keep int_*_bunchSpacing_*',
'keep *_genPUProtons*_*_*',
'keep *_*_genPUProtons*_*')
)

# mods for HGCAL
Expand Down
1 change: 1 addition & 0 deletions SimGeneral/DataMixingModule/plugins/BuildFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<use name="DataFormats/SiPixelDigi"/>
<use name="DataFormats/SiStripDigi"/>
<use name="DataFormats/TrackReco"/>
<use name="DataFormats/HepMCCandidate"/>
<use name="FWCore/Framework"/>
<use name="FWCore/MessageLogger"/>
<use name="FWCore/ParameterSet"/>
Expand Down
8 changes: 8 additions & 0 deletions SimGeneral/DataMixingModule/plugins/DataMixingModule.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
//
//
#include "SimDataFormats/CrossingFrame/interface/CrossingFramePlaybackInfoNew.h"
#include "DataFormats/HepMCCandidate/interface/GenParticle.h"
#include "DataMixingModule.h"
#include "SimGeneral/MixingModule/interface/PileUpEventPrincipal.h"

Expand Down Expand Up @@ -235,6 +236,13 @@ namespace edm
produces< int >("bunchSpacing");
produces<CrossingFramePlaybackInfoNew>();

std::vector<edm::InputTag> GenPUProtonsInputTags;
if( ps.exists("GenPUProtonsInputTags") )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be made a standard parameter in all relevant configs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The data mixing is needed when running premixing, for which I have updated as part of this PR the configuration at:
SimGeneral/DataMixingModule/python/mixOne_simraw_on_sim_cfi.py
I could update similarly the configuration at:
​SimGeneral/​DataMixingModule/​python/​mixOne_sim_on_sim_cfi.py
Could you point me to which workflow uses it (so I can run a basic test)?
The other two files with configurations for "data on data" and "data on sim" do not apply in this case.
Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you point me to which workflow uses it

I don't know offhand; git grep can help.

if( ps.exists use should be avoided

GenPUProtonsInputTags = ps.getParameter<std::vector<edm::InputTag> >("GenPUProtonsInputTags");
for(std::vector<edm::InputTag>::const_iterator it_InputTag = GenPUProtonsInputTags.begin();
it_InputTag != GenPUProtonsInputTags.end(); ++it_InputTag)
produces< std::vector<reco::GenParticle> >( it_InputTag->label() );

PUWorker_ = new DataMixingPileupCopy(ps, consumesCollector());
}

Expand Down
27 changes: 27 additions & 0 deletions SimGeneral/DataMixingModule/plugins/DataMixingPileupCopy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "DataFormats/Common/interface/Handle.h"
#include "DataFormats/Provenance/interface/Provenance.h"
#include "DataFormats/Provenance/interface/BranchDescription.h"

#include "DataFormats/HepMCCandidate/interface/GenParticle.h"
//
//
#include "DataMixingPileupCopy.h"
Expand All @@ -38,6 +40,8 @@ namespace edm
BunchSpacingInputTag_ = ps.getParameter<edm::InputTag>("BunchSpacingInputTag");
CFPlaybackInputTag_ = ps.getParameter<edm::InputTag>("CFPlaybackInputTag");

if( ps.exists("GenPUProtonsInputTags") )
GenPUProtonsInputTags_ = ps.getParameter<std::vector<edm::InputTag> >("GenPUProtonsInputTags");

// apparently, we don't need consumes from Secondary input stream
//iC.consumes<std::vector<PileupSummaryInfo>>(PileupInfoInputTag_);
Expand Down Expand Up @@ -77,6 +81,17 @@ namespace edm
bsStorage_=10000;
}

// Gen. PU protons
std::shared_ptr<edm::Wrapper<std::vector<reco::GenParticle> > const> GenPUProtonsPTR;
for(std::vector<edm::InputTag>::const_iterator it_InputTag = GenPUProtonsInputTags_.begin();
it_InputTag != GenPUProtonsInputTags_.end(); ++it_InputTag){
GenPUProtonsPTR = getProductByTag<std::vector<reco::GenParticle> >( *ep, *it_InputTag , mcc);
if( GenPUProtonsPTR != nullptr ){
GenPUProtons_.push_back( *( GenPUProtonsPTR->product() ) );
GenPUProtons_labels_.push_back( it_InputTag->label() );
} else edm::LogWarning("DataMixingPileupCopy") << "Missing product with label: " << ( *it_InputTag ).label();
}

// Playback
std::shared_ptr<Wrapper<CrossingFramePlaybackInfoNew> const> PlaybackPTR =
getProductByTag<CrossingFramePlaybackInfoNew>(*ep,CFPlaybackInputTag_, mcc);
Expand Down Expand Up @@ -105,7 +120,19 @@ namespace edm
e.put(std::move(PSIVector));
e.put(std::move(bsInt),"bunchSpacing");

// Gen. PU protons
for(size_t idx = 0; idx < GenPUProtons_.size(); ++idx){
std::unique_ptr<std::vector<reco::GenParticle> > GenPUProtons_ptr( new std::vector<reco::GenParticle>() );
std::vector<reco::GenParticle>::const_iterator it_GenParticle = GenPUProtons_.at(idx).begin();
std::vector<reco::GenParticle>::const_iterator it_GenParticle_end = GenPUProtons_.at(idx).end();
for(; it_GenParticle != it_GenParticle_end; ++ it_GenParticle) GenPUProtons_ptr->push_back( *it_GenParticle );

e.put( std::move(GenPUProtons_ptr), GenPUProtons_labels_.at(idx) );
}

// clear local storage after this event
PileupSummaryStorage_.clear();
GenPUProtons_.clear();
GenPUProtons_labels_.clear();
}
} //edm
Loading